Okay, the attachment isn't coming through, so here it is inline:
L.Browser.svg = !!(document.createElementNS && document.createElementNS(L.Path.SVG_NS, 'svg').createSVGRect);
L.SvgPath = L.Class.extend({
// first all the Path Stuff
includes: [L.Mixin.Events],
statics: {
CLIP_PADDING: 0.5,
SVG: L.Browser.svg,
_createElement: function (name) {
return document.createElementNS(L.Path.SVG_NS, name);
}
},
options: {
stroke: true,
color: '#0033ff',
weight: 5,
opacity: 0.5,
fill: false,
fillColor: null, //same as color by default
fillOpacity: 0.2,
clickable: true,
// TODO remove this, as all paths now update on moveend
updateOnMoveEnd: true
},
initialize: function (options) {
L.Util.setOptions(this, options);
},
onAdd: function (map) {
this._map = map;
this._initElements();
this._initEvents();
this.projectLatlngs();
this._updatePath();
map.on('viewreset', this.projectLatlngs, this);
this._updateTrigger = this.options.updateOnMoveEnd ? 'moveend' : 'viewreset';
map.on(this._updateTrigger, this._updatePath, this);
},
onRemove: function (map) {
this._map = null;
map._pathRoot.removeChild(this._container);
map.off('viewreset', this.projectLatlngs, this);
map.off(this._updateTrigger, this._updatePath, this);
},
projectLatlngs: function () {
// do all projection stuff here
},
setStyle: function (style) {
L.Util.setOptions(this, style);
if (this._container) {
this._updateStyle();
}
return this;
},
_redraw: function () {
if (this._map) {
this.projectLatlngs();
this._updatePath();
}
},
// now all the non-overridden methods from Path.SVG
getPathString: function () {
// form path string here
},
_initElements: function () {
this._map._initPathRoot();
this._initPath();
this._initStyle();
},
_initPath: function () {
this._container = L.SvgPath._createElement('g');
this._path = L.SvgPath._createElement('circle');
this._label = L.SvgPath._createElement('text');
this._mask = L.SvgPath._createElement('rect');
this._container.appendChild(this._path);
this._container.appendChild(this._label);
this._container.appendChild(this._mask);
this._map._pathRoot.appendChild(this._container);
},
_initStyle: function () {
if (this.options.stroke) {
this._path.setAttribute('stroke-linejoin', 'round');
this._path.setAttribute('stroke-linecap', 'round');
}
if (this.options.fill) {
this._path.setAttribute('fill-rule', 'evenodd');
} else {
this._path.setAttribute('fill', 'none');
}
this._updateStyle();
},
_updateStyle: function () {
if (this.options.stroke) {
this._path.setAttribute('stroke', this.options.color);
this._path.setAttribute('stroke-opacity', this.options.opacity);
this._path.setAttribute('stroke-width', this.options.weight);
}
if (this.options.fill) {
this._path.setAttribute('fill', this.options.fillColor || this.options.color);
this._path.setAttribute('fill-opacity', this.options.fillOpacity);
}
if (this.options.radius) {
this._path.setAttribute('r', this.options.radius);
}
if (this.options.label) {
this._label.textContent = this.options.label;
this._label.setAttribute("text-anchor", this.options.textAnchor);
this._label.setAttribute("font-family", this.options.fontFamily);
this._label.setAttribute("font-size", this.options.fontSize + "px");
this._label.setAttribute("font-weight", this.options.fontWeight);
this._label.setAttribute("stroke", this.options.labelStrokeColor);
this._label.setAttribute("fill", this.options.labelFillColor);
}
},
_updatePath: function () {
if (this._point) {
this._path.setAttribute("cx", this._point.x);
this._path.setAttribute("cy", this._point.y);
}
if (this._label) {
// set label's position
var y = this._point.y + (this.options.fontSize / 4) + this.options.yOffset;
this._label.setAttribute("x", this._point.x + this.options.xOffset);
this._label.setAttribute("y", y);
// set mask's position
var maskX = this._point.x - this.options.radius;
var maskY = this._point.y - this.options.radius;
this._mask.setAttribute("x", maskX);
this._mask.setAttribute("y", maskY);
this._mask.setAttribute("width", this.options.radius * 2);
this._mask.setAttribute("height", this.options.radius * 2);
this._mask.setAttribute("opacity", 0);
}
},
_initEvents: function () {
if (this.options.clickable) {
if (!L.Browser.vml) {
this._path.setAttribute('class', 'leaflet-clickable');
}
L.DomEvent.addListener(this._container, 'click', this._onMouseClick, this);
var events = ['dblclick', 'mousedown', 'mouseover', 'mouseout', 'mousemove'];
for (var i = 0; i < events.length; i++) {
L.DomEvent.addListener(this._container, events[i], this._fireMouseEvent, this);
}
}
},
_onMouseClick: function (e) {
if (this._map.dragging && this._map.dragging.moved()) {
return;
}
this._fireMouseEvent(e);
},
_fireMouseEvent: function (e) {
if (!this.hasEventListeners(e.type)) {
return;
}
this.fire(e.type, {
latlng: this._map.mouseEventToLatLng(e),
layerPoint: this._map.mouseEventToLayerPoint(e)
});
L.DomEvent.stopPropagation(e);
},
updateLabelText: function (newLabelText) {
this.options.label = newLabelText;
this._updateStyle();
},
updateCircle: function (circleOptions) {
L.Util.setOptions(this, circleOptions);
this._updatePath();
this._updateStyle();
}
});
L.Map.include({
_updatePathViewport: function () {
var p = L.Path.CLIP_PADDING,
size = this.getSize(),
//TODO this._map._getMapPanePos()
panePos = L.DomUtil.getPosition(this._mapPane),
min = panePos.multiplyBy(-1).subtract(size.multiplyBy(p)),
max = min.add(size.multiplyBy(1 + p * 2));
this._pathViewport = new L.Bounds(min, max);
}
});
L.LabeledCircle = L.SvgPath.extend({
initialize: function (latlng, radius, options) {
L.Path.prototype.initialize.call(this, options);
this._latlng = latlng;
this._mRadius = radius;
},
options: {
fill: true,
label: "hola",
xOffset: 0,
yOffset: 0,
textAnchor: "middle",
fontFamily: "Arial",
fontSize: "12",
fontWeight: "bold",
labelStrokeColor: "white",
labelFillColor: "white"
},
setLatLng: function (latlng) {
this._latlng = latlng;
this._redraw();
return this;
},
setRadius: function (radius) {
this._mRadius = radius;
this._redraw();
return this;
},
projectLatlngs: function () {
var equatorLength = 40075017,
hLength = equatorLength * Math.cos(L.LatLng.DEG_TO_RAD * this._latlng.lat);
var lngSpan = (this._mRadius / hLength) * 360,
latlng2 = new L.LatLng(this._latlng.lat, this._latlng.lng - lngSpan, true),
point2 = this._map.latLngToLayerPoint(latlng2);
this._point = this._map.latLngToLayerPoint(this._latlng);
this._radius = Math.round(this._point.x - point2.x);
},
getPathString: function () {
var p = this._point,
r = this._radius;
if (this._checkIfEmpty()) {
return '';
}
if (L.Browser.svg) {
return "M" + p.x + "," + (p.y - r) +
"A" + r + "," + r + ",0,1,1," +
(p.x - 0.1) + "," + (p.y - r) + " z";
} else {
p._round();
r = Math.round(r);
return "AL " + p.x + "," + p.y + " " + r + "," + r + " 0," + (65535 * 360);
}
},
_checkIfEmpty: function () {
var vp = this._map._pathViewport,
r = this._radius,
p = this._point;
return p.x - r > vp.max.x || p.y - r > vp.max.y ||
p.x + r < vp.min.x || p.y + r < vp.min.y;
}
});
L.LabeledCircleMarker = L.LabeledCircle.extend({
options: {
radius: 30,
weight: 2
},
initialize: function (latlng, options) {
L.LabeledCircle.prototype.initialize.call(this, latlng, null, options);
this._radius = this.options.radius;
},
projectLatlngs: function () {
this._point = this._map.latLngToLayerPoint(this._latlng);
},
setRadius: function (radius) {
this._radius = radius;
this._redraw();
return this;
}
});