//Leaflet-SVGIcon //SVG icon for any marker class //Ilya Atkin //ilya.atkin@unh.edu L.DivIcon.SVGIcon = L.DivIcon.extend({ options: { "className": "svg-icon", "circleAnchor": null, //defaults to [iconSize.x/2, iconSize.x/2] "circleColor": null, //defaults to color "circleFillColor": "rgb(255,255,255)", "circleFillOpacity": null, //default to opacity "circleImageAnchor": null, //defaults to [(iconSize.x - circleImageSize.x)/2, (iconSize.x - circleImageSize.x)/2] "circleImagePath": null, //no default, preference over circleText "circleImageSize": null, //defaults to [iconSize.x/4, iconSize.x/4] if circleImage is supplied "circleOpacity": null, // defaults to opacity "circleRatio": 0.5, "circleText": "", "circleWeight": null, //defaults to weight "color": "rgb(0,102,255)", "fillColor": null, // defaults to color "fillOpacity": 0.4, "fontColor": "rgb(0, 0, 0)", "fontOpacity": "1", "fontSize": null, // defaults to iconSize.x/4 "fontWeight": "normal", "iconAnchor": null, //defaults to [iconSize.x/2, iconSize.y] (point tip) "iconSize": L.point(32,48), "opacity": 1, "popupAnchor": null, "shadowAngle": 45, "shadowBlur": 1, "shadowColor": "rgb(0,0,10)", "shadowEnable": false, "shadowLength": .75, "shadowOpacity": 0.5, "shadowTranslate": L.point(0,0), "weight": 2 }, initialize: function(options) { options = L.Util.setOptions(this, options) //iconSize needs to be converted to a Point object if it is not passed as one options.iconSize = L.point(options.iconSize) //in addition to setting option dependant defaults, Point-based options are converted to Point objects if (!options.circleAnchor) { options.circleAnchor = L.point(Number(options.iconSize.x)/2, Number(options.iconSize.x)/2) } else { options.circleAnchor = L.point(options.circleAnchor) } if (!options.circleColor) { options.circleColor = options.color } if (!options.circleFillOpacity) { options.circleFillOpacity = options.opacity } if (!options.circleOpacity) { options.circleOpacity = options.opacity } if (!options.circleWeight) { options.circleWeight = options.weight } if (!options.fillColor) { options.fillColor = options.color } if (!options.fontSize) { options.fontSize = Number(options.iconSize.x/4) } if (!options.iconAnchor) { options.iconAnchor = L.point(Number(options.iconSize.x)/2, Number(options.iconSize.y)) } else { options.iconAnchor = L.point(options.iconAnchor) } if (!options.popupAnchor) { options.popupAnchor = L.point(0, (-0.75)*(options.iconSize.y)) } else { options.popupAnchor = L.point(options.popupAnchor) } if (options.circleImagePath && !options.circleImageSize) { options.circleImageSize = L.point(Number(options.iconSize.x)/4, Number(options.iconSize.x)/4) } else { options.circleImageSize = L.point(options.circleImageSize) } if (options.circleImagePath && !options.circleImageAnchor) { options.circleImageAnchor = L.point( (Number(options.iconSize.x) - Number(options.circleImageSize.x))/2, (Number(options.iconSize.x) - Number(options.circleImageSize.y))/2 ) } else { options.circleImageAnchor = L.point(options.circleImageAnchor) } options.html = this._createSVG() }, _createCircle: function() { var cx = Number(this.options.circleAnchor.x) var cy = Number(this.options.circleAnchor.y) var radius = this.options.iconSize.x/2 * Number(this.options.circleRatio) var fill = this.options.circleFillColor var fillOpacity = this.options.circleFillOpacity var stroke = this.options.circleColor var strokeOpacity = this.options.circleOpacity var strokeWidth = this.options.circleWeight var className = this.options.className + "-circle" var circle = '' return circle }, _createCircleImage: function() { var x = this.options.circleImageAnchor.x var y = this.options.circleImageAnchor.y var height = this.options.circleImageSize.y var width = this.options.circleImageSize.x var href = this.options.circleImagePath var image = '' return image }, _createPathDescription: function() { var height = Number(this.options.iconSize.y) var width = Number(this.options.iconSize.x) var weight = Number(this.options.weight) var margin = weight / 2 var startPoint = "M " + margin + " " + (width/2) + " " var leftLine = "L " + (width/2) + " " + (height - weight) + " " var rightLine = "L " + (width - margin) + " " + (width/2) + " " var arc = "A " + (width/4) + " " + (width/4) + " 0 0 0 " + margin + " " + (width/2) + " Z" var d = startPoint + leftLine + rightLine + arc return d }, _createPath: function() { var pathDescription = this._createPathDescription() var strokeWidth = this.options.weight var stroke = this.options.color var strokeOpacity = this.options.opacity var fill = this.options.fillColor var fillOpacity = this.options.fillOpacity var className = this.options.className + "-path" var path = '' return path }, _createShadow: function() { var pathDescription = this._createPathDescription() var strokeWidth = this.options.weight var stroke = this.options.shadowColor var fill = this.options.shadowColor var className = this.options.className + "-shadow" var origin = (this.options.iconSize.x / 2) + "px " + (this.options.iconSize.y) + "px" var rotation = this.options.shadowAngle var height = this.options.shadowLength var opacity = this.options.shadowOpacity var blur = this.options.shadowBlur var translate = this.options.shadowTranslate.x + "px, " + this.options.shadowTranslate.y + "px" var blurFilter = "" var shadow = '' return blurFilter+shadow }, _createSVG: function() { var path = this._createPath() var circle = this._createCircle() var shadow = this.options.shadowEnable ? this._createShadow() : "" var innerCircle = this.options.circleImagePath ? this._createCircleImage() : this._createText() var className = this.options.className + "-svg" var width = this.options.iconSize.x var height = this.options.iconSize.y if (this.options.shadowEnable) { width += this.options.iconSize.y * this.options.shadowLength - (this.options.iconSize.x / 2) width = Math.max(width, 32) height += this.options.iconSize.y * this.options.shadowLength } var style = "width:" + width + "px; height:" + height var svg = '' + shadow + path + circle + innerCircle + '' return svg }, _createText: function() { var fontSize = this.options.fontSize + "px" var fontWeight = this.options.fontWeight var lineHeight = Number(this.options.fontSize) var x = this.options.circleAnchor.x var y = this.options.circleAnchor.y + (lineHeight * 0.35) //35% was found experimentally var circleText = this.options.circleText var textColor = this.options.fontColor.replace("rgb(", "rgba(").replace(")", "," + this.options.fontOpacity + ")") var text = '' + circleText + '' return text } }) L.divIcon.svgIcon = function(options) { return new L.DivIcon.SVGIcon(options) } L.Marker.SVGMarker = L.Marker.extend({ options: { "iconFactory": L.divIcon.svgIcon, "iconOptions": {} }, initialize: function(latlng, options) { options = L.Util.setOptions(this, options) options.icon = options.iconFactory(options.iconOptions) this._latlng = latlng }, onAdd: function(map) { L.Marker.prototype.onAdd.call(this, map) }, setStyle: function(style) { if (this._icon) { var svg = this._icon.children[0] var iconBody = this._icon.children[0].children[0] var iconCircle = this._icon.children[0].children[1] if (style.color && !style.iconOptions) { var stroke = style.color.replace("rgb","rgba").replace(")", ","+this.options.icon.options.opacity+")") var fill = style.color.replace("rgb","rgba").replace(")", ","+this.options.icon.options.fillOpacity+")") iconBody.setAttribute("stroke", stroke) iconBody.setAttribute("fill", fill) iconCircle.setAttribute("stroke", stroke) this.options.icon.fillColor = fill this.options.icon.color = stroke this.options.icon.circleColor = stroke } if (style.opacity) { this.setOpacity(style.opacity) } if (style.iconOptions) { if (style.color) { style.iconOptions.color = style.color } var iconOptions = L.Util.setOptions(this.options.icon, style.iconOptions) this.setIcon(L.divIcon.svgIcon(iconOptions)) } } } }) L.marker.svgMarker = function(latlng, options) { return new L.Marker.SVGMarker(latlng, options) }