@hpcc-js/map 3.4.10 → 3.4.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/LICENSE +43 -43
  2. package/README.md +88 -88
  3. package/TopoJSON/BR.json +122 -122
  4. package/TopoJSON/GB_idx.json +1 -1
  5. package/TopoJSON/IE_idx.json +1 -1
  6. package/TopoJSON/ND_idx.json +1 -1
  7. package/TopoJSON/countries.json +257 -257
  8. package/TopoJSON/us-counties.json +16550 -16550
  9. package/TopoJSON/us-states.json +458 -458
  10. package/dist/index.js +1 -1
  11. package/dist/index.js.map +1 -1
  12. package/dist/index.umd.cjs +1 -1
  13. package/dist/index.umd.cjs.map +1 -1
  14. package/package.json +7 -7
  15. package/src/CanvasPinLayer.ts +99 -99
  16. package/src/CanvasPins.ts +397 -397
  17. package/src/Choropleth.css +27 -27
  18. package/src/Choropleth.ts +203 -203
  19. package/src/ChoroplethContinents.ts +13 -13
  20. package/src/ChoroplethCounties.ts +111 -111
  21. package/src/ChoroplethCountries.ts +100 -100
  22. package/src/ChoroplethStates.ts +103 -103
  23. package/src/ChoroplethStatesHeat.ts +8 -8
  24. package/src/GMap.css +16 -16
  25. package/src/GMap.ts +880 -880
  26. package/src/GMapCounties.ts +93 -93
  27. package/src/GMapGraph.ts +61 -61
  28. package/src/GMapHeat.ts +27 -27
  29. package/src/GMapLayered.ts +94 -94
  30. package/src/GMapPin.ts +115 -115
  31. package/src/GMapPinLine.ts +138 -138
  32. package/src/GeoHash.css +15 -15
  33. package/src/GeoHash.ts +139 -139
  34. package/src/Graph.css +10 -10
  35. package/src/Graph.ts +98 -98
  36. package/src/Graticule.css +13 -13
  37. package/src/Graticule.ts +97 -97
  38. package/src/Heat.css +2 -2
  39. package/src/Heat.ts +87 -87
  40. package/src/IChoropleth.ts +8 -8
  41. package/src/Layer.ts +99 -99
  42. package/src/Layered.css +19 -19
  43. package/src/Layered.ts +206 -206
  44. package/src/Lines.css +9 -9
  45. package/src/Lines.ts +78 -78
  46. package/src/OpenStreet.css +15 -15
  47. package/src/OpenStreet.ts +126 -126
  48. package/src/Pins.css +18 -18
  49. package/src/Pins.ts +350 -350
  50. package/src/Projection.ts +42 -42
  51. package/src/TestHeatMap.ts +8 -8
  52. package/src/TopoJSONChoropleth.ts +125 -125
  53. package/src/Utility.ts +484 -484
  54. package/src/__package__.ts +3 -3
  55. package/src/index.ts +33 -33
  56. package/src/leaflet/AlbersPR.ts +48 -48
  57. package/src/leaflet/Blank.ts +9 -9
  58. package/src/leaflet/Circles.ts +139 -139
  59. package/src/leaflet/ClusterCircles.css +26 -26
  60. package/src/leaflet/ClusterCircles.ts +88 -88
  61. package/src/leaflet/Countries.ts +43 -43
  62. package/src/leaflet/DrawLayer.ts +167 -167
  63. package/src/leaflet/FeatureLayer.ts +138 -138
  64. package/src/leaflet/GMap.ts +44 -44
  65. package/src/leaflet/HeatLayer.ts +77 -77
  66. package/src/leaflet/Icons.ts +60 -60
  67. package/src/leaflet/Leaflet.css +3 -3
  68. package/src/leaflet/Leaflet.ts +239 -239
  69. package/src/leaflet/MapBox.ts +35 -35
  70. package/src/leaflet/Markers.ts +109 -109
  71. package/src/leaflet/OpenStreet.ts +27 -27
  72. package/src/leaflet/Path.ts +138 -138
  73. package/src/leaflet/Pins.ts +73 -73
  74. package/src/leaflet/Polygons.ts +113 -113
  75. package/src/leaflet/Region.ts +138 -138
  76. package/src/leaflet/Text.ts +99 -99
  77. package/src/leaflet/TileLayer.ts +81 -81
  78. package/src/leaflet/TopoJSON.ts +146 -146
  79. package/src/leaflet/US.ts +15 -15
  80. package/src/leaflet/USCounties.ts +43 -43
  81. package/src/leaflet/USStates.ts +41 -41
  82. package/src/leaflet/World.css +3 -3
  83. package/src/leaflet/World.ts +172 -172
  84. package/src/leaflet/index.ts +18 -18
  85. package/src/leaflet/leaflet-shim.ts +18 -18
  86. package/src/leaflet/plugins/BeautifyIcon.css +44 -44
  87. package/src/leaflet/plugins/BeautifyIcon.ts +190 -190
  88. package/src/leaflet/plugins/BeutifyIcon.licence +20 -20
  89. package/src/leaflet/plugins/D3SvgOverlay.css +3 -3
  90. package/src/leaflet/plugins/D3SvgOverlay.licence +20 -20
  91. package/src/leaflet/plugins/D3SvgOverlay.ts +175 -175
  92. package/src/leaflet/plugins/HeatLayer.license +21 -21
  93. package/src/leaflet/plugins/HeatLayer.ts +224 -224
  94. package/src/leaflet/plugins/Leaflet.GoogleMutant.ts +424 -424
  95. package/src/leaflet/plugins/lru_map.ts +352 -352
  96. package/src/test.ts +114 -114
