1 | 1 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,2062 @@ |
1 |
+'use strict'; |
|
2 |
+ |
|
3 |
+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;}} |
|
4 |
+L.SVG.Tile = L.SVG.extend({ |
|
5 |
+ |
|
6 |
+ initialize: function (tileCoord, tileSize, options) { |
|
7 |
+ L.SVG.prototype.initialize.call(this, options); |
|
8 |
+ this._tileCoord = tileCoord; |
|
9 |
+ this._size = tileSize; |
|
10 |
+ |
|
11 |
+ this._initContainer(); |
|
12 |
+ this._container.setAttribute('width', this._size.x); |
|
13 |
+ this._container.setAttribute('height', this._size.y); |
|
14 |
+ this._container.setAttribute('viewBox', [0, 0, this._size.x, this._size.y].join(' ')); |
|
15 |
+ |
|
16 |
+ this._layers = {}; |
|
17 |
+ }, |
|
18 |
+ |
|
19 |
+ getCoord: function() { |
|
20 |
+ return this._tileCoord; |
|
21 |
+ }, |
|
22 |
+ |
|
23 |
+ getContainer: function() { |
|
24 |
+ return this._container; |
|
25 |
+ }, |
|
26 |
+ |
|
27 |
+ onAdd: L.Util.falseFn, |
|
28 |
+ |
|
29 |
+ addTo: function(map) { |
|
30 |
+ this._map = map; |
|
31 |
+ if (this.options.interactive) { |
|
32 |
+ for (var i in this._layers) { |
|
33 |
+ var layer = this._layers[i]; |
|
34 |
+ // By default, Leaflet tiles do not have pointer events. |
|
35 |
+ layer._path.style.pointerEvents = 'auto'; |
|
36 |
+ this._map._targets[L.stamp(layer._path)] = layer; |
|
37 |
+ } |
|
38 |
+ } |
|
39 |
+ }, |
|
40 |
+ |
|
41 |
+ removeFrom: function (map) { |
|
42 |
+ if (this.options.interactive) { |
|
43 |
+ for (var i in this._layers) { |
|
44 |
+ var layer = this._layers[i]; |
|
45 |
+ delete this._map._targets[L.stamp(layer._path)]; |
|
46 |
+ } |
|
47 |
+ } |
|
48 |
+ delete this._map; |
|
49 |
+ }, |
|
50 |
+ |
|
51 |
+ _initContainer: function() { |
|
52 |
+ L.SVG.prototype._initContainer.call(this); |
|
53 |
+ var rect = L.SVG.create('rect'); |
|
54 |
+ }, |
|
55 |
+ |
|
56 |
+ /// TODO: Modify _initPath to include an extra parameter, a group name |
|
57 |
+ /// to order symbolizers by z-index |
|
58 |
+ |
|
59 |
+ _addPath: function (layer) { |
|
60 |
+ this._rootGroup.appendChild(layer._path); |
|
61 |
+ this._layers[L.stamp(layer)] = layer; |
|
62 |
+ }, |
|
63 |
+ |
|
64 |
+ _updateIcon: function (layer) { |
|
65 |
+ var path = layer._path = L.SVG.create('image'), |
|
66 |
+ icon = layer.options.icon, |
|
67 |
+ options = icon.options, |
|
68 |
+ size = L.point(options.iconSize), |
|
69 |
+ anchor = options.iconAnchor || |
|
70 |
+ size && size.divideBy(2, true), |
|
71 |
+ p = layer._point.subtract(anchor); |
|
72 |
+ path.setAttribute('x', p.x); |
|
73 |
+ path.setAttribute('y', p.y); |
|
74 |
+ path.setAttribute('width', size.x + 'px'); |
|
75 |
+ path.setAttribute('height', size.y + 'px'); |
|
76 |
+ path.setAttribute('href', options.iconUrl); |
|
77 |
+ } |
|
78 |
+}); |
|
79 |
+ |
|
80 |
+ |
|
81 |
+L.svg.tile = function(tileCoord, tileSize, opts){ |
|
82 |
+ return new L.SVG.Tile(tileCoord, tileSize, opts); |
|
83 |
+}; |
|
84 |
+ |
|
85 |
+// 🍂class Symbolizer |
|
86 |
+// 🍂inherits Class |
|
87 |
+// The abstract Symbolizer class is mostly equivalent in concept to a `L.Path` - it's an interface for |
|
88 |
+// polylines, polygons and circles. But instead of representing leaflet Layers, |
|
89 |
+// it represents things that have to be drawn inside a vector tile. |
|
90 |
+ |
|
91 |
+// A vector tile *data layer* might have zero, one, or more *symbolizer definitions* |
|
92 |
+// A vector tile *feature* might have zero, one, or more *symbolizers*. |
|
93 |
+// The actual symbolizers applied will depend on filters and the symbolizer functions. |
|
94 |
+ |
|
95 |
+var Symbolizer = L.Class.extend({ |
|
96 |
+ // 🍂method initialize(feature: GeoJSON, pxPerExtent: Number) |
|
97 |
+ // Initializes a new Line Symbolizer given a GeoJSON feature and the |
|
98 |
+ // pixel-to-coordinate-units ratio. Internal use only. |
|
99 |
+ |
|
100 |
+ // 🍂method render(renderer, style) |
|
101 |
+ // Renders this symbolizer in the given tiled renderer, with the given |
|
102 |
+ // `L.Path` options. Internal use only. |
|
103 |
+ render: function(renderer, style) { |
|
104 |
+ this._renderer = renderer; |
|
105 |
+ this.options = style; |
|
106 |
+ renderer._initPath(this); |
|
107 |
+ renderer._updateStyle(this); |
|
108 |
+ }, |
|
109 |
+ |
|
110 |
+ // 🍂method render(renderer, style) |
|
111 |
+ // Updates the `L.Path` options used to style this symbolizer, and re-renders it. |
|
112 |
+ // Internal use only. |
|
113 |
+ updateStyle: function(renderer, style) { |
|
114 |
+ this.options = style; |
|
115 |
+ renderer._updateStyle(this); |
|
116 |
+ }, |
|
117 |
+ |
|
118 |
+ _getPixelBounds: function() { |
|
119 |
+ var parts = this._parts; |
|
120 |
+ var bounds = L.bounds([]); |
|
121 |
+ for (var i = 0; i < parts.length; i++) { |
|
122 |
+ var part = parts[i]; |
|
123 |
+ for (var j = 0; j < part.length; j++) { |
|
124 |
+ bounds.extend(part[j]); |
|
125 |
+ } |
|
126 |
+ } |
|
127 |
+ |
|
128 |
+ var w = this._clickTolerance(), |
|
129 |
+ p = new L.Point(w, w); |
|
130 |
+ |
|
131 |
+ bounds.min._subtract(p); |
|
132 |
+ bounds.max._add(p); |
|
133 |
+ |
|
134 |
+ return bounds; |
|
135 |
+ }, |
|
136 |
+ _clickTolerance: L.Path.prototype._clickTolerance, |
|
137 |
+}); |
|
138 |
+ |
|
139 |
+// Contains mixins which are common to the Line Symbolizer and the Fill Symbolizer. |
|
140 |
+ |
|
141 |
+var PolyBase = { |
|
142 |
+ _makeFeatureParts: function(feat, pxPerExtent) { |
|
143 |
+ var rings = feat.geometry; |
|
144 |
+ var coord; |
|
145 |
+ |
|
146 |
+ this._parts = []; |
|
147 |
+ for (var i = 0; i < rings.length; i++) { |
|
148 |
+ var ring = rings[i]; |
|
149 |
+ var part = []; |
|
150 |
+ for (var j = 0; j < ring.length; j++) { |
|
151 |
+ coord = ring[j]; |
|
152 |
+ // Protobuf vector tiles return {x: , y:} |
|
153 |
+ // Geojson-vt returns [,] |
|
154 |
+ part.push(L.point(coord).scaleBy(pxPerExtent)); |
|
155 |
+ } |
|
156 |
+ this._parts.push(part); |
|
157 |
+ } |
|
158 |
+ }, |
|
159 |
+ |
|
160 |
+ makeInteractive: function() { |
|
161 |
+ this._pxBounds = this._getPixelBounds(); |
|
162 |
+ } |
|
163 |
+}; |
|
164 |
+ |
|
165 |
+// 🍂class PointSymbolizer |
|
166 |
+// 🍂inherits CircleMarker |
|
167 |
+// A symbolizer for points. |
|
168 |
+ |
|
169 |
+var PointSymbolizer = L.CircleMarker.extend({ |
|
170 |
+ includes: Symbolizer.prototype, |
|
171 |
+ |
|
172 |
+ statics: { |
|
173 |
+ iconCache: {} |
|
174 |
+ }, |
|
175 |
+ |
|
176 |
+ initialize: function(feature, pxPerExtent) { |
|
177 |
+ this.properties = feature.properties; |
|
178 |
+ this._makeFeatureParts(feature, pxPerExtent); |
|
179 |
+ }, |
|
180 |
+ |
|
181 |
+ render: function(renderer, style) { |
|
182 |
+ Symbolizer.prototype.render.call(this, renderer, style); |
|
183 |
+ this._radius = style.radius || L.CircleMarker.prototype.options.radius; |
|
184 |
+ this._updatePath(); |
|
185 |
+ }, |
|
186 |
+ |
|
187 |
+ _makeFeatureParts: function(feat, pxPerExtent) { |
|
188 |
+ var coord = feat.geometry[0]; |
|
189 |
+ if (typeof coord[0] === 'object' && 'x' in coord[0]) { |
|
190 |
+ // Protobuf vector tiles return [{x: , y:}] |
|
191 |
+ this._point = L.point(coord[0]).scaleBy(pxPerExtent); |
|
192 |
+ this._empty = L.Util.falseFn; |
|
193 |
+ } else { |
|
194 |
+ // Geojson-vt returns [,] |
|
195 |
+ this._point = L.point(coord).scaleBy(pxPerExtent); |
|
196 |
+ this._empty = L.Util.falseFn; |
|
197 |
+ } |
|
198 |
+ }, |
|
199 |
+ |
|
200 |
+ makeInteractive: function() { |
|
201 |
+ this._updateBounds(); |
|
202 |
+ }, |
|
203 |
+ |
|
204 |
+ updateStyle: function(renderer, style) { |
|
205 |
+ this._radius = style.radius || this._radius; |
|
206 |
+ this._updateBounds(); |
|
207 |
+ return Symbolizer.prototype.updateStyle.call(this, renderer, style); |
|
208 |
+ }, |
|
209 |
+ |
|
210 |
+ _updateBounds: function() { |
|
211 |
+ var icon = this.options.icon; |
|
212 |
+ if (icon) { |
|
213 |
+ var size = L.point(icon.options.iconSize), |
|
214 |
+ anchor = icon.options.iconAnchor || |
|
215 |
+ size && size.divideBy(2, true), |
|
216 |
+ p = this._point.subtract(anchor); |
|
217 |
+ this._pxBounds = new L.Bounds(p, p.add(icon.options.iconSize)); |
|
218 |
+ } else { |
|
219 |
+ L.CircleMarker.prototype._updateBounds.call(this); |
|
220 |
+ } |
|
221 |
+ }, |
|
222 |
+ |
|
223 |
+ _updatePath: function() { |
|
224 |
+ if (this.options.icon) { |
|
225 |
+ this._renderer._updateIcon(this); |
|
226 |
+ } else { |
|
227 |
+ L.CircleMarker.prototype._updatePath.call(this); |
|
228 |
+ } |
|
229 |
+ }, |
|
230 |
+ |
|
231 |
+ _getImage: function () { |
|
232 |
+ if (this.options.icon) { |
|
233 |
+ var url = this.options.icon.options.iconUrl, |
|
234 |
+ img = PointSymbolizer.iconCache[url]; |
|
235 |
+ if (!img) { |
|
236 |
+ var icon = this.options.icon; |
|
237 |
+ img = PointSymbolizer.iconCache[url] = icon.createIcon(); |
|
238 |
+ } |
|
239 |
+ return img; |
|
240 |
+ } else { |
|
241 |
+ return null; |
|
242 |
+ } |
|
243 |
+ |
|
244 |
+ }, |
|
245 |
+ |
|
246 |
+ _containsPoint: function(p) { |
|
247 |
+ var icon = this.options.icon; |
|
248 |
+ if (icon) { |
|
249 |
+ return this._pxBounds.contains(p); |
|
250 |
+ } else { |
|
251 |
+ return L.CircleMarker.prototype._containsPoint.call(this, p); |
|
252 |
+ } |
|
253 |
+ } |
|
254 |
+}); |
|
255 |
+ |
|
256 |
+// 🍂class LineSymbolizer |
|
257 |
+// 🍂inherits Polyline |
|
258 |
+// A symbolizer for lines. Can be applied to line and polygon features. |
|
259 |
+ |
|
260 |
+var LineSymbolizer = L.Polyline.extend({ |
|
261 |
+ includes: [Symbolizer.prototype, PolyBase], |
|
262 |
+ |
|
263 |
+ initialize: function(feature, pxPerExtent) { |
|
264 |
+ this.properties = feature.properties; |
|
265 |
+ this._makeFeatureParts(feature, pxPerExtent); |
|
266 |
+ }, |
|
267 |
+ |
|
268 |
+ render: function(renderer, style) { |
|
269 |
+ style.fill = false; |
|
270 |
+ Symbolizer.prototype.render.call(this, renderer, style); |
|
271 |
+ this._updatePath(); |
|
272 |
+ }, |
|
273 |
+ |
|
274 |
+ updateStyle: function(renderer, style) { |
|
275 |
+ style.fill = false; |
|
276 |
+ Symbolizer.prototype.updateStyle.call(this, renderer, style); |
|
277 |
+ }, |
|
278 |
+}); |
|
279 |
+ |
|
280 |
+// 🍂class FillSymbolizer |
|
281 |
+// 🍂inherits Polyline |
|
282 |
+// A symbolizer for filled areas. Applies only to polygon features. |
|
283 |
+ |
|
284 |
+var FillSymbolizer = L.Polygon.extend({ |
|
285 |
+ includes: [Symbolizer.prototype, PolyBase], |
|
286 |
+ |
|
287 |
+ initialize: function(feature, pxPerExtent) { |
|
288 |
+ this.properties = feature.properties; |
|
289 |
+ this._makeFeatureParts(feature, pxPerExtent); |
|
290 |
+ }, |
|
291 |
+ |
|
292 |
+ render: function(renderer, style) { |
|
293 |
+ Symbolizer.prototype.render.call(this, renderer, style); |
|
294 |
+ this._updatePath(); |
|
295 |
+ } |
|
296 |
+}); |
|
297 |
+ |
|
298 |
+/* 🍂class VectorGrid |
|
299 |
+ * 🍂inherits GridLayer |
|
300 |
+ * |
|
301 |
+ * A `VectorGrid` is a generic, abstract class for displaying tiled vector data. |
|
302 |
+ * it provides facilities for symbolizing and rendering the data in the vector |
|
303 |
+ * tiles, but lacks the functionality to fetch the vector tiles from wherever |
|
304 |
+ * they are. |
|
305 |
+ * |
|
306 |
+ * Extends Leaflet's `L.GridLayer`. |
|
307 |
+ */ |
|
308 |
+ |
|
309 |
+L.VectorGrid = L.GridLayer.extend({ |
|
310 |
+ |
|
311 |
+ options: { |
|
312 |
+ // 🍂option rendererFactory = L.svg.tile |
|
313 |
+ // A factory method which will be used to instantiate the per-tile renderers. |
|
314 |
+ rendererFactory: L.svg.tile, |
|
315 |
+ |
|
316 |
+ // 🍂option vectorTileLayerStyles: Object = {} |
|
317 |
+ // A data structure holding initial symbolizer definitions for the vector features. |
|
318 |
+ vectorTileLayerStyles: {}, |
|
319 |
+ |
|
320 |
+ // 🍂option interactive: Boolean = false |
|
321 |
+ // Whether this `VectorGrid` fires `Interactive Layer` events. |
|
322 |
+ interactive: false, |
|
323 |
+ |
|
324 |
+ // 🍂option getFeatureId: Function = undefined |
|
325 |
+ // A function that, given a vector feature, returns an unique identifier for it, e.g. |
|
326 |
+ // `function(feat) { return feat.properties.uniqueIdField; }`. |
|
327 |
+ // Must be defined for `setFeatureStyle` to work. |
|
328 |
+ }, |
|
329 |
+ |
|
330 |
+ initialize: function(options) { |
|
331 |
+ L.setOptions(this, options); |
|
332 |
+ L.GridLayer.prototype.initialize.apply(this, arguments); |
|
333 |
+ if (this.options.getFeatureId) { |
|
334 |
+ this._vectorTiles = {}; |
|
335 |
+ this._overriddenStyles = {}; |
|
336 |
+ this.on('tileunload', function(e) { |
|
337 |
+ var key = this._tileCoordsToKey(e.coords), |
|
338 |
+ tile = this._vectorTiles[key]; |
|
339 |
+ |
|
340 |
+ if (tile && this._map) { |
|
341 |
+ tile.removeFrom(this._map); |
|
342 |
+ } |
|
343 |
+ delete this._vectorTiles[key]; |
|
344 |
+ }, this); |
|
345 |
+ } |
|
346 |
+ this._dataLayerNames = {}; |
|
347 |
+ }, |
|
348 |
+ |
|
349 |
+ createTile: function(coords, done) { |
|
350 |
+ var storeFeatures = this.options.getFeatureId; |
|
351 |
+ |
|
352 |
+ var tileSize = this.getTileSize(); |
|
353 |
+ var renderer = this.options.rendererFactory(coords, tileSize, this.options); |
|
354 |
+ |
|
355 |
+ var vectorTilePromise = this._getVectorTilePromise(coords); |
|
356 |
+ |
|
357 |
+ if (storeFeatures) { |
|
358 |
+ this._vectorTiles[this._tileCoordsToKey(coords)] = renderer; |
|
359 |
+ renderer._features = {}; |
|
360 |
+ } |
|
361 |
+ |
|
362 |
+ vectorTilePromise.then( function renderTile(vectorTile) { |
|
363 |
+ for (var layerName in vectorTile.layers) { |
|
364 |
+ this._dataLayerNames[layerName] = true; |
|
365 |
+ var layer = vectorTile.layers[layerName]; |
|
366 |
+ |
|
367 |
+ var pxPerExtent = this.getTileSize().divideBy(layer.extent); |
|
368 |
+ |
|
369 |
+ var layerStyle = this.options.vectorTileLayerStyles[ layerName ] || |
|
370 |
+ L.Path.prototype.options; |
|
371 |
+ |
|
372 |
+ for (var i = 0; i < layer.features.length; i++) { |
|
373 |
+ var feat = layer.features[i]; |
|
374 |
+ var id; |
|
375 |
+ |
|
376 |
+ var styleOptions = layerStyle; |
|
377 |
+ if (storeFeatures) { |
|
378 |
+ id = this.options.getFeatureId(feat); |
|
379 |
+ var styleOverride = this._overriddenStyles[id]; |
|
380 |
+ if (styleOverride) { |
|
381 |
+ if (styleOverride[layerName]) { |
|
382 |
+ styleOptions = styleOverride[layerName]; |
|
383 |
+ } else { |
|
384 |
+ styleOptions = styleOverride; |
|
385 |
+ } |
|
386 |
+ } |
|
387 |
+ } |
|
388 |
+ |
|
389 |
+ if (styleOptions instanceof Function) { |
|
390 |
+ styleOptions = styleOptions(feat.properties, coords.z); |
|
391 |
+ } |
|
392 |
+ |
|
393 |
+ if (!(styleOptions instanceof Array)) { |
|
394 |
+ styleOptions = [styleOptions]; |
|
395 |
+ } |
|
396 |
+ |
|
397 |
+ if (!styleOptions.length) { |
|
398 |
+ continue; |
|
399 |
+ } |
|
400 |
+ |
|
401 |
+ var featureLayer = this._createLayer(feat, pxPerExtent); |
|
402 |
+ |
|
403 |
+ for (var j = 0; j < styleOptions.length; j++) { |
|
404 |
+ var style = L.extend({}, L.Path.prototype.options, styleOptions[j]); |
|
405 |
+ featureLayer.render(renderer, style); |
|
406 |
+ renderer._addPath(featureLayer); |
|
407 |
+ } |
|
408 |
+ |
|
409 |
+ if (this.options.interactive) { |
|
410 |
+ featureLayer.makeInteractive(); |
|
411 |
+ } |
|
412 |
+ |
|
413 |
+ if (storeFeatures) { |
|
414 |
+ renderer._features[id] = { |
|
415 |
+ layerName: layerName, |
|
416 |
+ feature: featureLayer |
|
417 |
+ }; |
|
418 |
+ } |
|
419 |
+ } |
|
420 |
+ |
|
421 |
+ } |
|
422 |
+ if (this._map != null) { |
|
423 |
+ renderer.addTo(this._map); |
|
424 |
+ } |
|
425 |
+ L.Util.requestAnimFrame(done.bind(coords, null, null)); |
|
426 |
+ }.bind(this)); |
|
427 |
+ |
|
428 |
+ return renderer.getContainer(); |
|
429 |
+ }, |
|
430 |
+ |
|
431 |
+ // 🍂method setFeatureStyle(id: Number, layerStyle: L.Path Options): this |
|
432 |
+ // Given the unique ID for a vector features (as per the `getFeatureId` option), |
|
433 |
+ // re-symbolizes that feature across all tiles it appears in. |
|
434 |
+ setFeatureStyle: function(id, layerStyle) { |
|
435 |
+ this._overriddenStyles[id] = layerStyle; |
|
436 |
+ |
|
437 |
+ for (var tileKey in this._vectorTiles) { |
|
438 |
+ var tile = this._vectorTiles[tileKey]; |
|
439 |
+ var features = tile._features; |
|
440 |
+ var data = features[id]; |
|
441 |
+ if (data) { |
|
442 |
+ var feat = data.feature; |
|
443 |
+ |
|
444 |
+ var styleOptions = layerStyle; |
|
445 |
+ if (layerStyle[data.layerName]) { |
|
446 |
+ styleOptions = layerStyle[data.layerName]; |
|
447 |
+ } |
|
448 |
+ |
|
449 |
+ this._updateStyles(feat, tile, styleOptions); |
|
450 |
+ } |
|
451 |
+ } |
|
452 |
+ return this; |
|
453 |
+ }, |
|
454 |
+ |
|
455 |
+ // 🍂method setFeatureStyle(id: Number): this |
|
456 |
+ // Reverts the effects of a previous `setFeatureStyle` call. |
|
457 |
+ resetFeatureStyle: function(id) { |
|
458 |
+ delete this._overriddenStyles[id]; |
|
459 |
+ |
|
460 |
+ for (var tileKey in this._vectorTiles) { |
|
461 |
+ var tile = this._vectorTiles[tileKey]; |
|
462 |
+ var features = tile._features; |
|
463 |
+ var data = features[id]; |
|
464 |
+ if (data) { |
|
465 |
+ var feat = data.feature; |
|
466 |
+ var styleOptions = this.options.vectorTileLayerStyles[ data.layerName ] || |
|
467 |
+ L.Path.prototype.options; |
|
468 |
+ this._updateStyles(feat, tile, styleOptions); |
|
469 |
+ } |
|
470 |
+ } |
|
471 |
+ return this; |
|
472 |
+ }, |
|
473 |
+ |
|
474 |
+ // 🍂method getDataLayerNames(): Array |
|
475 |
+ // Returns an array of strings, with all the known names of data layers in |
|
476 |
+ // the vector tiles displayed. Useful for introspection. |
|
477 |
+ getDataLayerNames: function() { |
|
478 |
+ return Object.keys(this._dataLayerNames); |
|
479 |
+ }, |
|
480 |
+ |
|
481 |
+ _updateStyles: function(feat, renderer, styleOptions) { |
|
482 |
+ styleOptions = (styleOptions instanceof Function) ? |
|
483 |
+ styleOptions(feat.properties, renderer.getCoord().z) : |
|
484 |
+ styleOptions; |
|
485 |
+ |
|
486 |
+ if (!(styleOptions instanceof Array)) { |
|
487 |
+ styleOptions = [styleOptions]; |
|
488 |
+ } |
|
489 |
+ |
|
490 |
+ for (var j = 0; j < styleOptions.length; j++) { |
|
491 |
+ var style = L.extend({}, L.Path.prototype.options, styleOptions[j]); |
|
492 |
+ feat.updateStyle(renderer, style); |
|
493 |
+ } |
|
494 |
+ }, |
|
495 |
+ |
|
496 |
+ _createLayer: function(feat, pxPerExtent, layerStyle) { |
|
497 |
+ var layer; |
|
498 |
+ switch (feat.type) { |
|
499 |
+ case 1: |
|
500 |
+ layer = new PointSymbolizer(feat, pxPerExtent); |
|
501 |
+ break; |
|
502 |
+ case 2: |
|
503 |
+ layer = new LineSymbolizer(feat, pxPerExtent); |
|
504 |
+ break; |
|
505 |
+ case 3: |
|
506 |
+ layer = new FillSymbolizer(feat, pxPerExtent); |
|
507 |
+ break; |
|
508 |
+ } |
|
509 |
+ |
|
510 |
+ if (this.options.interactive) { |
|
511 |
+ layer.addEventParent(this); |
|
512 |
+ } |
|
513 |
+ |
|
514 |
+ return layer; |
|
515 |
+ }, |
|
516 |
+}); |
|
517 |
+ |
|
518 |
+/* |
|
519 |
+ * 🍂section Extension methods |
|
520 |
+ * |
|
521 |
+ * Classes inheriting from `VectorGrid` **must** define the `_getVectorTilePromise` private method. |
|
522 |
+ * |
|
523 |
+ * 🍂method getVectorTilePromise(coords: Object): Promise |
|
524 |
+ * Given a `coords` object in the form of `{x: Number, y: Number, z: Number}`, |
|
525 |
+ * this function must return a `Promise` for a vector tile. |
|
526 |
+ * |
|
527 |
+ */ |
|
528 |
+L.vectorGrid = function (options) { |
|
529 |
+ return new L.VectorGrid(options); |
|
530 |
+}; |
|
531 |
+ |
|
532 |
+var read = function (buffer, offset, isLE, mLen, nBytes) { |
|
533 |
+ var e, m; |
|
534 |
+ var eLen = nBytes * 8 - mLen - 1; |
|
535 |
+ var eMax = (1 << eLen) - 1; |
|
536 |
+ var eBias = eMax >> 1; |
|
537 |
+ var nBits = -7; |
|
538 |
+ var i = isLE ? (nBytes - 1) : 0; |
|
539 |
+ var d = isLE ? -1 : 1; |
|
540 |
+ var s = buffer[offset + i]; |
|
541 |
+ |
|
542 |
+ i += d; |
|
543 |
+ |
|
544 |
+ e = s & ((1 << (-nBits)) - 1); |
|
545 |
+ s >>= (-nBits); |
|
546 |
+ nBits += eLen; |
|
547 |
+ for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {} |
|
548 |
+ |
|
549 |
+ m = e & ((1 << (-nBits)) - 1); |
|
550 |
+ e >>= (-nBits); |
|
551 |
+ nBits += mLen; |
|
552 |
+ for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {} |
|
553 |
+ |
|
554 |
+ if (e === 0) { |
|
555 |
+ e = 1 - eBias; |
|
556 |
+ } else if (e === eMax) { |
|
557 |
+ return m ? NaN : ((s ? -1 : 1) * Infinity) |
|
558 |
+ } else { |
|
559 |
+ m = m + Math.pow(2, mLen); |
|
560 |
+ e = e - eBias; |
|
561 |
+ } |
|
562 |
+ return (s ? -1 : 1) * m * Math.pow(2, e - mLen) |
|
563 |
+}; |
|
564 |
+ |
|
565 |
+var write = function (buffer, value, offset, isLE, mLen, nBytes) { |
|
566 |
+ var e, m, c; |
|
567 |
+ var eLen = nBytes * 8 - mLen - 1; |
|
568 |
+ var eMax = (1 << eLen) - 1; |
|
569 |
+ var eBias = eMax >> 1; |
|
570 |
+ var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0); |
|
571 |
+ var i = isLE ? 0 : (nBytes - 1); |
|
572 |
+ var d = isLE ? 1 : -1; |
|
573 |
+ var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0; |
|
574 |
+ |
|
575 |
+ value = Math.abs(value); |
|
576 |
+ |
|
577 |
+ if (isNaN(value) || value === Infinity) { |
|
578 |
+ m = isNaN(value) ? 1 : 0; |
|
579 |
+ e = eMax; |
|
580 |
+ } else { |
|
581 |
+ e = Math.floor(Math.log(value) / Math.LN2); |
|
582 |
+ if (value * (c = Math.pow(2, -e)) < 1) { |
|
583 |
+ e--; |
|
584 |
+ c *= 2; |
|
585 |
+ } |
|
586 |
+ if (e + eBias >= 1) { |
|
587 |
+ value += rt / c; |
|
588 |
+ } else { |
|
589 |
+ value += rt * Math.pow(2, 1 - eBias); |
|
590 |
+ } |
|
591 |
+ if (value * c >= 2) { |
|
592 |
+ e++; |
|
593 |
+ c /= 2; |
|
594 |
+ } |
|
595 |
+ |
|
596 |
+ if (e + eBias >= eMax) { |
|
597 |
+ m = 0; |
|
598 |
+ e = eMax; |
|
599 |
+ } else if (e + eBias >= 1) { |
|
600 |
+ m = (value * c - 1) * Math.pow(2, mLen); |
|
601 |
+ e = e + eBias; |
|
602 |
+ } else { |
|
603 |
+ m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen); |
|
604 |
+ e = 0; |
|
605 |
+ } |
|
606 |
+ } |
|
607 |
+ |
|
608 |
+ for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {} |
|
609 |
+ |
|
610 |
+ e = (e << mLen) | m; |
|
611 |
+ eLen += mLen; |
|
612 |
+ for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {} |
|
613 |
+ |
|
614 |
+ buffer[offset + i - d] |= s * 128; |
|
615 |
+}; |
|
616 |
+ |
|
617 |
+var index$1 = { |
|
618 |
+ read: read, |
|
619 |
+ write: write |
|
620 |
+}; |
|
621 |
+ |
|
622 |
+var index = Pbf; |
|
623 |
+ |
|
624 |
+var ieee754 = index$1; |
|
625 |
+ |
|
626 |
+function Pbf(buf) { |
|
627 |
+ this.buf = ArrayBuffer.isView && ArrayBuffer.isView(buf) ? buf : new Uint8Array(buf || 0); |
|
628 |
+ this.pos = 0; |
|
629 |
+ this.type = 0; |
|
630 |
+ this.length = this.buf.length; |
|
631 |
+} |
|
632 |
+ |
|
633 |
+Pbf.Varint = 0; // varint: int32, int64, uint32, uint64, sint32, sint64, bool, enum |
|
634 |
+Pbf.Fixed64 = 1; // 64-bit: double, fixed64, sfixed64 |
|
635 |
+Pbf.Bytes = 2; // length-delimited: string, bytes, embedded messages, packed repeated fields |
|
636 |
+Pbf.Fixed32 = 5; // 32-bit: float, fixed32, sfixed32 |
|
637 |
+ |
|
638 |
+var SHIFT_LEFT_32 = (1 << 16) * (1 << 16); |
|
639 |
+var SHIFT_RIGHT_32 = 1 / SHIFT_LEFT_32; |
|
640 |
+ |
|
641 |
+Pbf.prototype = { |
|
642 |
+ |
|
643 |
+ destroy: function() { |
|
644 |
+ this.buf = null; |
|
645 |
+ }, |
|
646 |
+ |
|
647 |
+ // === READING ================================================================= |
|
648 |
+ |
|
649 |
+ readFields: function(readField, result, end) { |
|
650 |
+ var this$1 = this; |
|
651 |
+ |
|
652 |
+ end = end || this.length; |
|
653 |
+ |
|
654 |
+ while (this.pos < end) { |
|
655 |
+ var val = this$1.readVarint(), |
|
656 |
+ tag = val >> 3, |
|
657 |
+ startPos = this$1.pos; |
|
658 |
+ |
|
659 |
+ this$1.type = val & 0x7; |
|
660 |
+ readField(tag, result, this$1); |
|
661 |
+ |
|
662 |
+ if (this$1.pos === startPos) { this$1.skip(val); } |
|
663 |
+ } |
|
664 |
+ return result; |
|
665 |
+ }, |
|
666 |
+ |
|
667 |
+ readMessage: function(readField, result) { |
|
668 |
+ return this.readFields(readField, result, this.readVarint() + this.pos); |
|
669 |
+ }, |
|
670 |
+ |
|
671 |
+ readFixed32: function() { |
|
672 |
+ var val = readUInt32(this.buf, this.pos); |
|
673 |
+ this.pos += 4; |
|
674 |
+ return val; |
|
675 |
+ }, |
|
676 |
+ |
|
677 |
+ readSFixed32: function() { |
|
678 |
+ var val = readInt32(this.buf, this.pos); |
|
679 |
+ this.pos += 4; |
|
680 |
+ return val; |
|
681 |
+ }, |
|
682 |
+ |
|
683 |
+ // 64-bit int handling is based on github.com/dpw/node-buffer-more-ints (MIT-licensed) |
|
684 |
+ |
|
685 |
+ readFixed64: function() { |
|
686 |
+ var val = readUInt32(this.buf, this.pos) + readUInt32(this.buf, this.pos + 4) * SHIFT_LEFT_32; |
|
687 |
+ this.pos += 8; |
|
688 |
+ return val; |
|
689 |
+ }, |
|
690 |
+ |
|
691 |
+ readSFixed64: function() { |
|
692 |
+ var val = readUInt32(this.buf, this.pos) + readInt32(this.buf, this.pos + 4) * SHIFT_LEFT_32; |
|
693 |
+ this.pos += 8; |
|
694 |
+ return val; |
|
695 |
+ }, |
|
696 |
+ |
|
697 |
+ readFloat: function() { |
|
698 |
+ var val = ieee754.read(this.buf, this.pos, true, 23, 4); |
|
699 |
+ this.pos += 4; |
|
700 |
+ return val; |
|
701 |
+ }, |
|
702 |
+ |
|
703 |
+ readDouble: function() { |
|
704 |
+ var val = ieee754.read(this.buf, this.pos, true, 52, 8); |
|
705 |
+ this.pos += 8; |
|
706 |
+ return val; |
|
707 |
+ }, |
|
708 |
+ |
|
709 |
+ readVarint: function(isSigned) { |
|
710 |
+ var buf = this.buf, |
|
711 |
+ val, b; |
|
712 |
+ |
|
713 |
+ b = buf[this.pos++]; val = b & 0x7f; if (b < 0x80) { return val; } |
|
714 |
+ b = buf[this.pos++]; val |= (b & 0x7f) << 7; if (b < 0x80) { return val; } |
|
715 |
+ b = buf[this.pos++]; val |= (b & 0x7f) << 14; if (b < 0x80) { return val; } |
|
716 |
+ b = buf[this.pos++]; val |= (b & 0x7f) << 21; if (b < 0x80) { return val; } |
|
717 |
+ b = buf[this.pos]; val |= (b & 0x0f) << 28; |
|
718 |
+ |
|
719 |
+ return readVarintRemainder(val, isSigned, this); |
|
720 |
+ }, |
|
721 |
+ |
|
722 |
+ readVarint64: function() { // for compatibility with v2.0.1 |
|
723 |
+ return this.readVarint(true); |
|
724 |
+ }, |
|
725 |
+ |
|
726 |
+ readSVarint: function() { |
|
727 |
+ var num = this.readVarint(); |
|
728 |
+ return num % 2 === 1 ? (num + 1) / -2 : num / 2; // zigzag encoding |
|
729 |
+ }, |
|
730 |
+ |
|
731 |
+ readBoolean: function() { |
|
732 |
+ return Boolean(this.readVarint()); |
|
733 |
+ }, |
|
734 |
+ |
|
735 |
+ readString: function() { |
|
736 |
+ var end = this.readVarint() + this.pos, |
|
737 |
+ str = readUtf8(this.buf, this.pos, end); |
|
738 |
+ this.pos = end; |
|
739 |
+ return str; |
|
740 |
+ }, |
|
741 |
+ |
|
742 |
+ readBytes: function() { |
|
743 |
+ var end = this.readVarint() + this.pos, |
|
744 |
+ buffer = this.buf.subarray(this.pos, end); |
|
745 |
+ this.pos = end; |
|
746 |
+ return buffer; |
|
747 |
+ }, |
|
748 |
+ |
|
749 |
+ // verbose for performance reasons; doesn't affect gzipped size |
|
750 |
+ |
|
751 |
+ readPackedVarint: function(arr, isSigned) { |
|
752 |
+ var this$1 = this; |
|
753 |
+ |
|
754 |
+ var end = readPackedEnd(this); |
|
755 |
+ arr = arr || []; |
|
756 |
+ while (this.pos < end) { arr.push(this$1.readVarint(isSigned)); } |
|
757 |
+ return arr; |
|
758 |
+ }, |
|
759 |
+ readPackedSVarint: function(arr) { |
|
760 |
+ var this$1 = this; |
|
761 |
+ |
|
762 |
+ var end = readPackedEnd(this); |
|
763 |
+ arr = arr || []; |
|
764 |
+ while (this.pos < end) { arr.push(this$1.readSVarint()); } |
|
765 |
+ return arr; |
|
766 |
+ }, |
|
767 |
+ readPackedBoolean: function(arr) { |
|
768 |
+ var this$1 = this; |
|
769 |
+ |
|
770 |
+ var end = readPackedEnd(this); |
|
771 |
+ arr = arr || []; |
|
772 |
+ while (this.pos < end) { arr.push(this$1.readBoolean()); } |
|
773 |
+ return arr; |
|
774 |
+ }, |
|
775 |
+ readPackedFloat: function(arr) { |
|
776 |
+ var this$1 = this; |
|
777 |
+ |
|
778 |
+ var end = readPackedEnd(this); |
|
779 |
+ arr = arr || []; |
|
780 |
+ while (this.pos < end) { arr.push(this$1.readFloat()); } |
|
781 |
+ return arr; |
|
782 |
+ }, |
|
783 |
+ readPackedDouble: function(arr) { |
|
784 |
+ var this$1 = this; |
|
785 |
+ |
|
786 |
+ var end = readPackedEnd(this); |
|
787 |
+ arr = arr || []; |
|
788 |
+ while (this.pos < end) { arr.push(this$1.readDouble()); } |
|
789 |
+ return arr; |
|
790 |
+ }, |
|
791 |
+ readPackedFixed32: function(arr) { |
|
792 |
+ var this$1 = this; |
|
793 |
+ |
|
794 |
+ var end = readPackedEnd(this); |
|
795 |
+ arr = arr || []; |
|
796 |
+ while (this.pos < end) { arr.push(this$1.readFixed32()); } |
|
797 |
+ return arr; |
|
798 |
+ }, |
|
799 |
+ readPackedSFixed32: function(arr) { |
|
800 |
+ var this$1 = this; |
|
801 |
+ |
|
802 |
+ var end = readPackedEnd(this); |
|
803 |
+ arr = arr || []; |
|
804 |
+ while (this.pos < end) { arr.push(this$1.readSFixed32()); } |
|
805 |
+ return arr; |
|
806 |
+ }, |
|
807 |
+ readPackedFixed64: function(arr) { |
|
808 |
+ var this$1 = this; |
|
809 |
+ |
|
810 |
+ var end = readPackedEnd(this); |
|
811 |
+ arr = arr || []; |
|
812 |
+ while (this.pos < end) { arr.push(this$1.readFixed64()); } |
|
813 |
+ return arr; |
|
814 |
+ }, |
|
815 |
+ readPackedSFixed64: function(arr) { |
|
816 |
+ var this$1 = this; |
|
817 |
+ |
|
818 |
+ var end = readPackedEnd(this); |
|
819 |
+ arr = arr || []; |
|
820 |
+ while (this.pos < end) { arr.push(this$1.readSFixed64()); } |
|
821 |
+ return arr; |
|
822 |
+ }, |
|
823 |
+ |
|
824 |
+ skip: function(val) { |
|
825 |
+ var type = val & 0x7; |
|
826 |
+ if (type === Pbf.Varint) { while (this.buf[this.pos++] > 0x7f) {} } |
|
827 |
+ else if (type === Pbf.Bytes) { this.pos = this.readVarint() + this.pos; } |
|
828 |
+ else if (type === Pbf.Fixed32) { this.pos += 4; } |
|
829 |
+ else if (type === Pbf.Fixed64) { this.pos += 8; } |
|
830 |
+ else { throw new Error('Unimplemented type: ' + type); } |
|
831 |
+ }, |
|
832 |
+ |
|
833 |
+ // === WRITING ================================================================= |
|
834 |
+ |
|
835 |
+ writeTag: function(tag, type) { |
|
836 |
+ this.writeVarint((tag << 3) | type); |
|
837 |
+ }, |
|
838 |
+ |
|
839 |
+ realloc: function(min) { |
|
840 |
+ var length = this.length || 16; |
|
841 |
+ |
|
842 |
+ while (length < this.pos + min) { length *= 2; } |
|
843 |
+ |
|
844 |
+ if (length !== this.length) { |
|
845 |
+ var buf = new Uint8Array(length); |
|
846 |
+ buf.set(this.buf); |
|
847 |
+ this.buf = buf; |
|
848 |
+ this.length = length; |
|
849 |
+ } |
|
850 |
+ }, |
|
851 |
+ |
|
852 |
+ finish: function() { |
|
853 |
+ this.length = this.pos; |
|
854 |
+ this.pos = 0; |
|
855 |
+ return this.buf.subarray(0, this.length); |
|
856 |
+ }, |
|
857 |
+ |
|
858 |
+ writeFixed32: function(val) { |
|
859 |
+ this.realloc(4); |
|
860 |
+ writeInt32(this.buf, val, this.pos); |
|
861 |
+ this.pos += 4; |
|
862 |
+ }, |
|
863 |
+ |
|
864 |
+ writeSFixed32: function(val) { |
|
865 |
+ this.realloc(4); |
|
866 |
+ writeInt32(this.buf, val, this.pos); |
|
867 |
+ this.pos += 4; |
|
868 |
+ }, |
|
869 |
+ |
|
870 |
+ writeFixed64: function(val) { |
|
871 |
+ this.realloc(8); |
|
872 |
+ writeInt32(this.buf, val & -1, this.pos); |
|
873 |
+ writeInt32(this.buf, Math.floor(val * SHIFT_RIGHT_32), this.pos + 4); |
|
874 |
+ this.pos += 8; |
|
875 |
+ }, |
|
876 |
+ |
|
877 |
+ writeSFixed64: function(val) { |
|
878 |
+ this.realloc(8); |
|
879 |
+ writeInt32(this.buf, val & -1, this.pos); |
|
880 |
+ writeInt32(this.buf, Math.floor(val * SHIFT_RIGHT_32), this.pos + 4); |
|
881 |
+ this.pos += 8; |
|
882 |
+ }, |
|
883 |
+ |
|
884 |
+ writeVarint: function(val) { |
|
885 |
+ val = +val || 0; |
|
886 |
+ |
|
887 |
+ if (val > 0xfffffff || val < 0) { |
|
888 |
+ writeBigVarint(val, this); |
|
889 |
+ return; |
|
890 |
+ } |
|
891 |
+ |
|
892 |
+ this.realloc(4); |
|
893 |
+ |
|
894 |
+ this.buf[this.pos++] = val & 0x7f | (val > 0x7f ? 0x80 : 0); if (val <= 0x7f) { return; } |
|
895 |
+ this.buf[this.pos++] = ((val >>>= 7) & 0x7f) | (val > 0x7f ? 0x80 : 0); if (val <= 0x7f) { return; } |
|
896 |
+ this.buf[this.pos++] = ((val >>>= 7) & 0x7f) | (val > 0x7f ? 0x80 : 0); if (val <= 0x7f) { return; } |
|
897 |
+ this.buf[this.pos++] = (val >>> 7) & 0x7f; |
|
898 |
+ }, |
|
899 |
+ |
|
900 |
+ writeSVarint: function(val) { |
|
901 |
+ this.writeVarint(val < 0 ? -val * 2 - 1 : val * 2); |
|
902 |
+ }, |
|
903 |
+ |
|
904 |
+ writeBoolean: function(val) { |
|
905 |
+ this.writeVarint(Boolean(val)); |
|
906 |
+ }, |
|
907 |
+ |
|
908 |
+ writeString: function(str) { |
|
909 |
+ str = String(str); |
|
910 |
+ this.realloc(str.length * 4); |
|
911 |
+ |
|
912 |
+ this.pos++; // reserve 1 byte for short string length |
|
913 |
+ |
|
914 |
+ var startPos = this.pos; |
|
915 |
+ // write the string directly to the buffer and see how much was written |
|
916 |
+ this.pos = writeUtf8(this.buf, str, this.pos); |
|
917 |
+ var len = this.pos - startPos; |
|
918 |
+ |
|
919 |
+ if (len >= 0x80) { makeRoomForExtraLength(startPos, len, this); } |
|
920 |
+ |
|
921 |
+ // finally, write the message length in the reserved place and restore the position |
|
922 |
+ this.pos = startPos - 1; |
|
923 |
+ this.writeVarint(len); |
|
924 |
+ this.pos += len; |
|
925 |
+ }, |
|
926 |
+ |
|
927 |
+ writeFloat: function(val) { |
|
928 |
+ this.realloc(4); |
|
929 |
+ ieee754.write(this.buf, val, this.pos, true, 23, 4); |
|
930 |
+ this.pos += 4; |
|
931 |
+ }, |
|
932 |
+ |
|
933 |
+ writeDouble: function(val) { |
|
934 |
+ this.realloc(8); |
|
935 |
+ ieee754.write(this.buf, val, this.pos, true, 52, 8); |
|
936 |
+ this.pos += 8; |
|
937 |
+ }, |
|
938 |
+ |
|
939 |
+ writeBytes: function(buffer) { |
|
940 |
+ var this$1 = this; |
|
941 |
+ |
|
942 |
+ var len = buffer.length; |
|
943 |
+ this.writeVarint(len); |
|
944 |
+ this.realloc(len); |
|
945 |
+ for (var i = 0; i < len; i++) { this$1.buf[this$1.pos++] = buffer[i]; } |
|
946 |
+ }, |
|
947 |
+ |
|
948 |
+ writeRawMessage: function(fn, obj) { |
|
949 |
+ this.pos++; // reserve 1 byte for short message length |
|
950 |
+ |
|
951 |
+ // write the message directly to the buffer and see how much was written |
|
952 |
+ var startPos = this.pos; |
|
953 |
+ fn(obj, this); |
|
954 |
+ var len = this.pos - startPos; |
|
955 |
+ |
|
956 |
+ if (len >= 0x80) { makeRoomForExtraLength(startPos, len, this); } |
|
957 |
+ |
|
958 |
+ // finally, write the message length in the reserved place and restore the position |
|
959 |
+ this.pos = startPos - 1; |
|
960 |
+ this.writeVarint(len); |
|
961 |
+ this.pos += len; |
|
962 |
+ }, |
|
963 |
+ |
|
964 |
+ writeMessage: function(tag, fn, obj) { |
|
965 |
+ this.writeTag(tag, Pbf.Bytes); |
|
966 |
+ this.writeRawMessage(fn, obj); |
|
967 |
+ }, |
|
968 |
+ |
|
969 |
+ writePackedVarint: function(tag, arr) { this.writeMessage(tag, writePackedVarint, arr); }, |
|
970 |
+ writePackedSVarint: function(tag, arr) { this.writeMessage(tag, writePackedSVarint, arr); }, |
|
971 |
+ writePackedBoolean: function(tag, arr) { this.writeMessage(tag, writePackedBoolean, arr); }, |
|
972 |
+ writePackedFloat: function(tag, arr) { this.writeMessage(tag, writePackedFloat, arr); }, |
|
973 |
+ writePackedDouble: function(tag, arr) { this.writeMessage(tag, writePackedDouble, arr); }, |
|
974 |
+ writePackedFixed32: function(tag, arr) { this.writeMessage(tag, writePackedFixed32, arr); }, |
|
975 |
+ writePackedSFixed32: function(tag, arr) { this.writeMessage(tag, writePackedSFixed32, arr); }, |
|
976 |
+ writePackedFixed64: function(tag, arr) { this.writeMessage(tag, writePackedFixed64, arr); }, |
|
977 |
+ writePackedSFixed64: function(tag, arr) { this.writeMessage(tag, writePackedSFixed64, arr); }, |
|
978 |
+ |
|
979 |
+ writeBytesField: function(tag, buffer) { |
|
980 |
+ this.writeTag(tag, Pbf.Bytes); |
|
981 |
+ this.writeBytes(buffer); |
|
982 |
+ }, |
|
983 |
+ writeFixed32Field: function(tag, val) { |
|
984 |
+ this.writeTag(tag, Pbf.Fixed32); |
|
985 |
+ this.writeFixed32(val); |
|
986 |
+ }, |
|
987 |
+ writeSFixed32Field: function(tag, val) { |
|
988 |
+ this.writeTag(tag, Pbf.Fixed32); |
|
989 |
+ this.writeSFixed32(val); |
|
990 |
+ }, |
|
991 |
+ writeFixed64Field: function(tag, val) { |
|
992 |
+ this.writeTag(tag, Pbf.Fixed64); |
|
993 |
+ this.writeFixed64(val); |
|
994 |
+ }, |
|
995 |
+ writeSFixed64Field: function(tag, val) { |
|
996 |
+ this.writeTag(tag, Pbf.Fixed64); |
|
997 |
+ this.writeSFixed64(val); |
|
998 |
+ }, |
|
999 |
+ writeVarintField: function(tag, val) { |
|
1000 |
+ this.writeTag(tag, Pbf.Varint); |
|
1001 |
+ this.writeVarint(val); |
|
1002 |
+ }, |
|
1003 |
+ writeSVarintField: function(tag, val) { |
|
1004 |
+ this.writeTag(tag, Pbf.Varint); |
|
1005 |
+ this.writeSVarint(val); |
|
1006 |
+ }, |
|
1007 |
+ writeStringField: function(tag, str) { |
|
1008 |
+ this.writeTag(tag, Pbf.Bytes); |
|
1009 |
+ this.writeString(str); |
|
1010 |
+ }, |
|
1011 |
+ writeFloatField: function(tag, val) { |
|
1012 |
+ this.writeTag(tag, Pbf.Fixed32); |
|
1013 |
+ this.writeFloat(val); |
|
1014 |
+ }, |
|
1015 |
+ writeDoubleField: function(tag, val) { |
|
1016 |
+ this.writeTag(tag, Pbf.Fixed64); |
|
1017 |
+ this.writeDouble(val); |
|
1018 |
+ }, |
|
1019 |
+ writeBooleanField: function(tag, val) { |
|
1020 |
+ this.writeVarintField(tag, Boolean(val)); |
|
1021 |
+ } |
|
1022 |
+}; |
|
1023 |
+ |
|
1024 |
+function readVarintRemainder(l, s, p) { |
|
1025 |
+ var buf = p.buf, |
|
1026 |
+ h, b; |
|
1027 |
+ |
|
1028 |
+ b = buf[p.pos++]; h = (b & 0x70) >> 4; if (b < 0x80) { return toNum(l, h, s); } |
|
1029 |
+ b = buf[p.pos++]; h |= (b & 0x7f) << 3; if (b < 0x80) { return toNum(l, h, s); } |
|
1030 |
+ b = buf[p.pos++]; h |= (b & 0x7f) << 10; if (b < 0x80) { return toNum(l, h, s); } |
|
1031 |
+ b = buf[p.pos++]; h |= (b & 0x7f) << 17; if (b < 0x80) { return toNum(l, h, s); } |
|
1032 |
+ b = buf[p.pos++]; h |= (b & 0x7f) << 24; if (b < 0x80) { return toNum(l, h, s); } |
|
1033 |
+ b = buf[p.pos++]; h |= (b & 0x01) << 31; if (b < 0x80) { return toNum(l, h, s); } |
|
1034 |
+ |
|
1035 |
+ throw new Error('Expected varint not more than 10 bytes'); |
|
1036 |
+} |
|
1037 |
+ |
|
1038 |
+function readPackedEnd(pbf) { |
|
1039 |
+ return pbf.type === Pbf.Bytes ? |
|
1040 |
+ pbf.readVarint() + pbf.pos : pbf.pos + 1; |
|
1041 |
+} |
|
1042 |
+ |
|
1043 |
+function toNum(low, high, isSigned) { |
|
1044 |
+ if (isSigned) { |
|
1045 |
+ return high * 0x100000000 + (low >>> 0); |
|
1046 |
+ } |
|
1047 |
+ |
|
1048 |
+ return ((high >>> 0) * 0x100000000) + (low >>> 0); |
|
1049 |
+} |
|
1050 |
+ |
|
1051 |
+function writeBigVarint(val, pbf) { |
|
1052 |
+ var low, high; |
|
1053 |
+ |
|
1054 |
+ if (val >= 0) { |
|
1055 |
+ low = (val % 0x100000000) | 0; |
|
1056 |
+ high = (val / 0x100000000) | 0; |
|
1057 |
+ } else { |
|
1058 |
+ low = ~(-val % 0x100000000); |
|
1059 |
+ high = ~(-val / 0x100000000); |
|
1060 |
+ |
|
1061 |
+ if (low ^ 0xffffffff) { |
|
1062 |
+ low = (low + 1) | 0; |
|
1063 |
+ } else { |
|
1064 |
+ low = 0; |
|
1065 |
+ high = (high + 1) | 0; |
|
1066 |
+ } |
|
1067 |
+ } |
|
1068 |
+ |
|
1069 |
+ if (val >= 0x10000000000000000 || val < -0x10000000000000000) { |
|
1070 |
+ throw new Error('Given varint doesn\'t fit into 10 bytes'); |
|
1071 |
+ } |
|
1072 |
+ |
|
1073 |
+ pbf.realloc(10); |
|
1074 |
+ |
|
1075 |
+ writeBigVarintLow(low, high, pbf); |
|
1076 |
+ writeBigVarintHigh(high, pbf); |
|
1077 |
+} |
|
1078 |
+ |
|
1079 |
+function writeBigVarintLow(low, high, pbf) { |
|
1080 |
+ pbf.buf[pbf.pos++] = low & 0x7f | 0x80; low >>>= 7; |
|
1081 |
+ pbf.buf[pbf.pos++] = low & 0x7f | 0x80; low >>>= 7; |
|
1082 |
+ pbf.buf[pbf.pos++] = low & 0x7f | 0x80; low >>>= 7; |
|
1083 |
+ pbf.buf[pbf.pos++] = low & 0x7f | 0x80; low >>>= 7; |
|
1084 |
+ pbf.buf[pbf.pos] = low & 0x7f; |
|
1085 |
+} |
|
1086 |
+ |
|
1087 |
+function writeBigVarintHigh(high, pbf) { |
|
1088 |
+ var lsb = (high & 0x07) << 4; |
|
1089 |
+ |
|
1090 |
+ pbf.buf[pbf.pos++] |= lsb | ((high >>>= 3) ? 0x80 : 0); if (!high) { return; } |
|
1091 |
+ pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0); if (!high) { return; } |
|
1092 |
+ pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0); if (!high) { return; } |
|
1093 |
+ pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0); if (!high) { return; } |
|
1094 |
+ pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0); if (!high) { return; } |
|
1095 |
+ pbf.buf[pbf.pos++] = high & 0x7f; |
|
1096 |
+} |
|
1097 |
+ |
|
1098 |
+function makeRoomForExtraLength(startPos, len, pbf) { |
|
1099 |
+ var extraLen = |
|
1100 |
+ len <= 0x3fff ? 1 : |
|
1101 |
+ len <= 0x1fffff ? 2 : |
|
1102 |
+ len <= 0xfffffff ? 3 : Math.ceil(Math.log(len) / (Math.LN2 * 7)); |
|
1103 |
+ |
|
1104 |
+ // if 1 byte isn't enough for encoding message length, shift the data to the right |
|
1105 |
+ pbf.realloc(extraLen); |
|
1106 |
+ for (var i = pbf.pos - 1; i >= startPos; i--) { pbf.buf[i + extraLen] = pbf.buf[i]; } |
|
1107 |
+} |
|
1108 |
+ |
|
1109 |
+function writePackedVarint(arr, pbf) { for (var i = 0; i < arr.length; i++) { pbf.writeVarint(arr[i]); } } |
|
1110 |
+function writePackedSVarint(arr, pbf) { for (var i = 0; i < arr.length; i++) { pbf.writeSVarint(arr[i]); } } |
|
1111 |
+function writePackedFloat(arr, pbf) { for (var i = 0; i < arr.length; i++) { pbf.writeFloat(arr[i]); } } |
|
1112 |
+function writePackedDouble(arr, pbf) { for (var i = 0; i < arr.length; i++) { pbf.writeDouble(arr[i]); } } |
|
1113 |
+function writePackedBoolean(arr, pbf) { for (var i = 0; i < arr.length; i++) { pbf.writeBoolean(arr[i]); } } |
|
1114 |
+function writePackedFixed32(arr, pbf) { for (var i = 0; i < arr.length; i++) { pbf.writeFixed32(arr[i]); } } |
|
1115 |
+function writePackedSFixed32(arr, pbf) { for (var i = 0; i < arr.length; i++) { pbf.writeSFixed32(arr[i]); } } |
|
1116 |
+function writePackedFixed64(arr, pbf) { for (var i = 0; i < arr.length; i++) { pbf.writeFixed64(arr[i]); } } |
|
1117 |
+function writePackedSFixed64(arr, pbf) { for (var i = 0; i < arr.length; i++) { pbf.writeSFixed64(arr[i]); } } |
|
1118 |
+ |
|
1119 |
+// Buffer code below from https://github.com/feross/buffer, MIT-licensed |
|
1120 |
+ |
|
1121 |
+function readUInt32(buf, pos) { |
|
1122 |
+ return ((buf[pos]) | |
|
1123 |
+ (buf[pos + 1] << 8) | |
|
1124 |
+ (buf[pos + 2] << 16)) + |
|
1125 |
+ (buf[pos + 3] * 0x1000000); |
|
1126 |
+} |
|
1127 |
+ |
|
1128 |
+function writeInt32(buf, val, pos) { |
|
1129 |
+ buf[pos] = val; |
|
1130 |
+ buf[pos + 1] = (val >>> 8); |
|
1131 |
+ buf[pos + 2] = (val >>> 16); |
|
1132 |
+ buf[pos + 3] = (val >>> 24); |
|
1133 |
+} |
|
1134 |
+ |
|
1135 |
+function readInt32(buf, pos) { |
|
1136 |
+ return ((buf[pos]) | |
|
1137 |
+ (buf[pos + 1] << 8) | |
|
1138 |
+ (buf[pos + 2] << 16)) + |
|
1139 |
+ (buf[pos + 3] << 24); |
|
1140 |
+} |
|
1141 |
+ |
|
1142 |
+function readUtf8(buf, pos, end) { |
|
1143 |
+ var str = ''; |
|
1144 |
+ var i = pos; |
|
1145 |
+ |
|
1146 |
+ while (i < end) { |
|
1147 |
+ var b0 = buf[i]; |
|
1148 |
+ var c = null; // codepoint |
|
1149 |
+ var bytesPerSequence = |
|
1150 |
+ b0 > 0xEF ? 4 : |
|
1151 |
+ b0 > 0xDF ? 3 : |
|
1152 |
+ b0 > 0xBF ? 2 : 1; |
|
1153 |
+ |
|
1154 |
+ if (i + bytesPerSequence > end) { break; } |
|
1155 |
+ |
|
1156 |
+ var b1, b2, b3; |
|
1157 |
+ |
|
1158 |
+ if (bytesPerSequence === 1) { |
|
1159 |
+ if (b0 < 0x80) { |
|
1160 |
+ c = b0; |
|
1161 |
+ } |
|
1162 |
+ } else if (bytesPerSequence === 2) { |
|
1163 |
+ b1 = buf[i + 1]; |
|
1164 |
+ if ((b1 & 0xC0) === 0x80) { |
|
1165 |
+ c = (b0 & 0x1F) << 0x6 | (b1 & 0x3F); |
|
1166 |
+ if (c <= 0x7F) { |
|
1167 |
+ c = null; |
|
1168 |
+ } |
|
1169 |
+ } |
|
1170 |
+ } else if (bytesPerSequence === 3) { |
|
1171 |
+ b1 = buf[i + 1]; |
|
1172 |
+ b2 = buf[i + 2]; |
|
1173 |
+ if ((b1 & 0xC0) === 0x80 && (b2 & 0xC0) === 0x80) { |
|
1174 |
+ c = (b0 & 0xF) << 0xC | (b1 & 0x3F) << 0x6 | (b2 & 0x3F); |
|
1175 |
+ if (c <= 0x7FF || (c >= 0xD800 && c <= 0xDFFF)) { |
|
1176 |
+ c = null; |
|
1177 |
+ } |
|
1178 |
+ } |
|
1179 |
+ } else if (bytesPerSequence === 4) { |
|
1180 |
+ b1 = buf[i + 1]; |
|
1181 |
+ b2 = buf[i + 2]; |
|
1182 |
+ b3 = buf[i + 3]; |
|
1183 |
+ if ((b1 & 0xC0) === 0x80 && (b2 & 0xC0) === 0x80 && (b3 & 0xC0) === 0x80) { |
|
1184 |
+ c = (b0 & 0xF) << 0x12 | (b1 & 0x3F) << 0xC | (b2 & 0x3F) << 0x6 | (b3 & 0x3F); |
|
1185 |
+ if (c <= 0xFFFF || c >= 0x110000) { |
|
1186 |
+ c = null; |
|
1187 |
+ } |
|
1188 |
+ } |
|
1189 |
+ } |
|
1190 |
+ |
|
1191 |
+ if (c === null) { |
|
1192 |
+ c = 0xFFFD; |
|
1193 |
+ bytesPerSequence = 1; |
|
1194 |
+ |
|
1195 |
+ } else if (c > 0xFFFF) { |
|
1196 |
+ c -= 0x10000; |
|
1197 |
+ str += String.fromCharCode(c >>> 10 & 0x3FF | 0xD800); |
|
1198 |
+ c = 0xDC00 | c & 0x3FF; |
|
1199 |
+ } |
|
1200 |
+ |
|
1201 |
+ str += String.fromCharCode(c); |
|
1202 |
+ i += bytesPerSequence; |
|
1203 |
+ } |
|
1204 |
+ |
|
1205 |
+ return str; |
|
1206 |
+} |
|
1207 |
+ |
|
1208 |
+function writeUtf8(buf, str, pos) { |
|
1209 |
+ for (var i = 0, c, lead; i < str.length; i++) { |
|
1210 |
+ c = str.charCodeAt(i); // code point |
|
1211 |
+ |
|
1212 |
+ if (c > 0xD7FF && c < 0xE000) { |
|
1213 |
+ if (lead) { |
|
1214 |
+ if (c < 0xDC00) { |
|
1215 |
+ buf[pos++] = 0xEF; |
|
1216 |
+ buf[pos++] = 0xBF; |
|
1217 |
+ buf[pos++] = 0xBD; |
|
1218 |
+ lead = c; |
|
1219 |
+ continue; |
|
1220 |
+ } else { |
|
1221 |
+ c = lead - 0xD800 << 10 | c - 0xDC00 | 0x10000; |
|
1222 |
+ lead = null; |
|
1223 |
+ } |
|
1224 |
+ } else { |
|
1225 |
+ if (c > 0xDBFF || (i + 1 === str.length)) { |
|
1226 |
+ buf[pos++] = 0xEF; |
|
1227 |
+ buf[pos++] = 0xBF; |
|
1228 |
+ buf[pos++] = 0xBD; |
|
1229 |
+ } else { |
|
1230 |
+ lead = c; |
|
1231 |
+ } |
|
1232 |
+ continue; |
|
1233 |
+ } |
|
1234 |
+ } else if (lead) { |
|
1235 |
+ buf[pos++] = 0xEF; |
|
1236 |
+ buf[pos++] = 0xBF; |
|
1237 |
+ buf[pos++] = 0xBD; |
|
1238 |
+ lead = null; |
|
1239 |
+ } |
|
1240 |
+ |
|
1241 |
+ if (c < 0x80) { |
|
1242 |
+ buf[pos++] = c; |
|
1243 |
+ } else { |
|
1244 |
+ if (c < 0x800) { |
|
1245 |
+ buf[pos++] = c >> 0x6 | 0xC0; |
|
1246 |
+ } else { |
|
1247 |
+ if (c < 0x10000) { |
|
1248 |
+ buf[pos++] = c >> 0xC | 0xE0; |
|
1249 |
+ } else { |
|
1250 |
+ buf[pos++] = c >> 0x12 | 0xF0; |
|
1251 |
+ buf[pos++] = c >> 0xC & 0x3F | 0x80; |
|
1252 |
+ } |
|
1253 |
+ buf[pos++] = c >> 0x6 & 0x3F | 0x80; |
|
1254 |
+ } |
|
1255 |
+ buf[pos++] = c & 0x3F | 0x80; |
|
1256 |
+ } |
|
1257 |
+ } |
|
1258 |
+ return pos; |
|
1259 |
+} |
|
1260 |
+ |
|
1261 |
+var index$5 = Point$1; |
|
1262 |
+ |
|
1263 |
+function Point$1(x, y) { |
|
1264 |
+ this.x = x; |
|
1265 |
+ this.y = y; |
|
1266 |
+} |
|
1267 |
+ |
|
1268 |
+Point$1.prototype = { |
|
1269 |
+ clone: function() { return new Point$1(this.x, this.y); }, |
|
1270 |
+ |
|
1271 |
+ add: function(p) { return this.clone()._add(p); }, |
|
1272 |
+ sub: function(p) { return this.clone()._sub(p); }, |
|
1273 |
+ mult: function(k) { return this.clone()._mult(k); }, |
|
1274 |
+ div: function(k) { return this.clone()._div(k); }, |
|
1275 |
+ rotate: function(a) { return this.clone()._rotate(a); }, |
|
1276 |
+ matMult: function(m) { return this.clone()._matMult(m); }, |
|
1277 |
+ unit: function() { return this.clone()._unit(); }, |
|
1278 |
+ perp: function() { return this.clone()._perp(); }, |
|
1279 |
+ round: function() { return this.clone()._round(); }, |
|
1280 |
+ |
|
1281 |
+ mag: function() { |
|
1282 |
+ return Math.sqrt(this.x * this.x + this.y * this.y); |
|
1283 |
+ }, |
|
1284 |
+ |
|
1285 |
+ equals: function(p) { |
|
1286 |
+ return this.x === p.x && |
|
1287 |
+ this.y === p.y; |
|
1288 |
+ }, |
|
1289 |
+ |
|
1290 |
+ dist: function(p) { |
|
1291 |
+ return Math.sqrt(this.distSqr(p)); |
|
1292 |
+ }, |
|
1293 |
+ |
|
1294 |
+ distSqr: function(p) { |
|
1295 |
+ var dx = p.x - this.x, |
|
1296 |
+ dy = p.y - this.y; |
|
1297 |
+ return dx * dx + dy * dy; |
|
1298 |
+ }, |
|
1299 |
+ |
|
1300 |
+ angle: function() { |
|
1301 |
+ return Math.atan2(this.y, this.x); |
|
1302 |
+ }, |
|
1303 |
+ |
|
1304 |
+ angleTo: function(b) { |
|
1305 |
+ return Math.atan2(this.y - b.y, this.x - b.x); |
|
1306 |
+ }, |
|
1307 |
+ |
|
1308 |
+ angleWith: function(b) { |
|
1309 |
+ return this.angleWithSep(b.x, b.y); |
|
1310 |
+ }, |
|
1311 |
+ |
|
1312 |
+ // Find the angle of the two vectors, solving the formula for the cross product a x b = |a||b|sin(θ) for θ. |
|
1313 |
+ angleWithSep: function(x, y) { |
|
1314 |
+ return Math.atan2( |
|
1315 |
+ this.x * y - this.y * x, |
|
1316 |
+ this.x * x + this.y * y); |
|
1317 |
+ }, |
|
1318 |
+ |
|
1319 |
+ _matMult: function(m) { |
|
1320 |
+ var x = m[0] * this.x + m[1] * this.y, |
|
1321 |
+ y = m[2] * this.x + m[3] * this.y; |
|
1322 |
+ this.x = x; |
|
1323 |
+ this.y = y; |
|
1324 |
+ return this; |
|
1325 |
+ }, |
|
1326 |
+ |
|
1327 |
+ _add: function(p) { |
|
1328 |
+ this.x += p.x; |
|
1329 |
+ this.y += p.y; |
|
1330 |
+ return this; |
|
1331 |
+ }, |
|
1332 |
+ |
|
1333 |
+ _sub: function(p) { |
|
1334 |
+ this.x -= p.x; |
|
1335 |
+ this.y -= p.y; |
|
1336 |
+ return this; |
|
1337 |
+ }, |
|
1338 |
+ |
|
1339 |
+ _mult: function(k) { |
|
1340 |
+ this.x *= k; |
|
1341 |
+ this.y *= k; |
|
1342 |
+ return this; |
|
1343 |
+ }, |
|
1344 |
+ |
|
1345 |
+ _div: function(k) { |
|
1346 |
+ this.x /= k; |
|
1347 |
+ this.y /= k; |
|
1348 |
+ return this; |
|
1349 |
+ }, |
|
1350 |
+ |
|
1351 |
+ _unit: function() { |
|
1352 |
+ this._div(this.mag()); |
|
1353 |
+ return this; |
|
1354 |
+ }, |
|
1355 |
+ |
|
1356 |
+ _perp: function() { |
|
1357 |
+ var y = this.y; |
|
1358 |
+ this.y = this.x; |
|
1359 |
+ this.x = -y; |
|
1360 |
+ return this; |
|
1361 |
+ }, |
|
1362 |
+ |
|
1363 |
+ _rotate: function(angle) { |
|
1364 |
+ var cos = Math.cos(angle), |
|
1365 |
+ sin = Math.sin(angle), |
|
1366 |
+ x = cos * this.x - sin * this.y, |
|
1367 |
+ y = sin * this.x + cos * this.y; |
|
1368 |
+ this.x = x; |
|
1369 |
+ this.y = y; |
|
1370 |
+ return this; |
|
1371 |
+ }, |
|
1372 |
+ |
|
1373 |
+ _round: function() { |
|
1374 |
+ this.x = Math.round(this.x); |
|
1375 |
+ this.y = Math.round(this.y); |
|
1376 |
+ return this; |
|
1377 |
+ } |
|
1378 |
+}; |
|
1379 |
+ |
|
1380 |
+// constructs Point from an array if necessary |
|
1381 |
+Point$1.convert = function (a) { |
|
1382 |
+ if (a instanceof Point$1) { |
|
1383 |
+ return a; |
|
1384 |
+ } |
|
1385 |
+ if (Array.isArray(a)) { |
|
1386 |
+ return new Point$1(a[0], a[1]); |
|
1387 |
+ } |
|
1388 |
+ return a; |
|
1389 |
+}; |
|
1390 |
+ |
|
1391 |
+var Point = index$5; |
|
1392 |
+ |
|
1393 |
+var vectortilefeature = VectorTileFeature$2; |
|
1394 |
+ |
|
1395 |
+function VectorTileFeature$2(pbf, end, extent, keys, values) { |
|
1396 |
+ // Public |
|
1397 |
+ this.properties = {}; |
|
1398 |
+ this.extent = extent; |
|
1399 |
+ this.type = 0; |
|
1400 |
+ |
|
1401 |
+ // Private |
|
1402 |
+ this._pbf = pbf; |
|
1403 |
+ this._geometry = -1; |
|
1404 |
+ this._keys = keys; |
|
1405 |
+ this._values = values; |
|
1406 |
+ |
|
1407 |
+ pbf.readFields(readFeature, this, end); |
|
1408 |
+} |
|
1409 |
+ |
|
1410 |
+function readFeature(tag, feature, pbf) { |
|
1411 |
+ if (tag == 1) { feature.id = pbf.readVarint(); } |
|
1412 |
+ else if (tag == 2) { readTag(pbf, feature); } |
|
1413 |
+ else if (tag == 3) { feature.type = pbf.readVarint(); } |
|
1414 |
+ else if (tag == 4) { feature._geometry = pbf.pos; } |
|
1415 |
+} |
|
1416 |
+ |
|
1417 |
+function readTag(pbf, feature) { |
|
1418 |
+ var end = pbf.readVarint() + pbf.pos; |
|
1419 |
+ |
|
1420 |
+ while (pbf.pos < end) { |
|
1421 |
+ var key = feature._keys[pbf.readVarint()], |
|
1422 |
+ value = feature._values[pbf.readVarint()]; |
|
1423 |
+ feature.properties[key] = value; |
|
1424 |
+ } |
|
1425 |
+} |
|
1426 |
+ |
|
1427 |
+VectorTileFeature$2.types = ['Unknown', 'Point', 'LineString', 'Polygon']; |
|
1428 |
+ |
|
1429 |
+VectorTileFeature$2.prototype.loadGeometry = function() { |
|
1430 |
+ var pbf = this._pbf; |
|
1431 |
+ pbf.pos = this._geometry; |
|
1432 |
+ |
|
1433 |
+ var end = pbf.readVarint() + pbf.pos, |
|
1434 |
+ cmd = 1, |
|
1435 |
+ length = 0, |
|
1436 |
+ x = 0, |
|
1437 |
+ y = 0, |
|
1438 |
+ lines = [], |
|
1439 |
+ line; |
|
1440 |
+ |
|
1441 |
+ while (pbf.pos < end) { |
|
1442 |
+ if (!length) { |
|
1443 |
+ var cmdLen = pbf.readVarint(); |
|
1444 |
+ cmd = cmdLen & 0x7; |
|
1445 |
+ length = cmdLen >> 3; |
|
1446 |
+ } |
|
1447 |
+ |
|
1448 |
+ length--; |
|
1449 |
+ |
|
1450 |
+ if (cmd === 1 || cmd === 2) { |
|
1451 |
+ x += pbf.readSVarint(); |
|
1452 |
+ y += pbf.readSVarint(); |
|
1453 |
+ |
|
1454 |
+ if (cmd === 1) { // moveTo |
|
1455 |
+ if (line) { lines.push(line); } |
|
1456 |
+ line = []; |
|
1457 |
+ } |
|
1458 |
+ |
|
1459 |
+ line.push(new Point(x, y)); |
|
1460 |
+ |
|
1461 |
+ } else if (cmd === 7) { |
|
1462 |
+ |
|
1463 |
+ // Workaround for https://github.com/mapbox/mapnik-vector-tile/issues/90 |
|
1464 |
+ if (line) { |
|
1465 |
+ line.push(line[0].clone()); // closePolygon |
|
1466 |
+ } |
|
1467 |
+ |
|
1468 |
+ } else { |
|
1469 |
+ throw new Error('unknown command ' + cmd); |
|
1470 |
+ } |
|
1471 |
+ } |
|
1472 |
+ |
|
1473 |
+ if (line) { lines.push(line); } |
|
1474 |
+ |
|
1475 |
+ return lines; |
|
1476 |
+}; |
|
1477 |
+ |
|
1478 |
+VectorTileFeature$2.prototype.bbox = function() { |
|
1479 |
+ var pbf = this._pbf; |
|
1480 |
+ pbf.pos = this._geometry; |
|
1481 |
+ |
|
1482 |
+ var end = pbf.readVarint() + pbf.pos, |
|
1483 |
+ cmd = 1, |
|
1484 |
+ length = 0, |
|
1485 |
+ x = 0, |
|
1486 |
+ y = 0, |
|
1487 |
+ x1 = Infinity, |
|
1488 |
+ x2 = -Infinity, |
|
1489 |
+ y1 = Infinity, |
|
1490 |
+ y2 = -Infinity; |
|
1491 |
+ |
|
1492 |
+ while (pbf.pos < end) { |
|
1493 |
+ if (!length) { |
|
1494 |
+ var cmdLen = pbf.readVarint(); |
|
1495 |
+ cmd = cmdLen & 0x7; |
|
1496 |
+ length = cmdLen >> 3; |
|
1497 |
+ } |
|
1498 |
+ |
|
1499 |
+ length--; |
|
1500 |
+ |
|
1501 |
+ if (cmd === 1 || cmd === 2) { |
|
1502 |
+ x += pbf.readSVarint(); |
|
1503 |
+ y += pbf.readSVarint(); |
|
1504 |
+ if (x < x1) { x1 = x; } |
|
1505 |
+ if (x > x2) { x2 = x; } |
|
1506 |
+ if (y < y1) { y1 = y; } |
|
1507 |
+ if (y > y2) { y2 = y; } |
|
1508 |
+ |
|
1509 |
+ } else if (cmd !== 7) { |
|
1510 |
+ throw new Error('unknown command ' + cmd); |
|
1511 |
+ } |
|
1512 |
+ } |
|
1513 |
+ |
|
1514 |
+ return [x1, y1, x2, y2]; |
|
1515 |
+}; |
|
1516 |
+ |
|
1517 |
+VectorTileFeature$2.prototype.toGeoJSON = function(x, y, z) { |
|
1518 |
+ var size = this.extent * Math.pow(2, z), |
|
1519 |
+ x0 = this.extent * x, |
|
1520 |
+ y0 = this.extent * y, |
|
1521 |
+ coords = this.loadGeometry(), |
|
1522 |
+ type = VectorTileFeature$2.types[this.type], |
|
1523 |
+ i, j; |
|
1524 |
+ |
|
1525 |
+ function project(line) { |
|
1526 |
+ for (var j = 0; j < line.length; j++) { |
|
1527 |
+ var p = line[j], y2 = 180 - (p.y + y0) * 360 / size; |
|
1528 |
+ line[j] = [ |
|
1529 |
+ (p.x + x0) * 360 / size - 180, |
|
1530 |
+ 360 / Math.PI * Math.atan(Math.exp(y2 * Math.PI / 180)) - 90 |
|
1531 |
+ ]; |
|
1532 |
+ } |
|
1533 |
+ } |
|
1534 |
+ |
|
1535 |
+ switch (this.type) { |
|
1536 |
+ case 1: |
|
1537 |
+ var points = []; |
|
1538 |
+ for (i = 0; i < coords.length; i++) { |
|
1539 |
+ points[i] = coords[i][0]; |
|
1540 |
+ } |
|
1541 |
+ coords = points; |
|
1542 |
+ project(coords); |
|
1543 |
+ break; |
|
1544 |
+ |
|
1545 |
+ case 2: |
|
1546 |
+ for (i = 0; i < coords.length; i++) { |
|
1547 |
+ project(coords[i]); |
|
1548 |
+ } |
|
1549 |
+ break; |
|
1550 |
+ |
|
1551 |
+ case 3: |
|
1552 |
+ coords = classifyRings(coords); |
|
1553 |
+ for (i = 0; i < coords.length; i++) { |
|
1554 |
+ for (j = 0; j < coords[i].length; j++) { |
|
1555 |
+ project(coords[i][j]); |
|
1556 |
+ } |
|
1557 |
+ } |
|
1558 |
+ break; |
|
1559 |
+ } |
|
1560 |
+ |
|
1561 |
+ if (coords.length === 1) { |
|
1562 |
+ coords = coords[0]; |
|
1563 |
+ } else { |
|
1564 |
+ type = 'Multi' + type; |
|
1565 |
+ } |
|
1566 |
+ |
|
1567 |
+ var result = { |
|
1568 |
+ type: "Feature", |
|
1569 |
+ geometry: { |
|
1570 |
+ type: type, |
|
1571 |
+ coordinates: coords |
|
1572 |
+ }, |
|
1573 |
+ properties: this.properties |
|
1574 |
+ }; |
|
1575 |
+ |
|
1576 |
+ if ('id' in this) { |
|
1577 |
+ result.id = this.id; |
|
1578 |
+ } |
|
1579 |
+ |
|
1580 |
+ return result; |
|
1581 |
+}; |
|
1582 |
+ |
|
1583 |
+// classifies an array of rings into polygons with outer rings and holes |
|
1584 |
+ |
|
1585 |
+function classifyRings(rings) { |
|
1586 |
+ var len = rings.length; |
|
1587 |
+ |
|
1588 |
+ if (len <= 1) { return [rings]; } |
|
1589 |
+ |
|
1590 |
+ var polygons = [], |
|
1591 |
+ polygon, |
|
1592 |
+ ccw; |
|
1593 |
+ |
|
1594 |
+ for (var i = 0; i < len; i++) { |
|
1595 |
+ var area = signedArea(rings[i]); |
|
1596 |
+ if (area === 0) { continue; } |
|
1597 |
+ |
|
1598 |
+ if (ccw === undefined) { ccw = area < 0; } |
|
1599 |
+ |
|
1600 |
+ if (ccw === area < 0) { |
|
1601 |
+ if (polygon) { polygons.push(polygon); } |
|
1602 |
+ polygon = [rings[i]]; |
|
1603 |
+ |
|
1604 |
+ } else { |
|
1605 |
+ polygon.push(rings[i]); |
|
1606 |
+ } |
|
1607 |
+ } |
|
1608 |
+ if (polygon) { polygons.push(polygon); } |
|
1609 |
+ |
|
1610 |
+ return polygons; |
|
1611 |
+} |
|
1612 |
+ |
|
1613 |
+function signedArea(ring) { |
|
1614 |
+ var sum = 0; |
|
1615 |
+ for (var i = 0, len = ring.length, j = len - 1, p1, p2; i < len; j = i++) { |
|
1616 |
+ p1 = ring[i]; |
|
1617 |
+ p2 = ring[j]; |
|
1618 |
+ sum += (p2.x - p1.x) * (p1.y + p2.y); |
|
1619 |
+ } |
|
1620 |
+ return sum; |
|
1621 |
+} |
|
1622 |
+ |
|
1623 |
+var VectorTileFeature$1 = vectortilefeature; |
|
1624 |
+ |
|
1625 |
+var vectortilelayer = VectorTileLayer$2; |
|
1626 |
+ |
|
1627 |
+function VectorTileLayer$2(pbf, end) { |
|
1628 |
+ // Public |
|
1629 |
+ this.version = 1; |
|
1630 |
+ this.name = null; |
|
1631 |
+ this.extent = 4096; |
|
1632 |
+ this.length = 0; |
|
1633 |
+ |
|
1634 |
+ // Private |
|
1635 |
+ this._pbf = pbf; |
|
1636 |
+ this._keys = []; |
|
1637 |
+ this._values = []; |
|
1638 |
+ this._features = []; |
|
1639 |
+ |
|
1640 |
+ pbf.readFields(readLayer, this, end); |
|
1641 |
+ |
|
1642 |
+ this.length = this._features.length; |
|
1643 |
+} |
|
1644 |
+ |
|
1645 |
+function readLayer(tag, layer, pbf) { |
|
1646 |
+ if (tag === 15) { layer.version = pbf.readVarint(); } |
|
1647 |
+ else if (tag === 1) { layer.name = pbf.readString(); } |
|
1648 |
+ else if (tag === 5) { layer.extent = pbf.readVarint(); } |
|
1649 |
+ else if (tag === 2) { layer._features.push(pbf.pos); } |
|
1650 |
+ else if (tag === 3) { layer._keys.push(pbf.readString()); } |
|
1651 |
+ else if (tag === 4) { layer._values.push(readValueMessage(pbf)); } |
|
1652 |
+} |
|
1653 |
+ |
|
1654 |
+function readValueMessage(pbf) { |
|
1655 |
+ var value = null, |
|
1656 |
+ end = pbf.readVarint() + pbf.pos; |
|
1657 |
+ |
|
1658 |
+ while (pbf.pos < end) { |
|
1659 |
+ var tag = pbf.readVarint() >> 3; |
|
1660 |
+ |
|
1661 |
+ value = tag === 1 ? pbf.readString() : |
|
1662 |
+ tag === 2 ? pbf.readFloat() : |
|
1663 |
+ tag === 3 ? pbf.readDouble() : |
|
1664 |
+ tag === 4 ? pbf.readVarint64() : |
|
1665 |
+ tag === 5 ? pbf.readVarint() : |
|
1666 |
+ tag === 6 ? pbf.readSVarint() : |
|
1667 |
+ tag === 7 ? pbf.readBoolean() : null; |
|
1668 |
+ } |
|
1669 |
+ |
|
1670 |
+ return value; |
|
1671 |
+} |
|
1672 |
+ |
|
1673 |
+// return feature `i` from this layer as a `VectorTileFeature` |
|
1674 |
+VectorTileLayer$2.prototype.feature = function(i) { |
|
1675 |
+ if (i < 0 || i >= this._features.length) { throw new Error('feature index out of bounds'); } |
|
1676 |
+ |
|
1677 |
+ this._pbf.pos = this._features[i]; |
|
1678 |
+ |
|
1679 |
+ var end = this._pbf.readVarint() + this._pbf.pos; |
|
1680 |
+ return new VectorTileFeature$1(this._pbf, end, this.extent, this._keys, this._values); |
|
1681 |
+}; |
|
1682 |
+ |
|
1683 |
+var VectorTileLayer$1 = vectortilelayer; |
|
1684 |
+ |
|
1685 |
+var vectortile = VectorTile$1; |
|
1686 |
+ |
|
1687 |
+function VectorTile$1(pbf, end) { |
|
1688 |
+ this.layers = pbf.readFields(readTile, {}, end); |
|
1689 |
+} |
|
1690 |
+ |
|
1691 |
+function readTile(tag, layers, pbf) { |
|
1692 |
+ if (tag === 3) { |
|
1693 |
+ var layer = new VectorTileLayer$1(pbf, pbf.readVarint() + pbf.pos); |
|
1694 |
+ if (layer.length) { layers[layer.name] = layer; } |
|
1695 |
+ } |
|
1696 |
+} |
|
1697 |
+ |
|
1698 |
+var VectorTile = vectortile; |
|
1699 |
+ |
|
1700 |
+/* |
|
1701 |
+ * 🍂class VectorGrid.Protobuf |
|
1702 |
+ * 🍂extends VectorGrid |
|
1703 |
+ * |
|
1704 |
+ * A `VectorGrid` for vector tiles fetched from the internet. |
|
1705 |
+ * Tiles are supposed to be protobufs (AKA "protobuffer" or "Protocol Buffers"), |
|
1706 |
+ * containing data which complies with the |
|
1707 |
+ * [MapBox Vector Tile Specification](https://github.com/mapbox/vector-tile-spec/tree/master/2.1). |
|
1708 |
+ * |
|
1709 |
+ * This is the format used by: |
|
1710 |
+ * - Mapbox Vector Tiles |
|
1711 |
+ * - Mapzen Vector Tiles |
|
1712 |
+ * - ESRI Vector Tiles |
|
1713 |
+ * - [OpenMapTiles hosted Vector Tiles](https://openmaptiles.com/hosting/) |
|
1714 |
+ * |
|
1715 |
+ * 🍂example |
|
1716 |
+ * |
|
1717 |
+ * You must initialize a `VectorGrid.Protobuf` with a URL template, just like in |
|
1718 |
+ * `L.TileLayer`s. The difference is that the template must point to vector tiles |
|
1719 |
+ * (usually `.pbf` or `.mvt`) instead of raster (`.png` or `.jpg`) tiles, and that |
|
1720 |
+ * you should define the styling for all the features. |
|
1721 |
+ * |
|
1722 |
+ * <br><br> |
|
1723 |
+ * |
|
1724 |
+ * For OpenMapTiles, with a key from [https://openmaptiles.org/docs/host/use-cdn/](https://openmaptiles.org/docs/host/use-cdn/), |
|
1725 |
+ * initialization looks like this: |
|
1726 |
+ * |
|
1727 |
+ * ``` |
|
1728 |
+ * L.vectorGrid.protobuf("https://free-{s}.tilehosting.com/data/v3/{z}/{x}/{y}.pbf.pict?key={key}", { |
|
1729 |
+ * vectorTileLayerStyles: { ... }, |
|
1730 |
+ * subdomains: "0123", |
|
1731 |
+ * key: 'abcdefghi01234567890', |
|
1732 |
+ * maxNativeZoom: 14 |
|
1733 |
+ * }).addTo(map); |
|
1734 |
+ * ``` |
|
1735 |
+ * |
|
1736 |
+ * And for Mapbox vector tiles, it looks like this: |
|
1737 |
+ * |
|
1738 |
+ * ``` |
|
1739 |
+ * L.vectorGrid.protobuf("https://{s}.tiles.mapbox.com/v4/mapbox.mapbox-streets-v6/{z}/{x}/{y}.vector.pbf?access_token={token}", { |
|
1740 |
+ * vectorTileLayerStyles: { ... }, |
|
1741 |
+ * subdomains: "abcd", |
|
1742 |
+ * token: "pk.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRTS.TUVWXTZ0123456789abcde" |
|
1743 |
+ * }).addTo(map); |
|
1744 |
+ * ``` |
|
1745 |
+ */ |
|
1746 |
+L.VectorGrid.Protobuf = L.VectorGrid.extend({ |
|
1747 |
+ |
|
1748 |
+ options: { |
|
1749 |
+ // 🍂section |
|
1750 |
+ // As with `L.TileLayer`, the URL template might contain a reference to |
|
1751 |
+ // any option (see the example above and note the `{key}` or `token` in the URL |
|
1752 |
+ // template, and the corresponding option). |
|
1753 |
+ // |
|
1754 |
+ // 🍂option subdomains: String = 'abc' |
|
1755 |
+ // Akin to the `subdomains` option for `L.TileLayer`. |
|
1756 |
+ subdomains: 'abc', // Like L.TileLayer |
|
1757 |
+ // |
|
1758 |
+ // 🍂option fetchOptions: Object = {} |
|
1759 |
+ // options passed to `fetch`, e.g. {credentials: 'same-origin'} to send cookie for the current domain |
|
1760 |
+ fetchOptions: {} |
|
1761 |
+ }, |
|
1762 |
+ |
|
1763 |
+ initialize: function(url, options) { |
|
1764 |
+ // Inherits options from geojson-vt! |
|
1765 |
+// this._slicer = geojsonvt(geojson, options); |
|
1766 |
+ this._url = url; |
|
1767 |
+ L.VectorGrid.prototype.initialize.call(this, options); |
|
1768 |
+ }, |
|
1769 |
+ |
|
1770 |
+ // 🍂method setUrl(url: String, noRedraw?: Boolean): this |
|
1771 |
+ // Updates the layer's URL template and redraws it (unless `noRedraw` is set to `true`). |
|
1772 |
+ setUrl: function(url, noRedraw) { |
|
1773 |
+ this._url = url; |
|
1774 |
+ |
|
1775 |
+ if (!noRedraw) { |
|
1776 |
+ this.redraw(); |
|
1777 |
+ } |
|
1778 |
+ |
|
1779 |
+ return this; |
|
1780 |
+ }, |
|
1781 |
+ |
|
1782 |
+ _getSubdomain: L.TileLayer.prototype._getSubdomain, |
|
1783 |
+ |
|
1784 |
+ _getVectorTilePromise: function(coords) { |
|
1785 |
+ var data = { |
|
1786 |
+ s: this._getSubdomain(coords), |
|
1787 |
+ x: coords.x, |
|
1788 |
+ y: coords.y, |
|
1789 |
+ z: coords.z |
|
1790 |
+// z: this._getZoomForUrl() /// TODO: Maybe replicate TileLayer's maxNativeZoom |
|
1791 |
+ }; |
|
1792 |
+ if (this._map && !this._map.options.crs.infinite) { |
|
1793 |
+ var invertedY = this._globalTileRange.max.y - coords.y; |
|
1794 |
+ if (this.options.tms) { // Should this option be available in Leaflet.VectorGrid? |
|
1795 |
+ data['y'] = invertedY; |
|
1796 |
+ } |
|
1797 |
+ data['-y'] = invertedY; |
|
1798 |
+ } |
|
1799 |
+ |
|
1800 |
+ var tileUrl = L.Util.template(this._url, L.extend(data, this.options)); |
|
1801 |
+ |
|
1802 |
+ return fetch(tileUrl, this.options.fetchOptions).then(function(response){ |
|
1803 |
+ |
|
1804 |
+ if (!response.ok) { |
|
1805 |
+ return {layers:[]}; |
|
1806 |
+ } |
|
1807 |
+ |
|
1808 |
+ return response.blob().then( function (blob) { |
|
1809 |
+// console.log(blob); |
|
1810 |
+ |
|
1811 |
+ var reader = new FileReader(); |
|
1812 |
+ return new Promise(function(resolve){ |
|
1813 |
+ reader.addEventListener("loadend", function() { |
|
1814 |
+ // reader.result contains the contents of blob as a typed array |
|
1815 |
+ |
|
1816 |
+ // blob.type === 'application/x-protobuf' |
|
1817 |
+ var pbf = new index( reader.result ); |
|
1818 |
+// console.log(pbf); |
|
1819 |
+ return resolve(new VectorTile( pbf )); |
|
1820 |
+ |
|
1821 |
+ }); |
|
1822 |
+ reader.readAsArrayBuffer(blob); |
|
1823 |
+ }); |
|
1824 |
+ }); |
|
1825 |
+ }).then(function(json){ |
|
1826 |
+ |
|
1827 |
+// console.log('Vector tile:', json.layers); |
|
1828 |
+// console.log('Vector tile water:', json.layers.water); // Instance of VectorTileLayer |
|
1829 |
+ |
|
1830 |
+ // Normalize feature getters into actual instanced features |
|
1831 |
+ for (var layerName in json.layers) { |
|
1832 |
+ var feats = []; |
|
1833 |
+ |
|
1834 |
+ for (var i=0; i<json.layers[layerName].length; i++) { |
|
1835 |
+ var feat = json.layers[layerName].feature(i); |
|
1836 |
+ feat.geometry = feat.loadGeometry(); |
|
1837 |
+ feats.push(feat); |
|
1838 |
+ } |
|
1839 |
+ |
|
1840 |
+ json.layers[layerName].features = feats; |
|
1841 |
+ } |
|
1842 |
+ |
|
1843 |
+ return json; |
|
1844 |
+ }); |
|
1845 |
+ } |
|
1846 |
+}); |
|
1847 |
+ |
|
1848 |
+ |
|
1849 |
+// 🍂factory L.vectorGrid.protobuf(url: String, options) |
|
1850 |
+// Instantiates a new protobuf VectorGrid with the given URL template and options |
|
1851 |
+L.vectorGrid.protobuf = function (url, options) { |
|
1852 |
+ return new L.VectorGrid.Protobuf(url, options); |
|
1853 |
+}; |
|
1854 |
+ |
|
1855 |
+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); |
|
1856 |
+ |
|
1857 |
+// The geojson/topojson is sliced into tiles via a web worker. |
|
1858 |
+// This import statement depends on rollup-file-as-blob, so that the |
|
1859 |
+// variable 'workerCode' is a blob URL. |
|
1860 |
+ |
|
1861 |
+/* |
|
1862 |
+ * 🍂class VectorGrid.Slicer |
|
1863 |
+ * 🍂extends VectorGrid |
|
1864 |
+ * |
|
1865 |
+ * A `VectorGrid` for slicing up big GeoJSON or TopoJSON documents in vector |
|
1866 |
+ * tiles, leveraging [`geojson-vt`](https://github.com/mapbox/geojson-vt). |
|
1867 |
+ * |
|
1868 |
+ * 🍂example |
|
1869 |
+ * |
|
1870 |
+ * ``` |
|
1871 |
+ * var geoJsonDocument = { |
|
1872 |
+ * type: 'FeatureCollection', |
|
1873 |
+ * features: [ ... ] |
|
1874 |
+ * }; |
|
1875 |
+ * |
|
1876 |
+ * L.vectorGrid.slicer(geoJsonDocument, { |
|
1877 |
+ * vectorTileLayerStyles: { |
|
1878 |
+ * sliced: { ... } |
|
1879 |
+ * } |
|
1880 |
+ * }).addTo(map); |
|
1881 |
+ * |
|
1882 |
+ * ``` |
|
1883 |
+ * |
|
1884 |
+ * `VectorGrid.Slicer` can also handle [TopoJSON](https://github.com/mbostock/topojson) transparently: |
|
1885 |
+ * ```js |
|
1886 |
+ * var layer = L.vectorGrid.slicer(topojson, options); |
|
1887 |
+ * ``` |
|
1888 |
+ * |
|
1889 |
+ * The TopoJSON format [implicitly groups features into "objects"](https://github.com/mbostock/topojson-specification/blob/master/README.md#215-objects). |
|
1890 |
+ * These will be transformed into vector tile layer names when styling (the |
|
1891 |
+ * `vectorTileLayerName` option is ignored when using TopoJSON). |
|
1892 |
+ * |
|
1893 |
+ */ |
|
1894 |
+ |
|
1895 |
+L.VectorGrid.Slicer = L.VectorGrid.extend({ |
|
1896 |
+ |
|
1897 |
+ options: { |
|
1898 |
+ // 🍂section |
|
1899 |
+ // Additionally to these options, `VectorGrid.Slicer` can take in any |
|
1900 |
+ // of the [`geojson-vt` options](https://github.com/mapbox/geojson-vt#options). |
|
1901 |
+ |
|
1902 |
+ // 🍂option vectorTileLayerName: String = 'sliced' |
|
1903 |
+ // Vector tiles contain a set of *data layers*, and those data layers |
|
1904 |
+ // contain features. Thus, the slicer creates one data layer, with |
|
1905 |
+ // the name given in this option. This is important for symbolizing the data. |
|
1906 |
+ vectorTileLayerName: 'sliced', |
|
1907 |
+ |
|
1908 |
+ extent: 4096, // Default for geojson-vt |
|
1909 |
+ maxZoom: 14 // Default for geojson-vt |
|
1910 |
+ }, |
|
1911 |
+ |
|
1912 |
+ initialize: function(geojson, options) { |
|
1913 |
+ L.VectorGrid.prototype.initialize.call(this, options); |
|
1914 |
+ |
|
1915 |
+ // Create a shallow copy of this.options, excluding things that might |
|
1916 |
+ // be functions - we only care about topojson/geojsonvt options |
|
1917 |
+ var options = {}; |
|
1918 |
+ for (var i in this.options) { |
|
1919 |
+ if (i !== 'rendererFactory' && |
|
1920 |
+ i !== 'vectorTileLayerStyles' && |
|
1921 |
+ typeof (this.options[i]) !== 'function' |
|
1922 |
+ ) { |
|
1923 |
+ options[i] = this.options[i]; |
|
1924 |
+ } |
|
1925 |
+ } |
|
1926 |
+ |
|
1927 |
+// this._worker = new Worker(window.URL.createObjectURL(new Blob([workerCode]))); |
|
1928 |
+ this._worker = new Worker(workerCode); |
|
1929 |
+ |
|
1930 |
+ // Send initial data to worker. |
|
1931 |
+ this._worker.postMessage(['slice', geojson, options]); |
|
1932 |
+ |
|
1933 |
+ }, |
|
1934 |
+ |
|
1935 |
+ |
|
1936 |
+ _getVectorTilePromise: function(coords) { |
|
1937 |
+ |
|
1938 |
+ var _this = this; |
|
1939 |
+ |
|
1940 |
+ var p = new Promise( function waitForWorker(res) { |
|
1941 |
+ _this._worker.addEventListener('message', function recv(m) { |
|
1942 |
+ if (m.data.coords && |
|
1943 |
+ m.data.coords.x === coords.x && |
|
1944 |
+ m.data.coords.y === coords.y && |
|
1945 |
+ m.data.coords.z === coords.z ) { |
|
1946 |
+ |
|
1947 |
+ res(m.data); |
|
1948 |
+ _this._worker.removeEventListener('message', recv); |
|
1949 |
+ } |
|
1950 |
+ }); |
|
1951 |
+ }); |
|
1952 |
+ |
|
1953 |
+ this._worker.postMessage(['get', coords]); |
|
1954 |
+ |
|
1955 |
+ return p; |
|
1956 |
+ }, |
|
1957 |
+ |
|
1958 |
+}); |
|
1959 |
+ |
|
1960 |
+ |
|
1961 |
+L.vectorGrid.slicer = function (geojson, options) { |
|
1962 |
+ return new L.VectorGrid.Slicer(geojson, options); |
|
1963 |
+}; |
|
1964 |
+ |
|
1965 |
+L.Canvas.Tile = L.Canvas.extend({ |
|
1966 |
+ |
|
1967 |
+ initialize: function (tileCoord, tileSize, options) { |
|
1968 |
+ L.Canvas.prototype.initialize.call(this, options); |
|
1969 |
+ this._tileCoord = tileCoord; |
|
1970 |
+ this._size = tileSize; |
|
1971 |
+ |
|
1972 |
+ this._initContainer(); |
|
1973 |
+ this._container.setAttribute('width', this._size.x); |
|
1974 |
+ this._container.setAttribute('height', this._size.y); |
|
1975 |
+ this._layers = {}; |
|
1976 |
+ this._drawnLayers = {}; |
|
1977 |
+ this._drawing = true; |
|
1978 |
+ |
|
1979 |
+ if (options.interactive) { |
|
1980 |
+ // By default, Leaflet tiles do not have pointer events |
|
1981 |
+ this._container.style.pointerEvents = 'auto'; |
|
1982 |
+ } |
|
1983 |
+ }, |
|
1984 |
+ |
|
1985 |
+ getCoord: function() { |
|
1986 |
+ return this._tileCoord; |
|
1987 |
+ }, |
|
1988 |
+ |
|
1989 |
+ getContainer: function() { |
|
1990 |
+ return this._container; |
|
1991 |
+ }, |
|
1992 |
+ |
|
1993 |
+ getOffset: function() { |
|
1994 |
+ return this._tileCoord.scaleBy(this._size).subtract(this._map.getPixelOrigin()); |
|
1995 |
+ }, |
|
1996 |
+ |
|
1997 |
+ onAdd: L.Util.falseFn, |
|
1998 |
+ |
|
1999 |
+ addTo: function(map) { |
|
2000 |
+ this._map = map; |
|
2001 |
+ }, |
|
2002 |
+ |
|
2003 |
+ removeFrom: function (map) { |
|
2004 |
+ delete this._map; |
|
2005 |
+ }, |
|
2006 |
+ |
|
2007 |
+ _onClick: function (e) { |
|
2008 |
+ var point = this._map.mouseEventToLayerPoint(e).subtract(this.getOffset()), layer, clickedLayer; |
|
2009 |
+ |
|
2010 |
+ for (var id in this._layers) { |
|
2011 |
+ layer = this._layers[id]; |
|
2012 |
+ if (layer.options.interactive && layer._containsPoint(point) && !this._map._draggableMoved(layer)) { |
|
2013 |
+ clickedLayer = layer; |
|
2014 |
+ } |
|
2015 |
+ } |
|
2016 |
+ if (clickedLayer) { |
|
2017 |
+ L.DomEvent.fakeStop(e); |
|
2018 |
+ this._fireEvent([clickedLayer], e); |
|
2019 |
+ } |
|
2020 |
+ }, |
|
2021 |
+ |
|
2022 |
+ _onMouseMove: function (e) { |
|
2023 |
+ if (!this._map || this._map.dragging.moving() || this._map._animatingZoom) { return; } |
|
2024 |
+ |
|
2025 |
+ var point = this._map.mouseEventToLayerPoint(e).subtract(this.getOffset()); |
|
2026 |
+ this._handleMouseHover(e, point); |
|
2027 |
+ }, |
|
2028 |
+ |
|
2029 |
+ /// TODO: Modify _initPath to include an extra parameter, a group name |
|
2030 |
+ /// to order symbolizers by z-index |
|
2031 |
+ |
|
2032 |
+ _updateIcon: function (layer) { |
|
2033 |
+ if (!this._drawing) { return; } |
|
2034 |
+ |
|
2035 |
+ var icon = layer.options.icon, |
|
2036 |
+ options = icon.options, |
|
2037 |
+ size = L.point(options.iconSize), |
|
2038 |
+ anchor = options.iconAnchor || |
|
2039 |
+ size && size.divideBy(2, true), |
|
2040 |
+ p = layer._point.subtract(anchor), |
|
2041 |
+ ctx = this._ctx, |
|
2042 |
+ img = layer._getImage(); |
|
2043 |
+ |
|
2044 |
+ if (img.complete) { |
|
2045 |
+ ctx.drawImage(img, p.x, p.y, size.x, size.y); |
|
2046 |
+ } else { |
|
2047 |
+ L.DomEvent.on(img, 'load', function() { |
|
2048 |
+ ctx.drawImage(img, p.x, p.y, size.x, size.y); |
|
2049 |
+ }); |
|
2050 |
+ } |
|
2051 |
+ |
|
2052 |
+ this._drawnLayers[layer._leaflet_id] = layer; |
|
2053 |
+ } |
|
2054 |
+}); |
|
2055 |
+ |
|
2056 |
+ |
|
2057 |
+L.canvas.tile = function(tileCoord, tileSize, opts){ |
|
2058 |
+ return new L.Canvas.Tile(tileCoord, tileSize, opts); |
|
2059 |
+}; |
|
2060 |
+ |
|
2061 |
+// Aux file to bundle everything together |
|
2062 |
+//# sourceMappingURL=Leaflet.VectorGrid.js.map |