/* * Extends L.Path with SVG-specific rendering code. */ L.Path.SVG_NS = 'http://www.w3.org/2000/svg'; L.Browser.svg = !!(document.createElementNS && document.createElementNS(L.Path.SVG_NS, 'svg').createSVGRect); L.Path = L.Path.extend({ statics: { SVG: L.Browser.svg }, bringToFront: function () { var root = this._map._pathRoot, path = this._container; if (path && root.lastChild !== path) { root.appendChild(path); } return this; }, bringToBack: function () { var root = this._map._pathRoot, path = this._container, first = root.firstChild; if (path && first !== path) { root.insertBefore(path, first); } return this; }, getPathString: function () { // form path string here }, _createElement: function (name) { return document.createElementNS(L.Path.SVG_NS, name); }, _initElements: function () { this._map._initPathRoot(); this._initPath(); this._initStyle(); }, _initPath: function () { this._container = this._createElement('g'); this._path = this._createElement('path'); if (this.options.className) { L.DomUtil.addClass(this._path, this.options.className); } this._container.appendChild(this._path); }, _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'); } if (this.options.pointerEvents) { this._path.setAttribute('pointer-events', this.options.pointerEvents); } if (!this.options.clickable && !this.options.pointerEvents) { this._path.setAttribute('pointer-events', '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.dashArray) { this._path.setAttribute('stroke-dasharray', this.options.dashArray); } else { this._path.removeAttribute('stroke-dasharray'); } if (this.options.lineCap) { this._path.setAttribute('stroke-linecap', this.options.lineCap); } if (this.options.lineJoin) { this._path.setAttribute('stroke-linejoin', this.options.lineJoin); } } else { this._path.setAttribute('stroke', 'none'); } if (this.options.fill) { this._path.setAttribute('fill', this.options.fillColor || this.options.color); this._path.setAttribute('fill-opacity', this.options.fillOpacity); } else { this._path.setAttribute('fill', 'none'); } }, _updatePath: function () { var str = this.getPathString(); if (!str) { // fix webkit empty string parsing bug str = 'M0 0'; } this._path.setAttribute('d', str); }, // TODO remove duplication with L.Map _initEvents: function () { if (this.options.clickable) { if (L.Browser.svg || !L.Browser.vml) { L.DomUtil.addClass(this._path, 'leaflet-clickable'); } L.DomEvent.on(this._container, 'click', this._onMouseClick, this); var events = ['dblclick', 'mousedown', 'mouseover', 'mouseout', 'mousemove', 'contextmenu']; for (var i = 0; i < events.length; i++) { L.DomEvent.on(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._map || !this.hasEventListeners(e.type)) { return; } var map = this._map, containerPoint = map.mouseEventToContainerPoint(e), layerPoint = map.containerPointToLayerPoint(containerPoint), latlng = map.layerPointToLatLng(layerPoint); this.fire(e.type, { latlng: latlng, layerPoint: layerPoint, containerPoint: containerPoint, originalEvent: e }); if (e.type === 'contextmenu') { L.DomEvent.preventDefault(e); } if (e.type !== 'mousemove') { L.DomEvent.stopPropagation(e); } } }); L.Map.include({ _initPathRoot: function () { if (!this._pathRoot) { this._pathRoot = L.Path.prototype._createElement('svg'); this._panes.overlayPane.appendChild(this._pathRoot); if (this.options.zoomAnimation && L.Browser.any3d) { L.DomUtil.addClass(this._pathRoot, 'leaflet-zoom-animated'); this.on({ 'zoomanim': this._animatePathZoom, 'zoomend': this._endPathZoom }); } else { L.DomUtil.addClass(this._pathRoot, 'leaflet-zoom-hide'); } this.on('moveend', this._updateSvgViewport); this._updateSvgViewport(); } }, _animatePathZoom: function (e) { var scale = this.getZoomScale(e.zoom), offset = this._getCenterOffset(e.center)._multiplyBy(-scale)._add(this._pathViewport.min); this._pathRoot.style[L.DomUtil.TRANSFORM] = L.DomUtil.getTranslateString(offset) + ' scale(' + scale + ') '; this._pathZooming = true; }, _endPathZoom: function () { this._pathZooming = false; }, _updateSvgViewport: function () { if (this._pathZooming) { // Do not update SVGs while a zoom animation is going on otherwise the animation will break. // When the zoom animation ends we will be updated again anyway // This fixes the case where you do a momentum move and zoom while the move is still ongoing. return; } this._updatePathViewport(); var vp = this._pathViewport, min = vp.min, max = vp.max, width = max.x - min.x, height = max.y - min.y, root = this._pathRoot, pane = this._panes.overlayPane; // Hack to make flicker on drag end on mobile webkit less irritating if (L.Browser.mobileWebkit) { pane.removeChild(root); } L.DomUtil.setPosition(root, min); root.setAttribute('width', width); root.setAttribute('height', height); root.setAttribute('viewBox', [min.x, min.y, width, height].join(' ')); if (L.Browser.mobileWebkit) { pane.appendChild(root); } } });