@@ -1,425 +1,425 @@
1
- /* eslint-disable */
2
- //@ts-nocheck
3
-
4
- // GoogleMutant by Iván Sánchez Ortega <ivan@sanchezortega.es>
5
-
6
- // Based on https://github.com/shramov/leaflet-plugins
7
- // GridLayer like https://avinmathew.com/leaflet-and-google-maps/ , but using MutationObserver instead of jQuery
8
-
9
- /*
10
- "THE BEER-WARE LICENSE":
11
- <ivan@sanchezortega.es> wrote this file. As long as you retain this notice you
12
- can do whatever you want with this stuff. If we meet some day, and you think
13
- this stuff is worth it, you can buy me a beer in return.
14
- */
15
-
16
- import { LRUMap } from "./lru_map.js";
17
-
18
- function waitForAPI(callback, context) {
19
- let checkCounter = 0,
20
- intervalId = null;
21
-
22
- intervalId = setInterval(function () {
23
- if (checkCounter >= 20) {
24
- clearInterval(intervalId);
25
- throw new Error("window.google not found after 10 seconds");
26
- }
27
- if (!!window.google && !!window.google.maps && !!window.google.maps.Map) {
28
- clearInterval(intervalId);
29
- callback.call(context);
30
- }
31
- ++checkCounter;
32
- }, 500);
33
- }
34
-
35
- // 🍂class GridLayer.GoogleMutant
36
- // 🍂extends GridLayer
37
- L.GridLayer.GoogleMutant = L.GridLayer.extend({
38
- options: {
39
- maxZoom: 21, // can be 23, but ugly if more than maxNativeZoom
40
- // 🍂option type: String = 'roadmap'
41
- // Google's map type. Valid values are 'roadmap', 'satellite', 'terrain' or 'hybrid'.
42
- type: "roadmap",
43
- maxNativeZoom: 21,
44
- },
45
-
46
- initialize: function (options) {
47
- L.GridLayer.prototype.initialize.call(this, options);
48
-
49
- // Couple data structures indexed by tile key
50
- this._tileCallbacks = {}; // Callbacks for promises for tiles that are expected
51
- this._lru = new LRUMap(100); // Tile LRU cache
52
-
53
- this._imagesPerTile = this.options.type === "hybrid" ? 2 : 1;
54
-
55
- this._boundOnMutatedImage = this._onMutatedImage.bind(this);
56
- },
57
-
58
- onAdd: function (map) {
59
- L.GridLayer.prototype.onAdd.call(this, map);
60
- this._initMutantContainer();
61
-
62
- // Attribution and logo nodes are not mutated a second time if the
63
- // mutant is removed and re-added to the map, hence they are
64
- // not cleaned up on layer removal, so they can be added here.
65
- if (this._logoContainer) {
66
- map._controlCorners.bottomleft.appendChild(this._logoContainer);
67
- }
68
- if (this._attributionContainer) {
69
- map._controlCorners.bottomright.appendChild(this._attributionContainer);
70
- }
71
-
72
- waitForAPI(() => {
73
- if (!this._map) {
74
- return;
75
- }
76
- this._initMutant();
77
-
78
- //handle layer being added to a map for which there are no Google tiles at the given zoom
79
- google.maps.event.addListenerOnce(this._mutant, "idle", () => {
80
- if (!this._map) {
81
- return;
82
- }
83
- this._checkZoomLevels();
84
- this._mutantIsReady = true;
85
- });
86
- });
87
- },
88
-
89
- onRemove: function (map) {
90
- L.GridLayer.prototype.onRemove.call(this, map);
91
- this._observer.disconnect();
92
- map._container.removeChild(this._mutantContainer);
93
- if (this._logoContainer) {
94
- L.DomUtil.remove(this._logoContainer);
95
- }
96
- if (this._attributionContainer) {
97
- L.DomUtil.remove(this._attributionContainer);
98
- }
99
- if (this._mutant) {
100
- google.maps.event.clearListeners(this._mutant, "idle");
101
- }
102
- },
103
-
104
- // 🍂method addGoogleLayer(name: String, options?: Object): this
105
- // Adds layer with the given name and options to the google Map instance.
106
- // `name`: one of the google maps API layers, with it's constructor available in `google.maps` object.
107
- // currently following values supported: 'TrafficLayer', 'TransitLayer', 'BicyclingLayer'.
108
- // `options`: see https://developers.google.com/maps/documentation/javascript/reference/map
109
- addGoogleLayer: function (googleLayerName, options) {
110
- if (!this._subLayers) this._subLayers = {};
111
- this.whenReady(() => {
112
- var Constructor = google.maps[googleLayerName];
113
- var googleLayer = new Constructor(options);
114
- googleLayer.setMap(this._mutant);
115
- this._subLayers[googleLayerName] = googleLayer;
116
- });
117
- return this;
118
- },
119
-
120
- // 🍂method removeGoogleLayer(name: String): this
121
- // Removes layer with the given name from the google Map instance.
122
- removeGoogleLayer: function (googleLayerName) {
123
- this.whenReady(() => {
124
- var googleLayer = this._subLayers && this._subLayers[googleLayerName];
125
- if (googleLayer) {
126
- googleLayer.setMap(null);
127
- delete this._subLayers[googleLayerName];
128
- }
129
- });
130
- return this;
131
- },
132
-
133
- _initMutantContainer: function () {
134
- if (!this._mutantContainer) {
135
- this._mutantContainer = L.DomUtil.create(
136
- "div",
137
- "leaflet-google-mutant leaflet-top leaflet-left"
138
- );
139
- this._mutantContainer.id = "_MutantContainer_" + L.Util.stamp(this._mutantContainer);
140
- this._mutantContainer.style.pointerEvents = "none";
141
- this._mutantContainer.style.visibility = "hidden";
142
-
143
- L.DomEvent.off(this._mutantContainer);
144
- }
145
- this._map.getContainer().appendChild(this._mutantContainer);
146
-
147
- this.setOpacity(this.options.opacity);
148
- const style = this._mutantContainer.style;
149
- if (this._map.options.zoomSnap < 1) {
150
- // Fractional zoom needs a bigger mutant container in order to load more (smaller) tiles
151
- style.width = "180%";
152
- style.height = "180%";
153
- } else {
154
- style.width = "100%";
155
- style.height = "100%";
156
- }
157
- style.zIndex = -1;
158
-
159
- this._attachObserver(this._mutantContainer);
160
- },
161
-
162
- _initMutant: function () {
163
- if (this._mutant) {
164
- return;
165
- }
166
-
167
- var options = {
168
- center: { lat: 0, lng: 0 },
169
- zoom: 0,
170
- tilt: 0,
171
- mapTypeId: this.options.type,
172
- disableDefaultUI: true,
173
- keyboardShortcuts: false,
174
- draggable: false,
175
- disableDoubleClickZoom: true,
176
- scrollwheel: false,
177
- styles: this.options.styles || [],
178
- backgroundColor: "transparent",
179
- };
180
- if (this.options.mapId != null) {
181
- options.mapId = this.options.mapId;
182
- }
183
- var map = new google.maps.Map(this._mutantContainer, options);
184
-
185
- this._mutant = map;
186
-
187
- this._update();
188
-
189
- // 🍂event spawned
190
- // Fired when the mutant has been created.
191
- this.fire("spawned", { mapObject: map });
192
-
193
- this._waitControls();
194
- this.once('controls_ready', this._setupAttribution);
195
- },
196
-
197
- _attachObserver: function _attachObserver(node) {
198
- if (!this._observer) this._observer = new MutationObserver(this._onMutations.bind(this));
199
-
200
- // pass in the target node, as well as the observer options
201
- this._observer.observe(node, { childList: true, subtree: true });
202
-
203
- // if we are reusing an old _mutantContainer, we must manually detect
204
- // all existing tiles in it
205
- Array.prototype.forEach.call(node.querySelectorAll("img"), this._boundOnMutatedImage);
206
- },
207
-
208
- _waitControls: function () {
209
- const id = setInterval(() => {
210
- const layoutManager = this._mutant.__gm.layoutManager;
211
- if (!layoutManager) { return; }
212
- clearInterval(id);
213
- let positions;
214
- // iterate through obfuscated key names to find positions set (atm: layoutManager.o)
215
- Object.keys(layoutManager).forEach(function (key) {
216
- const el = layoutManager[key];
217
- if (el.get) {
218
- if (el.get(1) instanceof Node) {
219
- positions = el;
220
- }
221
- }
222
- });
223
- // 🍂event controls_ready
224
- // Fired when controls positions get available (passed in `positions` property).
225
- this.fire("controls_ready", { positions });
226
- }, 50);
227
- },
228
-
229
- _setupAttribution: function (ev) {
230
- if (!this._map) {
231
- return;
232
- }
233
- // https://developers.google.com/maps/documentation/javascript/reference/control#ControlPosition
234
- const pos = google.maps.ControlPosition;
235
- const ctr = this._attributionContainer = ev.positions.get(pos.BOTTOM_RIGHT);
236
- L.DomUtil.addClass(ctr, "leaflet-control leaflet-control-attribution");
237
- L.DomEvent.disableClickPropagation(ctr);
238
- ctr.style.height = "14px";
239
- this._map._controlCorners.bottomright.appendChild(ctr);
240
-
241
- this._logoContainer = ev.positions.get(pos.BOTTOM_LEFT);
242
- this._logoContainer.style.pointerEvents = "auto";
243
- this._map._controlCorners.bottomleft.appendChild(this._logoContainer);
244
- },
245
-
246
- _onMutations: function _onMutations(mutations) {
247
- for (var i = 0; i < mutations.length; ++i) {
248
- var mutation = mutations[i];
249
- for (var j = 0; j < mutation.addedNodes.length; ++j) {
250
- var node = mutation.addedNodes[j];
251
-
252
- if (node instanceof HTMLImageElement) {
253
- this._onMutatedImage(node);
254
- } else if (node instanceof HTMLElement) {
255
- Array.prototype.forEach.call(
256
- node.querySelectorAll("img"),
257
- this._boundOnMutatedImage
258
- );
259
- }
260
- }
261
- }
262
- },
263
-
264
- // Only images which 'src' attrib match this will be considered for moving around.
265
- // Looks like some kind of string-based protobuf, maybe??
266
- // Only the roads (and terrain, and vector-based stuff) match this pattern
267
- _roadRegexp: /!1i(\d+)!2i(\d+)!3i(\d+|VinaFnapurmBegrtn)!/,
268
-
269
- // On the other hand, raster imagery matches this other pattern
270
- _satRegexp: /x=(\d+)&y=(\d+)&z=(\d+|VinaFnapurmBegrtn)/,
271
-
272
- _onMutatedImage: function _onMutatedImage(imgNode) {
273
- let coords;
274
- let match = imgNode.src.match(this._roadRegexp);
275
- let sublayer = 0;
276
-
277
- if (match) {
278
- coords = {
279
- z: match[1],
280
- x: match[2],
281
- y: match[3],
282
- };
283
- if (this._imagesPerTile > 1) {
284
- imgNode.style.zIndex = 1;
285
- sublayer = 1;
286
- }
287
- } else {
288
- match = imgNode.src.match(this._satRegexp);
289
- if (match) {
290
- coords = {
291
- x: match[1],
292
- y: match[2],
293
- z: match[3],
294
- };
295
- }
296
- // imgNode.style.zIndex = 0;
297
- sublayer = 0;
298
- }
299
-
300
- if (coords) {
301
- var tileKey = this._tileCoordsToKey(coords);
302
- imgNode.style.position = "absolute";
303
-
304
- var key = tileKey + "/" + sublayer;
305
- // Cache img so it can also be used in subsequent tile requests
306
- this._lru.set(key, imgNode);
307
-
308
- if (key in this._tileCallbacks && this._tileCallbacks[key]) {
309
- // Use the tile for *all* pending callbacks. They'll be cloned anyway.
310
- this._tileCallbacks[key].forEach((callback) => callback(imgNode));
311
- delete this._tileCallbacks[key];
312
- }
313
- }
314
- },
315
-
316
- createTile: function (coords, done) {
317
- const key = this._tileCoordsToKey(coords),
318
- tileContainer = L.DomUtil.create("div");
319
-
320
- tileContainer.style.textAlign = "left";
321
- tileContainer.dataset.pending = this._imagesPerTile;
322
- done = done.bind(this, null, tileContainer);
323
-
324
- for (var i = 0; i < this._imagesPerTile; ++i) {
325
- const key2 = key + "/" + i,
326
- imgNode = this._lru.get(key2);
327
- if (imgNode) {
328
- tileContainer.appendChild(this._clone(imgNode));
329
- --tileContainer.dataset.pending;
330
- } else {
331
- this._tileCallbacks[key2] = this._tileCallbacks[key2] || [];
332
- this._tileCallbacks[key2].push(
333
- function (c /*, k2*/) {
334
- return function (imgNode) {
335
- c.appendChild(this._clone(imgNode));
336
- --c.dataset.pending;
337
- if (!parseInt(c.dataset.pending)) {
338
- done();
339
- }
340
- }.bind(this);
341
- }.bind(this)(tileContainer /*, key2*/)
342
- );
343
- }
344
- }
345
-
346
- if (!parseInt(tileContainer.dataset.pending)) {
347
- L.Util.requestAnimFrame(done);
348
- }
349
- return tileContainer;
350
- },
351
-
352
- _clone: function (imgNode) {
353
- const clonedImgNode = imgNode.cloneNode(true);
354
- clonedImgNode.style.visibility = "visible";
355
- return clonedImgNode;
356
- },
357
-
358
- _checkZoomLevels: function () {
359
- //setting the zoom level on the Google map may result in a different zoom level than the one requested
360
- //(it won't go beyond the level for which they have data).
361
- const zoomLevel = this._map.getZoom(),
362
- gMapZoomLevel = this._mutant.getZoom();
363
-
364
- if (!zoomLevel || !gMapZoomLevel) return;
365
-
366
- if (
367
- gMapZoomLevel !== zoomLevel || //zoom levels are out of sync, Google doesn't have data
368
- gMapZoomLevel > this.options.maxNativeZoom
369
- ) {
370
- //at current location, Google does have data (contrary to maxNativeZoom)
371
- //Update maxNativeZoom
372
- this._setMaxNativeZoom(gMapZoomLevel);
373
- }
374
- },
375
-
376
- _setMaxNativeZoom: function (zoomLevel) {
377
- if (zoomLevel !== this.options.maxNativeZoom) {
378
- this.options.maxNativeZoom = zoomLevel;
379
- this._resetView();
380
- }
381
- },
382
-
383
- _update: function (center) {
384
- // zoom level check needs to happen before super's implementation (tile addition/creation)
385
- // otherwise tiles may be missed if maxNativeZoom is not yet correctly determined
386
- if (this._mutant) {
387
- center = center || this._map.getCenter();
388
- const _center = new google.maps.LatLng(center.lat, center.lng),
389
- zoom = Math.round(this._map.getZoom()),
390
- mutantZoom = this._mutant.getZoom();
391
-
392
- this._mutant.setCenter(_center);
393
-
394
- //ignore fractional zoom levels
395
- if (zoom !== mutantZoom) {
396
- this._mutant.setZoom(zoom);
397
-
398
- if (this._mutantIsReady) this._checkZoomLevels();
399
- //else zoom level check will be done later by 'idle' handler
400
- }
401
- }
402
-
403
- L.GridLayer.prototype._update.call(this, center);
404
- },
405
-
406
- // @method whenReady(fn: Function, context?: Object): this
407
- // Runs the given function `fn` when the mutant gets initialized, or immediately
408
- // if it's already initialized, optionally passing a function context.
409
- whenReady: function (callback, context) {
410
- if (this._mutant) {
411
- callback.call(context || this, { target: this });
412
- } else {
413
- this.on("spawned", callback, context);
414
- }
415
- return this;
416
- },
417
- });
418
-
419
- // 🍂factory gridLayer.googleMutant(options)
420
- // Returns a new `GridLayer.GoogleMutant` given its options
421
- L.gridLayer.googleMutant = function (options) {
422
- return new L.GridLayer.GoogleMutant(options);
423
- };
424
-
1
+ /* eslint-disable */
2
+ //@ts-nocheck
3
+
4
+ // GoogleMutant by Iván Sánchez Ortega <ivan@sanchezortega.es>
5
+
6
+ // Based on https://github.com/shramov/leaflet-plugins
7
+ // GridLayer like https://avinmathew.com/leaflet-and-google-maps/ , but using MutationObserver instead of jQuery
8
+
9
+ /*
10
+ "THE BEER-WARE LICENSE":
11
+ <ivan@sanchezortega.es> wrote this file. As long as you retain this notice you
12
+ can do whatever you want with this stuff. If we meet some day, and you think
13
+ this stuff is worth it, you can buy me a beer in return.
14
+ */
15
+
16
+ import { LRUMap } from "./lru_map.js";
17
+
18
+ function waitForAPI(callback, context) {
19
+ let checkCounter = 0,
20
+ intervalId = null;
21
+
22
+ intervalId = setInterval(function () {
23
+ if (checkCounter >= 20) {
24
+ clearInterval(intervalId);
25
+ throw new Error("window.google not found after 10 seconds");
26
+ }
27
+ if (!!window.google && !!window.google.maps && !!window.google.maps.Map) {
28
+ clearInterval(intervalId);
29
+ callback.call(context);
30
+ }
31
+ ++checkCounter;
32
+ }, 500);
33
+ }
34
+
35
+ // 🍂class GridLayer.GoogleMutant
36
+ // 🍂extends GridLayer
37
+ L.GridLayer.GoogleMutant = L.GridLayer.extend({
38
+ options: {
39
+ maxZoom: 21, // can be 23, but ugly if more than maxNativeZoom
40
+ // 🍂option type: String = 'roadmap'
41
+ // Google's map type. Valid values are 'roadmap', 'satellite', 'terrain' or 'hybrid'.
42
+ type: "roadmap",
43
+ maxNativeZoom: 21,
44
+ },
45
+
46
+ initialize: function (options) {
47
+ L.GridLayer.prototype.initialize.call(this, options);
48
+
49
+ // Couple data structures indexed by tile key
50
+ this._tileCallbacks = {}; // Callbacks for promises for tiles that are expected
51
+ this._lru = new LRUMap(100); // Tile LRU cache
52
+
53
+ this._imagesPerTile = this.options.type === "hybrid" ? 2 : 1;
54
+
55
+ this._boundOnMutatedImage = this._onMutatedImage.bind(this);
56
+ },
57
+
58
+ onAdd: function (map) {
59
+ L.GridLayer.prototype.onAdd.call(this, map);
60
+ this._initMutantContainer();
61
+
62
+ // Attribution and logo nodes are not mutated a second time if the
63
+ // mutant is removed and re-added to the map, hence they are
64
+ // not cleaned up on layer removal, so they can be added here.
65
+ if (this._logoContainer) {
66
+ map._controlCorners.bottomleft.appendChild(this._logoContainer);
67
+ }
68
+ if (this._attributionContainer) {
69
+ map._controlCorners.bottomright.appendChild(this._attributionContainer);
70
+ }
71
+
72
+ waitForAPI(() => {
73
+ if (!this._map) {
74
+ return;
75
+ }
76
+ this._initMutant();
77
+
78
+ //handle layer being added to a map for which there are no Google tiles at the given zoom
79
+ google.maps.event.addListenerOnce(this._mutant, "idle", () => {
80
+ if (!this._map) {
81
+ return;
82
+ }
83
+ this._checkZoomLevels();
84
+ this._mutantIsReady = true;
85
+ });
86
+ });
87
+ },
88
+
89
+ onRemove: function (map) {
90
+ L.GridLayer.prototype.onRemove.call(this, map);
91
+ this._observer.disconnect();
92
+ map._container.removeChild(this._mutantContainer);
93
+ if (this._logoContainer) {
94
+ L.DomUtil.remove(this._logoContainer);
95
+ }
96
+ if (this._attributionContainer) {
97
+ L.DomUtil.remove(this._attributionContainer);
98
+ }
99
+ if (this._mutant) {
100
+ google.maps.event.clearListeners(this._mutant, "idle");
101
+ }
102
+ },
103
+
104
+ // 🍂method addGoogleLayer(name: String, options?: Object): this
105
+ // Adds layer with the given name and options to the google Map instance.
106
+ // `name`: one of the google maps API layers, with it's constructor available in `google.maps` object.
107
+ // currently following values supported: 'TrafficLayer', 'TransitLayer', 'BicyclingLayer'.
108
+ // `options`: see https://developers.google.com/maps/documentation/javascript/reference/map
109
+ addGoogleLayer: function (googleLayerName, options) {
110
+ if (!this._subLayers) this._subLayers = {};
111
+ this.whenReady(() => {
112
+ var Constructor = google.maps[googleLayerName];
113
+ var googleLayer = new Constructor(options);
114
+ googleLayer.setMap(this._mutant);
115
+ this._subLayers[googleLayerName] = googleLayer;
116
+ });
117
+ return this;
118
+ },
119
+
120
+ // 🍂method removeGoogleLayer(name: String): this
121
+ // Removes layer with the given name from the google Map instance.
122
+ removeGoogleLayer: function (googleLayerName) {
123
+ this.whenReady(() => {
124
+ var googleLayer = this._subLayers && this._subLayers[googleLayerName];
125
+ if (googleLayer) {
126
+ googleLayer.setMap(null);
127
+ delete this._subLayers[googleLayerName];
128
+ }
129
+ });
130
+ return this;
131
+ },
132
+
133
+ _initMutantContainer: function () {
134
+ if (!this._mutantContainer) {
135
+ this._mutantContainer = L.DomUtil.create(
136
+ "div",
137
+ "leaflet-google-mutant leaflet-top leaflet-left"
138
+ );
139
+ this._mutantContainer.id = "_MutantContainer_" + L.Util.stamp(this._mutantContainer);
140
+ this._mutantContainer.style.pointerEvents = "none";
141
+ this._mutantContainer.style.visibility = "hidden";
142
+
143
+ L.DomEvent.off(this._mutantContainer);
144
+ }
145
+ this._map.getContainer().appendChild(this._mutantContainer);
146
+
147
+ this.setOpacity(this.options.opacity);
148
+ const style = this._mutantContainer.style;
149
+ if (this._map.options.zoomSnap < 1) {
150
+ // Fractional zoom needs a bigger mutant container in order to load more (smaller) tiles
151
+ style.width = "180%";
152
+ style.height = "180%";
153
+ } else {
154
+ style.width = "100%";
155
+ style.height = "100%";
156
+ }
157
+ style.zIndex = -1;
158
+
159
+ this._attachObserver(this._mutantContainer);
160
+ },
161
+
162
+ _initMutant: function () {
163
+ if (this._mutant) {
164
+ return;
165
+ }
166
+
167
+ var options = {
168
+ center: { lat: 0, lng: 0 },
169
+ zoom: 0,
170
+ tilt: 0,
171
+ mapTypeId: this.options.type,
172
+ disableDefaultUI: true,
173
+ keyboardShortcuts: false,
174
+ draggable: false,
175
+ disableDoubleClickZoom: true,
176
+ scrollwheel: false,
177
+ styles: this.options.styles || [],
178
+ backgroundColor: "transparent",
179
+ };
180
+ if (this.options.mapId != null) {
181
+ options.mapId = this.options.mapId;
182
+ }
183
+ var map = new google.maps.Map(this._mutantContainer, options);
184
+
185
+ this._mutant = map;
186
+
187
+ this._update();
188
+
189
+ // 🍂event spawned
190
+ // Fired when the mutant has been created.
191
+ this.fire("spawned", { mapObject: map });
192
+
193
+ this._waitControls();
194
+ this.once('controls_ready', this._setupAttribution);
195
+ },
196
+
197
+ _attachObserver: function _attachObserver(node) {
198
+ if (!this._observer) this._observer = new MutationObserver(this._onMutations.bind(this));
199
+
200
+ // pass in the target node, as well as the observer options
201
+ this._observer.observe(node, { childList: true, subtree: true });
202
+
203
+ // if we are reusing an old _mutantContainer, we must manually detect
204
+ // all existing tiles in it
205
+ Array.prototype.forEach.call(node.querySelectorAll("img"), this._boundOnMutatedImage);
206
+ },
207
+
208
+ _waitControls: function () {
209
+ const id = setInterval(() => {
210
+ const layoutManager = this._mutant.__gm.layoutManager;
211
+ if (!layoutManager) { return; }
212
+ clearInterval(id);
213
+ let positions;
214
+ // iterate through obfuscated key names to find positions set (atm: layoutManager.o)
215
+ Object.keys(layoutManager).forEach(function (key) {
216
+ const el = layoutManager[key];
217
+ if (el.get) {
218
+ if (el.get(1) instanceof Node) {
219
+ positions = el;
220
+ }
221
+ }
222
+ });
223
+ // 🍂event controls_ready
224
+ // Fired when controls positions get available (passed in `positions` property).
225
+ this.fire("controls_ready", { positions });
226
+ }, 50);
227
+ },
228
+
229
+ _setupAttribution: function (ev) {
230
+ if (!this._map) {
231
+ return;
232
+ }
233
+ // https://developers.google.com/maps/documentation/javascript/reference/control#ControlPosition
234
+ const pos = google.maps.ControlPosition;
235
+ const ctr = this._attributionContainer = ev.positions.get(pos.BOTTOM_RIGHT);
236
+ L.DomUtil.addClass(ctr, "leaflet-control leaflet-control-attribution");
237
+ L.DomEvent.disableClickPropagation(ctr);
238
+ ctr.style.height = "14px";
239
+ this._map._controlCorners.bottomright.appendChild(ctr);
240
+
241
+ this._logoContainer = ev.positions.get(pos.BOTTOM_LEFT);
242
+ this._logoContainer.style.pointerEvents = "auto";
243
+ this._map._controlCorners.bottomleft.appendChild(this._logoContainer);
244
+ },
245
+
246
+ _onMutations: function _onMutations(mutations) {
247
+ for (var i = 0; i < mutations.length; ++i) {
248
+ var mutation = mutations[i];
249
+ for (var j = 0; j < mutation.addedNodes.length; ++j) {
250
+ var node = mutation.addedNodes[j];
251
+
252
+ if (node instanceof HTMLImageElement) {
253
+ this._onMutatedImage(node);
254
+ } else if (node instanceof HTMLElement) {
255
+ Array.prototype.forEach.call(
256
+ node.querySelectorAll("img"),
257
+ this._boundOnMutatedImage
258
+ );
259
+ }
260
+ }
261
+ }
262
+ },
263
+
264
+ // Only images which 'src' attrib match this will be considered for moving around.
265
+ // Looks like some kind of string-based protobuf, maybe??
266
+ // Only the roads (and terrain, and vector-based stuff) match this pattern
267
+ _roadRegexp: /!1i(\d+)!2i(\d+)!3i(\d+|VinaFnapurmBegrtn)!/,
268
+
269
+ // On the other hand, raster imagery matches this other pattern
270
+ _satRegexp: /x=(\d+)&y=(\d+)&z=(\d+|VinaFnapurmBegrtn)/,
271
+
272
+ _onMutatedImage: function _onMutatedImage(imgNode) {
273
+ let coords;
274
+ let match = imgNode.src.match(this._roadRegexp);
275
+ let sublayer = 0;
276
+
277
+ if (match) {
278
+ coords = {
279
+ z: match[1],
280
+ x: match[2],
281
+ y: match[3],
282
+ };
283
+ if (this._imagesPerTile > 1) {
284
+ imgNode.style.zIndex = 1;
285
+ sublayer = 1;
286
+ }
287
+ } else {
288
+ match = imgNode.src.match(this._satRegexp);
289
+ if (match) {
290
+ coords = {
291
+ x: match[1],
292
+ y: match[2],
293
+ z: match[3],
294
+ };
295
+ }
296
+ // imgNode.style.zIndex = 0;
297
+ sublayer = 0;
298
+ }
299
+
300
+ if (coords) {
301
+ var tileKey = this._tileCoordsToKey(coords);
302
+ imgNode.style.position = "absolute";
303
+
304
+ var key = tileKey + "/" + sublayer;
305
+ // Cache img so it can also be used in subsequent tile requests
306
+ this._lru.set(key, imgNode);
307
+
308
+ if (key in this._tileCallbacks && this._tileCallbacks[key]) {
309
+ // Use the tile for *all* pending callbacks. They'll be cloned anyway.
310
+ this._tileCallbacks[key].forEach((callback) => callback(imgNode));
311
+ delete this._tileCallbacks[key];
312
+ }
313
+ }
314
+ },
315
+
316
+ createTile: function (coords, done) {
317
+ const key = this._tileCoordsToKey(coords),
318
+ tileContainer = L.DomUtil.create("div");
319
+
320
+ tileContainer.style.textAlign = "left";
321
+ tileContainer.dataset.pending = this._imagesPerTile;
322
+ done = done.bind(this, null, tileContainer);
323
+
324
+ for (var i = 0; i < this._imagesPerTile; ++i) {
325
+ const key2 = key + "/" + i,
326
+ imgNode = this._lru.get(key2);
327
+ if (imgNode) {
328
+ tileContainer.appendChild(this._clone(imgNode));
329
+ --tileContainer.dataset.pending;
330
+ } else {
331
+ this._tileCallbacks[key2] = this._tileCallbacks[key2] || [];
332
+ this._tileCallbacks[key2].push(
333
+ function (c /*, k2*/) {
334
+ return function (imgNode) {
335
+ c.appendChild(this._clone(imgNode));
336
+ --c.dataset.pending;
337
+ if (!parseInt(c.dataset.pending)) {
338
+ done();
339
+ }
340
+ }.bind(this);
341
+ }.bind(this)(tileContainer /*, key2*/)
342
+ );
343
+ }
344
+ }
345
+
346
+ if (!parseInt(tileContainer.dataset.pending)) {
347
+ L.Util.requestAnimFrame(done);
348
+ }
349
+ return tileContainer;
350
+ },
351
+
352
+ _clone: function (imgNode) {
353
+ const clonedImgNode = imgNode.cloneNode(true);
354
+ clonedImgNode.style.visibility = "visible";
355
+ return clonedImgNode;
356
+ },
357
+
358
+ _checkZoomLevels: function () {
359
+ //setting the zoom level on the Google map may result in a different zoom level than the one requested
360
+ //(it won't go beyond the level for which they have data).
361
+ const zoomLevel = this._map.getZoom(),
362
+ gMapZoomLevel = this._mutant.getZoom();
363
+
364
+ if (!zoomLevel || !gMapZoomLevel) return;
365
+
366
+ if (
367
+ gMapZoomLevel !== zoomLevel || //zoom levels are out of sync, Google doesn't have data
368
+ gMapZoomLevel > this.options.maxNativeZoom
369
+ ) {
370
+ //at current location, Google does have data (contrary to maxNativeZoom)
371
+ //Update maxNativeZoom
372
+ this._setMaxNativeZoom(gMapZoomLevel);
373
+ }
374
+ },
375
+
376
+ _setMaxNativeZoom: function (zoomLevel) {
377
+ if (zoomLevel !== this.options.maxNativeZoom) {
378
+ this.options.maxNativeZoom = zoomLevel;
379
+ this._resetView();
380
+ }
381
+ },
382
+
383
+ _update: function (center) {
384
+ // zoom level check needs to happen before super's implementation (tile addition/creation)
385
+ // otherwise tiles may be missed if maxNativeZoom is not yet correctly determined
386
+ if (this._mutant) {
387
+ center = center || this._map.getCenter();
388
+ const _center = new google.maps.LatLng(center.lat, center.lng),
389
+ zoom = Math.round(this._map.getZoom()),
390
+ mutantZoom = this._mutant.getZoom();
391
+
392
+ this._mutant.setCenter(_center);
393
+
394
+ //ignore fractional zoom levels
395
+ if (zoom !== mutantZoom) {
396
+ this._mutant.setZoom(zoom);
397
+
398
+ if (this._mutantIsReady) this._checkZoomLevels();
399
+ //else zoom level check will be done later by 'idle' handler
400
+ }
401
+ }
402
+
403
+ L.GridLayer.prototype._update.call(this, center);
404
+ },
405
+
406
+ // @method whenReady(fn: Function, context?: Object): this
407
+ // Runs the given function `fn` when the mutant gets initialized, or immediately
408
+ // if it's already initialized, optionally passing a function context.
409
+ whenReady: function (callback, context) {
410
+ if (this._mutant) {
411
+ callback.call(context || this, { target: this });
412
+ } else {
413
+ this.on("spawned", callback, context);
414
+ }
415
+ return this;
416
+ },
417
+ });
418
+
419
+ // 🍂factory gridLayer.googleMutant(options)
420
+ // Returns a new `GridLayer.GoogleMutant` given its options
421
+ L.gridLayer.googleMutant = function (options) {
422
+ return new L.GridLayer.GoogleMutant(options);
423
+ };
424
+
425
425
  export const GoogleMutant = L.GridLayer.GoogleMutant;