- Created minimal, tree-shaken vendor bundles: * Core bundle (3KB): Always loaded utilities and theme management * Map bundle (255KB): Leaflet + plugins, loaded only for map pages * Chart bundle (205KB): Chart.js, loaded only for chart pages * Date adapter (50KB): Chart.js time scale support - Total optimized size: 513KB JS + 12KB CSS (was 547KB + 17KB) - Implemented conditional loading via VendorLoader utility - Bundle loading triggered by LiveView hooks when needed - Fixed Chart.js date adapter dependency loading - Eliminated unused JavaScript from being sent to browsers - Created separate esbuild configs for each optimized bundle Performance improvements: - Map pages: Core + Map bundles = 258KB (47% of original) - Chart pages: Core + Chart + Adapter = 258KB (47% of original) - Other pages: Core bundle only = 3KB (0.5% of original) - Reduced initial page load by 94% for non-map/chart pages 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
2567 lines
150 KiB
JavaScript
2567 lines
150 KiB
JavaScript
// Optimized plugins bundle
|
|
|
|
/* leaflet-heat.js */
|
|
/*
|
|
(c) 2014, Vladimir Agafonkin
|
|
simpleheat, a tiny JavaScript library for drawing heatmaps with Canvas
|
|
https://github.com/mourner/simpleheat
|
|
*/
|
|
!function(){"use strict";function t(i){return this instanceof t?(this._canvas=i="string"==typeof i?document.getElementById(i):i,this._ctx=i.getContext("2d"),this._width=i.width,this._height=i.height,this._max=1,void this.clear()):new t(i)}t.prototype={defaultRadius:25,defaultGradient:{.4:"blue",.6:"cyan",.7:"lime",.8:"yellow",1:"red"},data:function(t,i){return this._data=t,this},max:function(t){return this._max=t,this},add:function(t){return this._data.push(t),this},clear:function(){return this._data=[],this},radius:function(t,i){i=i||15;var a=this._circle=document.createElement("canvas"),s=a.getContext("2d"),e=this._r=t+i;return a.width=a.height=2*e,s.shadowOffsetX=s.shadowOffsetY=200,s.shadowBlur=i,s.shadowColor="black",s.beginPath(),s.arc(e-200,e-200,t,0,2*Math.PI,!0),s.closePath(),s.fill(),this},gradient:function(t){var i=document.createElement("canvas"),a=i.getContext("2d"),s=a.createLinearGradient(0,0,0,256);i.width=1,i.height=256;for(var e in t)s.addColorStop(e,t[e]);return a.fillStyle=s,a.fillRect(0,0,1,256),this._grad=a.getImageData(0,0,1,256).data,this},draw:function(t){this._circle||this.radius(this.defaultRadius),this._grad||this.gradient(this.defaultGradient);var i=this._ctx;i.clearRect(0,0,this._width,this._height);for(var a,s=0,e=this._data.length;e>s;s++)a=this._data[s],i.globalAlpha=Math.max(a[2]/this._max,t||.05),i.drawImage(this._circle,a[0]-this._r,a[1]-this._r);var n=i.getImageData(0,0,this._width,this._height);return this._colorize(n.data,this._grad),i.putImageData(n,0,0),this},_colorize:function(t,i){for(var a,s=3,e=t.length;e>s;s+=4)a=4*t[s],a&&(t[s-3]=i[a],t[s-2]=i[a+1],t[s-1]=i[a+2])}},window.simpleheat=t}(),/*
|
|
(c) 2014, Vladimir Agafonkin
|
|
Leaflet.heat, a tiny and fast heatmap plugin for Leaflet.
|
|
https://github.com/Leaflet/Leaflet.heat
|
|
*/
|
|
L.HeatLayer=(L.Layer?L.Layer:L.Class).extend({initialize:function(t,i){this._latlngs=t,L.setOptions(this,i)},setLatLngs:function(t){return this._latlngs=t,this.redraw()},addLatLng:function(t){return this._latlngs.push(t),this.redraw()},setOptions:function(t){return L.setOptions(this,t),this._heat&&this._updateOptions(),this.redraw()},redraw:function(){return!this._heat||this._frame||this._map._animating||(this._frame=L.Util.requestAnimFrame(this._redraw,this)),this},onAdd:function(t){this._map=t,this._canvas||this._initCanvas(),t._panes.overlayPane.appendChild(this._canvas),t.on("moveend",this._reset,this),t.options.zoomAnimation&&L.Browser.any3d&&t.on("zoomanim",this._animateZoom,this),this._reset()},onRemove:function(t){t.getPanes().overlayPane.removeChild(this._canvas),t.off("moveend",this._reset,this),t.options.zoomAnimation&&t.off("zoomanim",this._animateZoom,this)},addTo:function(t){return t.addLayer(this),this},_initCanvas:function(){var t=this._canvas=L.DomUtil.create("canvas","leaflet-heatmap-layer leaflet-layer"),i=L.DomUtil.testProp(["transformOrigin","WebkitTransformOrigin","msTransformOrigin"]);t.style[i]="50% 50%";var a=this._map.getSize();t.width=a.x,t.height=a.y;var s=this._map.options.zoomAnimation&&L.Browser.any3d;L.DomUtil.addClass(t,"leaflet-zoom-"+(s?"animated":"hide")),this._heat=simpleheat(t),this._updateOptions()},_updateOptions:function(){this._heat.radius(this.options.radius||this._heat.defaultRadius,this.options.blur),this.options.gradient&&this._heat.gradient(this.options.gradient),this.options.max&&this._heat.max(this.options.max)},_reset:function(){var t=this._map.containerPointToLayerPoint([0,0]);L.DomUtil.setPosition(this._canvas,t);var i=this._map.getSize();this._heat._width!==i.x&&(this._canvas.width=this._heat._width=i.x),this._heat._height!==i.y&&(this._canvas.height=this._heat._height=i.y),this._redraw()},_redraw:function(){var t,i,a,s,e,n,h,o,r,d=[],_=this._heat._r,l=this._map.getSize(),m=new L.Bounds(L.point([-_,-_]),l.add([_,_])),c=void 0===this.options.max?1:this.options.max,u=void 0===this.options.maxZoom?this._map.getMaxZoom():this.options.maxZoom,f=1/Math.pow(2,Math.max(0,Math.min(u-this._map.getZoom(),12))),g=_/2,p=[],v=this._map._getMapPanePos(),w=v.x%g,y=v.y%g;for(t=0,i=this._latlngs.length;i>t;t++)if(a=this._map.latLngToContainerPoint(this._latlngs[t]),m.contains(a)){e=Math.floor((a.x-w)/g)+2,n=Math.floor((a.y-y)/g)+2;var x=void 0!==this._latlngs[t].alt?this._latlngs[t].alt:void 0!==this._latlngs[t][2]?+this._latlngs[t][2]:1;r=x*f,p[n]=p[n]||[],s=p[n][e],s?(s[0]=(s[0]*s[2]+a.x*r)/(s[2]+r),s[1]=(s[1]*s[2]+a.y*r)/(s[2]+r),s[2]+=r):p[n][e]=[a.x,a.y,r]}for(t=0,i=p.length;i>t;t++)if(p[t])for(h=0,o=p[t].length;o>h;h++)s=p[t][h],s&&d.push([Math.round(s[0]),Math.round(s[1]),Math.min(s[2],c)]);this._heat.data(d).draw(this.options.minOpacity),this._frame=null},_animateZoom:function(t){var i=this._map.getZoomScale(t.zoom),a=this._map._getCenterOffset(t.center)._multiplyBy(-i).subtract(this._map._getMapPanePos());L.DomUtil.setTransform?L.DomUtil.setTransform(this._canvas,a,i):this._canvas.style[L.DomUtil.TRANSFORM]=L.DomUtil.getTranslateString(a)+" scale("+i+")"}}),L.heatLayer=function(t,i){return new L.HeatLayer(t,i)};
|
|
|
|
/* leaflet-markercluster.js */
|
|
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t(((e=e||self).Leaflet=e.Leaflet||{},e.Leaflet.markercluster={}))}(this,function(e){"use strict";var t=L.MarkerClusterGroup=L.FeatureGroup.extend({options:{maxClusterRadius:80,iconCreateFunction:null,clusterPane:L.Marker.prototype.options.pane,spiderfyOnEveryZoom:!1,spiderfyOnMaxZoom:!0,showCoverageOnHover:!0,zoomToBoundsOnClick:!0,singleMarkerMode:!1,disableClusteringAtZoom:null,removeOutsideVisibleBounds:!0,animate:!0,animateAddingMarkers:!1,spiderfyShapePositions:null,spiderfyDistanceMultiplier:1,spiderLegPolylineOptions:{weight:1.5,color:"#222",opacity:.5},chunkedLoading:!1,chunkInterval:200,chunkDelay:50,chunkProgress:null,polygonOptions:{}},initialize:function(e){L.Util.setOptions(this,e),this.options.iconCreateFunction||(this.options.iconCreateFunction=this._defaultIconCreateFunction),this._featureGroup=L.featureGroup(),this._featureGroup.addEventParent(this),this._nonPointGroup=L.featureGroup(),this._nonPointGroup.addEventParent(this),this._inZoomAnimation=0,this._needsClustering=[],this._needsRemoving=[],this._currentShownBounds=null,this._queue=[],this._childMarkerEventHandlers={dragstart:this._childMarkerDragStart,move:this._childMarkerMoved,dragend:this._childMarkerDragEnd};var t=L.DomUtil.TRANSITION&&this.options.animate;L.extend(this,t?this._withAnimation:this._noAnimation),this._markerCluster=t?L.MarkerCluster:L.MarkerClusterNonAnimated},addLayer:function(e){if(e instanceof L.LayerGroup)return this.addLayers([e]);if(!e.getLatLng)return this._nonPointGroup.addLayer(e),this.fire("layeradd",{layer:e}),this;if(!this._map)return this._needsClustering.push(e),this.fire("layeradd",{layer:e}),this;if(this.hasLayer(e))return this;this._unspiderfy&&this._unspiderfy(),this._addLayer(e,this._maxZoom),this.fire("layeradd",{layer:e}),this._topClusterLevel._recalculateBounds(),this._refreshClustersIcons();var t=e,i=this._zoom;if(e.__parent)for(;t.__parent._zoom>=i;)t=t.__parent;return this._currentShownBounds.contains(t.getLatLng())&&(this.options.animateAddingMarkers?this._animationAddLayer(e,t):this._animationAddLayerNonAnimated(e,t)),this},removeLayer:function(e){return e instanceof L.LayerGroup?this.removeLayers([e]):(e.getLatLng?this._map?e.__parent&&(this._unspiderfy&&(this._unspiderfy(),this._unspiderfyLayer(e)),this._removeLayer(e,!0),this.fire("layerremove",{layer:e}),this._topClusterLevel._recalculateBounds(),this._refreshClustersIcons(),e.off(this._childMarkerEventHandlers,this),this._featureGroup.hasLayer(e)&&(this._featureGroup.removeLayer(e),e.clusterShow&&e.clusterShow())):(!this._arraySplice(this._needsClustering,e)&&this.hasLayer(e)&&this._needsRemoving.push({layer:e,latlng:e._latlng}),this.fire("layerremove",{layer:e})):(this._nonPointGroup.removeLayer(e),this.fire("layerremove",{layer:e})),this)},addLayers:function(n,s){if(!L.Util.isArray(n))return this.addLayer(n);var o,a=this._featureGroup,h=this._nonPointGroup,l=this.options.chunkedLoading,u=this.options.chunkInterval,_=this.options.chunkProgress,d=n.length,p=0,c=!0;if(this._map){var f=(new Date).getTime(),m=L.bind(function(){var e=(new Date).getTime();for(this._map&&this._unspiderfy&&this._unspiderfy();p<d;p++){if(l&&p%200==0){var t=(new Date).getTime()-e;if(u<t)break}if((o=n[p])instanceof L.LayerGroup)c&&(n=n.slice(),c=!1),this._extractNonGroupLayers(o,n),d=n.length;else if(o.getLatLng){if(!this.hasLayer(o)&&(this._addLayer(o,this._maxZoom),s||this.fire("layeradd",{layer:o}),o.__parent&&2===o.__parent.getChildCount())){var i=o.__parent.getAllChildMarkers(),r=i[0]===o?i[1]:i[0];a.removeLayer(r)}}else h.addLayer(o),s||this.fire("layeradd",{layer:o})}_&&_(p,d,(new Date).getTime()-f),p===d?(this._topClusterLevel._recalculateBounds(),this._refreshClustersIcons(),this._topClusterLevel._recursivelyAddChildrenToMap(null,this._zoom,this._currentShownBounds)):setTimeout(m,this.options.chunkDelay)},this);m()}else for(var e=this._needsClustering;p<d;p++)(o=n[p])instanceof L.LayerGroup?(c&&(n=n.slice(),c=!1),this._extractNonGroupLayers(o,n),d=n.length):o.getLatLng?this.hasLayer(o)||e.push(o):h.addLayer(o);return this},removeLayers:function(e){var t,i,r=e.length,n=this._featureGroup,s=this._nonPointGroup,o=!0;if(!this._map){for(t=0;t<r;t++)(i=e[t])instanceof L.LayerGroup?(o&&(e=e.slice(),o=!1),this._extractNonGroupLayers(i,e),r=e.length):(this._arraySplice(this._needsClustering,i),s.removeLayer(i),this.hasLayer(i)&&this._needsRemoving.push({layer:i,latlng:i._latlng}),this.fire("layerremove",{layer:i}));return this}if(this._unspiderfy){this._unspiderfy();var a=e.slice(),h=r;for(t=0;t<h;t++)(i=a[t])instanceof L.LayerGroup?(this._extractNonGroupLayers(i,a),h=a.length):this._unspiderfyLayer(i)}for(t=0;t<r;t++)(i=e[t])instanceof L.LayerGroup?(o&&(e=e.slice(),o=!1),this._extractNonGroupLayers(i,e),r=e.length):i.__parent?(this._removeLayer(i,!0,!0),this.fire("layerremove",{layer:i}),n.hasLayer(i)&&(n.removeLayer(i),i.clusterShow&&i.clusterShow())):(s.removeLayer(i),this.fire("layerremove",{layer:i}));return this._topClusterLevel._recalculateBounds(),this._refreshClustersIcons(),this._topClusterLevel._recursivelyAddChildrenToMap(null,this._zoom,this._currentShownBounds),this},clearLayers:function(){return this._map||(this._needsClustering=[],this._needsRemoving=[],delete this._gridClusters,delete this._gridUnclustered),this._noanimationUnspiderfy&&this._noanimationUnspiderfy(),this._featureGroup.clearLayers(),this._nonPointGroup.clearLayers(),this.eachLayer(function(e){e.off(this._childMarkerEventHandlers,this),delete e.__parent},this),this._map&&this._generateInitialClusters(),this},getBounds:function(){var e=new L.LatLngBounds;this._topClusterLevel&&e.extend(this._topClusterLevel._bounds);for(var t=this._needsClustering.length-1;0<=t;t--)e.extend(this._needsClustering[t].getLatLng());return e.extend(this._nonPointGroup.getBounds()),e},eachLayer:function(e,t){var i,r,n,s=this._needsClustering.slice(),o=this._needsRemoving;for(this._topClusterLevel&&this._topClusterLevel.getAllChildMarkers(s),r=s.length-1;0<=r;r--){for(i=!0,n=o.length-1;0<=n;n--)if(o[n].layer===s[r]){i=!1;break}i&&e.call(t,s[r])}this._nonPointGroup.eachLayer(e,t)},getLayers:function(){var t=[];return this.eachLayer(function(e){t.push(e)}),t},getLayer:function(t){var i=null;return t=parseInt(t,10),this.eachLayer(function(e){L.stamp(e)===t&&(i=e)}),i},hasLayer:function(e){if(!e)return!1;var t,i=this._needsClustering;for(t=i.length-1;0<=t;t--)if(i[t]===e)return!0;for(t=(i=this._needsRemoving).length-1;0<=t;t--)if(i[t].layer===e)return!1;return!(!e.__parent||e.__parent._group!==this)||this._nonPointGroup.hasLayer(e)},zoomToShowLayer:function(e,t){var i=this._map;"function"!=typeof t&&(t=function(){});var r=function(){!i.hasLayer(e)&&!i.hasLayer(e.__parent)||this._inZoomAnimation||(this._map.off("moveend",r,this),this.off("animationend",r,this),i.hasLayer(e)?t():e.__parent._icon&&(this.once("spiderfied",t,this),e.__parent.spiderfy()))};e._icon&&this._map.getBounds().contains(e.getLatLng())?t():e.__parent._zoom<Math.round(this._map._zoom)?(this._map.on("moveend",r,this),this._map.panTo(e.getLatLng())):(this._map.on("moveend",r,this),this.on("animationend",r,this),e.__parent.zoomToBounds())},onAdd:function(e){var t,i,r;if(this._map=e,!isFinite(this._map.getMaxZoom()))throw"Map has no maxZoom specified";for(this._featureGroup.addTo(e),this._nonPointGroup.addTo(e),this._gridClusters||this._generateInitialClusters(),this._maxLat=e.options.crs.projection.MAX_LATITUDE,t=0,i=this._needsRemoving.length;t<i;t++)(r=this._needsRemoving[t]).newlatlng=r.layer._latlng,r.layer._latlng=r.latlng;for(t=0,i=this._needsRemoving.length;t<i;t++)r=this._needsRemoving[t],this._removeLayer(r.layer,!0),r.layer._latlng=r.newlatlng;this._needsRemoving=[],this._zoom=Math.round(this._map._zoom),this._currentShownBounds=this._getExpandedVisibleBounds(),this._map.on("zoomend",this._zoomEnd,this),this._map.on("moveend",this._moveEnd,this),this._spiderfierOnAdd&&this._spiderfierOnAdd(),this._bindEvents(),i=this._needsClustering,this._needsClustering=[],this.addLayers(i,!0)},onRemove:function(e){e.off("zoomend",this._zoomEnd,this),e.off("moveend",this._moveEnd,this),this._unbindEvents(),this._map._mapPane.className=this._map._mapPane.className.replace(" leaflet-cluster-anim",""),this._spiderfierOnRemove&&this._spiderfierOnRemove(),delete this._maxLat,this._hideCoverage(),this._featureGroup.remove(),this._nonPointGroup.remove(),this._featureGroup.clearLayers(),this._map=null},getVisibleParent:function(e){for(var t=e;t&&!t._icon;)t=t.__parent;return t||null},_arraySplice:function(e,t){for(var i=e.length-1;0<=i;i--)if(e[i]===t)return e.splice(i,1),!0},_removeFromGridUnclustered:function(e,t){for(var i=this._map,r=this._gridUnclustered,n=Math.floor(this._map.getMinZoom());n<=t&&r[t].removeObject(e,i.project(e.getLatLng(),t));t--);},_childMarkerDragStart:function(e){e.target.__dragStart=e.target._latlng},_childMarkerMoved:function(e){if(!this._ignoreMove&&!e.target.__dragStart){var t=e.target._popup&&e.target._popup.isOpen();this._moveChild(e.target,e.oldLatLng,e.latlng),t&&e.target.openPopup()}},_moveChild:function(e,t,i){e._latlng=t,this.removeLayer(e),e._latlng=i,this.addLayer(e)},_childMarkerDragEnd:function(e){var t=e.target.__dragStart;delete e.target.__dragStart,t&&this._moveChild(e.target,t,e.target._latlng)},_removeLayer:function(e,t,i){var r=this._gridClusters,n=this._gridUnclustered,s=this._featureGroup,o=this._map,a=Math.floor(this._map.getMinZoom());t&&this._removeFromGridUnclustered(e,this._maxZoom);var h,l=e.__parent,u=l._markers;for(this._arraySplice(u,e);l&&(l._childCount--,l._boundsNeedUpdate=!0,!(l._zoom<a));)t&&l._childCount<=1?(h=l._markers[0]===e?l._markers[1]:l._markers[0],r[l._zoom].removeObject(l,o.project(l._cLatLng,l._zoom)),n[l._zoom].addObject(h,o.project(h.getLatLng(),l._zoom)),this._arraySplice(l.__parent._childClusters,l),l.__parent._markers.push(h),h.__parent=l.__parent,l._icon&&(s.removeLayer(l),i||s.addLayer(h))):l._iconNeedsUpdate=!0,l=l.__parent;delete e.__parent},_isOrIsParent:function(e,t){for(;t;){if(e===t)return!0;t=t.parentNode}return!1},fire:function(e,t,i){if(t&&t.layer instanceof L.MarkerCluster){if(t.originalEvent&&this._isOrIsParent(t.layer._icon,t.originalEvent.relatedTarget))return;e="cluster"+e}L.FeatureGroup.prototype.fire.call(this,e,t,i)},listens:function(e,t){return L.FeatureGroup.prototype.listens.call(this,e,t)||L.FeatureGroup.prototype.listens.call(this,"cluster"+e,t)},_defaultIconCreateFunction:function(e){var t=e.getChildCount(),i=" marker-cluster-";return i+=t<10?"small":t<100?"medium":"large",new L.DivIcon({html:"<div><span>"+t+"</span></div>",className:"marker-cluster"+i,iconSize:new L.Point(40,40)})},_bindEvents:function(){var e=this._map,t=this.options.spiderfyOnMaxZoom,i=this.options.showCoverageOnHover,r=this.options.zoomToBoundsOnClick,n=this.options.spiderfyOnEveryZoom;(t||r||n)&&this.on("clusterclick clusterkeypress",this._zoomOrSpiderfy,this),i&&(this.on("clustermouseover",this._showCoverage,this),this.on("clustermouseout",this._hideCoverage,this),e.on("zoomend",this._hideCoverage,this))},_zoomOrSpiderfy:function(e){var t=e.layer,i=t;if("clusterkeypress"!==e.type||!e.originalEvent||13===e.originalEvent.keyCode){for(;1===i._childClusters.length;)i=i._childClusters[0];i._zoom===this._maxZoom&&i._childCount===t._childCount&&this.options.spiderfyOnMaxZoom?t.spiderfy():this.options.zoomToBoundsOnClick&&t.zoomToBounds(),this.options.spiderfyOnEveryZoom&&t.spiderfy(),e.originalEvent&&13===e.originalEvent.keyCode&&this._map._container.focus()}},_showCoverage:function(e){var t=this._map;this._inZoomAnimation||(this._shownPolygon&&t.removeLayer(this._shownPolygon),2<e.layer.getChildCount()&&e.layer!==this._spiderfied&&(this._shownPolygon=new L.Polygon(e.layer.getConvexHull(),this.options.polygonOptions),t.addLayer(this._shownPolygon)))},_hideCoverage:function(){this._shownPolygon&&(this._map.removeLayer(this._shownPolygon),this._shownPolygon=null)},_unbindEvents:function(){var e=this.options.spiderfyOnMaxZoom,t=this.options.showCoverageOnHover,i=this.options.zoomToBoundsOnClick,r=this.options.spiderfyOnEveryZoom,n=this._map;(e||i||r)&&this.off("clusterclick clusterkeypress",this._zoomOrSpiderfy,this),t&&(this.off("clustermouseover",this._showCoverage,this),this.off("clustermouseout",this._hideCoverage,this),n.off("zoomend",this._hideCoverage,this))},_zoomEnd:function(){this._map&&(this._mergeSplitClusters(),this._zoom=Math.round(this._map._zoom),this._currentShownBounds=this._getExpandedVisibleBounds())},_moveEnd:function(){if(!this._inZoomAnimation){var e=this._getExpandedVisibleBounds();this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds,Math.floor(this._map.getMinZoom()),this._zoom,e),this._topClusterLevel._recursivelyAddChildrenToMap(null,Math.round(this._map._zoom),e),this._currentShownBounds=e}},_generateInitialClusters:function(){var e=Math.ceil(this._map.getMaxZoom()),t=Math.floor(this._map.getMinZoom()),i=this.options.maxClusterRadius,r=i;"function"!=typeof i&&(r=function(){return i}),null!==this.options.disableClusteringAtZoom&&(e=this.options.disableClusteringAtZoom-1),this._maxZoom=e,this._gridClusters={},this._gridUnclustered={};for(var n=e;t<=n;n--)this._gridClusters[n]=new L.DistanceGrid(r(n)),this._gridUnclustered[n]=new L.DistanceGrid(r(n));this._topClusterLevel=new this._markerCluster(this,t-1)},_addLayer:function(e,t){var i,r,n=this._gridClusters,s=this._gridUnclustered,o=Math.floor(this._map.getMinZoom());for(this.options.singleMarkerMode&&this._overrideMarkerIcon(e),e.on(this._childMarkerEventHandlers,this);o<=t;t--){i=this._map.project(e.getLatLng(),t);var a=n[t].getNearObject(i);if(a)return a._addChild(e),void(e.__parent=a);if(a=s[t].getNearObject(i)){var h=a.__parent;h&&this._removeLayer(a,!1);var l=new this._markerCluster(this,t,a,e);n[t].addObject(l,this._map.project(l._cLatLng,t)),a.__parent=l;var u=e.__parent=l;for(r=t-1;r>h._zoom;r--)u=new this._markerCluster(this,r,u),n[r].addObject(u,this._map.project(a.getLatLng(),r));return h._addChild(u),void this._removeFromGridUnclustered(a,t)}s[t].addObject(e,i)}this._topClusterLevel._addChild(e),e.__parent=this._topClusterLevel},_refreshClustersIcons:function(){this._featureGroup.eachLayer(function(e){e instanceof L.MarkerCluster&&e._iconNeedsUpdate&&e._updateIcon()})},_enqueue:function(e){this._queue.push(e),this._queueTimeout||(this._queueTimeout=setTimeout(L.bind(this._processQueue,this),300))},_processQueue:function(){for(var e=0;e<this._queue.length;e++)this._queue[e].call(this);this._queue.length=0,clearTimeout(this._queueTimeout),this._queueTimeout=null},_mergeSplitClusters:function(){var e=Math.round(this._map._zoom);this._processQueue(),this._zoom<e&&this._currentShownBounds.intersects(this._getExpandedVisibleBounds())?(this._animationStart(),this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds,Math.floor(this._map.getMinZoom()),this._zoom,this._getExpandedVisibleBounds()),this._animationZoomIn(this._zoom,e)):this._zoom>e?(this._animationStart(),this._animationZoomOut(this._zoom,e)):this._moveEnd()},_getExpandedVisibleBounds:function(){return this.options.removeOutsideVisibleBounds?L.Browser.mobile?this._checkBoundsMaxLat(this._map.getBounds()):this._checkBoundsMaxLat(this._map.getBounds().pad(1)):this._mapBoundsInfinite},_checkBoundsMaxLat:function(e){var t=this._maxLat;return void 0!==t&&(e.getNorth()>=t&&(e._northEast.lat=1/0),e.getSouth()<=-t&&(e._southWest.lat=-1/0)),e},_animationAddLayerNonAnimated:function(e,t){if(t===e)this._featureGroup.addLayer(e);else if(2===t._childCount){t._addToMap();var i=t.getAllChildMarkers();this._featureGroup.removeLayer(i[0]),this._featureGroup.removeLayer(i[1])}else t._updateIcon()},_extractNonGroupLayers:function(e,t){var i,r=e.getLayers(),n=0;for(t=t||[];n<r.length;n++)(i=r[n])instanceof L.LayerGroup?this._extractNonGroupLayers(i,t):t.push(i);return t},_overrideMarkerIcon:function(e){return e.options.icon=this.options.iconCreateFunction({getChildCount:function(){return 1},getAllChildMarkers:function(){return[e]}})}});L.MarkerClusterGroup.include({_mapBoundsInfinite:new L.LatLngBounds(new L.LatLng(-1/0,-1/0),new L.LatLng(1/0,1/0))}),L.MarkerClusterGroup.include({_noAnimation:{_animationStart:function(){},_animationZoomIn:function(e,t){this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds,Math.floor(this._map.getMinZoom()),e),this._topClusterLevel._recursivelyAddChildrenToMap(null,t,this._getExpandedVisibleBounds()),this.fire("animationend")},_animationZoomOut:function(e,t){this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds,Math.floor(this._map.getMinZoom()),e),this._topClusterLevel._recursivelyAddChildrenToMap(null,t,this._getExpandedVisibleBounds()),this.fire("animationend")},_animationAddLayer:function(e,t){this._animationAddLayerNonAnimated(e,t)}},_withAnimation:{_animationStart:function(){this._map._mapPane.className+=" leaflet-cluster-anim",this._inZoomAnimation++},_animationZoomIn:function(n,s){var o,a=this._getExpandedVisibleBounds(),h=this._featureGroup,e=Math.floor(this._map.getMinZoom());this._ignoreMove=!0,this._topClusterLevel._recursively(a,n,e,function(e){var t,i=e._latlng,r=e._markers;for(a.contains(i)||(i=null),e._isSingleParent()&&n+1===s?(h.removeLayer(e),e._recursivelyAddChildrenToMap(null,s,a)):(e.clusterHide(),e._recursivelyAddChildrenToMap(i,s,a)),o=r.length-1;0<=o;o--)t=r[o],a.contains(t._latlng)||h.removeLayer(t)}),this._forceLayout(),this._topClusterLevel._recursivelyBecomeVisible(a,s),h.eachLayer(function(e){e instanceof L.MarkerCluster||!e._icon||e.clusterShow()}),this._topClusterLevel._recursively(a,n,s,function(e){e._recursivelyRestoreChildPositions(s)}),this._ignoreMove=!1,this._enqueue(function(){this._topClusterLevel._recursively(a,n,e,function(e){h.removeLayer(e),e.clusterShow()}),this._animationEnd()})},_animationZoomOut:function(e,t){this._animationZoomOutSingle(this._topClusterLevel,e-1,t),this._topClusterLevel._recursivelyAddChildrenToMap(null,t,this._getExpandedVisibleBounds()),this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds,Math.floor(this._map.getMinZoom()),e,this._getExpandedVisibleBounds())},_animationAddLayer:function(e,t){var i=this,r=this._featureGroup;r.addLayer(e),t!==e&&(2<t._childCount?(t._updateIcon(),this._forceLayout(),this._animationStart(),e._setPos(this._map.latLngToLayerPoint(t.getLatLng())),e.clusterHide(),this._enqueue(function(){r.removeLayer(e),e.clusterShow(),i._animationEnd()})):(this._forceLayout(),i._animationStart(),i._animationZoomOutSingle(t,this._map.getMaxZoom(),this._zoom)))}},_animationZoomOutSingle:function(t,i,r){var n=this._getExpandedVisibleBounds(),s=Math.floor(this._map.getMinZoom());t._recursivelyAnimateChildrenInAndAddSelfToMap(n,s,i+1,r);var o=this;this._forceLayout(),t._recursivelyBecomeVisible(n,r),this._enqueue(function(){if(1===t._childCount){var e=t._markers[0];this._ignoreMove=!0,e.setLatLng(e.getLatLng()),this._ignoreMove=!1,e.clusterShow&&e.clusterShow()}else t._recursively(n,r,s,function(e){e._recursivelyRemoveChildrenFromMap(n,s,i+1)});o._animationEnd()})},_animationEnd:function(){this._map&&(this._map._mapPane.className=this._map._mapPane.className.replace(" leaflet-cluster-anim","")),this._inZoomAnimation--,this.fire("animationend")},_forceLayout:function(){L.Util.falseFn(document.body.offsetWidth)}}),L.markerClusterGroup=function(e){return new L.MarkerClusterGroup(e)};var i=L.MarkerCluster=L.Marker.extend({options:L.Icon.prototype.options,initialize:function(e,t,i,r){L.Marker.prototype.initialize.call(this,i?i._cLatLng||i.getLatLng():new L.LatLng(0,0),{icon:this,pane:e.options.clusterPane}),this._group=e,this._zoom=t,this._markers=[],this._childClusters=[],this._childCount=0,this._iconNeedsUpdate=!0,this._boundsNeedUpdate=!0,this._bounds=new L.LatLngBounds,i&&this._addChild(i),r&&this._addChild(r)},getAllChildMarkers:function(e,t){e=e||[];for(var i=this._childClusters.length-1;0<=i;i--)this._childClusters[i].getAllChildMarkers(e,t);for(var r=this._markers.length-1;0<=r;r--)t&&this._markers[r].__dragStart||e.push(this._markers[r]);return e},getChildCount:function(){return this._childCount},zoomToBounds:function(e){for(var t,i=this._childClusters.slice(),r=this._group._map,n=r.getBoundsZoom(this._bounds),s=this._zoom+1,o=r.getZoom();0<i.length&&s<n;){s++;var a=[];for(t=0;t<i.length;t++)a=a.concat(i[t]._childClusters);i=a}s<n?this._group._map.setView(this._latlng,s):n<=o?this._group._map.setView(this._latlng,o+1):this._group._map.fitBounds(this._bounds,e)},getBounds:function(){var e=new L.LatLngBounds;return e.extend(this._bounds),e},_updateIcon:function(){this._iconNeedsUpdate=!0,this._icon&&this.setIcon(this)},createIcon:function(){return this._iconNeedsUpdate&&(this._iconObj=this._group.options.iconCreateFunction(this),this._iconNeedsUpdate=!1),this._iconObj.createIcon()},createShadow:function(){return this._iconObj.createShadow()},_addChild:function(e,t){this._iconNeedsUpdate=!0,this._boundsNeedUpdate=!0,this._setClusterCenter(e),e instanceof L.MarkerCluster?(t||(this._childClusters.push(e),e.__parent=this),this._childCount+=e._childCount):(t||this._markers.push(e),this._childCount++),this.__parent&&this.__parent._addChild(e,!0)},_setClusterCenter:function(e){this._cLatLng||(this._cLatLng=e._cLatLng||e._latlng)},_resetBounds:function(){var e=this._bounds;e._southWest&&(e._southWest.lat=1/0,e._southWest.lng=1/0),e._northEast&&(e._northEast.lat=-1/0,e._northEast.lng=-1/0)},_recalculateBounds:function(){var e,t,i,r,n=this._markers,s=this._childClusters,o=0,a=0,h=this._childCount;if(0!==h){for(this._resetBounds(),e=0;e<n.length;e++)i=n[e]._latlng,this._bounds.extend(i),o+=i.lat,a+=i.lng;for(e=0;e<s.length;e++)(t=s[e])._boundsNeedUpdate&&t._recalculateBounds(),this._bounds.extend(t._bounds),i=t._wLatLng,r=t._childCount,o+=i.lat*r,a+=i.lng*r;this._latlng=this._wLatLng=new L.LatLng(o/h,a/h),this._boundsNeedUpdate=!1}},_addToMap:function(e){e&&(this._backupLatlng=this._latlng,this.setLatLng(e)),this._group._featureGroup.addLayer(this)},_recursivelyAnimateChildrenIn:function(e,n,t){this._recursively(e,this._group._map.getMinZoom(),t-1,function(e){var t,i,r=e._markers;for(t=r.length-1;0<=t;t--)(i=r[t])._icon&&(i._setPos(n),i.clusterHide())},function(e){var t,i,r=e._childClusters;for(t=r.length-1;0<=t;t--)(i=r[t])._icon&&(i._setPos(n),i.clusterHide())})},_recursivelyAnimateChildrenInAndAddSelfToMap:function(t,i,r,n){this._recursively(t,n,i,function(e){e._recursivelyAnimateChildrenIn(t,e._group._map.latLngToLayerPoint(e.getLatLng()).round(),r),e._isSingleParent()&&r-1===n?(e.clusterShow(),e._recursivelyRemoveChildrenFromMap(t,i,r)):e.clusterHide(),e._addToMap()})},_recursivelyBecomeVisible:function(e,t){this._recursively(e,this._group._map.getMinZoom(),t,null,function(e){e.clusterShow()})},_recursivelyAddChildrenToMap:function(r,n,s){this._recursively(s,this._group._map.getMinZoom()-1,n,function(e){if(n!==e._zoom)for(var t=e._markers.length-1;0<=t;t--){var i=e._markers[t];s.contains(i._latlng)&&(r&&(i._backupLatlng=i.getLatLng(),i.setLatLng(r),i.clusterHide&&i.clusterHide()),e._group._featureGroup.addLayer(i))}},function(e){e._addToMap(r)})},_recursivelyRestoreChildPositions:function(e){for(var t=this._markers.length-1;0<=t;t--){var i=this._markers[t];i._backupLatlng&&(i.setLatLng(i._backupLatlng),delete i._backupLatlng)}if(e-1===this._zoom)for(var r=this._childClusters.length-1;0<=r;r--)this._childClusters[r]._restorePosition();else for(var n=this._childClusters.length-1;0<=n;n--)this._childClusters[n]._recursivelyRestoreChildPositions(e)},_restorePosition:function(){this._backupLatlng&&(this.setLatLng(this._backupLatlng),delete this._backupLatlng)},_recursivelyRemoveChildrenFromMap:function(e,t,i,r){var n,s;this._recursively(e,t-1,i-1,function(e){for(s=e._markers.length-1;0<=s;s--)n=e._markers[s],r&&r.contains(n._latlng)||(e._group._featureGroup.removeLayer(n),n.clusterShow&&n.clusterShow())},function(e){for(s=e._childClusters.length-1;0<=s;s--)n=e._childClusters[s],r&&r.contains(n._latlng)||(e._group._featureGroup.removeLayer(n),n.clusterShow&&n.clusterShow())})},_recursively:function(e,t,i,r,n){var s,o,a=this._childClusters,h=this._zoom;if(t<=h&&(r&&r(this),n&&h===i&&n(this)),h<t||h<i)for(s=a.length-1;0<=s;s--)(o=a[s])._boundsNeedUpdate&&o._recalculateBounds(),e.intersects(o._bounds)&&o._recursively(e,t,i,r,n)},_isSingleParent:function(){return 0<this._childClusters.length&&this._childClusters[0]._childCount===this._childCount}});L.Marker.include({clusterHide:function(){var e=this.options.opacity;return this.setOpacity(0),this.options.opacity=e,this},clusterShow:function(){return this.setOpacity(this.options.opacity)}}),L.DistanceGrid=function(e){this._cellSize=e,this._sqCellSize=e*e,this._grid={},this._objectPoint={}},L.DistanceGrid.prototype={addObject:function(e,t){var i=this._getCoord(t.x),r=this._getCoord(t.y),n=this._grid,s=n[r]=n[r]||{},o=s[i]=s[i]||[],a=L.Util.stamp(e);this._objectPoint[a]=t,o.push(e)},updateObject:function(e,t){this.removeObject(e),this.addObject(e,t)},removeObject:function(e,t){var i,r,n=this._getCoord(t.x),s=this._getCoord(t.y),o=this._grid,a=o[s]=o[s]||{},h=a[n]=a[n]||[];for(delete this._objectPoint[L.Util.stamp(e)],i=0,r=h.length;i<r;i++)if(h[i]===e)return h.splice(i,1),1===r&&delete a[n],!0},eachObject:function(e,t){var i,r,n,s,o,a,h=this._grid;for(i in h)for(r in o=h[i])for(n=0,s=(a=o[r]).length;n<s;n++)e.call(t,a[n])&&(n--,s--)},getNearObject:function(e){var t,i,r,n,s,o,a,h,l=this._getCoord(e.x),u=this._getCoord(e.y),_=this._objectPoint,d=this._sqCellSize,p=null;for(t=u-1;t<=u+1;t++)if(n=this._grid[t])for(i=l-1;i<=l+1;i++)if(s=n[i])for(r=0,o=s.length;r<o;r++)a=s[r],((h=this._sqDist(_[L.Util.stamp(a)],e))<d||h<=d&&null===p)&&(d=h,p=a);return p},_getCoord:function(e){var t=Math.floor(e/this._cellSize);return isFinite(t)?t:e},_sqDist:function(e,t){var i=t.x-e.x,r=t.y-e.y;return i*i+r*r}},L.QuickHull={getDistant:function(e,t){var i=t[1].lat-t[0].lat;return(t[0].lng-t[1].lng)*(e.lat-t[0].lat)+i*(e.lng-t[0].lng)},findMostDistantPointFromBaseLine:function(e,t){var i,r,n,s=0,o=null,a=[];for(i=t.length-1;0<=i;i--)r=t[i],0<(n=this.getDistant(r,e))&&(a.push(r),s<n&&(s=n,o=r));return{maxPoint:o,newPoints:a}},buildConvexHull:function(e,t){var i=[],r=this.findMostDistantPointFromBaseLine(e,t);return r.maxPoint?i=(i=i.concat(this.buildConvexHull([e[0],r.maxPoint],r.newPoints))).concat(this.buildConvexHull([r.maxPoint,e[1]],r.newPoints)):[e[0]]},getConvexHull:function(e){var t,i=!1,r=!1,n=!1,s=!1,o=null,a=null,h=null,l=null,u=null,_=null;for(t=e.length-1;0<=t;t--){var d=e[t];(!1===i||d.lat>i)&&(i=(o=d).lat),(!1===r||d.lat<r)&&(r=(a=d).lat),(!1===n||d.lng>n)&&(n=(h=d).lng),(!1===s||d.lng<s)&&(s=(l=d).lng)}return u=r!==i?(_=a,o):(_=l,h),[].concat(this.buildConvexHull([_,u],e),this.buildConvexHull([u,_],e))}},L.MarkerCluster.include({getConvexHull:function(){var e,t,i=this.getAllChildMarkers(),r=[];for(t=i.length-1;0<=t;t--)e=i[t].getLatLng(),r.push(e);return L.QuickHull.getConvexHull(r)}}),L.MarkerCluster.include({_2PI:2*Math.PI,_circleFootSeparation:25,_circleStartAngle:0,_spiralFootSeparation:28,_spiralLengthStart:11,_spiralLengthFactor:5,_circleSpiralSwitchover:9,spiderfy:function(){if(this._group._spiderfied!==this&&!this._group._inZoomAnimation){var e,t=this.getAllChildMarkers(null,!0),i=this._group._map.latLngToLayerPoint(this._latlng);this._group._unspiderfy(),e=(this._group._spiderfied=this)._group.options.spiderfyShapePositions?this._group.options.spiderfyShapePositions(t.length,i):t.length>=this._circleSpiralSwitchover?this._generatePointsSpiral(t.length,i):(i.y+=10,this._generatePointsCircle(t.length,i)),this._animationSpiderfy(t,e)}},unspiderfy:function(e){this._group._inZoomAnimation||(this._animationUnspiderfy(e),this._group._spiderfied=null)},_generatePointsCircle:function(e,t){var i,r,n=this._group.options.spiderfyDistanceMultiplier*this._circleFootSeparation*(2+e)/this._2PI,s=this._2PI/e,o=[];for(n=Math.max(n,35),o.length=e,i=0;i<e;i++)r=this._circleStartAngle+i*s,o[i]=new L.Point(t.x+n*Math.cos(r),t.y+n*Math.sin(r))._round();return o},_generatePointsSpiral:function(e,t){var i,r=this._group.options.spiderfyDistanceMultiplier,n=r*this._spiralLengthStart,s=r*this._spiralFootSeparation,o=r*this._spiralLengthFactor*this._2PI,a=0,h=[];for(i=h.length=e;0<=i;i--)i<e&&(h[i]=new L.Point(t.x+n*Math.cos(a),t.y+n*Math.sin(a))._round()),n+=o/(a+=s/n+5e-4*i);return h},_noanimationUnspiderfy:function(){var e,t,i=this._group,r=i._map,n=i._featureGroup,s=this.getAllChildMarkers(null,!0);for(i._ignoreMove=!0,this.setOpacity(1),t=s.length-1;0<=t;t--)e=s[t],n.removeLayer(e),e._preSpiderfyLatlng&&(e.setLatLng(e._preSpiderfyLatlng),delete e._preSpiderfyLatlng),e.setZIndexOffset&&e.setZIndexOffset(0),e._spiderLeg&&(r.removeLayer(e._spiderLeg),delete e._spiderLeg);i.fire("unspiderfied",{cluster:this,markers:s}),i._ignoreMove=!1,i._spiderfied=null}}),L.MarkerClusterNonAnimated=L.MarkerCluster.extend({_animationSpiderfy:function(e,t){var i,r,n,s,o=this._group,a=o._map,h=o._featureGroup,l=this._group.options.spiderLegPolylineOptions;for(o._ignoreMove=!0,i=0;i<e.length;i++)s=a.layerPointToLatLng(t[i]),r=e[i],n=new L.Polyline([this._latlng,s],l),a.addLayer(n),r._spiderLeg=n,r._preSpiderfyLatlng=r._latlng,r.setLatLng(s),r.setZIndexOffset&&r.setZIndexOffset(1e6),h.addLayer(r);this.setOpacity(.3),o._ignoreMove=!1,o.fire("spiderfied",{cluster:this,markers:e})},_animationUnspiderfy:function(){this._noanimationUnspiderfy()}}),L.MarkerCluster.include({_animationSpiderfy:function(e,t){var i,r,n,s,o,a,h=this,l=this._group,u=l._map,_=l._featureGroup,d=this._latlng,p=u.latLngToLayerPoint(d),c=L.Path.SVG,f=L.extend({},this._group.options.spiderLegPolylineOptions),m=f.opacity;for(void 0===m&&(m=L.MarkerClusterGroup.prototype.options.spiderLegPolylineOptions.opacity),c?(f.opacity=0,f.className=(f.className||"")+" leaflet-cluster-spider-leg"):f.opacity=m,l._ignoreMove=!0,i=0;i<e.length;i++)r=e[i],a=u.layerPointToLatLng(t[i]),n=new L.Polyline([d,a],f),u.addLayer(n),r._spiderLeg=n,c&&(o=(s=n._path).getTotalLength()+.1,s.style.strokeDasharray=o,s.style.strokeDashoffset=o),r.setZIndexOffset&&r.setZIndexOffset(1e6),r.clusterHide&&r.clusterHide(),_.addLayer(r),r._setPos&&r._setPos(p);for(l._forceLayout(),l._animationStart(),i=e.length-1;0<=i;i--)a=u.layerPointToLatLng(t[i]),(r=e[i])._preSpiderfyLatlng=r._latlng,r.setLatLng(a),r.clusterShow&&r.clusterShow(),c&&((s=(n=r._spiderLeg)._path).style.strokeDashoffset=0,n.setStyle({opacity:m}));this.setOpacity(.3),l._ignoreMove=!1,setTimeout(function(){l._animationEnd(),l.fire("spiderfied",{cluster:h,markers:e})},200)},_animationUnspiderfy:function(e){var t,i,r,n,s,o,a=this,h=this._group,l=h._map,u=h._featureGroup,_=e?l._latLngToNewLayerPoint(this._latlng,e.zoom,e.center):l.latLngToLayerPoint(this._latlng),d=this.getAllChildMarkers(null,!0),p=L.Path.SVG;for(h._ignoreMove=!0,h._animationStart(),this.setOpacity(1),i=d.length-1;0<=i;i--)(t=d[i])._preSpiderfyLatlng&&(t.closePopup(),t.setLatLng(t._preSpiderfyLatlng),delete t._preSpiderfyLatlng,o=!0,t._setPos&&(t._setPos(_),o=!1),t.clusterHide&&(t.clusterHide(),o=!1),o&&u.removeLayer(t),p&&(s=(n=(r=t._spiderLeg)._path).getTotalLength()+.1,n.style.strokeDashoffset=s,r.setStyle({opacity:0})));h._ignoreMove=!1,setTimeout(function(){var e=0;for(i=d.length-1;0<=i;i--)(t=d[i])._spiderLeg&&e++;for(i=d.length-1;0<=i;i--)(t=d[i])._spiderLeg&&(t.clusterShow&&t.clusterShow(),t.setZIndexOffset&&t.setZIndexOffset(0),1<e&&u.removeLayer(t),l.removeLayer(t._spiderLeg),delete t._spiderLeg);h._animationEnd(),h.fire("unspiderfied",{cluster:a,markers:d})},200)}}),L.MarkerClusterGroup.include({_spiderfied:null,unspiderfy:function(){this._unspiderfy.apply(this,arguments)},_spiderfierOnAdd:function(){this._map.on("click",this._unspiderfyWrapper,this),this._map.options.zoomAnimation&&this._map.on("zoomstart",this._unspiderfyZoomStart,this),this._map.on("zoomend",this._noanimationUnspiderfy,this),L.Browser.touch||this._map.getRenderer(this)},_spiderfierOnRemove:function(){this._map.off("click",this._unspiderfyWrapper,this),this._map.off("zoomstart",this._unspiderfyZoomStart,this),this._map.off("zoomanim",this._unspiderfyZoomAnim,this),this._map.off("zoomend",this._noanimationUnspiderfy,this),this._noanimationUnspiderfy()},_unspiderfyZoomStart:function(){this._map&&this._map.on("zoomanim",this._unspiderfyZoomAnim,this)},_unspiderfyZoomAnim:function(e){L.DomUtil.hasClass(this._map._mapPane,"leaflet-touching")||(this._map.off("zoomanim",this._unspiderfyZoomAnim,this),this._unspiderfy(e))},_unspiderfyWrapper:function(){this._unspiderfy()},_unspiderfy:function(e){this._spiderfied&&this._spiderfied.unspiderfy(e)},_noanimationUnspiderfy:function(){this._spiderfied&&this._spiderfied._noanimationUnspiderfy()},_unspiderfyLayer:function(e){e._spiderLeg&&(this._featureGroup.removeLayer(e),e.clusterShow&&e.clusterShow(),e.setZIndexOffset&&e.setZIndexOffset(0),this._map.removeLayer(e._spiderLeg),delete e._spiderLeg)}}),L.MarkerClusterGroup.include({refreshClusters:function(e){return e?e instanceof L.MarkerClusterGroup?e=e._topClusterLevel.getAllChildMarkers():e instanceof L.LayerGroup?e=e._layers:e instanceof L.MarkerCluster?e=e.getAllChildMarkers():e instanceof L.Marker&&(e=[e]):e=this._topClusterLevel.getAllChildMarkers(),this._flagParentsIconsNeedUpdate(e),this._refreshClustersIcons(),this.options.singleMarkerMode&&this._refreshSingleMarkerModeMarkers(e),this},_flagParentsIconsNeedUpdate:function(e){var t,i;for(t in e)for(i=e[t].__parent;i;)i._iconNeedsUpdate=!0,i=i.__parent},_refreshSingleMarkerModeMarkers:function(e){var t,i;for(t in e)i=e[t],this.hasLayer(i)&&i.setIcon(this._overrideMarkerIcon(i))}}),L.Marker.include({refreshIconOptions:function(e,t){var i=this.options.icon;return L.setOptions(i,e),this.setIcon(i),t&&this.__parent&&this.__parent._group.refreshClusters(this),this}}),e.MarkerClusterGroup=t,e.MarkerCluster=i,Object.defineProperty(e,"__esModule",{value:!0})});
|
|
//# sourceMappingURL=leaflet.markercluster.js.map
|
|
|
|
/* overlapping-marker-spiderfier.js */
|
|
!function(){"use strict";var l={}.hasOwnProperty,u=[].slice;(function(){var t,o;if(null!=this.L)return this.OverlappingMarkerSpiderfier=((t=e.prototype).VERSION="0.2.6",o=2*Math.PI,t.keepSpiderfied=!1,t.nearbyDistance=20,t.circleSpiralSwitchover=9,t.circleFootSeparation=25,t.circleStartAngle=o/12,t.spiralFootSeparation=28,t.spiralLengthStart=11,t.spiralLengthFactor=5,t.legWeight=1.5,t.legColors={usual:"#222",highlighted:"#f00"},t.initMarkerArrays=function(){return this.markers=[],this.markerListeners=[]},t.addMarker=function(t){var e,r;return null!=t._oms||(t._oms=!0,r=this,e=function(){return r.spiderListener(t)},t.addEventListener("click",e),this.markerListeners.push(e),this.markers.push(t)),this},t.getMarkers=function(){return this.markers.slice(0)},t.removeMarker=function(t){var e,r;return null!=t._omsData&&this.unspiderfy(),(e=this.arrIndexOf(this.markers,t))<0||(r=this.markerListeners.splice(e,1)[0],t.removeEventListener("click",r),delete t._oms,this.markers.splice(e,1)),this},t.clearMarkers=function(){var t,e,r,i,n,s;for(this.unspiderfy(),t=e=0,r=(s=this.markers).length;e<r;t=++e)i=s[t],n=this.markerListeners[t],i.removeEventListener("click",n),delete i._oms;return this.initMarkerArrays(),this},t.addListener=function(t,e){var r;return(null!=(r=this.listeners)[t]?r[t]:r[t]=[]).push(e),this},t.removeListener=function(t,e){var r;return(r=this.arrIndexOf(this.listeners[t],e))<0||this.listeners[t].splice(r,1),this},t.clearListeners=function(t){return this.listeners[t]=[],this},t.trigger=function(){var t,e,r,i,n,s,a,h;for(e=arguments[0],t=2<=arguments.length?u.call(arguments,1):[],h=[],i=0,n=(a=null!=(s=this.listeners[e])?s:[]).length;i<n;i++)r=a[i],h.push(r.apply(null,t));return h},t.generatePtsCircle=function(t,e){var r,i,n,s,a,h,l;for(a=this.circleFootSeparation*(2+t)/o,i=o/t,l=[],n=s=0,h=t;0<=h?s<h:h<s;n=0<=h?++s:--s)r=this.circleStartAngle+n*i,l.push(new L.Point(e.x+a*Math.cos(r),e.y+a*Math.sin(r)));return l},t.generatePtsSpiral=function(t,e){var r,i,n,s,a,h,l;for(s=this.spiralLengthStart,l=[],i=n=r=0,h=t;0<=h?n<h:h<n;i=0<=h?++n:--n)r+=this.spiralFootSeparation/s+5e-4*i,a=new L.Point(e.x+s*Math.cos(r),e.y+s*Math.sin(r)),s+=o*this.spiralLengthFactor/r,l.push(a);return l},t.spiderListener=function(t){var e,r,i,n,s,a,h,l,o,u;if((a=null!=t._omsData)&&this.keepSpiderfied||this.unspiderfy(),a)return this.trigger("click",t);for(h=[],l=[],o=this.nearbyDistance*this.nearbyDistance,s=this.map.latLngToLayerPoint(t.getLatLng()),e=0,r=(u=this.markers).length;e<r;e++)i=u[e],this.map.hasLayer(i)&&(n=this.map.latLngToLayerPoint(i.getLatLng()),this.ptDistanceSq(n,s)<o?h.push({marker:i,markerPt:n}):l.push(i));return 1===h.length?this.trigger("click",t):this.spiderfy(h,l)},t.makeHighlightListeners=function(t){return{highlight:(r=this,function(){return t._omsData.leg.setStyle({color:r.legColors.highlighted})}),unhighlight:(e=this,function(){return t._omsData.leg.setStyle({color:e.legColors.usual})})};var e,r},t.spiderfy=function(i,t){var e,n,s,a,h,l,o,u,g,r,c;return this.spiderfying=!0,r=i.length,e=this.ptAverage(function(){var t,e,r;for(r=[],t=0,e=i.length;t<e;t++)o=i[t],r.push(o.markerPt);return r}()),a=r>=this.circleSpiralSwitchover?this.generatePtsSpiral(r,e).reverse():this.generatePtsCircle(r,e),c=function(){var t,e,r;for(r=[],t=0,e=a.length;t<e;t++)s=a[t],n=this.map.layerPointToLatLng(s),g=this.minExtract(i,function(e){return function(t){return e.ptDistanceSq(t.markerPt,s)}}(this)),l=g.marker,h=new L.Polyline([l.getLatLng(),n],{color:this.legColors.usual,weight:this.legWeight,clickable:!1}),this.map.addLayer(h),l._omsData={usualPosition:l.getLatLng(),leg:h},this.legColors.highlighted!==this.legColors.usual&&(u=this.makeHighlightListeners(l),l._omsData.highlightListeners=u,l.addEventListener("mouseover",u.highlight),l.addEventListener("mouseout",u.unhighlight)),l.setLatLng(n),l.setZIndexOffset(l.options.zIndexOffset+1e6),r.push(l);return r}.call(this),delete this.spiderfying,this.spiderfied=!0,this.trigger("spiderfy",c,t)},t.unspiderfy=function(t){var e,r,i,n,s,a,h;if(null==t&&(t=null),null==this.spiderfied)return this;for(this.unspiderfying=!0,h=[],s=[],e=0,r=(a=this.markers).length;e<r;e++)null!=(i=a[e])._omsData?(this.map.removeLayer(i._omsData.leg),i!==t&&i.setLatLng(i._omsData.usualPosition),i.setZIndexOffset(i.options.zIndexOffset-1e6),null!=(n=i._omsData.highlightListeners)&&(i.removeEventListener("mouseover",n.highlight),i.removeEventListener("mouseout",n.unhighlight)),delete i._omsData,h.push(i)):s.push(i);return delete this.unspiderfying,delete this.spiderfied,this.trigger("unspiderfy",h,s),this},t.ptDistanceSq=function(t,e){var r,i;return(r=t.x-e.x)*r+(i=t.y-e.y)*i},t.ptAverage=function(t){var e,r,i,n,s,a;for(s=a=0,e=0,r=t.length;e<r;e++)s+=(n=t[e]).x,a+=n.y;return i=t.length,new L.Point(s/i,a/i)},t.minExtract=function(t,e){var r,i,n,s,a,h;for(n=s=0,a=t.length;s<a;n=++s)h=e(t[n]),(null==r||h<i)&&(i=h,r=n);return t.splice(r,1)[0]},t.arrIndexOf=function(t,e){var r,i,n;if(null!=t.indexOf)return t.indexOf(e);for(r=i=0,n=t.length;i<n;r=++i)if(t[r]===e)return r;return-1},e);function e(t,e){var r,i,n,s,a,h;for(n in this.map=t,null==e&&(e={}),e)l.call(e,n)&&(h=e[n],this[n]=h);for(this.initMarkerArrays(),this.listeners={},i=0,s=(a=["click","zoomend"]).length;i<s;i++)r=a[i],this.map.addEventListener(r,function(t){return function(){return t.unspiderfy()}}(this))}}).call(window)}();
|
|
|
|
|
|
/* topbar.js */
|
|
/**
|
|
* @license MIT
|
|
* topbar 3.0.0
|
|
* http://buunguyen.github.io/topbar
|
|
* Copyright (c) 2024 Buu Nguyen
|
|
*/
|
|
(function(window,document){"use strict";function repaint(){canvas.width=window.innerWidth,canvas.height=5*options.barThickness;var ctx=canvas.getContext("2d");ctx.shadowBlur=options.shadowBlur,ctx.shadowColor=options.shadowColor;var stop,lineGradient=ctx.createLinearGradient(0,0,canvas.width,0);for(stop in options.barColors)lineGradient.addColorStop(stop,options.barColors[stop]);ctx.lineWidth=options.barThickness,ctx.beginPath(),ctx.moveTo(0,options.barThickness/2),ctx.lineTo(Math.ceil(currentProgress*canvas.width),options.barThickness/2),ctx.strokeStyle=lineGradient,ctx.stroke()}var canvas,currentProgress,showing,progressTimerId=null,fadeTimerId=null,delayTimerId=null,options={autoRun:!0,barThickness:3,barColors:{0:"rgba(26, 188, 156, .9)",".25":"rgba(52, 152, 219, .9)",".50":"rgba(241, 196, 15, .9)",".75":"rgba(230, 126, 34, .9)","1.0":"rgba(211, 84, 0, .9)"},shadowBlur:10,shadowColor:"rgba(0, 0, 0, .6)",className:null},topbar={config:function(opts){for(var key in opts)options.hasOwnProperty(key)&&(options[key]=opts[key])},show:function(handler){var type,elem;showing||(handler?delayTimerId=delayTimerId||setTimeout(()=>topbar.show(),handler):(showing=!0,null!==fadeTimerId&&window.cancelAnimationFrame(fadeTimerId),canvas||((elem=(canvas=document.createElement("canvas")).style).position="fixed",elem.top=elem.left=elem.right=elem.margin=elem.padding=0,elem.zIndex=100001,elem.display="none",options.className&&canvas.classList.add(options.className),type="resize",handler=repaint,(elem=window).addEventListener?elem.addEventListener(type,handler,!1):elem.attachEvent?elem.attachEvent("on"+type,handler):elem["on"+type]=handler),canvas.parentElement||document.body.appendChild(canvas),canvas.style.opacity=1,canvas.style.display="block",topbar.progress(0),options.autoRun&&function loop(){progressTimerId=window.requestAnimationFrame(loop),topbar.progress("+"+.05*Math.pow(1-Math.sqrt(currentProgress),2))}()))},progress:function(to){return void 0===to||("string"==typeof to&&(to=(0<=to.indexOf("+")||0<=to.indexOf("-")?currentProgress:0)+parseFloat(to)),currentProgress=1<to?1:to,repaint()),currentProgress},hide:function(){clearTimeout(delayTimerId),delayTimerId=null,showing&&(showing=!1,null!=progressTimerId&&(window.cancelAnimationFrame(progressTimerId),progressTimerId=null),function loop(){return 1<=topbar.progress("+.1")&&(canvas.style.opacity-=.05,canvas.style.opacity<=.05)?(canvas.style.display="none",void(fadeTimerId=null)):void(fadeTimerId=window.requestAnimationFrame(loop))}())}};"object"==typeof module&&"object"==typeof module.exports?module.exports=topbar:"function"==typeof define&&define.amd?define(function(){return topbar}):this.topbar=topbar}).call(this,window,document);
|
|
|
|
/* leaflet-vectorgrid.js - lazy loaded */
|
|
window.LeafletVectorGrid = (function() {
|
|
(function () {
|
|
'use strict';
|
|
|
|
function __$strToBlobUri(str, mime, isBinary) {try {return window.URL.createObjectURL(new Blob([Uint8Array.from(str.split('').map(function(c) {return c.charCodeAt(0)}))], {type: mime}));} catch (e) {return "data:" + mime + (isBinary ? ";base64," : ",") + str;}}
|
|
(function(self) {
|
|
'use strict';
|
|
|
|
if (self.fetch) {
|
|
return
|
|
}
|
|
|
|
var support = {
|
|
searchParams: 'URLSearchParams' in self,
|
|
iterable: 'Symbol' in self && 'iterator' in Symbol,
|
|
blob: 'FileReader' in self && 'Blob' in self && (function() {
|
|
try {
|
|
new Blob();
|
|
return true
|
|
} catch(e) {
|
|
return false
|
|
}
|
|
})(),
|
|
formData: 'FormData' in self,
|
|
arrayBuffer: 'ArrayBuffer' in self
|
|
};
|
|
|
|
if (support.arrayBuffer) {
|
|
var viewClasses = [
|
|
'[object Int8Array]',
|
|
'[object Uint8Array]',
|
|
'[object Uint8ClampedArray]',
|
|
'[object Int16Array]',
|
|
'[object Uint16Array]',
|
|
'[object Int32Array]',
|
|
'[object Uint32Array]',
|
|
'[object Float32Array]',
|
|
'[object Float64Array]'
|
|
];
|
|
|
|
var isDataView = function(obj) {
|
|
return obj && DataView.prototype.isPrototypeOf(obj)
|
|
};
|
|
|
|
var isArrayBufferView = ArrayBuffer.isView || function(obj) {
|
|
return obj && viewClasses.indexOf(Object.prototype.toString.call(obj)) > -1
|
|
};
|
|
}
|
|
|
|
function normalizeName(name) {
|
|
if (typeof name !== 'string') {
|
|
name = String(name);
|
|
}
|
|
if (/[^a-z0-9\-#$%&'*+.\^_`|~]/i.test(name)) {
|
|
throw new TypeError('Invalid character in header field name')
|
|
}
|
|
return name.toLowerCase()
|
|
}
|
|
|
|
function normalizeValue(value) {
|
|
if (typeof value !== 'string') {
|
|
value = String(value);
|
|
}
|
|
return value
|
|
}
|
|
|
|
// Build a destructive iterator for the value list
|
|
function iteratorFor(items) {
|
|
var iterator = {
|
|
next: function() {
|
|
var value = items.shift();
|
|
return {done: value === undefined, value: value}
|
|
}
|
|
};
|
|
|
|
if (support.iterable) {
|
|
iterator[Symbol.iterator] = function() {
|
|
return iterator
|
|
};
|
|
}
|
|
|
|
return iterator
|
|
}
|
|
|
|
function Headers(headers) {
|
|
this.map = {};
|
|
|
|
if (headers instanceof Headers) {
|
|
headers.forEach(function(value, name) {
|
|
this.append(name, value);
|
|
}, this);
|
|
} else if (Array.isArray(headers)) {
|
|
headers.forEach(function(header) {
|
|
this.append(header[0], header[1]);
|
|
}, this);
|
|
} else if (headers) {
|
|
Object.getOwnPropertyNames(headers).forEach(function(name) {
|
|
this.append(name, headers[name]);
|
|
}, this);
|
|
}
|
|
}
|
|
|
|
Headers.prototype.append = function(name, value) {
|
|
name = normalizeName(name);
|
|
value = normalizeValue(value);
|
|
var oldValue = this.map[name];
|
|
this.map[name] = oldValue ? oldValue+','+value : value;
|
|
};
|
|
|
|
Headers.prototype['delete'] = function(name) {
|
|
delete this.map[normalizeName(name)];
|
|
};
|
|
|
|
Headers.prototype.get = function(name) {
|
|
name = normalizeName(name);
|
|
return this.has(name) ? this.map[name] : null
|
|
};
|
|
|
|
Headers.prototype.has = function(name) {
|
|
return this.map.hasOwnProperty(normalizeName(name))
|
|
};
|
|
|
|
Headers.prototype.set = function(name, value) {
|
|
this.map[normalizeName(name)] = normalizeValue(value);
|
|
};
|
|
|
|
Headers.prototype.forEach = function(callback, thisArg) {
|
|
var this$1 = this;
|
|
|
|
for (var name in this.map) {
|
|
if (this$1.map.hasOwnProperty(name)) {
|
|
callback.call(thisArg, this$1.map[name], name, this$1);
|
|
}
|
|
}
|
|
};
|
|
|
|
Headers.prototype.keys = function() {
|
|
var items = [];
|
|
this.forEach(function(value, name) { items.push(name); });
|
|
return iteratorFor(items)
|
|
};
|
|
|
|
Headers.prototype.values = function() {
|
|
var items = [];
|
|
this.forEach(function(value) { items.push(value); });
|
|
return iteratorFor(items)
|
|
};
|
|
|
|
Headers.prototype.entries = function() {
|
|
var items = [];
|
|
this.forEach(function(value, name) { items.push([name, value]); });
|
|
return iteratorFor(items)
|
|
};
|
|
|
|
if (support.iterable) {
|
|
Headers.prototype[Symbol.iterator] = Headers.prototype.entries;
|
|
}
|
|
|
|
function consumed(body) {
|
|
if (body.bodyUsed) {
|
|
return Promise.reject(new TypeError('Already read'))
|
|
}
|
|
body.bodyUsed = true;
|
|
}
|
|
|
|
function fileReaderReady(reader) {
|
|
return new Promise(function(resolve, reject) {
|
|
reader.onload = function() {
|
|
resolve(reader.result);
|
|
};
|
|
reader.onerror = function() {
|
|
reject(reader.error);
|
|
};
|
|
})
|
|
}
|
|
|
|
function readBlobAsArrayBuffer(blob) {
|
|
var reader = new FileReader();
|
|
var promise = fileReaderReady(reader);
|
|
reader.readAsArrayBuffer(blob);
|
|
return promise
|
|
}
|
|
|
|
function readBlobAsText(blob) {
|
|
var reader = new FileReader();
|
|
var promise = fileReaderReady(reader);
|
|
reader.readAsText(blob);
|
|
return promise
|
|
}
|
|
|
|
function readArrayBufferAsText(buf) {
|
|
var view = new Uint8Array(buf);
|
|
var chars = new Array(view.length);
|
|
|
|
for (var i = 0; i < view.length; i++) {
|
|
chars[i] = String.fromCharCode(view[i]);
|
|
}
|
|
return chars.join('')
|
|
}
|
|
|
|
function bufferClone(buf) {
|
|
if (buf.slice) {
|
|
return buf.slice(0)
|
|
} else {
|
|
var view = new Uint8Array(buf.byteLength);
|
|
view.set(new Uint8Array(buf));
|
|
return view.buffer
|
|
}
|
|
}
|
|
|
|
function Body() {
|
|
this.bodyUsed = false;
|
|
|
|
this._initBody = function(body) {
|
|
this._bodyInit = body;
|
|
if (!body) {
|
|
this._bodyText = '';
|
|
} else if (typeof body === 'string') {
|
|
this._bodyText = body;
|
|
} else if (support.blob && Blob.prototype.isPrototypeOf(body)) {
|
|
this._bodyBlob = body;
|
|
} else if (support.formData && FormData.prototype.isPrototypeOf(body)) {
|
|
this._bodyFormData = body;
|
|
} else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {
|
|
this._bodyText = body.toString();
|
|
} else if (support.arrayBuffer && support.blob && isDataView(body)) {
|
|
this._bodyArrayBuffer = bufferClone(body.buffer);
|
|
// IE 10-11 can't handle a DataView body.
|
|
this._bodyInit = new Blob([this._bodyArrayBuffer]);
|
|
} else if (support.arrayBuffer && (ArrayBuffer.prototype.isPrototypeOf(body) || isArrayBufferView(body))) {
|
|
this._bodyArrayBuffer = bufferClone(body);
|
|
} else {
|
|
throw new Error('unsupported BodyInit type')
|
|
}
|
|
|
|
if (!this.headers.get('content-type')) {
|
|
if (typeof body === 'string') {
|
|
this.headers.set('content-type', 'text/plain;charset=UTF-8');
|
|
} else if (this._bodyBlob && this._bodyBlob.type) {
|
|
this.headers.set('content-type', this._bodyBlob.type);
|
|
} else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {
|
|
this.headers.set('content-type', 'application/x-www-form-urlencoded;charset=UTF-8');
|
|
}
|
|
}
|
|
};
|
|
|
|
if (support.blob) {
|
|
this.blob = function() {
|
|
var rejected = consumed(this);
|
|
if (rejected) {
|
|
return rejected
|
|
}
|
|
|
|
if (this._bodyBlob) {
|
|
return Promise.resolve(this._bodyBlob)
|
|
} else if (this._bodyArrayBuffer) {
|
|
return Promise.resolve(new Blob([this._bodyArrayBuffer]))
|
|
} else if (this._bodyFormData) {
|
|
throw new Error('could not read FormData body as blob')
|
|
} else {
|
|
return Promise.resolve(new Blob([this._bodyText]))
|
|
}
|
|
};
|
|
|
|
this.arrayBuffer = function() {
|
|
if (this._bodyArrayBuffer) {
|
|
return consumed(this) || Promise.resolve(this._bodyArrayBuffer)
|
|
} else {
|
|
return this.blob().then(readBlobAsArrayBuffer)
|
|
}
|
|
};
|
|
}
|
|
|
|
this.text = function() {
|
|
var rejected = consumed(this);
|
|
if (rejected) {
|
|
return rejected
|
|
}
|
|
|
|
if (this._bodyBlob) {
|
|
return readBlobAsText(this._bodyBlob)
|
|
} else if (this._bodyArrayBuffer) {
|
|
return Promise.resolve(readArrayBufferAsText(this._bodyArrayBuffer))
|
|
} else if (this._bodyFormData) {
|
|
throw new Error('could not read FormData body as text')
|
|
} else {
|
|
return Promise.resolve(this._bodyText)
|
|
}
|
|
};
|
|
|
|
if (support.formData) {
|
|
this.formData = function() {
|
|
return this.text().then(decode)
|
|
};
|
|
}
|
|
|
|
this.json = function() {
|
|
return this.text().then(JSON.parse)
|
|
};
|
|
|
|
return this
|
|
}
|
|
|
|
// HTTP methods whose capitalization should be normalized
|
|
var methods = ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT'];
|
|
|
|
function normalizeMethod(method) {
|
|
var upcased = method.toUpperCase();
|
|
return (methods.indexOf(upcased) > -1) ? upcased : method
|
|
}
|
|
|
|
function Request(input, options) {
|
|
options = options || {};
|
|
var body = options.body;
|
|
|
|
if (input instanceof Request) {
|
|
if (input.bodyUsed) {
|
|
throw new TypeError('Already read')
|
|
}
|
|
this.url = input.url;
|
|
this.credentials = input.credentials;
|
|
if (!options.headers) {
|
|
this.headers = new Headers(input.headers);
|
|
}
|
|
this.method = input.method;
|
|
this.mode = input.mode;
|
|
if (!body && input._bodyInit != null) {
|
|
body = input._bodyInit;
|
|
input.bodyUsed = true;
|
|
}
|
|
} else {
|
|
this.url = String(input);
|
|
}
|
|
|
|
this.credentials = options.credentials || this.credentials || 'omit';
|
|
if (options.headers || !this.headers) {
|
|
this.headers = new Headers(options.headers);
|
|
}
|
|
this.method = normalizeMethod(options.method || this.method || 'GET');
|
|
this.mode = options.mode || this.mode || null;
|
|
this.referrer = null;
|
|
|
|
if ((this.method === 'GET' || this.method === 'HEAD') && body) {
|
|
throw new TypeError('Body not allowed for GET or HEAD requests')
|
|
}
|
|
this._initBody(body);
|
|
}
|
|
|
|
Request.prototype.clone = function() {
|
|
return new Request(this, { body: this._bodyInit })
|
|
};
|
|
|
|
function decode(body) {
|
|
var form = new FormData();
|
|
body.trim().split('&').forEach(function(bytes) {
|
|
if (bytes) {
|
|
var split = bytes.split('=');
|
|
var name = split.shift().replace(/\+/g, ' ');
|
|
var value = split.join('=').replace(/\+/g, ' ');
|
|
form.append(decodeURIComponent(name), decodeURIComponent(value));
|
|
}
|
|
});
|
|
return form
|
|
}
|
|
|
|
function parseHeaders(rawHeaders) {
|
|
var headers = new Headers();
|
|
rawHeaders.split(/\r?\n/).forEach(function(line) {
|
|
var parts = line.split(':');
|
|
var key = parts.shift().trim();
|
|
if (key) {
|
|
var value = parts.join(':').trim();
|
|
headers.append(key, value);
|
|
}
|
|
});
|
|
return headers
|
|
}
|
|
|
|
Body.call(Request.prototype);
|
|
|
|
function Response(bodyInit, options) {
|
|
if (!options) {
|
|
options = {};
|
|
}
|
|
|
|
this.type = 'default';
|
|
this.status = 'status' in options ? options.status : 200;
|
|
this.ok = this.status >= 200 && this.status < 300;
|
|
this.statusText = 'statusText' in options ? options.statusText : 'OK';
|
|
this.headers = new Headers(options.headers);
|
|
this.url = options.url || '';
|
|
this._initBody(bodyInit);
|
|
}
|
|
|
|
Body.call(Response.prototype);
|
|
|
|
Response.prototype.clone = function() {
|
|
return new Response(this._bodyInit, {
|
|
status: this.status,
|
|
statusText: this.statusText,
|
|
headers: new Headers(this.headers),
|
|
url: this.url
|
|
})
|
|
};
|
|
|
|
Response.error = function() {
|
|
var response = new Response(null, {status: 0, statusText: ''});
|
|
response.type = 'error';
|
|
return response
|
|
};
|
|
|
|
var redirectStatuses = [301, 302, 303, 307, 308];
|
|
|
|
Response.redirect = function(url, status) {
|
|
if (redirectStatuses.indexOf(status) === -1) {
|
|
throw new RangeError('Invalid status code')
|
|
}
|
|
|
|
return new Response(null, {status: status, headers: {location: url}})
|
|
};
|
|
|
|
self.Headers = Headers;
|
|
self.Request = Request;
|
|
self.Response = Response;
|
|
|
|
self.fetch = function(input, init) {
|
|
return new Promise(function(resolve, reject) {
|
|
var request = new Request(input, init);
|
|
var xhr = new XMLHttpRequest();
|
|
|
|
xhr.onload = function() {
|
|
var options = {
|
|
status: xhr.status,
|
|
statusText: xhr.statusText,
|
|
headers: parseHeaders(xhr.getAllResponseHeaders() || '')
|
|
};
|
|
options.url = 'responseURL' in xhr ? xhr.responseURL : options.headers.get('X-Request-URL');
|
|
var body = 'response' in xhr ? xhr.response : xhr.responseText;
|
|
resolve(new Response(body, options));
|
|
};
|
|
|
|
xhr.onerror = function() {
|
|
reject(new TypeError('Network request failed'));
|
|
};
|
|
|
|
xhr.ontimeout = function() {
|
|
reject(new TypeError('Network request failed'));
|
|
};
|
|
|
|
xhr.open(request.method, request.url, true);
|
|
|
|
if (request.credentials === 'include') {
|
|
xhr.withCredentials = true;
|
|
}
|
|
|
|
if ('responseType' in xhr && support.blob) {
|
|
xhr.responseType = 'blob';
|
|
}
|
|
|
|
request.headers.forEach(function(value, name) {
|
|
xhr.setRequestHeader(name, value);
|
|
});
|
|
|
|
xhr.send(typeof request._bodyInit === 'undefined' ? null : request._bodyInit);
|
|
})
|
|
};
|
|
self.fetch.polyfill = true;
|
|
})(typeof self !== 'undefined' ? self : undefined);
|
|
|
|
var read = function (buffer, offset, isLE, mLen, nBytes) {
|
|
var e, m;
|
|
var eLen = nBytes * 8 - mLen - 1;
|
|
var eMax = (1 << eLen) - 1;
|
|
var eBias = eMax >> 1;
|
|
var nBits = -7;
|
|
var i = isLE ? (nBytes - 1) : 0;
|
|
var d = isLE ? -1 : 1;
|
|
var s = buffer[offset + i];
|
|
|
|
i += d;
|
|
|
|
e = s & ((1 << (-nBits)) - 1);
|
|
s >>= (-nBits);
|
|
nBits += eLen;
|
|
for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {}
|
|
|
|
m = e & ((1 << (-nBits)) - 1);
|
|
e >>= (-nBits);
|
|
nBits += mLen;
|
|
for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {}
|
|
|
|
if (e === 0) {
|
|
e = 1 - eBias;
|
|
} else if (e === eMax) {
|
|
return m ? NaN : ((s ? -1 : 1) * Infinity)
|
|
} else {
|
|
m = m + Math.pow(2, mLen);
|
|
e = e - eBias;
|
|
}
|
|
return (s ? -1 : 1) * m * Math.pow(2, e - mLen)
|
|
};
|
|
|
|
var write = function (buffer, value, offset, isLE, mLen, nBytes) {
|
|
var e, m, c;
|
|
var eLen = nBytes * 8 - mLen - 1;
|
|
var eMax = (1 << eLen) - 1;
|
|
var eBias = eMax >> 1;
|
|
var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0);
|
|
var i = isLE ? 0 : (nBytes - 1);
|
|
var d = isLE ? 1 : -1;
|
|
var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0;
|
|
|
|
value = Math.abs(value);
|
|
|
|
if (isNaN(value) || value === Infinity) {
|
|
m = isNaN(value) ? 1 : 0;
|
|
e = eMax;
|
|
} else {
|
|
e = Math.floor(Math.log(value) / Math.LN2);
|
|
if (value * (c = Math.pow(2, -e)) < 1) {
|
|
e--;
|
|
c *= 2;
|
|
}
|
|
if (e + eBias >= 1) {
|
|
value += rt / c;
|
|
} else {
|
|
value += rt * Math.pow(2, 1 - eBias);
|
|
}
|
|
if (value * c >= 2) {
|
|
e++;
|
|
c /= 2;
|
|
}
|
|
|
|
if (e + eBias >= eMax) {
|
|
m = 0;
|
|
e = eMax;
|
|
} else if (e + eBias >= 1) {
|
|
m = (value * c - 1) * Math.pow(2, mLen);
|
|
e = e + eBias;
|
|
} else {
|
|
m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen);
|
|
e = 0;
|
|
}
|
|
}
|
|
|
|
for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}
|
|
|
|
e = (e << mLen) | m;
|
|
eLen += mLen;
|
|
for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}
|
|
|
|
buffer[offset + i - d] |= s * 128;
|
|
};
|
|
|
|
var index$1 = {
|
|
read: read,
|
|
write: write
|
|
};
|
|
|
|
var index = Pbf;
|
|
|
|
var ieee754 = index$1;
|
|
|
|
function Pbf(buf) {
|
|
this.buf = ArrayBuffer.isView && ArrayBuffer.isView(buf) ? buf : new Uint8Array(buf || 0);
|
|
this.pos = 0;
|
|
this.type = 0;
|
|
this.length = this.buf.length;
|
|
}
|
|
|
|
Pbf.Varint = 0; // varint: int32, int64, uint32, uint64, sint32, sint64, bool, enum
|
|
Pbf.Fixed64 = 1; // 64-bit: double, fixed64, sfixed64
|
|
Pbf.Bytes = 2; // length-delimited: string, bytes, embedded messages, packed repeated fields
|
|
Pbf.Fixed32 = 5; // 32-bit: float, fixed32, sfixed32
|
|
|
|
var SHIFT_LEFT_32 = (1 << 16) * (1 << 16);
|
|
var SHIFT_RIGHT_32 = 1 / SHIFT_LEFT_32;
|
|
|
|
Pbf.prototype = {
|
|
|
|
destroy: function() {
|
|
this.buf = null;
|
|
},
|
|
|
|
// === READING =================================================================
|
|
|
|
readFields: function(readField, result, end) {
|
|
var this$1 = this;
|
|
|
|
end = end || this.length;
|
|
|
|
while (this.pos < end) {
|
|
var val = this$1.readVarint(),
|
|
tag = val >> 3,
|
|
startPos = this$1.pos;
|
|
|
|
this$1.type = val & 0x7;
|
|
readField(tag, result, this$1);
|
|
|
|
if (this$1.pos === startPos) { this$1.skip(val); }
|
|
}
|
|
return result;
|
|
},
|
|
|
|
readMessage: function(readField, result) {
|
|
return this.readFields(readField, result, this.readVarint() + this.pos);
|
|
},
|
|
|
|
readFixed32: function() {
|
|
var val = readUInt32(this.buf, this.pos);
|
|
this.pos += 4;
|
|
return val;
|
|
},
|
|
|
|
readSFixed32: function() {
|
|
var val = readInt32(this.buf, this.pos);
|
|
this.pos += 4;
|
|
return val;
|
|
},
|
|
|
|
// 64-bit int handling is based on github.com/dpw/node-buffer-more-ints (MIT-licensed)
|
|
|
|
readFixed64: function() {
|
|
var val = readUInt32(this.buf, this.pos) + readUInt32(this.buf, this.pos + 4) * SHIFT_LEFT_32;
|
|
this.pos += 8;
|
|
return val;
|
|
},
|
|
|
|
readSFixed64: function() {
|
|
var val = readUInt32(this.buf, this.pos) + readInt32(this.buf, this.pos + 4) * SHIFT_LEFT_32;
|
|
this.pos += 8;
|
|
return val;
|
|
},
|
|
|
|
readFloat: function() {
|
|
var val = ieee754.read(this.buf, this.pos, true, 23, 4);
|
|
this.pos += 4;
|
|
return val;
|
|
},
|
|
|
|
readDouble: function() {
|
|
var val = ieee754.read(this.buf, this.pos, true, 52, 8);
|
|
this.pos += 8;
|
|
return val;
|
|
},
|
|
|
|
readVarint: function(isSigned) {
|
|
var buf = this.buf,
|
|
val, b;
|
|
|
|
b = buf[this.pos++]; val = b & 0x7f; if (b < 0x80) { return val; }
|
|
b = buf[this.pos++]; val |= (b & 0x7f) << 7; if (b < 0x80) { return val; }
|
|
b = buf[this.pos++]; val |= (b & 0x7f) << 14; if (b < 0x80) { return val; }
|
|
b = buf[this.pos++]; val |= (b & 0x7f) << 21; if (b < 0x80) { return val; }
|
|
b = buf[this.pos]; val |= (b & 0x0f) << 28;
|
|
|
|
return readVarintRemainder(val, isSigned, this);
|
|
},
|
|
|
|
readVarint64: function() { // for compatibility with v2.0.1
|
|
return this.readVarint(true);
|
|
},
|
|
|
|
readSVarint: function() {
|
|
var num = this.readVarint();
|
|
return num % 2 === 1 ? (num + 1) / -2 : num / 2; // zigzag encoding
|
|
},
|
|
|
|
readBoolean: function() {
|
|
return Boolean(this.readVarint());
|
|
},
|
|
|
|
readString: function() {
|
|
var end = this.readVarint() + this.pos,
|
|
str = readUtf8(this.buf, this.pos, end);
|
|
this.pos = end;
|
|
return str;
|
|
},
|
|
|
|
readBytes: function() {
|
|
var end = this.readVarint() + this.pos,
|
|
buffer = this.buf.subarray(this.pos, end);
|
|
this.pos = end;
|
|
return buffer;
|
|
},
|
|
|
|
// verbose for performance reasons; doesn't affect gzipped size
|
|
|
|
readPackedVarint: function(arr, isSigned) {
|
|
var this$1 = this;
|
|
|
|
var end = readPackedEnd(this);
|
|
arr = arr || [];
|
|
while (this.pos < end) { arr.push(this$1.readVarint(isSigned)); }
|
|
return arr;
|
|
},
|
|
readPackedSVarint: function(arr) {
|
|
var this$1 = this;
|
|
|
|
var end = readPackedEnd(this);
|
|
arr = arr || [];
|
|
while (this.pos < end) { arr.push(this$1.readSVarint()); }
|
|
return arr;
|
|
},
|
|
readPackedBoolean: function(arr) {
|
|
var this$1 = this;
|
|
|
|
var end = readPackedEnd(this);
|
|
arr = arr || [];
|
|
while (this.pos < end) { arr.push(this$1.readBoolean()); }
|
|
return arr;
|
|
},
|
|
readPackedFloat: function(arr) {
|
|
var this$1 = this;
|
|
|
|
var end = readPackedEnd(this);
|
|
arr = arr || [];
|
|
while (this.pos < end) { arr.push(this$1.readFloat()); }
|
|
return arr;
|
|
},
|
|
readPackedDouble: function(arr) {
|
|
var this$1 = this;
|
|
|
|
var end = readPackedEnd(this);
|
|
arr = arr || [];
|
|
while (this.pos < end) { arr.push(this$1.readDouble()); }
|
|
return arr;
|
|
},
|
|
readPackedFixed32: function(arr) {
|
|
var this$1 = this;
|
|
|
|
var end = readPackedEnd(this);
|
|
arr = arr || [];
|
|
while (this.pos < end) { arr.push(this$1.readFixed32()); }
|
|
return arr;
|
|
},
|
|
readPackedSFixed32: function(arr) {
|
|
var this$1 = this;
|
|
|
|
var end = readPackedEnd(this);
|
|
arr = arr || [];
|
|
while (this.pos < end) { arr.push(this$1.readSFixed32()); }
|
|
return arr;
|
|
},
|
|
readPackedFixed64: function(arr) {
|
|
var this$1 = this;
|
|
|
|
var end = readPackedEnd(this);
|
|
arr = arr || [];
|
|
while (this.pos < end) { arr.push(this$1.readFixed64()); }
|
|
return arr;
|
|
},
|
|
readPackedSFixed64: function(arr) {
|
|
var this$1 = this;
|
|
|
|
var end = readPackedEnd(this);
|
|
arr = arr || [];
|
|
while (this.pos < end) { arr.push(this$1.readSFixed64()); }
|
|
return arr;
|
|
},
|
|
|
|
skip: function(val) {
|
|
var type = val & 0x7;
|
|
if (type === Pbf.Varint) { while (this.buf[this.pos++] > 0x7f) {} }
|
|
else if (type === Pbf.Bytes) { this.pos = this.readVarint() + this.pos; }
|
|
else if (type === Pbf.Fixed32) { this.pos += 4; }
|
|
else if (type === Pbf.Fixed64) { this.pos += 8; }
|
|
else { throw new Error('Unimplemented type: ' + type); }
|
|
},
|
|
|
|
// === WRITING =================================================================
|
|
|
|
writeTag: function(tag, type) {
|
|
this.writeVarint((tag << 3) | type);
|
|
},
|
|
|
|
realloc: function(min) {
|
|
var length = this.length || 16;
|
|
|
|
while (length < this.pos + min) { length *= 2; }
|
|
|
|
if (length !== this.length) {
|
|
var buf = new Uint8Array(length);
|
|
buf.set(this.buf);
|
|
this.buf = buf;
|
|
this.length = length;
|
|
}
|
|
},
|
|
|
|
finish: function() {
|
|
this.length = this.pos;
|
|
this.pos = 0;
|
|
return this.buf.subarray(0, this.length);
|
|
},
|
|
|
|
writeFixed32: function(val) {
|
|
this.realloc(4);
|
|
writeInt32(this.buf, val, this.pos);
|
|
this.pos += 4;
|
|
},
|
|
|
|
writeSFixed32: function(val) {
|
|
this.realloc(4);
|
|
writeInt32(this.buf, val, this.pos);
|
|
this.pos += 4;
|
|
},
|
|
|
|
writeFixed64: function(val) {
|
|
this.realloc(8);
|
|
writeInt32(this.buf, val & -1, this.pos);
|
|
writeInt32(this.buf, Math.floor(val * SHIFT_RIGHT_32), this.pos + 4);
|
|
this.pos += 8;
|
|
},
|
|
|
|
writeSFixed64: function(val) {
|
|
this.realloc(8);
|
|
writeInt32(this.buf, val & -1, this.pos);
|
|
writeInt32(this.buf, Math.floor(val * SHIFT_RIGHT_32), this.pos + 4);
|
|
this.pos += 8;
|
|
},
|
|
|
|
writeVarint: function(val) {
|
|
val = +val || 0;
|
|
|
|
if (val > 0xfffffff || val < 0) {
|
|
writeBigVarint(val, this);
|
|
return;
|
|
}
|
|
|
|
this.realloc(4);
|
|
|
|
this.buf[this.pos++] = val & 0x7f | (val > 0x7f ? 0x80 : 0); if (val <= 0x7f) { return; }
|
|
this.buf[this.pos++] = ((val >>>= 7) & 0x7f) | (val > 0x7f ? 0x80 : 0); if (val <= 0x7f) { return; }
|
|
this.buf[this.pos++] = ((val >>>= 7) & 0x7f) | (val > 0x7f ? 0x80 : 0); if (val <= 0x7f) { return; }
|
|
this.buf[this.pos++] = (val >>> 7) & 0x7f;
|
|
},
|
|
|
|
writeSVarint: function(val) {
|
|
this.writeVarint(val < 0 ? -val * 2 - 1 : val * 2);
|
|
},
|
|
|
|
writeBoolean: function(val) {
|
|
this.writeVarint(Boolean(val));
|
|
},
|
|
|
|
writeString: function(str) {
|
|
str = String(str);
|
|
this.realloc(str.length * 4);
|
|
|
|
this.pos++; // reserve 1 byte for short string length
|
|
|
|
var startPos = this.pos;
|
|
// write the string directly to the buffer and see how much was written
|
|
this.pos = writeUtf8(this.buf, str, this.pos);
|
|
var len = this.pos - startPos;
|
|
|
|
if (len >= 0x80) { makeRoomForExtraLength(startPos, len, this); }
|
|
|
|
// finally, write the message length in the reserved place and restore the position
|
|
this.pos = startPos - 1;
|
|
this.writeVarint(len);
|
|
this.pos += len;
|
|
},
|
|
|
|
writeFloat: function(val) {
|
|
this.realloc(4);
|
|
ieee754.write(this.buf, val, this.pos, true, 23, 4);
|
|
this.pos += 4;
|
|
},
|
|
|
|
writeDouble: function(val) {
|
|
this.realloc(8);
|
|
ieee754.write(this.buf, val, this.pos, true, 52, 8);
|
|
this.pos += 8;
|
|
},
|
|
|
|
writeBytes: function(buffer) {
|
|
var this$1 = this;
|
|
|
|
var len = buffer.length;
|
|
this.writeVarint(len);
|
|
this.realloc(len);
|
|
for (var i = 0; i < len; i++) { this$1.buf[this$1.pos++] = buffer[i]; }
|
|
},
|
|
|
|
writeRawMessage: function(fn, obj) {
|
|
this.pos++; // reserve 1 byte for short message length
|
|
|
|
// write the message directly to the buffer and see how much was written
|
|
var startPos = this.pos;
|
|
fn(obj, this);
|
|
var len = this.pos - startPos;
|
|
|
|
if (len >= 0x80) { makeRoomForExtraLength(startPos, len, this); }
|
|
|
|
// finally, write the message length in the reserved place and restore the position
|
|
this.pos = startPos - 1;
|
|
this.writeVarint(len);
|
|
this.pos += len;
|
|
},
|
|
|
|
writeMessage: function(tag, fn, obj) {
|
|
this.writeTag(tag, Pbf.Bytes);
|
|
this.writeRawMessage(fn, obj);
|
|
},
|
|
|
|
writePackedVarint: function(tag, arr) { this.writeMessage(tag, writePackedVarint, arr); },
|
|
writePackedSVarint: function(tag, arr) { this.writeMessage(tag, writePackedSVarint, arr); },
|
|
writePackedBoolean: function(tag, arr) { this.writeMessage(tag, writePackedBoolean, arr); },
|
|
writePackedFloat: function(tag, arr) { this.writeMessage(tag, writePackedFloat, arr); },
|
|
writePackedDouble: function(tag, arr) { this.writeMessage(tag, writePackedDouble, arr); },
|
|
writePackedFixed32: function(tag, arr) { this.writeMessage(tag, writePackedFixed32, arr); },
|
|
writePackedSFixed32: function(tag, arr) { this.writeMessage(tag, writePackedSFixed32, arr); },
|
|
writePackedFixed64: function(tag, arr) { this.writeMessage(tag, writePackedFixed64, arr); },
|
|
writePackedSFixed64: function(tag, arr) { this.writeMessage(tag, writePackedSFixed64, arr); },
|
|
|
|
writeBytesField: function(tag, buffer) {
|
|
this.writeTag(tag, Pbf.Bytes);
|
|
this.writeBytes(buffer);
|
|
},
|
|
writeFixed32Field: function(tag, val) {
|
|
this.writeTag(tag, Pbf.Fixed32);
|
|
this.writeFixed32(val);
|
|
},
|
|
writeSFixed32Field: function(tag, val) {
|
|
this.writeTag(tag, Pbf.Fixed32);
|
|
this.writeSFixed32(val);
|
|
},
|
|
writeFixed64Field: function(tag, val) {
|
|
this.writeTag(tag, Pbf.Fixed64);
|
|
this.writeFixed64(val);
|
|
},
|
|
writeSFixed64Field: function(tag, val) {
|
|
this.writeTag(tag, Pbf.Fixed64);
|
|
this.writeSFixed64(val);
|
|
},
|
|
writeVarintField: function(tag, val) {
|
|
this.writeTag(tag, Pbf.Varint);
|
|
this.writeVarint(val);
|
|
},
|
|
writeSVarintField: function(tag, val) {
|
|
this.writeTag(tag, Pbf.Varint);
|
|
this.writeSVarint(val);
|
|
},
|
|
writeStringField: function(tag, str) {
|
|
this.writeTag(tag, Pbf.Bytes);
|
|
this.writeString(str);
|
|
},
|
|
writeFloatField: function(tag, val) {
|
|
this.writeTag(tag, Pbf.Fixed32);
|
|
this.writeFloat(val);
|
|
},
|
|
writeDoubleField: function(tag, val) {
|
|
this.writeTag(tag, Pbf.Fixed64);
|
|
this.writeDouble(val);
|
|
},
|
|
writeBooleanField: function(tag, val) {
|
|
this.writeVarintField(tag, Boolean(val));
|
|
}
|
|
};
|
|
|
|
function readVarintRemainder(l, s, p) {
|
|
var buf = p.buf,
|
|
h, b;
|
|
|
|
b = buf[p.pos++]; h = (b & 0x70) >> 4; if (b < 0x80) { return toNum(l, h, s); }
|
|
b = buf[p.pos++]; h |= (b & 0x7f) << 3; if (b < 0x80) { return toNum(l, h, s); }
|
|
b = buf[p.pos++]; h |= (b & 0x7f) << 10; if (b < 0x80) { return toNum(l, h, s); }
|
|
b = buf[p.pos++]; h |= (b & 0x7f) << 17; if (b < 0x80) { return toNum(l, h, s); }
|
|
b = buf[p.pos++]; h |= (b & 0x7f) << 24; if (b < 0x80) { return toNum(l, h, s); }
|
|
b = buf[p.pos++]; h |= (b & 0x01) << 31; if (b < 0x80) { return toNum(l, h, s); }
|
|
|
|
throw new Error('Expected varint not more than 10 bytes');
|
|
}
|
|
|
|
function readPackedEnd(pbf) {
|
|
return pbf.type === Pbf.Bytes ?
|
|
pbf.readVarint() + pbf.pos : pbf.pos + 1;
|
|
}
|
|
|
|
function toNum(low, high, isSigned) {
|
|
if (isSigned) {
|
|
return high * 0x100000000 + (low >>> 0);
|
|
}
|
|
|
|
return ((high >>> 0) * 0x100000000) + (low >>> 0);
|
|
}
|
|
|
|
function writeBigVarint(val, pbf) {
|
|
var low, high;
|
|
|
|
if (val >= 0) {
|
|
low = (val % 0x100000000) | 0;
|
|
high = (val / 0x100000000) | 0;
|
|
} else {
|
|
low = ~(-val % 0x100000000);
|
|
high = ~(-val / 0x100000000);
|
|
|
|
if (low ^ 0xffffffff) {
|
|
low = (low + 1) | 0;
|
|
} else {
|
|
low = 0;
|
|
high = (high + 1) | 0;
|
|
}
|
|
}
|
|
|
|
if (val >= 0x10000000000000000 || val < -0x10000000000000000) {
|
|
throw new Error('Given varint doesn\'t fit into 10 bytes');
|
|
}
|
|
|
|
pbf.realloc(10);
|
|
|
|
writeBigVarintLow(low, high, pbf);
|
|
writeBigVarintHigh(high, pbf);
|
|
}
|
|
|
|
function writeBigVarintLow(low, high, pbf) {
|
|
pbf.buf[pbf.pos++] = low & 0x7f | 0x80; low >>>= 7;
|
|
pbf.buf[pbf.pos++] = low & 0x7f | 0x80; low >>>= 7;
|
|
pbf.buf[pbf.pos++] = low & 0x7f | 0x80; low >>>= 7;
|
|
pbf.buf[pbf.pos++] = low & 0x7f | 0x80; low >>>= 7;
|
|
pbf.buf[pbf.pos] = low & 0x7f;
|
|
}
|
|
|
|
function writeBigVarintHigh(high, pbf) {
|
|
var lsb = (high & 0x07) << 4;
|
|
|
|
pbf.buf[pbf.pos++] |= lsb | ((high >>>= 3) ? 0x80 : 0); if (!high) { return; }
|
|
pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0); if (!high) { return; }
|
|
pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0); if (!high) { return; }
|
|
pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0); if (!high) { return; }
|
|
pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0); if (!high) { return; }
|
|
pbf.buf[pbf.pos++] = high & 0x7f;
|
|
}
|
|
|
|
function makeRoomForExtraLength(startPos, len, pbf) {
|
|
var extraLen =
|
|
len <= 0x3fff ? 1 :
|
|
len <= 0x1fffff ? 2 :
|
|
len <= 0xfffffff ? 3 : Math.ceil(Math.log(len) / (Math.LN2 * 7));
|
|
|
|
// if 1 byte isn't enough for encoding message length, shift the data to the right
|
|
pbf.realloc(extraLen);
|
|
for (var i = pbf.pos - 1; i >= startPos; i--) { pbf.buf[i + extraLen] = pbf.buf[i]; }
|
|
}
|
|
|
|
function writePackedVarint(arr, pbf) { for (var i = 0; i < arr.length; i++) { pbf.writeVarint(arr[i]); } }
|
|
function writePackedSVarint(arr, pbf) { for (var i = 0; i < arr.length; i++) { pbf.writeSVarint(arr[i]); } }
|
|
function writePackedFloat(arr, pbf) { for (var i = 0; i < arr.length; i++) { pbf.writeFloat(arr[i]); } }
|
|
function writePackedDouble(arr, pbf) { for (var i = 0; i < arr.length; i++) { pbf.writeDouble(arr[i]); } }
|
|
function writePackedBoolean(arr, pbf) { for (var i = 0; i < arr.length; i++) { pbf.writeBoolean(arr[i]); } }
|
|
function writePackedFixed32(arr, pbf) { for (var i = 0; i < arr.length; i++) { pbf.writeFixed32(arr[i]); } }
|
|
function writePackedSFixed32(arr, pbf) { for (var i = 0; i < arr.length; i++) { pbf.writeSFixed32(arr[i]); } }
|
|
function writePackedFixed64(arr, pbf) { for (var i = 0; i < arr.length; i++) { pbf.writeFixed64(arr[i]); } }
|
|
function writePackedSFixed64(arr, pbf) { for (var i = 0; i < arr.length; i++) { pbf.writeSFixed64(arr[i]); } }
|
|
|
|
// Buffer code below from https://github.com/feross/buffer, MIT-licensed
|
|
|
|
function readUInt32(buf, pos) {
|
|
return ((buf[pos]) |
|
|
(buf[pos + 1] << 8) |
|
|
(buf[pos + 2] << 16)) +
|
|
(buf[pos + 3] * 0x1000000);
|
|
}
|
|
|
|
function writeInt32(buf, val, pos) {
|
|
buf[pos] = val;
|
|
buf[pos + 1] = (val >>> 8);
|
|
buf[pos + 2] = (val >>> 16);
|
|
buf[pos + 3] = (val >>> 24);
|
|
}
|
|
|
|
function readInt32(buf, pos) {
|
|
return ((buf[pos]) |
|
|
(buf[pos + 1] << 8) |
|
|
(buf[pos + 2] << 16)) +
|
|
(buf[pos + 3] << 24);
|
|
}
|
|
|
|
function readUtf8(buf, pos, end) {
|
|
var str = '';
|
|
var i = pos;
|
|
|
|
while (i < end) {
|
|
var b0 = buf[i];
|
|
var c = null; // codepoint
|
|
var bytesPerSequence =
|
|
b0 > 0xEF ? 4 :
|
|
b0 > 0xDF ? 3 :
|
|
b0 > 0xBF ? 2 : 1;
|
|
|
|
if (i + bytesPerSequence > end) { break; }
|
|
|
|
var b1, b2, b3;
|
|
|
|
if (bytesPerSequence === 1) {
|
|
if (b0 < 0x80) {
|
|
c = b0;
|
|
}
|
|
} else if (bytesPerSequence === 2) {
|
|
b1 = buf[i + 1];
|
|
if ((b1 & 0xC0) === 0x80) {
|
|
c = (b0 & 0x1F) << 0x6 | (b1 & 0x3F);
|
|
if (c <= 0x7F) {
|
|
c = null;
|
|
}
|
|
}
|
|
} else if (bytesPerSequence === 3) {
|
|
b1 = buf[i + 1];
|
|
b2 = buf[i + 2];
|
|
if ((b1 & 0xC0) === 0x80 && (b2 & 0xC0) === 0x80) {
|
|
c = (b0 & 0xF) << 0xC | (b1 & 0x3F) << 0x6 | (b2 & 0x3F);
|
|
if (c <= 0x7FF || (c >= 0xD800 && c <= 0xDFFF)) {
|
|
c = null;
|
|
}
|
|
}
|
|
} else if (bytesPerSequence === 4) {
|
|
b1 = buf[i + 1];
|
|
b2 = buf[i + 2];
|
|
b3 = buf[i + 3];
|
|
if ((b1 & 0xC0) === 0x80 && (b2 & 0xC0) === 0x80 && (b3 & 0xC0) === 0x80) {
|
|
c = (b0 & 0xF) << 0x12 | (b1 & 0x3F) << 0xC | (b2 & 0x3F) << 0x6 | (b3 & 0x3F);
|
|
if (c <= 0xFFFF || c >= 0x110000) {
|
|
c = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (c === null) {
|
|
c = 0xFFFD;
|
|
bytesPerSequence = 1;
|
|
|
|
} else if (c > 0xFFFF) {
|
|
c -= 0x10000;
|
|
str += String.fromCharCode(c >>> 10 & 0x3FF | 0xD800);
|
|
c = 0xDC00 | c & 0x3FF;
|
|
}
|
|
|
|
str += String.fromCharCode(c);
|
|
i += bytesPerSequence;
|
|
}
|
|
|
|
return str;
|
|
}
|
|
|
|
function writeUtf8(buf, str, pos) {
|
|
for (var i = 0, c, lead; i < str.length; i++) {
|
|
c = str.charCodeAt(i); // code point
|
|
|
|
if (c > 0xD7FF && c < 0xE000) {
|
|
if (lead) {
|
|
if (c < 0xDC00) {
|
|
buf[pos++] = 0xEF;
|
|
buf[pos++] = 0xBF;
|
|
buf[pos++] = 0xBD;
|
|
lead = c;
|
|
continue;
|
|
} else {
|
|
c = lead - 0xD800 << 10 | c - 0xDC00 | 0x10000;
|
|
lead = null;
|
|
}
|
|
} else {
|
|
if (c > 0xDBFF || (i + 1 === str.length)) {
|
|
buf[pos++] = 0xEF;
|
|
buf[pos++] = 0xBF;
|
|
buf[pos++] = 0xBD;
|
|
} else {
|
|
lead = c;
|
|
}
|
|
continue;
|
|
}
|
|
} else if (lead) {
|
|
buf[pos++] = 0xEF;
|
|
buf[pos++] = 0xBF;
|
|
buf[pos++] = 0xBD;
|
|
lead = null;
|
|
}
|
|
|
|
if (c < 0x80) {
|
|
buf[pos++] = c;
|
|
} else {
|
|
if (c < 0x800) {
|
|
buf[pos++] = c >> 0x6 | 0xC0;
|
|
} else {
|
|
if (c < 0x10000) {
|
|
buf[pos++] = c >> 0xC | 0xE0;
|
|
} else {
|
|
buf[pos++] = c >> 0x12 | 0xF0;
|
|
buf[pos++] = c >> 0xC & 0x3F | 0x80;
|
|
}
|
|
buf[pos++] = c >> 0x6 & 0x3F | 0x80;
|
|
}
|
|
buf[pos++] = c & 0x3F | 0x80;
|
|
}
|
|
}
|
|
return pos;
|
|
}
|
|
|
|
var index$5 = Point$1;
|
|
|
|
function Point$1(x, y) {
|
|
this.x = x;
|
|
this.y = y;
|
|
}
|
|
|
|
Point$1.prototype = {
|
|
clone: function() { return new Point$1(this.x, this.y); },
|
|
|
|
add: function(p) { return this.clone()._add(p); },
|
|
sub: function(p) { return this.clone()._sub(p); },
|
|
mult: function(k) { return this.clone()._mult(k); },
|
|
div: function(k) { return this.clone()._div(k); },
|
|
rotate: function(a) { return this.clone()._rotate(a); },
|
|
matMult: function(m) { return this.clone()._matMult(m); },
|
|
unit: function() { return this.clone()._unit(); },
|
|
perp: function() { return this.clone()._perp(); },
|
|
round: function() { return this.clone()._round(); },
|
|
|
|
mag: function() {
|
|
return Math.sqrt(this.x * this.x + this.y * this.y);
|
|
},
|
|
|
|
equals: function(p) {
|
|
return this.x === p.x &&
|
|
this.y === p.y;
|
|
},
|
|
|
|
dist: function(p) {
|
|
return Math.sqrt(this.distSqr(p));
|
|
},
|
|
|
|
distSqr: function(p) {
|
|
var dx = p.x - this.x,
|
|
dy = p.y - this.y;
|
|
return dx * dx + dy * dy;
|
|
},
|
|
|
|
angle: function() {
|
|
return Math.atan2(this.y, this.x);
|
|
},
|
|
|
|
angleTo: function(b) {
|
|
return Math.atan2(this.y - b.y, this.x - b.x);
|
|
},
|
|
|
|
angleWith: function(b) {
|
|
return this.angleWithSep(b.x, b.y);
|
|
},
|
|
|
|
// Find the angle of the two vectors, solving the formula for the cross product a x b = |a||b|sin(θ) for θ.
|
|
angleWithSep: function(x, y) {
|
|
return Math.atan2(
|
|
this.x * y - this.y * x,
|
|
this.x * x + this.y * y);
|
|
},
|
|
|
|
_matMult: function(m) {
|
|
var x = m[0] * this.x + m[1] * this.y,
|
|
y = m[2] * this.x + m[3] * this.y;
|
|
this.x = x;
|
|
this.y = y;
|
|
return this;
|
|
},
|
|
|
|
_add: function(p) {
|
|
this.x += p.x;
|
|
this.y += p.y;
|
|
return this;
|
|
},
|
|
|
|
_sub: function(p) {
|
|
this.x -= p.x;
|
|
this.y -= p.y;
|
|
return this;
|
|
},
|
|
|
|
_mult: function(k) {
|
|
this.x *= k;
|
|
this.y *= k;
|
|
return this;
|
|
},
|
|
|
|
_div: function(k) {
|
|
this.x /= k;
|
|
this.y /= k;
|
|
return this;
|
|
},
|
|
|
|
_unit: function() {
|
|
this._div(this.mag());
|
|
return this;
|
|
},
|
|
|
|
_perp: function() {
|
|
var y = this.y;
|
|
this.y = this.x;
|
|
this.x = -y;
|
|
return this;
|
|
},
|
|
|
|
_rotate: function(angle) {
|
|
var cos = Math.cos(angle),
|
|
sin = Math.sin(angle),
|
|
x = cos * this.x - sin * this.y,
|
|
y = sin * this.x + cos * this.y;
|
|
this.x = x;
|
|
this.y = y;
|
|
return this;
|
|
},
|
|
|
|
_round: function() {
|
|
this.x = Math.round(this.x);
|
|
this.y = Math.round(this.y);
|
|
return this;
|
|
}
|
|
};
|
|
|
|
// constructs Point from an array if necessary
|
|
Point$1.convert = function (a) {
|
|
if (a instanceof Point$1) {
|
|
return a;
|
|
}
|
|
if (Array.isArray(a)) {
|
|
return new Point$1(a[0], a[1]);
|
|
}
|
|
return a;
|
|
};
|
|
|
|
var Point = index$5;
|
|
|
|
var vectortilefeature = VectorTileFeature$2;
|
|
|
|
function VectorTileFeature$2(pbf, end, extent, keys, values) {
|
|
// Public
|
|
this.properties = {};
|
|
this.extent = extent;
|
|
this.type = 0;
|
|
|
|
// Private
|
|
this._pbf = pbf;
|
|
this._geometry = -1;
|
|
this._keys = keys;
|
|
this._values = values;
|
|
|
|
pbf.readFields(readFeature, this, end);
|
|
}
|
|
|
|
function readFeature(tag, feature, pbf) {
|
|
if (tag == 1) { feature.id = pbf.readVarint(); }
|
|
else if (tag == 2) { readTag(pbf, feature); }
|
|
else if (tag == 3) { feature.type = pbf.readVarint(); }
|
|
else if (tag == 4) { feature._geometry = pbf.pos; }
|
|
}
|
|
|
|
function readTag(pbf, feature) {
|
|
var end = pbf.readVarint() + pbf.pos;
|
|
|
|
while (pbf.pos < end) {
|
|
var key = feature._keys[pbf.readVarint()],
|
|
value = feature._values[pbf.readVarint()];
|
|
feature.properties[key] = value;
|
|
}
|
|
}
|
|
|
|
VectorTileFeature$2.types = ['Unknown', 'Point', 'LineString', 'Polygon'];
|
|
|
|
VectorTileFeature$2.prototype.loadGeometry = function() {
|
|
var pbf = this._pbf;
|
|
pbf.pos = this._geometry;
|
|
|
|
var end = pbf.readVarint() + pbf.pos,
|
|
cmd = 1,
|
|
length = 0,
|
|
x = 0,
|
|
y = 0,
|
|
lines = [],
|
|
line;
|
|
|
|
while (pbf.pos < end) {
|
|
if (!length) {
|
|
var cmdLen = pbf.readVarint();
|
|
cmd = cmdLen & 0x7;
|
|
length = cmdLen >> 3;
|
|
}
|
|
|
|
length--;
|
|
|
|
if (cmd === 1 || cmd === 2) {
|
|
x += pbf.readSVarint();
|
|
y += pbf.readSVarint();
|
|
|
|
if (cmd === 1) { // moveTo
|
|
if (line) { lines.push(line); }
|
|
line = [];
|
|
}
|
|
|
|
line.push(new Point(x, y));
|
|
|
|
} else if (cmd === 7) {
|
|
|
|
// Workaround for https://github.com/mapbox/mapnik-vector-tile/issues/90
|
|
if (line) {
|
|
line.push(line[0].clone()); // closePolygon
|
|
}
|
|
|
|
} else {
|
|
throw new Error('unknown command ' + cmd);
|
|
}
|
|
}
|
|
|
|
if (line) { lines.push(line); }
|
|
|
|
return lines;
|
|
};
|
|
|
|
VectorTileFeature$2.prototype.bbox = function() {
|
|
var pbf = this._pbf;
|
|
pbf.pos = this._geometry;
|
|
|
|
var end = pbf.readVarint() + pbf.pos,
|
|
cmd = 1,
|
|
length = 0,
|
|
x = 0,
|
|
y = 0,
|
|
x1 = Infinity,
|
|
x2 = -Infinity,
|
|
y1 = Infinity,
|
|
y2 = -Infinity;
|
|
|
|
while (pbf.pos < end) {
|
|
if (!length) {
|
|
var cmdLen = pbf.readVarint();
|
|
cmd = cmdLen & 0x7;
|
|
length = cmdLen >> 3;
|
|
}
|
|
|
|
length--;
|
|
|
|
if (cmd === 1 || cmd === 2) {
|
|
x += pbf.readSVarint();
|
|
y += pbf.readSVarint();
|
|
if (x < x1) { x1 = x; }
|
|
if (x > x2) { x2 = x; }
|
|
if (y < y1) { y1 = y; }
|
|
if (y > y2) { y2 = y; }
|
|
|
|
} else if (cmd !== 7) {
|
|
throw new Error('unknown command ' + cmd);
|
|
}
|
|
}
|
|
|
|
return [x1, y1, x2, y2];
|
|
};
|
|
|
|
VectorTileFeature$2.prototype.toGeoJSON = function(x, y, z) {
|
|
var size = this.extent * Math.pow(2, z),
|
|
x0 = this.extent * x,
|
|
y0 = this.extent * y,
|
|
coords = this.loadGeometry(),
|
|
type = VectorTileFeature$2.types[this.type],
|
|
i, j;
|
|
|
|
function project(line) {
|
|
for (var j = 0; j < line.length; j++) {
|
|
var p = line[j], y2 = 180 - (p.y + y0) * 360 / size;
|
|
line[j] = [
|
|
(p.x + x0) * 360 / size - 180,
|
|
360 / Math.PI * Math.atan(Math.exp(y2 * Math.PI / 180)) - 90
|
|
];
|
|
}
|
|
}
|
|
|
|
switch (this.type) {
|
|
case 1:
|
|
var points = [];
|
|
for (i = 0; i < coords.length; i++) {
|
|
points[i] = coords[i][0];
|
|
}
|
|
coords = points;
|
|
project(coords);
|
|
break;
|
|
|
|
case 2:
|
|
for (i = 0; i < coords.length; i++) {
|
|
project(coords[i]);
|
|
}
|
|
break;
|
|
|
|
case 3:
|
|
coords = classifyRings(coords);
|
|
for (i = 0; i < coords.length; i++) {
|
|
for (j = 0; j < coords[i].length; j++) {
|
|
project(coords[i][j]);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (coords.length === 1) {
|
|
coords = coords[0];
|
|
} else {
|
|
type = 'Multi' + type;
|
|
}
|
|
|
|
var result = {
|
|
type: "Feature",
|
|
geometry: {
|
|
type: type,
|
|
coordinates: coords
|
|
},
|
|
properties: this.properties
|
|
};
|
|
|
|
if ('id' in this) {
|
|
result.id = this.id;
|
|
}
|
|
|
|
return result;
|
|
};
|
|
|
|
// classifies an array of rings into polygons with outer rings and holes
|
|
|
|
function classifyRings(rings) {
|
|
var len = rings.length;
|
|
|
|
if (len <= 1) { return [rings]; }
|
|
|
|
var polygons = [],
|
|
polygon,
|
|
ccw;
|
|
|
|
for (var i = 0; i < len; i++) {
|
|
var area = signedArea(rings[i]);
|
|
if (area === 0) { continue; }
|
|
|
|
if (ccw === undefined) { ccw = area < 0; }
|
|
|
|
if (ccw === area < 0) {
|
|
if (polygon) { polygons.push(polygon); }
|
|
polygon = [rings[i]];
|
|
|
|
} else {
|
|
polygon.push(rings[i]);
|
|
}
|
|
}
|
|
if (polygon) { polygons.push(polygon); }
|
|
|
|
return polygons;
|
|
}
|
|
|
|
function signedArea(ring) {
|
|
var sum = 0;
|
|
for (var i = 0, len = ring.length, j = len - 1, p1, p2; i < len; j = i++) {
|
|
p1 = ring[i];
|
|
p2 = ring[j];
|
|
sum += (p2.x - p1.x) * (p1.y + p2.y);
|
|
}
|
|
return sum;
|
|
}
|
|
|
|
var VectorTileFeature$1 = vectortilefeature;
|
|
|
|
var vectortilelayer = VectorTileLayer$2;
|
|
|
|
function VectorTileLayer$2(pbf, end) {
|
|
// Public
|
|
this.version = 1;
|
|
this.name = null;
|
|
this.extent = 4096;
|
|
this.length = 0;
|
|
|
|
// Private
|
|
this._pbf = pbf;
|
|
this._keys = [];
|
|
this._values = [];
|
|
this._features = [];
|
|
|
|
pbf.readFields(readLayer, this, end);
|
|
|
|
this.length = this._features.length;
|
|
}
|
|
|
|
function readLayer(tag, layer, pbf) {
|
|
if (tag === 15) { layer.version = pbf.readVarint(); }
|
|
else if (tag === 1) { layer.name = pbf.readString(); }
|
|
else if (tag === 5) { layer.extent = pbf.readVarint(); }
|
|
else if (tag === 2) { layer._features.push(pbf.pos); }
|
|
else if (tag === 3) { layer._keys.push(pbf.readString()); }
|
|
else if (tag === 4) { layer._values.push(readValueMessage(pbf)); }
|
|
}
|
|
|
|
function readValueMessage(pbf) {
|
|
var value = null,
|
|
end = pbf.readVarint() + pbf.pos;
|
|
|
|
while (pbf.pos < end) {
|
|
var tag = pbf.readVarint() >> 3;
|
|
|
|
value = tag === 1 ? pbf.readString() :
|
|
tag === 2 ? pbf.readFloat() :
|
|
tag === 3 ? pbf.readDouble() :
|
|
tag === 4 ? pbf.readVarint64() :
|
|
tag === 5 ? pbf.readVarint() :
|
|
tag === 6 ? pbf.readSVarint() :
|
|
tag === 7 ? pbf.readBoolean() : null;
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
// return feature `i` from this layer as a `VectorTileFeature`
|
|
VectorTileLayer$2.prototype.feature = function(i) {
|
|
if (i < 0 || i >= this._features.length) { throw new Error('feature index out of bounds'); }
|
|
|
|
this._pbf.pos = this._features[i];
|
|
|
|
var end = this._pbf.readVarint() + this._pbf.pos;
|
|
return new VectorTileFeature$1(this._pbf, end, this.extent, this._keys, this._values);
|
|
};
|
|
|
|
var VectorTileLayer$1 = vectortilelayer;
|
|
|
|
var vectortile = VectorTile$1;
|
|
|
|
function VectorTile$1(pbf, end) {
|
|
this.layers = pbf.readFields(readTile, {}, end);
|
|
}
|
|
|
|
function readTile(tag, layers, pbf) {
|
|
if (tag === 3) {
|
|
var layer = new VectorTileLayer$1(pbf, pbf.readVarint() + pbf.pos);
|
|
if (layer.length) { layers[layer.name] = layer; }
|
|
}
|
|
}
|
|
|
|
var VectorTile = vectortile;
|
|
|
|
L.SVG.Tile = L.SVG.extend({
|
|
|
|
initialize: function (tileCoord, tileSize, options) {
|
|
L.SVG.prototype.initialize.call(this, options);
|
|
this._tileCoord = tileCoord;
|
|
this._size = tileSize;
|
|
|
|
this._initContainer();
|
|
this._container.setAttribute('width', this._size.x);
|
|
this._container.setAttribute('height', this._size.y);
|
|
this._container.setAttribute('viewBox', [0, 0, this._size.x, this._size.y].join(' '));
|
|
|
|
this._layers = {};
|
|
},
|
|
|
|
getCoord: function() {
|
|
return this._tileCoord;
|
|
},
|
|
|
|
getContainer: function() {
|
|
return this._container;
|
|
},
|
|
|
|
onAdd: L.Util.falseFn,
|
|
|
|
addTo: function(map) {
|
|
this._map = map;
|
|
if (this.options.interactive) {
|
|
for (var i in this._layers) {
|
|
var layer = this._layers[i];
|
|
// By default, Leaflet tiles do not have pointer events.
|
|
layer._path.style.pointerEvents = 'auto';
|
|
this._map._targets[L.stamp(layer._path)] = layer;
|
|
}
|
|
}
|
|
},
|
|
|
|
removeFrom: function (map) {
|
|
if (this.options.interactive) {
|
|
for (var i in this._layers) {
|
|
var layer = this._layers[i];
|
|
delete this._map._targets[L.stamp(layer._path)];
|
|
}
|
|
}
|
|
delete this._map;
|
|
},
|
|
|
|
_initContainer: function() {
|
|
L.SVG.prototype._initContainer.call(this);
|
|
var rect = L.SVG.create('rect');
|
|
},
|
|
|
|
/// TODO: Modify _initPath to include an extra parameter, a group name
|
|
/// to order symbolizers by z-index
|
|
|
|
_addPath: function (layer) {
|
|
this._rootGroup.appendChild(layer._path);
|
|
this._layers[L.stamp(layer)] = layer;
|
|
},
|
|
|
|
_updateIcon: function (layer) {
|
|
var path = layer._path = L.SVG.create('image'),
|
|
icon = layer.options.icon,
|
|
options = icon.options,
|
|
size = L.point(options.iconSize),
|
|
anchor = options.iconAnchor ||
|
|
size && size.divideBy(2, true),
|
|
p = layer._point.subtract(anchor);
|
|
path.setAttribute('x', p.x);
|
|
path.setAttribute('y', p.y);
|
|
path.setAttribute('width', size.x + 'px');
|
|
path.setAttribute('height', size.y + 'px');
|
|
path.setAttribute('href', options.iconUrl);
|
|
}
|
|
});
|
|
|
|
|
|
L.svg.tile = function(tileCoord, tileSize, opts){
|
|
return new L.SVG.Tile(tileCoord, tileSize, opts);
|
|
};
|
|
|
|
// 🍂class Symbolizer
|
|
// 🍂inherits Class
|
|
// The abstract Symbolizer class is mostly equivalent in concept to a `L.Path` - it's an interface for
|
|
// polylines, polygons and circles. But instead of representing leaflet Layers,
|
|
// it represents things that have to be drawn inside a vector tile.
|
|
|
|
// A vector tile *data layer* might have zero, one, or more *symbolizer definitions*
|
|
// A vector tile *feature* might have zero, one, or more *symbolizers*.
|
|
// The actual symbolizers applied will depend on filters and the symbolizer functions.
|
|
|
|
var Symbolizer = L.Class.extend({
|
|
// 🍂method initialize(feature: GeoJSON, pxPerExtent: Number)
|
|
// Initializes a new Line Symbolizer given a GeoJSON feature and the
|
|
// pixel-to-coordinate-units ratio. Internal use only.
|
|
|
|
// 🍂method render(renderer, style)
|
|
// Renders this symbolizer in the given tiled renderer, with the given
|
|
// `L.Path` options. Internal use only.
|
|
render: function(renderer, style) {
|
|
this._renderer = renderer;
|
|
this.options = style;
|
|
renderer._initPath(this);
|
|
renderer._updateStyle(this);
|
|
},
|
|
|
|
// 🍂method render(renderer, style)
|
|
// Updates the `L.Path` options used to style this symbolizer, and re-renders it.
|
|
// Internal use only.
|
|
updateStyle: function(renderer, style) {
|
|
this.options = style;
|
|
renderer._updateStyle(this);
|
|
},
|
|
|
|
_getPixelBounds: function() {
|
|
var parts = this._parts;
|
|
var bounds = L.bounds([]);
|
|
for (var i = 0; i < parts.length; i++) {
|
|
var part = parts[i];
|
|
for (var j = 0; j < part.length; j++) {
|
|
bounds.extend(part[j]);
|
|
}
|
|
}
|
|
|
|
var w = this._clickTolerance(),
|
|
p = new L.Point(w, w);
|
|
|
|
bounds.min._subtract(p);
|
|
bounds.max._add(p);
|
|
|
|
return bounds;
|
|
},
|
|
_clickTolerance: L.Path.prototype._clickTolerance,
|
|
});
|
|
|
|
// Contains mixins which are common to the Line Symbolizer and the Fill Symbolizer.
|
|
|
|
var PolyBase = {
|
|
_makeFeatureParts: function(feat, pxPerExtent) {
|
|
var rings = feat.geometry;
|
|
var coord;
|
|
|
|
this._parts = [];
|
|
for (var i = 0; i < rings.length; i++) {
|
|
var ring = rings[i];
|
|
var part = [];
|
|
for (var j = 0; j < ring.length; j++) {
|
|
coord = ring[j];
|
|
// Protobuf vector tiles return {x: , y:}
|
|
// Geojson-vt returns [,]
|
|
part.push(L.point(coord).scaleBy(pxPerExtent));
|
|
}
|
|
this._parts.push(part);
|
|
}
|
|
},
|
|
|
|
makeInteractive: function() {
|
|
this._pxBounds = this._getPixelBounds();
|
|
}
|
|
};
|
|
|
|
// 🍂class PointSymbolizer
|
|
// 🍂inherits CircleMarker
|
|
// A symbolizer for points.
|
|
|
|
var PointSymbolizer = L.CircleMarker.extend({
|
|
includes: Symbolizer.prototype,
|
|
|
|
statics: {
|
|
iconCache: {}
|
|
},
|
|
|
|
initialize: function(feature, pxPerExtent) {
|
|
this.properties = feature.properties;
|
|
this._makeFeatureParts(feature, pxPerExtent);
|
|
},
|
|
|
|
render: function(renderer, style) {
|
|
Symbolizer.prototype.render.call(this, renderer, style);
|
|
this._radius = style.radius || L.CircleMarker.prototype.options.radius;
|
|
this._updatePath();
|
|
},
|
|
|
|
_makeFeatureParts: function(feat, pxPerExtent) {
|
|
var coord = feat.geometry[0];
|
|
if (typeof coord[0] === 'object' && 'x' in coord[0]) {
|
|
// Protobuf vector tiles return [{x: , y:}]
|
|
this._point = L.point(coord[0]).scaleBy(pxPerExtent);
|
|
this._empty = L.Util.falseFn;
|
|
} else {
|
|
// Geojson-vt returns [,]
|
|
this._point = L.point(coord).scaleBy(pxPerExtent);
|
|
this._empty = L.Util.falseFn;
|
|
}
|
|
},
|
|
|
|
makeInteractive: function() {
|
|
this._updateBounds();
|
|
},
|
|
|
|
updateStyle: function(renderer, style) {
|
|
this._radius = style.radius || this._radius;
|
|
this._updateBounds();
|
|
return Symbolizer.prototype.updateStyle.call(this, renderer, style);
|
|
},
|
|
|
|
_updateBounds: function() {
|
|
var icon = this.options.icon;
|
|
if (icon) {
|
|
var size = L.point(icon.options.iconSize),
|
|
anchor = icon.options.iconAnchor ||
|
|
size && size.divideBy(2, true),
|
|
p = this._point.subtract(anchor);
|
|
this._pxBounds = new L.Bounds(p, p.add(icon.options.iconSize));
|
|
} else {
|
|
L.CircleMarker.prototype._updateBounds.call(this);
|
|
}
|
|
},
|
|
|
|
_updatePath: function() {
|
|
if (this.options.icon) {
|
|
this._renderer._updateIcon(this);
|
|
} else {
|
|
L.CircleMarker.prototype._updatePath.call(this);
|
|
}
|
|
},
|
|
|
|
_getImage: function () {
|
|
if (this.options.icon) {
|
|
var url = this.options.icon.options.iconUrl,
|
|
img = PointSymbolizer.iconCache[url];
|
|
if (!img) {
|
|
var icon = this.options.icon;
|
|
img = PointSymbolizer.iconCache[url] = icon.createIcon();
|
|
}
|
|
return img;
|
|
} else {
|
|
return null;
|
|
}
|
|
|
|
},
|
|
|
|
_containsPoint: function(p) {
|
|
var icon = this.options.icon;
|
|
if (icon) {
|
|
return this._pxBounds.contains(p);
|
|
} else {
|
|
return L.CircleMarker.prototype._containsPoint.call(this, p);
|
|
}
|
|
}
|
|
});
|
|
|
|
// 🍂class LineSymbolizer
|
|
// 🍂inherits Polyline
|
|
// A symbolizer for lines. Can be applied to line and polygon features.
|
|
|
|
var LineSymbolizer = L.Polyline.extend({
|
|
includes: [Symbolizer.prototype, PolyBase],
|
|
|
|
initialize: function(feature, pxPerExtent) {
|
|
this.properties = feature.properties;
|
|
this._makeFeatureParts(feature, pxPerExtent);
|
|
},
|
|
|
|
render: function(renderer, style) {
|
|
style.fill = false;
|
|
Symbolizer.prototype.render.call(this, renderer, style);
|
|
this._updatePath();
|
|
},
|
|
|
|
updateStyle: function(renderer, style) {
|
|
style.fill = false;
|
|
Symbolizer.prototype.updateStyle.call(this, renderer, style);
|
|
},
|
|
});
|
|
|
|
// 🍂class FillSymbolizer
|
|
// 🍂inherits Polyline
|
|
// A symbolizer for filled areas. Applies only to polygon features.
|
|
|
|
var FillSymbolizer = L.Polygon.extend({
|
|
includes: [Symbolizer.prototype, PolyBase],
|
|
|
|
initialize: function(feature, pxPerExtent) {
|
|
this.properties = feature.properties;
|
|
this._makeFeatureParts(feature, pxPerExtent);
|
|
},
|
|
|
|
render: function(renderer, style) {
|
|
Symbolizer.prototype.render.call(this, renderer, style);
|
|
this._updatePath();
|
|
}
|
|
});
|
|
|
|
/* 🍂class VectorGrid
|
|
* 🍂inherits GridLayer
|
|
*
|
|
* A `VectorGrid` is a generic, abstract class for displaying tiled vector data.
|
|
* it provides facilities for symbolizing and rendering the data in the vector
|
|
* tiles, but lacks the functionality to fetch the vector tiles from wherever
|
|
* they are.
|
|
*
|
|
* Extends Leaflet's `L.GridLayer`.
|
|
*/
|
|
|
|
L.VectorGrid = L.GridLayer.extend({
|
|
|
|
options: {
|
|
// 🍂option rendererFactory = L.svg.tile
|
|
// A factory method which will be used to instantiate the per-tile renderers.
|
|
rendererFactory: L.svg.tile,
|
|
|
|
// 🍂option vectorTileLayerStyles: Object = {}
|
|
// A data structure holding initial symbolizer definitions for the vector features.
|
|
vectorTileLayerStyles: {},
|
|
|
|
// 🍂option interactive: Boolean = false
|
|
// Whether this `VectorGrid` fires `Interactive Layer` events.
|
|
interactive: false,
|
|
|
|
// 🍂option getFeatureId: Function = undefined
|
|
// A function that, given a vector feature, returns an unique identifier for it, e.g.
|
|
// `function(feat) { return feat.properties.uniqueIdField; }`.
|
|
// Must be defined for `setFeatureStyle` to work.
|
|
},
|
|
|
|
initialize: function(options) {
|
|
L.setOptions(this, options);
|
|
L.GridLayer.prototype.initialize.apply(this, arguments);
|
|
if (this.options.getFeatureId) {
|
|
this._vectorTiles = {};
|
|
this._overriddenStyles = {};
|
|
this.on('tileunload', function(e) {
|
|
var key = this._tileCoordsToKey(e.coords),
|
|
tile = this._vectorTiles[key];
|
|
|
|
if (tile && this._map) {
|
|
tile.removeFrom(this._map);
|
|
}
|
|
delete this._vectorTiles[key];
|
|
}, this);
|
|
}
|
|
this._dataLayerNames = {};
|
|
},
|
|
|
|
createTile: function(coords, done) {
|
|
var storeFeatures = this.options.getFeatureId;
|
|
|
|
var tileSize = this.getTileSize();
|
|
var renderer = this.options.rendererFactory(coords, tileSize, this.options);
|
|
|
|
var vectorTilePromise = this._getVectorTilePromise(coords);
|
|
|
|
if (storeFeatures) {
|
|
this._vectorTiles[this._tileCoordsToKey(coords)] = renderer;
|
|
renderer._features = {};
|
|
}
|
|
|
|
vectorTilePromise.then( function renderTile(vectorTile) {
|
|
for (var layerName in vectorTile.layers) {
|
|
this._dataLayerNames[layerName] = true;
|
|
var layer = vectorTile.layers[layerName];
|
|
|
|
var pxPerExtent = this.getTileSize().divideBy(layer.extent);
|
|
|
|
var layerStyle = this.options.vectorTileLayerStyles[ layerName ] ||
|
|
L.Path.prototype.options;
|
|
|
|
for (var i = 0; i < layer.features.length; i++) {
|
|
var feat = layer.features[i];
|
|
var id;
|
|
|
|
var styleOptions = layerStyle;
|
|
if (storeFeatures) {
|
|
id = this.options.getFeatureId(feat);
|
|
var styleOverride = this._overriddenStyles[id];
|
|
if (styleOverride) {
|
|
if (styleOverride[layerName]) {
|
|
styleOptions = styleOverride[layerName];
|
|
} else {
|
|
styleOptions = styleOverride;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (styleOptions instanceof Function) {
|
|
styleOptions = styleOptions(feat.properties, coords.z);
|
|
}
|
|
|
|
if (!(styleOptions instanceof Array)) {
|
|
styleOptions = [styleOptions];
|
|
}
|
|
|
|
if (!styleOptions.length) {
|
|
continue;
|
|
}
|
|
|
|
var featureLayer = this._createLayer(feat, pxPerExtent);
|
|
|
|
for (var j = 0; j < styleOptions.length; j++) {
|
|
var style = L.extend({}, L.Path.prototype.options, styleOptions[j]);
|
|
featureLayer.render(renderer, style);
|
|
renderer._addPath(featureLayer);
|
|
}
|
|
|
|
if (this.options.interactive) {
|
|
featureLayer.makeInteractive();
|
|
}
|
|
|
|
if (storeFeatures) {
|
|
renderer._features[id] = {
|
|
layerName: layerName,
|
|
feature: featureLayer
|
|
};
|
|
}
|
|
}
|
|
|
|
}
|
|
if (this._map != null) {
|
|
renderer.addTo(this._map);
|
|
}
|
|
L.Util.requestAnimFrame(done.bind(coords, null, null));
|
|
}.bind(this));
|
|
|
|
return renderer.getContainer();
|
|
},
|
|
|
|
// 🍂method setFeatureStyle(id: Number, layerStyle: L.Path Options): this
|
|
// Given the unique ID for a vector features (as per the `getFeatureId` option),
|
|
// re-symbolizes that feature across all tiles it appears in.
|
|
setFeatureStyle: function(id, layerStyle) {
|
|
this._overriddenStyles[id] = layerStyle;
|
|
|
|
for (var tileKey in this._vectorTiles) {
|
|
var tile = this._vectorTiles[tileKey];
|
|
var features = tile._features;
|
|
var data = features[id];
|
|
if (data) {
|
|
var feat = data.feature;
|
|
|
|
var styleOptions = layerStyle;
|
|
if (layerStyle[data.layerName]) {
|
|
styleOptions = layerStyle[data.layerName];
|
|
}
|
|
|
|
this._updateStyles(feat, tile, styleOptions);
|
|
}
|
|
}
|
|
return this;
|
|
},
|
|
|
|
// 🍂method setFeatureStyle(id: Number): this
|
|
// Reverts the effects of a previous `setFeatureStyle` call.
|
|
resetFeatureStyle: function(id) {
|
|
delete this._overriddenStyles[id];
|
|
|
|
for (var tileKey in this._vectorTiles) {
|
|
var tile = this._vectorTiles[tileKey];
|
|
var features = tile._features;
|
|
var data = features[id];
|
|
if (data) {
|
|
var feat = data.feature;
|
|
var styleOptions = this.options.vectorTileLayerStyles[ data.layerName ] ||
|
|
L.Path.prototype.options;
|
|
this._updateStyles(feat, tile, styleOptions);
|
|
}
|
|
}
|
|
return this;
|
|
},
|
|
|
|
// 🍂method getDataLayerNames(): Array
|
|
// Returns an array of strings, with all the known names of data layers in
|
|
// the vector tiles displayed. Useful for introspection.
|
|
getDataLayerNames: function() {
|
|
return Object.keys(this._dataLayerNames);
|
|
},
|
|
|
|
_updateStyles: function(feat, renderer, styleOptions) {
|
|
styleOptions = (styleOptions instanceof Function) ?
|
|
styleOptions(feat.properties, renderer.getCoord().z) :
|
|
styleOptions;
|
|
|
|
if (!(styleOptions instanceof Array)) {
|
|
styleOptions = [styleOptions];
|
|
}
|
|
|
|
for (var j = 0; j < styleOptions.length; j++) {
|
|
var style = L.extend({}, L.Path.prototype.options, styleOptions[j]);
|
|
feat.updateStyle(renderer, style);
|
|
}
|
|
},
|
|
|
|
_createLayer: function(feat, pxPerExtent, layerStyle) {
|
|
var layer;
|
|
switch (feat.type) {
|
|
case 1:
|
|
layer = new PointSymbolizer(feat, pxPerExtent);
|
|
break;
|
|
case 2:
|
|
layer = new LineSymbolizer(feat, pxPerExtent);
|
|
break;
|
|
case 3:
|
|
layer = new FillSymbolizer(feat, pxPerExtent);
|
|
break;
|
|
}
|
|
|
|
if (this.options.interactive) {
|
|
layer.addEventParent(this);
|
|
}
|
|
|
|
return layer;
|
|
},
|
|
});
|
|
|
|
/*
|
|
* 🍂section Extension methods
|
|
*
|
|
* Classes inheriting from `VectorGrid` **must** define the `_getVectorTilePromise` private method.
|
|
*
|
|
* 🍂method getVectorTilePromise(coords: Object): Promise
|
|
* Given a `coords` object in the form of `{x: Number, y: Number, z: Number}`,
|
|
* this function must return a `Promise` for a vector tile.
|
|
*
|
|
*/
|
|
L.vectorGrid = function (options) {
|
|
return new L.VectorGrid(options);
|
|
};
|
|
|
|
/*
|
|
* 🍂class VectorGrid.Protobuf
|
|
* 🍂extends VectorGrid
|
|
*
|
|
* A `VectorGrid` for vector tiles fetched from the internet.
|
|
* Tiles are supposed to be protobufs (AKA "protobuffer" or "Protocol Buffers"),
|
|
* containing data which complies with the
|
|
* [MapBox Vector Tile Specification](https://github.com/mapbox/vector-tile-spec/tree/master/2.1).
|
|
*
|
|
* This is the format used by:
|
|
* - Mapbox Vector Tiles
|
|
* - Mapzen Vector Tiles
|
|
* - ESRI Vector Tiles
|
|
* - [OpenMapTiles hosted Vector Tiles](https://openmaptiles.com/hosting/)
|
|
*
|
|
* 🍂example
|
|
*
|
|
* You must initialize a `VectorGrid.Protobuf` with a URL template, just like in
|
|
* `L.TileLayer`s. The difference is that the template must point to vector tiles
|
|
* (usually `.pbf` or `.mvt`) instead of raster (`.png` or `.jpg`) tiles, and that
|
|
* you should define the styling for all the features.
|
|
*
|
|
* <br><br>
|
|
*
|
|
* For OpenMapTiles, with a key from [https://openmaptiles.org/docs/host/use-cdn/](https://openmaptiles.org/docs/host/use-cdn/),
|
|
* initialization looks like this:
|
|
*
|
|
* ```
|
|
* L.vectorGrid.protobuf("https://free-{s}.tilehosting.com/data/v3/{z}/{x}/{y}.pbf.pict?key={key}", {
|
|
* vectorTileLayerStyles: { ... },
|
|
* subdomains: "0123",
|
|
* key: 'abcdefghi01234567890',
|
|
* maxNativeZoom: 14
|
|
* }).addTo(map);
|
|
* ```
|
|
*
|
|
* And for Mapbox vector tiles, it looks like this:
|
|
*
|
|
* ```
|
|
* L.vectorGrid.protobuf("https://{s}.tiles.mapbox.com/v4/mapbox.mapbox-streets-v6/{z}/{x}/{y}.vector.pbf?access_token={token}", {
|
|
* vectorTileLayerStyles: { ... },
|
|
* subdomains: "abcd",
|
|
* token: "pk.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRTS.TUVWXTZ0123456789abcde"
|
|
* }).addTo(map);
|
|
* ```
|
|
*/
|
|
L.VectorGrid.Protobuf = L.VectorGrid.extend({
|
|
|
|
options: {
|
|
// 🍂section
|
|
// As with `L.TileLayer`, the URL template might contain a reference to
|
|
// any option (see the example above and note the `{key}` or `token` in the URL
|
|
// template, and the corresponding option).
|
|
//
|
|
// 🍂option subdomains: String = 'abc'
|
|
// Akin to the `subdomains` option for `L.TileLayer`.
|
|
subdomains: 'abc', // Like L.TileLayer
|
|
//
|
|
// 🍂option fetchOptions: Object = {}
|
|
// options passed to `fetch`, e.g. {credentials: 'same-origin'} to send cookie for the current domain
|
|
fetchOptions: {}
|
|
},
|
|
|
|
initialize: function(url, options) {
|
|
// Inherits options from geojson-vt!
|
|
// this._slicer = geojsonvt(geojson, options);
|
|
this._url = url;
|
|
L.VectorGrid.prototype.initialize.call(this, options);
|
|
},
|
|
|
|
// 🍂method setUrl(url: String, noRedraw?: Boolean): this
|
|
// Updates the layer's URL template and redraws it (unless `noRedraw` is set to `true`).
|
|
setUrl: function(url, noRedraw) {
|
|
this._url = url;
|
|
|
|
if (!noRedraw) {
|
|
this.redraw();
|
|
}
|
|
|
|
return this;
|
|
},
|
|
|
|
_getSubdomain: L.TileLayer.prototype._getSubdomain,
|
|
|
|
_getVectorTilePromise: function(coords) {
|
|
var data = {
|
|
s: this._getSubdomain(coords),
|
|
x: coords.x,
|
|
y: coords.y,
|
|
z: coords.z
|
|
// z: this._getZoomForUrl() /// TODO: Maybe replicate TileLayer's maxNativeZoom
|
|
};
|
|
if (this._map && !this._map.options.crs.infinite) {
|
|
var invertedY = this._globalTileRange.max.y - coords.y;
|
|
if (this.options.tms) { // Should this option be available in Leaflet.VectorGrid?
|
|
data['y'] = invertedY;
|
|
}
|
|
data['-y'] = invertedY;
|
|
}
|
|
|
|
var tileUrl = L.Util.template(this._url, L.extend(data, this.options));
|
|
|
|
return fetch(tileUrl, this.options.fetchOptions).then(function(response){
|
|
|
|
if (!response.ok) {
|
|
return {layers:[]};
|
|
}
|
|
|
|
return response.blob().then( function (blob) {
|
|
// console.log(blob);
|
|
|
|
var reader = new FileReader();
|
|
return new Promise(function(resolve){
|
|
reader.addEventListener("loadend", function() {
|
|
// reader.result contains the contents of blob as a typed array
|
|
|
|
// blob.type === 'application/x-protobuf'
|
|
var pbf = new index( reader.result );
|
|
// console.log(pbf);
|
|
return resolve(new VectorTile( pbf ));
|
|
|
|
});
|
|
reader.readAsArrayBuffer(blob);
|
|
});
|
|
});
|
|
}).then(function(json){
|
|
|
|
// console.log('Vector tile:', json.layers);
|
|
// console.log('Vector tile water:', json.layers.water); // Instance of VectorTileLayer
|
|
|
|
// Normalize feature getters into actual instanced features
|
|
for (var layerName in json.layers) {
|
|
var feats = [];
|
|
|
|
for (var i=0; i<json.layers[layerName].length; i++) {
|
|
var feat = json.layers[layerName].feature(i);
|
|
feat.geometry = feat.loadGeometry();
|
|
feats.push(feat);
|
|
}
|
|
|
|
json.layers[layerName].features = feats;
|
|
}
|
|
|
|
return json;
|
|
});
|
|
}
|
|
});
|
|
|
|
|
|
// 🍂factory L.vectorGrid.protobuf(url: String, options)
|
|
// Instantiates a new protobuf VectorGrid with the given URL template and options
|
|
L.vectorGrid.protobuf = function (url, options) {
|
|
return new L.VectorGrid.Protobuf(url, options);
|
|
};
|
|
|
|
var workerCode = __$strToBlobUri("'use strict';\n\nvar simplify_1 = simplify$1;\n\n// calculate simplification data using optimized Douglas-Peucker algorithm\n\nfunction simplify$1(points, tolerance) {\n\n var sqTolerance = tolerance * tolerance,\n len = points.length,\n first = 0,\n last = len - 1,\n stack = [],\n i, maxSqDist, sqDist, index;\n\n // always retain the endpoints (1 is the max value)\n points[first][2] = 1;\n points[last][2] = 1;\n\n // avoid recursion by using a stack\n while (last) {\n\n maxSqDist = 0;\n\n for (i = first + 1; i < last; i++) {\n sqDist = getSqSegDist(points[i], points[first], points[last]);\n\n if (sqDist > maxSqDist) {\n index = i;\n maxSqDist = sqDist;\n }\n }\n\n if (maxSqDist > sqTolerance) {\n points[index][2] = maxSqDist; // save the point importance in squared pixels as a z coordinate\n stack.push(first);\n stack.push(index);\n first = index;\n\n } else {\n last = stack.pop();\n first = stack.pop();\n }\n }\n}\n\n// square distance from a point to a segment\nfunction getSqSegDist(p, a, b) {\n\n var x = a[0], y = a[1],\n bx = b[0], by = b[1],\n px = p[0], py = p[1],\n dx = bx - x,\n dy = by - y;\n\n if (dx !== 0 || dy !== 0) {\n\n var t = ((px - x) * dx + (py - y) * dy) / (dx * dx + dy * dy);\n\n if (t > 1) {\n x = bx;\n y = by;\n\n } else if (t > 0) {\n x += dx * t;\n y += dy * t;\n }\n }\n\n dx = px - x;\n dy = py - y;\n\n return dx * dx + dy * dy;\n}\n\nvar convert_1 = convert$1;\n\nvar simplify = simplify_1;\n\n// converts GeoJSON feature into an intermediate projected JSON vector format with simplification data\n\nfunction convert$1(data, tolerance) {\n var features = [];\n\n if (data.type === 'FeatureCollection') {\n for (var i = 0; i < data.features.length; i++) {\n convertFeature(features, data.features[i], tolerance);\n }\n } else if (data.type === 'Feature') {\n convertFeature(features, data, tolerance);\n\n } else {\n // single geometry or a geometry collection\n convertFeature(features, {geometry: data}, tolerance);\n }\n return features;\n}\n\nfunction convertFeature(features, feature, tolerance) {\n if (feature.geometry === null) {\n // ignore features with null geometry\n return;\n }\n\n var geom = feature.geometry,\n type = geom.type,\n coords = geom.coordinates,\n tags = feature.properties,\n i, j, rings, projectedRing;\n\n if (type === 'Point') {\n features.push(create(tags, 1, [projectPoint(coords)]));\n\n } else if (type === 'MultiPoint') {\n features.push(create(tags, 1, project(coords)));\n\n } else if (type === 'LineString') {\n features.push(create(tags, 2, [project(coords, tolerance)]));\n\n } else if (type === 'MultiLineString' || type === 'Polygon') {\n rings = [];\n for (i = 0; i < coords.length; i++) {\n projectedRing = project(coords[i], tolerance);\n if (type === 'Polygon') { projectedRing.outer = (i === 0); }\n rings.push(projectedRing);\n }\n features.push(create(tags, type === 'Polygon' ? 3 : 2, rings));\n\n } else if (type === 'MultiPolygon') {\n rings = [];\n for (i = 0; i < coords.length; i++) {\n for (j = 0; j < coords[i].length; j++) {\n projectedRing = project(coords[i][j], tolerance);\n projectedRing.outer = (j === 0);\n rings.push(projectedRing);\n }\n }\n features.push(create(tags, 3, rings));\n\n } else if (type === 'GeometryCollection') {\n for (i = 0; i < geom.geometries.length; i++) {\n convertFeature(features, {\n geometry: geom.geometries[i],\n properties: tags\n }, tolerance);\n }\n\n } else {\n throw new Error('Input data is not a valid GeoJSON object.');\n }\n}\n\nfunction create(tags, type, geometry) {\n var feature = {\n geometry: geometry,\n type: type,\n tags: tags || null,\n min: [2, 1], // initial bbox values;\n max: [-1, 0] // note that coords are usually in [0..1] range\n };\n calcBBox(feature);\n return feature;\n}\n\nfunction project(lonlats, tolerance) {\n var projected = [];\n for (var i = 0; i < lonlats.length; i++) {\n projected.push(projectPoint(lonlats[i]));\n }\n if (tolerance) {\n simplify(projected, tolerance);\n calcSize(projected);\n }\n return projected;\n}\n\nfunction projectPoint(p) {\n var sin = Math.sin(p[1] * Math.PI / 180),\n x = (p[0] / 360 + 0.5),\n y = (0.5 - 0.25 * Math.log((1 + sin) / (1 - sin)) / Math.PI);\n\n y = y < 0 ? 0 :\n y > 1 ? 1 : y;\n\n return [x, y, 0];\n}\n\n// calculate area and length of the poly\nfunction calcSize(points) {\n var area = 0,\n dist = 0;\n\n for (var i = 0, a, b; i < points.length - 1; i++) {\n a = b || points[i];\n b = points[i + 1];\n\n area += a[0] * b[1] - b[0] * a[1];\n\n // use Manhattan distance instead of Euclidian one to avoid expensive square root computation\n dist += Math.abs(b[0] - a[0]) + Math.abs(b[1] - a[1]);\n }\n points.area = Math.abs(area / 2);\n points.dist = dist;\n}\n\n// calculate the feature bounding box for faster clipping later\nfunction calcBBox(feature) {\n var geometry = feature.geometry,\n min = feature.min,\n max = feature.max;\n\n if (feature.type === 1) { calcRingBBox(min, max, geometry); }\n else { for (var i = 0; i < geometry.length; i++) { calcRingBBox(min, max, geometry[i]); } }\n\n return feature;\n}\n\nfunction calcRingBBox(min, max, points) {\n for (var i = 0, p; i < points.length; i++) {\n p = points[i];\n min[0] = Math.min(p[0], min[0]);\n max[0] = Math.max(p[0], max[0]);\n min[1] = Math.min(p[1], min[1]);\n max[1] = Math.max(p[1], max[1]);\n }\n}\n\nvar tile = transformTile;\nvar point = transformPoint;\n\n// Transforms the coordinates of each feature in the given tile from\n// mercator-projected space into (extent x extent) tile space.\nfunction transformTile(tile, extent) {\n if (tile.transformed) { return tile; }\n\n var z2 = tile.z2,\n tx = tile.x,\n ty = tile.y,\n i, j, k;\n\n for (i = 0; i < tile.features.length; i++) {\n var feature = tile.features[i],\n geom = feature.geometry,\n type = feature.type;\n\n if (type === 1) {\n for (j = 0; j < geom.length; j++) { geom[j] = transformPoint(geom[j], extent, z2, tx, ty); }\n\n } else {\n for (j = 0; j < geom.length; j++) {\n var ring = geom[j];\n for (k = 0; k < ring.length; k++) { ring[k] = transformPoint(ring[k], extent, z2, tx, ty); }\n }\n }\n }\n\n tile.transformed = true;\n\n return tile;\n}\n\nfunction transformPoint(p, extent, z2, tx, ty) {\n var x = Math.round(extent * (p[0] * z2 - tx)),\n y = Math.round(extent * (p[1] * z2 - ty));\n return [x, y];\n}\n\nvar transform$1 = {\n tile: tile,\n point: point\n};\n\nvar clip_1 = clip$1;\n\n/* clip features between two axis-parallel lines:\n * | |\n * ___|___ | /\n * / | \____|____/\n * | |\n */\n\nfunction clip$1(features, scale, k1, k2, axis, intersect, minAll, maxAll) {\n\n k1 /= scale;\n k2 /= scale;\n\n if (minAll >= k1 && maxAll <= k2) { return features; } // trivial accept\n else if (minAll > k2 || maxAll < k1) { return null; } // trivial reject\n\n var clipped = [];\n\n for (var i = 0; i < features.length; i++) {\n\n var feature = features[i],\n geometry = feature.geometry,\n type = feature.type,\n min, max;\n\n min = feature.min[axis];\n max = feature.max[axis];\n\n if (min >= k1 && max <= k2) { // trivial accept\n clipped.push(feature);\n continue;\n } else if (min > k2 || max < k1) { continue; } // trivial reject\n\n var slices = type === 1 ?\n clipPoints(geometry, k1, k2, axis) :\n clipGeometry(geometry, k1, k2, axis, intersect, type === 3);\n\n if (slices.length) {\n // if a feature got clipped, it will likely get clipped on the next zoom level as well,\n // so there's no need to recalculate bboxes\n clipped.push({\n geometry: slices,\n type: type,\n tags: features[i].tags || null,\n min: feature.min,\n max: feature.max\n });\n }\n }\n\n return clipped.length ? clipped : null;\n}\n\nfunction clipPoints(geometry, k1, k2, axis) {\n var slice = [];\n\n for (var i = 0; i < geometry.length; i++) {\n var a = geometry[i],\n ak = a[axis];\n\n if (ak >= k1 && ak <= k2) { slice.push(a); }\n }\n return slice;\n}\n\nfunction clipGeometry(geometry, k1, k2, axis, intersect, closed) {\n\n var slices = [];\n\n for (var i = 0; i < geometry.length; i++) {\n\n var ak = 0,\n bk = 0,\n b = null,\n points = geometry[i],\n area = points.area,\n dist = points.dist,\n outer = points.outer,\n len = points.length,\n a, j, last;\n\n var slice = [];\n\n for (j = 0; j < len - 1; j++) {\n a = b || points[j];\n b = points[j + 1];\n ak = bk || a[axis];\n bk = b[axis];\n\n if (ak < k1) {\n\n if ((bk > k2)) { // ---|-----|-->\n slice.push(intersect(a, b, k1), intersect(a, b, k2));\n if (!closed) { slice = newSlice(slices, slice, area, dist, outer); }\n\n } else if (bk >= k1) { slice.push(intersect(a, b, k1)); } // ---|--> |\n\n } else if (ak > k2) {\n\n if ((bk < k1)) { // <--|-----|---\n slice.push(intersect(a, b, k2), intersect(a, b, k1));\n if (!closed) { slice = newSlice(slices, slice, area, dist, outer); }\n\n } else if (bk <= k2) { slice.push(intersect(a, b, k2)); } // | <--|---\n\n } else {\n\n slice.push(a);\n\n if (bk < k1) { // <--|--- |\n slice.push(intersect(a, b, k1));\n if (!closed) { slice = newSlice(slices, slice, area, dist, outer); }\n\n } else if (bk > k2) { // | ---|-->\n slice.push(intersect(a, b, k2));\n if (!closed) { slice = newSlice(slices, slice, area, dist, outer); }\n }\n // | --> |\n }\n }\n\n // add the last point\n a = points[len - 1];\n ak = a[axis];\n if (ak >= k1 && ak <= k2) { slice.push(a); }\n\n // close the polygon if its endpoints are not the same after clipping\n\n last = slice[slice.length - 1];\n if (closed && last && (slice[0][0] !== last[0] || slice[0][1] !== last[1])) { slice.push(slice[0]); }\n\n // add the final slice\n newSlice(slices, slice, area, dist, outer);\n }\n\n return slices;\n}\n\nfunction newSlice(slices, slice, area, dist, outer) {\n if (slice.length) {\n // we don't recalculate the area/length of the unclipped geometry because the case where it goes\n // below the visibility threshold as a result of clipping is rare, so we avoid doing unnecessary work\n slice.area = area;\n slice.dist = dist;\n if (outer !== undefined) { slice.outer = outer; }\n\n slices.push(slice);\n }\n return [];\n}\n\nvar clip$2 = clip_1;\n\nvar wrap_1 = wrap$1;\n\nfunction wrap$1(features, buffer, intersectX) {\n var merged = features,\n left = clip$2(features, 1, -1 - buffer, buffer, 0, intersectX, -1, 2), // left world copy\n right = clip$2(features, 1, 1 - buffer, 2 + buffer, 0, intersectX, -1, 2); // right world copy\n\n if (left || right) {\n merged = clip$2(features, 1, -buffer, 1 + buffer, 0, intersectX, -1, 2); // center world copy\n\n if (left) { merged = shiftFeatureCoords(left, 1).concat(merged); } // merge left into center\n if (right) { merged = merged.concat(shiftFeatureCoords(right, -1)); } // merge right into center\n }\n\n return merged;\n}\n\nfunction shiftFeatureCoords(features, offset) {\n var newFeatures = [];\n\n for (var i = 0; i < features.length; i++) {\n var feature = features[i],\n type = feature.type;\n\n var newGeometry;\n\n if (type === 1) {\n newGeometry = shiftCoords(feature.geometry, offset);\n } else {\n newGeometry = [];\n for (var j = 0; j < feature.geometry.length; j++) {\n newGeometry.push(shiftCoords(feature.geometry[j], offset));\n }\n }\n\n newFeatures.push({\n geometry: newGeometry,\n type: type,\n tags: feature.tags,\n min: [feature.min[0] + offset, feature.min[1]],\n max: [feature.max[0] + offset, feature.max[1]]\n });\n }\n\n return newFeatures;\n}\n\nfunction shiftCoords(points, offset) {\n var newPoints = [];\n newPoints.area = points.area;\n newPoints.dist = points.dist;\n\n for (var i = 0; i < points.length; i++) {\n newPoints.push([points[i][0] + offset, points[i][1], points[i][2]]);\n }\n return newPoints;\n}\n\nvar tile$1 = createTile$1;\n\nfunction createTile$1(features, z2, tx, ty, tolerance, noSimplify) {\n var tile = {\n features: [],\n numPoints: 0,\n numSimplified: 0,\n numFeatures: 0,\n source: null,\n x: tx,\n y: ty,\n z2: z2,\n transformed: false,\n min: [2, 1],\n max: [-1, 0]\n };\n for (var i = 0; i < features.length; i++) {\n tile.numFeatures++;\n addFeature(tile, features[i], tolerance, noSimplify);\n\n var min = features[i].min,\n max = features[i].max;\n\n if (min[0] < tile.min[0]) { tile.min[0] = min[0]; }\n if (min[1] < tile.min[1]) { tile.min[1] = min[1]; }\n if (max[0] > tile.max[0]) { tile.max[0] = max[0]; }\n if (max[1] > tile.max[1]) { tile.max[1] = max[1]; }\n }\n return tile;\n}\n\nfunction addFeature(tile, feature, tolerance, noSimplify) {\n\n var geom = feature.geometry,\n type = feature.type,\n simplified = [],\n sqTolerance = tolerance * tolerance,\n i, j, ring, p;\n\n if (type === 1) {\n for (i = 0; i < geom.length; i++) {\n simplified.push(geom[i]);\n tile.numPoints++;\n tile.numSimplified++;\n }\n\n } else {\n\n // simplify and transform projected coordinates for tile geometry\n for (i = 0; i < geom.length; i++) {\n ring = geom[i];\n\n // filter out tiny polylines & polygons\n if (!noSimplify && ((type === 2 && ring.dist < tolerance) ||\n (type === 3 && ring.area < sqTolerance))) {\n tile.numPoints += ring.length;\n continue;\n }\n\n var simplifiedRing = [];\n\n for (j = 0; j < ring.length; j++) {\n p = ring[j];\n // keep points with importance > tolerance\n if (noSimplify || p[2] > sqTolerance) {\n simplifiedRing.push(p);\n tile.numSimplified++;\n }\n tile.numPoints++;\n }\n\n if (type === 3) { rewind(simplifiedRing, ring.outer); }\n\n simplified.push(simplifiedRing);\n }\n }\n\n if (simplified.length) {\n tile.features.push({\n geometry: simplified,\n type: type,\n tags: feature.tags || null\n });\n }\n}\n\nfunction rewind(ring, clockwise) {\n var area = signedArea(ring);\n if (area < 0 === clockwise) { ring.reverse(); }\n}\n\nfunction signedArea(ring) {\n var sum = 0;\n for (var i = 0, len = ring.length, j = len - 1, p1, p2; i < len; j = i++) {\n p1 = ring[i];\n p2 = ring[j];\n sum += (p2[0] - p1[0]) * (p1[1] + p2[1]);\n }\n return sum;\n}\n\nvar index = geojsonvt;\n\nvar convert = convert_1;\nvar transform = transform$1;\nvar clip = clip_1;\nvar wrap = wrap_1;\nvar createTile = tile$1; // final simplified tile generation\n\n\nfunction geojsonvt(data, options) {\n return new GeoJSONVT(data, options);\n}\n\nfunction GeoJSONVT(data, options) {\n options = this.options = extend(Object.create(this.options), options);\n\n var debug = options.debug;\n\n if (debug) { console.time('preprocess data'); }\n\n var z2 = 1 << options.maxZoom, // 2^z\n features = convert(data, options.tolerance / (z2 * options.extent));\n\n this.tiles = {};\n this.tileCoords = [];\n\n if (debug) {\n console.timeEnd('preprocess data');\n console.log('index: maxZoom: %d, maxPoints: %d', options.indexMaxZoom, options.indexMaxPoints);\n console.time('generate tiles');\n this.stats = {};\n this.total = 0;\n }\n\n features = wrap(features, options.buffer / options.extent, intersectX);\n\n // start slicing from the top tile down\n if (features.length) { this.splitTile(features, 0, 0, 0); }\n\n if (debug) {\n if (features.length) { console.log('features: %d, points: %d', this.tiles[0].numFeatures, this.tiles[0].numPoints); }\n console.timeEnd('generate tiles');\n console.log('tiles generated:', this.total, JSON.stringify(this.stats));\n }\n}\n\nGeoJSONVT.prototype.options = {\n maxZoom: 14, // max zoom to preserve detail on\n indexMaxZoom: 5, // max zoom in the tile index\n indexMaxPoints: 100000, // max number of points per tile in the tile index\n solidChildren: false, // whether to tile solid square tiles further\n tolerance: 3, // simplification tolerance (higher means simpler)\n extent: 4096, // tile extent\n buffer: 64, // tile buffer on each side\n debug: 0 // logging level (0, 1 or 2)\n};\n\nGeoJSONVT.prototype.splitTile = function (features, z, x, y, cz, cx, cy) {\n var this$1 = this;\n\n\n var stack = [features, z, x, y],\n options = this.options,\n debug = options.debug,\n solid = null;\n\n // avoid recursion by using a processing queue\n while (stack.length) {\n y = stack.pop();\n x = stack.pop();\n z = stack.pop();\n features = stack.pop();\n\n var z2 = 1 << z,\n id = toID(z, x, y),\n tile = this$1.tiles[id],\n tileTolerance = z === options.maxZoom ? 0 : options.tolerance / (z2 * options.extent);\n\n if (!tile) {\n if (debug > 1) { console.time('creation'); }\n\n tile = this$1.tiles[id] = createTile(features, z2, x, y, tileTolerance, z === options.maxZoom);\n this$1.tileCoords.push({z: z, x: x, y: y});\n\n if (debug) {\n if (debug > 1) {\n console.log('tile z%d-%d-%d (features: %d, points: %d, simplified: %d)',\n z, x, y, tile.numFeatures, tile.numPoints, tile.numSimplified);\n console.timeEnd('creation');\n }\n var key = 'z' + z;\n this$1.stats[key] = (this$1.stats[key] || 0) + 1;\n this$1.total++;\n }\n }\n\n // save reference to original geometry in tile so that we can drill down later if we stop now\n tile.source = features;\n\n // if it's the first-pass tiling\n if (!cz) {\n // stop tiling if we reached max zoom, or if the tile is too simple\n if (z === options.indexMaxZoom || tile.numPoints <= options.indexMaxPoints) { continue; }\n\n // if a drilldown to a specific tile\n } else {\n // stop tiling if we reached base zoom or our target tile zoom\n if (z === options.maxZoom || z === cz) { continue; }\n\n // stop tiling if it's not an ancestor of the target tile\n var m = 1 << (cz - z);\n if (x !== Math.floor(cx / m) || y !== Math.floor(cy / m)) { continue; }\n }\n\n // stop tiling if the tile is solid clipped square\n if (!options.solidChildren && isClippedSquare(tile, options.extent, options.buffer)) {\n if (cz) { solid = z; } // and remember the zoom if we're drilling down\n continue;\n }\n\n // if we slice further down, no need to keep source geometry\n tile.source = null;\n\n if (debug > 1) { console.time('clipping'); }\n\n // values we'll use for clipping\n var k1 = 0.5 * options.buffer / options.extent,\n k2 = 0.5 - k1,\n k3 = 0.5 + k1,\n k4 = 1 + k1,\n tl, bl, tr, br, left, right;\n\n tl = bl = tr = br = null;\n\n left = clip(features, z2, x - k1, x + k3, 0, intersectX, tile.min[0], tile.max[0]);\n right = clip(features, z2, x + k2, x + k4, 0, intersectX, tile.min[0], tile.max[0]);\n\n if (left) {\n tl = clip(left, z2, y - k1, y + k3, 1, intersectY, tile.min[1], tile.max[1]);\n bl = clip(left, z2, y + k2, y + k4, 1, intersectY, tile.min[1], tile.max[1]);\n }\n\n if (right) {\n tr = clip(right, z2, y - k1, y + k3, 1, intersectY, tile.min[1], tile.max[1]);\n br = clip(right, z2, y + k2, y + k4, 1, intersectY, tile.min[1], tile.max[1]);\n }\n\n if (debug > 1) { console.timeEnd('clipping'); }\n\n if (tl) { stack.push(tl, z + 1, x * 2, y * 2); }\n if (bl) { stack.push(bl, z + 1, x * 2, y * 2 + 1); }\n if (tr) { stack.push(tr, z + 1, x * 2 + 1, y * 2); }\n if (br) { stack.push(br, z + 1, x * 2 + 1, y * 2 + 1); }\n }\n\n return solid;\n};\n\nGeoJSONVT.prototype.getTile = function (z, x, y) {\n var this$1 = this;\n\n var options = this.options,\n extent = options.extent,\n debug = options.debug;\n\n var z2 = 1 << z;\n x = ((x % z2) + z2) % z2; // wrap tile x coordinate\n\n var id = toID(z, x, y);\n if (this.tiles[id]) { return transform.tile(this.tiles[id], extent); }\n\n if (debug > 1) { console.log('drilling down to z%d-%d-%d', z, x, y); }\n\n var z0 = z,\n x0 = x,\n y0 = y,\n parent;\n\n while (!parent && z0 > 0) {\n z0--;\n x0 = Math.floor(x0 / 2);\n y0 = Math.floor(y0 / 2);\n parent = this$1.tiles[toID(z0, x0, y0)];\n }\n\n if (!parent || !parent.source) { return null; }\n\n // if we found a parent tile containing the original geometry, we can drill down from it\n if (debug > 1) { console.log('found parent tile z%d-%d-%d', z0, x0, y0); }\n\n // it parent tile is a solid clipped square, return it instead since it's identical\n if (isClippedSquare(parent, extent, options.buffer)) { return transform.tile(parent, extent); }\n\n if (debug > 1) { console.time('drilling down'); }\n var solid = this.splitTile(parent.source, z0, x0, y0, z, x, y);\n if (debug > 1) { console.timeEnd('drilling down'); }\n\n // one of the parent tiles was a solid clipped square\n if (solid !== null) {\n var m = 1 << (z - solid);\n id = toID(solid, Math.floor(x / m), Math.floor(y / m));\n }\n\n return this.tiles[id] ? transform.tile(this.tiles[id], extent) : null;\n};\n\nfunction toID(z, x, y) {\n return (((1 << z) * y + x) * 32) + z;\n}\n\nfunction intersectX(a, b, x) {\n return [x, (x - a[0]) * (b[1] - a[1]) / (b[0] - a[0]) + a[1], 1];\n}\nfunction intersectY(a, b, y) {\n return [(y - a[1]) * (b[0] - a[0]) / (b[1] - a[1]) + a[0], y, 1];\n}\n\nfunction extend(dest, src) {\n for (var i in src) { dest[i] = src[i]; }\n return dest;\n}\n\n// checks whether a tile is a whole-area fill after clipping; if it is, there's no sense slicing it further\nfunction isClippedSquare(tile, extent, buffer) {\n\n var features = tile.source;\n if (features.length !== 1) { return false; }\n\n var feature = features[0];\n if (feature.type !== 3 || feature.geometry.length > 1) { return false; }\n\n var len = feature.geometry[0].length;\n if (len !== 5) { return false; }\n\n for (var i = 0; i < len; i++) {\n var p = transform.point(feature.geometry[0][i], extent, tile.z2, tile.x, tile.y);\n if ((p[0] !== -buffer && p[0] !== extent + buffer) ||\n (p[1] !== -buffer && p[1] !== extent + buffer)) { return false; }\n }\n\n return true;\n}\n\nvar identity = function(x) {\n return x;\n};\n\nvar transform$3 = function(topology) {\n if ((transform = topology.transform) == null) { return identity; }\n var transform,\n x0,\n y0,\n kx = transform.scale[0],\n ky = transform.scale[1],\n dx = transform.translate[0],\n dy = transform.translate[1];\n return function(point, i) {\n if (!i) { x0 = y0 = 0; }\n point[0] = (x0 += point[0]) * kx + dx;\n point[1] = (y0 += point[1]) * ky + dy;\n return point;\n };\n};\n\nvar bbox = function(topology) {\n var bbox = topology.bbox;\n\n function bboxPoint(p0) {\n p1[0] = p0[0], p1[1] = p0[1], t(p1);\n if (p1[0] < x0) { x0 = p1[0]; }\n if (p1[0] > x1) { x1 = p1[0]; }\n if (p1[1] < y0) { y0 = p1[1]; }\n if (p1[1] > y1) { y1 = p1[1]; }\n }\n\n function bboxGeometry(o) {\n switch (o.type) {\n case \"GeometryCollection\": o.geometries.forEach(bboxGeometry); break;\n case \"Point\": bboxPoint(o.coordinates); break;\n case \"MultiPoint\": o.coordinates.forEach(bboxPoint); break;\n }\n }\n\n if (!bbox) {\n var t = transform$3(topology), p0, p1 = new Array(2), name,\n x0 = Infinity, y0 = x0, x1 = -x0, y1 = -x0;\n\n topology.arcs.forEach(function(arc) {\n var i = -1, n = arc.length;\n while (++i < n) {\n p0 = arc[i], p1[0] = p0[0], p1[1] = p0[1], t(p1, i);\n if (p1[0] < x0) { x0 = p1[0]; }\n if (p1[0] > x1) { x1 = p1[0]; }\n if (p1[1] < y0) { y0 = p1[1]; }\n if (p1[1] > y1) { y1 = p1[1]; }\n }\n });\n\n for (name in topology.objects) {\n bboxGeometry(topology.objects[name]);\n }\n\n bbox = topology.bbox = [x0, y0, x1, y1];\n }\n\n return bbox;\n};\n\nvar reverse = function(array, n) {\n var t, j = array.length, i = j - n;\n while (i < --j) { t = array[i], array[i++] = array[j], array[j] = t; }\n};\n\nvar feature = function(topology, o) {\n return o.type === \"GeometryCollection\"\n ? {type: \"FeatureCollection\", features: o.geometries.map(function(o) { return feature$1(topology, o); })}\n : feature$1(topology, o);\n};\n\nfunction feature$1(topology, o) {\n var id = o.id,\n bbox = o.bbox,\n properties = o.properties == null ? {} : o.properties,\n geometry = object(topology, o);\n return id == null && bbox == null ? {type: \"Feature\", properties: properties, geometry: geometry}\n : bbox == null ? {type: \"Feature\", id: id, properties: properties, geometry: geometry}\n : {type: \"Feature\", id: id, bbox: bbox, properties: properties, geometry: geometry};\n}\n\nfunction object(topology, o) {\n var transformPoint = transform$3(topology),\n arcs = topology.arcs;\n\n function arc(i, points) {\n if (points.length) { points.pop(); }\n for (var a = arcs[i < 0 ? ~i : i], k = 0, n = a.length; k < n; ++k) {\n points.push(transformPoint(a[k].slice(), k));\n }\n if (i < 0) { reverse(points, n); }\n }\n\n function point(p) {\n return transformPoint(p.slice());\n }\n\n function line(arcs) {\n var points = [];\n for (var i = 0, n = arcs.length; i < n; ++i) { arc(arcs[i], points); }\n if (points.length < 2) { points.push(points[0].slice()); }\n return points;\n }\n\n function ring(arcs) {\n var points = line(arcs);\n while (points.length < 4) { points.push(points[0].slice()); }\n return points;\n }\n\n function polygon(arcs) {\n return arcs.map(ring);\n }\n\n function geometry(o) {\n var type = o.type, coordinates;\n switch (type) {\n case \"GeometryCollection\": return {type: type, geometries: o.geometries.map(geometry)};\n case \"Point\": coordinates = point(o.coordinates); break;\n case \"MultiPoint\": coordinates = o.coordinates.map(point); break;\n case \"LineString\": coordinates = line(o.arcs); break;\n case \"MultiLineString\": coordinates = o.arcs.map(line); break;\n case \"Polygon\": coordinates = polygon(o.arcs); break;\n case \"MultiPolygon\": coordinates = o.arcs.map(polygon); break;\n default: return null;\n }\n return {type: type, coordinates: coordinates};\n }\n\n return geometry(o);\n}\n\nvar stitch = function(topology, arcs) {\n var stitchedArcs = {},\n fragmentByStart = {},\n fragmentByEnd = {},\n fragments = [],\n emptyIndex = -1;\n\n // Stitch empty arcs first, since they may be subsumed by other arcs.\n arcs.forEach(function(i, j) {\n var arc = topology.arcs[i < 0 ? ~i : i], t;\n if (arc.length < 3 && !arc[1][0] && !arc[1][1]) {\n t = arcs[++emptyIndex], arcs[emptyIndex] = i, arcs[j] = t;\n }\n });\n\n arcs.forEach(function(i) {\n var e = ends(i),\n start = e[0],\n end = e[1],\n f, g;\n\n if (f = fragmentByEnd[start]) {\n delete fragmentByEnd[f.end];\n f.push(i);\n f.end = end;\n if (g = fragmentByStart[end]) {\n delete fragmentByStart[g.start];\n var fg = g === f ? f : f.concat(g);\n fragmentByStart[fg.start = f.start] = fragmentByEnd[fg.end = g.end] = fg;\n } else {\n fragmentByStart[f.start] = fragmentByEnd[f.end] = f;\n }\n } else if (f = fragmentByStart[end]) {\n delete fragmentByStart[f.start];\n f.unshift(i);\n f.start = start;\n if (g = fragmentByEnd[start]) {\n delete fragmentByEnd[g.end];\n var gf = g === f ? f : g.concat(f);\n fragmentByStart[gf.start = g.start] = fragmentByEnd[gf.end = f.end] = gf;\n } else {\n fragmentByStart[f.start] = fragmentByEnd[f.end] = f;\n }\n } else {\n f = [i];\n fragmentByStart[f.start = start] = fragmentByEnd[f.end = end] = f;\n }\n });\n\n function ends(i) {\n var arc = topology.arcs[i < 0 ? ~i : i], p0 = arc[0], p1;\n if (topology.transform) { p1 = [0, 0], arc.forEach(function(dp) { p1[0] += dp[0], p1[1] += dp[1]; }); }\n else { p1 = arc[arc.length - 1]; }\n return i < 0 ? [p1, p0] : [p0, p1];\n }\n\n function flush(fragmentByEnd, fragmentByStart) {\n for (var k in fragmentByEnd) {\n var f = fragmentByEnd[k];\n delete fragmentByStart[f.start];\n delete f.start;\n delete f.end;\n f.forEach(function(i) { stitchedArcs[i < 0 ? ~i : i] = 1; });\n fragments.push(f);\n }\n }\n\n flush(fragmentByEnd, fragmentByStart);\n flush(fragmentByStart, fragmentByEnd);\n arcs.forEach(function(i) { if (!stitchedArcs[i < 0 ? ~i : i]) { fragments.push([i]); } });\n\n return fragments;\n};\n\nfunction extractArcs(topology, object$$1, filter) {\n var arcs = [],\n geomsByArc = [],\n geom;\n\n function extract0(i) {\n var j = i < 0 ? ~i : i;\n (geomsByArc[j] || (geomsByArc[j] = [])).push({i: i, g: geom});\n }\n\n function extract1(arcs) {\n arcs.forEach(extract0);\n }\n\n function extract2(arcs) {\n arcs.forEach(extract1);\n }\n\n function extract3(arcs) {\n arcs.forEach(extract2);\n }\n\n function geometry(o) {\n switch (geom = o, o.type) {\n case \"GeometryCollection\": o.geometries.forEach(geometry); break;\n case \"LineString\": extract1(o.arcs); break;\n case \"MultiLineString\": case \"Polygon\": extract2(o.arcs); break;\n case \"MultiPolygon\": extract3(o.arcs); break;\n }\n }\n\n geometry(object$$1);\n\n geomsByArc.forEach(filter == null\n ? function(geoms) { arcs.push(geoms[0].i); }\n : function(geoms) { if (filter(geoms[0].g, geoms[geoms.length - 1].g)) { arcs.push(geoms[0].i); } });\n\n return arcs;\n}\n\nfunction planarRingArea(ring) {\n var i = -1, n = ring.length, a, b = ring[n - 1], area = 0;\n while (++i < n) { a = b, b = ring[i], area += a[0] * b[1] - a[1] * b[0]; }\n return Math.abs(area); // Note: doubled area!\n}\n\nvar bisect = function(a, x) {\n var lo = 0, hi = a.length;\n while (lo < hi) {\n var mid = lo + hi >>> 1;\n if (a[mid] < x) { lo = mid + 1; }\n else { hi = mid; }\n }\n return lo;\n};\n\nvar slicers = {};\nvar options;\n\nonmessage = function (e) {\n if (e.data[0] === 'slice') {\n // Given a blob of GeoJSON and some topojson/geojson-vt options, do the slicing.\n var geojson = e.data[1];\n options = e.data[2];\n\n if (geojson.type && geojson.type === 'Topology') {\n for (var layerName in geojson.objects) {\n slicers[layerName] = index(\n feature(geojson, geojson.objects[layerName])\n , options);\n }\n } else {\n slicers[options.vectorTileLayerName] = index(geojson, options);\n }\n\n } else if (e.data[0] === 'get') {\n // Gets the vector tile for the given coordinates, sends it back as a message\n var coords = e.data[1];\n\n var tileLayers = {};\n for (var layerName in slicers) {\n var slicedTileLayer = slicers[layerName].getTile(coords.z, coords.x, coords.y);\n\n if (slicedTileLayer) {\n var vectorTileLayer = {\n features: [],\n extent: options.extent,\n name: options.vectorTileLayerName,\n length: slicedTileLayer.features.length\n };\n\n for (var i in slicedTileLayer.features) {\n var feat = {\n geometry: slicedTileLayer.features[i].geometry,\n properties: slicedTileLayer.features[i].tags,\n type: slicedTileLayer.features[i].type // 1 = point, 2 = line, 3 = polygon\n };\n vectorTileLayer.features.push(feat);\n }\n tileLayers[layerName] = vectorTileLayer;\n }\n }\n postMessage({ layers: tileLayers, coords: coords });\n }\n};\n//# sourceMap" + "pingURL=slicerWebWorker.js.worker.map\n", "text/plain; charset=us-ascii", false);
|
|
|
|
// The geojson/topojson is sliced into tiles via a web worker.
|
|
// This import statement depends on rollup-file-as-blob, so that the
|
|
// variable 'workerCode' is a blob URL.
|
|
|
|
/*
|
|
* 🍂class VectorGrid.Slicer
|
|
* 🍂extends VectorGrid
|
|
*
|
|
* A `VectorGrid` for slicing up big GeoJSON or TopoJSON documents in vector
|
|
* tiles, leveraging [`geojson-vt`](https://github.com/mapbox/geojson-vt).
|
|
*
|
|
* 🍂example
|
|
*
|
|
* ```
|
|
* var geoJsonDocument = {
|
|
* type: 'FeatureCollection',
|
|
* features: [ ... ]
|
|
* };
|
|
*
|
|
* L.vectorGrid.slicer(geoJsonDocument, {
|
|
* vectorTileLayerStyles: {
|
|
* sliced: { ... }
|
|
* }
|
|
* }).addTo(map);
|
|
*
|
|
* ```
|
|
*
|
|
* `VectorGrid.Slicer` can also handle [TopoJSON](https://github.com/mbostock/topojson) transparently:
|
|
* ```js
|
|
* var layer = L.vectorGrid.slicer(topojson, options);
|
|
* ```
|
|
*
|
|
* The TopoJSON format [implicitly groups features into "objects"](https://github.com/mbostock/topojson-specification/blob/master/README.md#215-objects).
|
|
* These will be transformed into vector tile layer names when styling (the
|
|
* `vectorTileLayerName` option is ignored when using TopoJSON).
|
|
*
|
|
*/
|
|
|
|
L.VectorGrid.Slicer = L.VectorGrid.extend({
|
|
|
|
options: {
|
|
// 🍂section
|
|
// Additionally to these options, `VectorGrid.Slicer` can take in any
|
|
// of the [`geojson-vt` options](https://github.com/mapbox/geojson-vt#options).
|
|
|
|
// 🍂option vectorTileLayerName: String = 'sliced'
|
|
// Vector tiles contain a set of *data layers*, and those data layers
|
|
// contain features. Thus, the slicer creates one data layer, with
|
|
// the name given in this option. This is important for symbolizing the data.
|
|
vectorTileLayerName: 'sliced',
|
|
|
|
extent: 4096, // Default for geojson-vt
|
|
maxZoom: 14 // Default for geojson-vt
|
|
},
|
|
|
|
initialize: function(geojson, options) {
|
|
L.VectorGrid.prototype.initialize.call(this, options);
|
|
|
|
// Create a shallow copy of this.options, excluding things that might
|
|
// be functions - we only care about topojson/geojsonvt options
|
|
var options = {};
|
|
for (var i in this.options) {
|
|
if (i !== 'rendererFactory' &&
|
|
i !== 'vectorTileLayerStyles' &&
|
|
typeof (this.options[i]) !== 'function'
|
|
) {
|
|
options[i] = this.options[i];
|
|
}
|
|
}
|
|
|
|
// this._worker = new Worker(window.URL.createObjectURL(new Blob([workerCode])));
|
|
this._worker = new Worker(workerCode);
|
|
|
|
// Send initial data to worker.
|
|
this._worker.postMessage(['slice', geojson, options]);
|
|
|
|
},
|
|
|
|
|
|
_getVectorTilePromise: function(coords) {
|
|
|
|
var _this = this;
|
|
|
|
var p = new Promise( function waitForWorker(res) {
|
|
_this._worker.addEventListener('message', function recv(m) {
|
|
if (m.data.coords &&
|
|
m.data.coords.x === coords.x &&
|
|
m.data.coords.y === coords.y &&
|
|
m.data.coords.z === coords.z ) {
|
|
|
|
res(m.data);
|
|
_this._worker.removeEventListener('message', recv);
|
|
}
|
|
});
|
|
});
|
|
|
|
this._worker.postMessage(['get', coords]);
|
|
|
|
return p;
|
|
},
|
|
|
|
});
|
|
|
|
|
|
L.vectorGrid.slicer = function (geojson, options) {
|
|
return new L.VectorGrid.Slicer(geojson, options);
|
|
};
|
|
|
|
L.Canvas.Tile = L.Canvas.extend({
|
|
|
|
initialize: function (tileCoord, tileSize, options) {
|
|
L.Canvas.prototype.initialize.call(this, options);
|
|
this._tileCoord = tileCoord;
|
|
this._size = tileSize;
|
|
|
|
this._initContainer();
|
|
this._container.setAttribute('width', this._size.x);
|
|
this._container.setAttribute('height', this._size.y);
|
|
this._layers = {};
|
|
this._drawnLayers = {};
|
|
this._drawing = true;
|
|
|
|
if (options.interactive) {
|
|
// By default, Leaflet tiles do not have pointer events
|
|
this._container.style.pointerEvents = 'auto';
|
|
}
|
|
},
|
|
|
|
getCoord: function() {
|
|
return this._tileCoord;
|
|
},
|
|
|
|
getContainer: function() {
|
|
return this._container;
|
|
},
|
|
|
|
getOffset: function() {
|
|
return this._tileCoord.scaleBy(this._size).subtract(this._map.getPixelOrigin());
|
|
},
|
|
|
|
onAdd: L.Util.falseFn,
|
|
|
|
addTo: function(map) {
|
|
this._map = map;
|
|
},
|
|
|
|
removeFrom: function (map) {
|
|
delete this._map;
|
|
},
|
|
|
|
_onClick: function (e) {
|
|
var point = this._map.mouseEventToLayerPoint(e).subtract(this.getOffset()), layer, clickedLayer;
|
|
|
|
for (var id in this._layers) {
|
|
layer = this._layers[id];
|
|
if (layer.options.interactive && layer._containsPoint(point) && !this._map._draggableMoved(layer)) {
|
|
clickedLayer = layer;
|
|
}
|
|
}
|
|
if (clickedLayer) {
|
|
L.DomEvent.fakeStop(e);
|
|
this._fireEvent([clickedLayer], e);
|
|
}
|
|
},
|
|
|
|
_onMouseMove: function (e) {
|
|
if (!this._map || this._map.dragging.moving() || this._map._animatingZoom) { return; }
|
|
|
|
var point = this._map.mouseEventToLayerPoint(e).subtract(this.getOffset());
|
|
this._handleMouseHover(e, point);
|
|
},
|
|
|
|
/// TODO: Modify _initPath to include an extra parameter, a group name
|
|
/// to order symbolizers by z-index
|
|
|
|
_updateIcon: function (layer) {
|
|
if (!this._drawing) { return; }
|
|
|
|
var icon = layer.options.icon,
|
|
options = icon.options,
|
|
size = L.point(options.iconSize),
|
|
anchor = options.iconAnchor ||
|
|
size && size.divideBy(2, true),
|
|
p = layer._point.subtract(anchor),
|
|
ctx = this._ctx,
|
|
img = layer._getImage();
|
|
|
|
if (img.complete) {
|
|
ctx.drawImage(img, p.x, p.y, size.x, size.y);
|
|
} else {
|
|
L.DomEvent.on(img, 'load', function() {
|
|
ctx.drawImage(img, p.x, p.y, size.x, size.y);
|
|
});
|
|
}
|
|
|
|
this._drawnLayers[layer._leaflet_id] = layer;
|
|
}
|
|
});
|
|
|
|
|
|
L.canvas.tile = function(tileCoord, tileSize, opts){
|
|
return new L.Canvas.Tile(tileCoord, tileSize, opts);
|
|
};
|
|
|
|
// Aux file to bundle everything together, including the optional dependencies
|
|
// for protobuf tiles
|
|
|
|
}());
|
|
//# sourceMappingURL=Leaflet.VectorGrid.bundled.js.map
|
|
|
|
return L.vectorGrid;
|
|
})();
|