@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.
- package/LICENSE +43 -43
- package/README.md +88 -88
- package/TopoJSON/BR.json +122 -122
- package/TopoJSON/GB_idx.json +1 -1
- package/TopoJSON/IE_idx.json +1 -1
- package/TopoJSON/ND_idx.json +1 -1
- package/TopoJSON/countries.json +257 -257
- package/TopoJSON/us-counties.json +16550 -16550
- package/TopoJSON/us-states.json +458 -458
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.umd.cjs +1 -1
- package/dist/index.umd.cjs.map +1 -1
- package/package.json +7 -7
- package/src/CanvasPinLayer.ts +99 -99
- package/src/CanvasPins.ts +397 -397
- package/src/Choropleth.css +27 -27
- package/src/Choropleth.ts +203 -203
- package/src/ChoroplethContinents.ts +13 -13
- package/src/ChoroplethCounties.ts +111 -111
- package/src/ChoroplethCountries.ts +100 -100
- package/src/ChoroplethStates.ts +103 -103
- package/src/ChoroplethStatesHeat.ts +8 -8
- package/src/GMap.css +16 -16
- package/src/GMap.ts +880 -880
- package/src/GMapCounties.ts +93 -93
- package/src/GMapGraph.ts +61 -61
- package/src/GMapHeat.ts +27 -27
- package/src/GMapLayered.ts +94 -94
- package/src/GMapPin.ts +115 -115
- package/src/GMapPinLine.ts +138 -138
- package/src/GeoHash.css +15 -15
- package/src/GeoHash.ts +139 -139
- package/src/Graph.css +10 -10
- package/src/Graph.ts +98 -98
- package/src/Graticule.css +13 -13
- package/src/Graticule.ts +97 -97
- package/src/Heat.css +2 -2
- package/src/Heat.ts +87 -87
- package/src/IChoropleth.ts +8 -8
- package/src/Layer.ts +99 -99
- package/src/Layered.css +19 -19
- package/src/Layered.ts +206 -206
- package/src/Lines.css +9 -9
- package/src/Lines.ts +78 -78
- package/src/OpenStreet.css +15 -15
- package/src/OpenStreet.ts +126 -126
- package/src/Pins.css +18 -18
- package/src/Pins.ts +350 -350
- package/src/Projection.ts +42 -42
- package/src/TestHeatMap.ts +8 -8
- package/src/TopoJSONChoropleth.ts +125 -125
- package/src/Utility.ts +484 -484
- package/src/__package__.ts +3 -3
- package/src/index.ts +33 -33
- package/src/leaflet/AlbersPR.ts +48 -48
- package/src/leaflet/Blank.ts +9 -9
- package/src/leaflet/Circles.ts +139 -139
- package/src/leaflet/ClusterCircles.css +26 -26
- package/src/leaflet/ClusterCircles.ts +88 -88
- package/src/leaflet/Countries.ts +43 -43
- package/src/leaflet/DrawLayer.ts +167 -167
- package/src/leaflet/FeatureLayer.ts +138 -138
- package/src/leaflet/GMap.ts +44 -44
- package/src/leaflet/HeatLayer.ts +77 -77
- package/src/leaflet/Icons.ts +60 -60
- package/src/leaflet/Leaflet.css +3 -3
- package/src/leaflet/Leaflet.ts +239 -239
- package/src/leaflet/MapBox.ts +35 -35
- package/src/leaflet/Markers.ts +109 -109
- package/src/leaflet/OpenStreet.ts +27 -27
- package/src/leaflet/Path.ts +138 -138
- package/src/leaflet/Pins.ts +73 -73
- package/src/leaflet/Polygons.ts +113 -113
- package/src/leaflet/Region.ts +138 -138
- package/src/leaflet/Text.ts +99 -99
- package/src/leaflet/TileLayer.ts +81 -81
- package/src/leaflet/TopoJSON.ts +146 -146
- package/src/leaflet/US.ts +15 -15
- package/src/leaflet/USCounties.ts +43 -43
- package/src/leaflet/USStates.ts +41 -41
- package/src/leaflet/World.css +3 -3
- package/src/leaflet/World.ts +172 -172
- package/src/leaflet/index.ts +18 -18
- package/src/leaflet/leaflet-shim.ts +18 -18
- package/src/leaflet/plugins/BeautifyIcon.css +44 -44
- package/src/leaflet/plugins/BeautifyIcon.ts +190 -190
- package/src/leaflet/plugins/BeutifyIcon.licence +20 -20
- package/src/leaflet/plugins/D3SvgOverlay.css +3 -3
- package/src/leaflet/plugins/D3SvgOverlay.licence +20 -20
- package/src/leaflet/plugins/D3SvgOverlay.ts +175 -175
- package/src/leaflet/plugins/HeatLayer.license +21 -21
- package/src/leaflet/plugins/HeatLayer.ts +224 -224
- package/src/leaflet/plugins/Leaflet.GoogleMutant.ts +424 -424
- package/src/leaflet/plugins/lru_map.ts +352 -352
- 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;
|