@superrouteca/smap-leaflet 0.0.0-stage → 1.1.0

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/src/compat.js ADDED
@@ -0,0 +1,847 @@
1
+ // @superrouteca/smap-leaflet/compat — Leaflet-style calls on an sMap map, so code written for Leaflet runs on sMap:
2
+ //
3
+ // const L = createLeafletCompat(smapMap); // smapMap: a map of @superrouteca/smap, after `await map.ready`
4
+ // L.marker([43.65, -79.38]).addTo(L.map).bindPopup('<b>Depot</b>');
5
+ // L.geoJSON(zones, { style: (f) => ({ color: f.properties.color }) }).addTo(L.map);
6
+ //
7
+ // Positions are [lat, lng] as in Leaflet; zoom levels are Leaflet's (one above the sMap map's own). Every layer is
8
+ // drawn with the sMap map's own calls (addPoints, addLines, addPolygons, addRasterLayer, addWmsLayer). Layers that
9
+ // share their look are drawn together (a GeoJSON layer of 10,000 features is a few sMap layers, not 10,000). No Leaflet
10
+ // is needed for this module. A layer without a slot draws on top in the order it was added, as in Leaflet.
11
+
12
+ let seq = 0;
13
+
14
+ // ------------------------------------------------------------------ positions
15
+
16
+ function isNum(v) { return typeof v === 'number' && !isNaN(v); }
17
+
18
+ /** A Leaflet position ([lat, lng], [lat, lng, alt], {lat, lng}, {lat, lon}) as {lat, lng}. */
19
+ export function toLatLng(v) {
20
+ if (v == null) { return null; }
21
+ if (Array.isArray(v)) {
22
+ if (!isNum(+v[0]) || !isNum(+v[1])) { return null; }
23
+ return { lat: +v[0], lng: +v[1] };
24
+ }
25
+ if (typeof v === 'object' && v.lat !== undefined) { return { lat: +v.lat, lng: +(v.lng !== undefined ? v.lng : v.lon) }; }
26
+ return null;
27
+ }
28
+
29
+ function lngLatArr(v) { const ll = toLatLng(v); return [ll.lng, ll.lat]; }
30
+
31
+ function isLatLngish(v) { return toLatLng(v) !== null && (!Array.isArray(v) || !Array.isArray(v[0])); }
32
+
33
+ /** A Leaflet bounds ([[s, w], [n, e]], two positions, or an object with getSouthWest / getNorthEast) as LatLngBounds. */
34
+ export function latLngBounds(a, b) {
35
+ if (a instanceof LatLngBounds) { return a; }
36
+ const bounds = new LatLngBounds();
37
+ if (b !== undefined) { bounds.extend(a).extend(b); return bounds; }
38
+ if (a && typeof a.getSouthWest === 'function') { return bounds.extend(a.getSouthWest()).extend(a.getNorthEast()); }
39
+ (a || []).forEach(function (p) { bounds.extend(p); });
40
+ return bounds;
41
+ }
42
+
43
+ export class LatLngBounds {
44
+ constructor() { this._sw = null; this._ne = null; }
45
+ extend(p) {
46
+ if (p instanceof LatLngBounds) { if (p.isValid()) { this.extend(p._sw).extend(p._ne); } return this; }
47
+ const ll = toLatLng(p);
48
+ if (!ll) { return this; }
49
+ if (!this._sw) { this._sw = { lat: ll.lat, lng: ll.lng }; this._ne = { lat: ll.lat, lng: ll.lng }; return this; }
50
+ this._sw = { lat: Math.min(this._sw.lat, ll.lat), lng: Math.min(this._sw.lng, ll.lng) };
51
+ this._ne = { lat: Math.max(this._ne.lat, ll.lat), lng: Math.max(this._ne.lng, ll.lng) };
52
+ return this;
53
+ }
54
+ isValid() { return !!this._sw; }
55
+ getSouthWest() { return this._sw; }
56
+ getNorthEast() { return this._ne; }
57
+ getNorthWest() { return { lat: this._ne.lat, lng: this._sw.lng }; }
58
+ getSouthEast() { return { lat: this._sw.lat, lng: this._ne.lng }; }
59
+ getWest() { return this._sw.lng; }
60
+ getSouth() { return this._sw.lat; }
61
+ getEast() { return this._ne.lng; }
62
+ getNorth() { return this._ne.lat; }
63
+ getCenter() { return { lat: (this._sw.lat + this._ne.lat) / 2, lng: (this._sw.lng + this._ne.lng) / 2 }; }
64
+ contains(p) {
65
+ if (p instanceof LatLngBounds) { return this.contains(p._sw) && this.contains(p._ne); }
66
+ const ll = toLatLng(p);
67
+ return !!ll && ll.lat >= this._sw.lat && ll.lat <= this._ne.lat && ll.lng >= this._sw.lng && ll.lng <= this._ne.lng;
68
+ }
69
+ /** As the sMap map takes bounds: [[west, south], [east, north]]. */
70
+ toLngLatArray() { return [[this._sw.lng, this._sw.lat], [this._ne.lng, this._ne.lat]]; }
71
+ }
72
+
73
+ // ------------------------------------------------------------------ colours
74
+
75
+ function hexToRgb(c) {
76
+ let h = c.slice(1);
77
+ if (h.length === 3 || h.length === 4) { h = h.split('').map(function (x) { return x + x; }).join(''); }
78
+ if (h.length !== 6 && h.length !== 8) { return null; }
79
+ return [parseInt(h.slice(0, 2), 16), parseInt(h.slice(2, 4), 16), parseInt(h.slice(4, 6), 16), h.length === 8 ? parseInt(h.slice(6, 8), 16) / 255 : 1];
80
+ }
81
+
82
+ /** A colour with an opacity applied (hex and rgb() colours; a named colour is returned as it is). */
83
+ export function withAlpha(color, alpha) {
84
+ if (alpha === undefined || alpha === null || alpha >= 1 || typeof color !== 'string') { return color; }
85
+ const c = color.trim();
86
+ let rgba = null;
87
+ if (c[0] === '#') { rgba = hexToRgb(c); }
88
+ const m = /^rgba?\(([^)]+)\)$/i.exec(c);
89
+ if (m) {
90
+ const parts = m[1].split(/[\s,/]+/).filter(Boolean).map(Number);
91
+ rgba = [parts[0], parts[1], parts[2], parts[3] !== undefined ? parts[3] : 1];
92
+ }
93
+ if (!rgba) { return c; }
94
+ const a = Math.max(0, Math.min(1, rgba[3] * alpha));
95
+ return 'rgba(' + rgba[0] + ', ' + rgba[1] + ', ' + rgba[2] + ', ' + Math.round(a * 1000) / 1000 + ')';
96
+ }
97
+
98
+ const TRANSPARENT = 'rgba(0, 0, 0, 0)';
99
+
100
+ // ------------------------------------------------------------------ events
101
+
102
+ class Evented {
103
+ constructor() { this._events = {}; }
104
+ on(types, fn, ctx) {
105
+ if (typeof types === 'object') { Object.keys(types).forEach(function (t) { this.on(t, types[t], fn); }, this); return this; }
106
+ String(types).split(/\s+/).forEach(function (t) { (this._events[t] = this._events[t] || []).push({ fn: fn, ctx: ctx }); }, this);
107
+ return this;
108
+ }
109
+ off(types, fn, ctx) {
110
+ if (types === undefined) { this._events = {}; return this; }
111
+ if (typeof types === 'object') { Object.keys(types).forEach(function (t) { this.off(t, types[t], fn); }, this); return this; }
112
+ String(types).split(/\s+/).forEach(function (t) {
113
+ if (!fn) { delete this._events[t]; return; }
114
+ this._events[t] = (this._events[t] || []).filter(function (l) { return l.fn !== fn || (ctx !== undefined && l.ctx !== ctx); });
115
+ }, this);
116
+ return this;
117
+ }
118
+ once(types, fn, ctx) {
119
+ const self = this;
120
+ const wrapped = function (e) { self.off(types, wrapped, ctx); return fn.call(ctx || self, e); };
121
+ return this.on(types, wrapped, ctx);
122
+ }
123
+ fire(type, data, propagate) {
124
+ const e = Object.assign({}, data || {}, { type: type, target: this, sourceTarget: (data && data.sourceTarget) || this });
125
+ (this._events[type] || []).slice().forEach(function (l) { l.fn.call(l.ctx || this, e); }, this);
126
+ if (propagate && this._eventParents) { this._eventParents.forEach(function (p) { p.fire(type, Object.assign({}, e, { layer: e.layer || this, propagatedFrom: this }), true); }, this); }
127
+ return this;
128
+ }
129
+ listens(type) { return !!(this._events[type] && this._events[type].length); }
130
+ }
131
+
132
+ // ------------------------------------------------------------------ popups
133
+
134
+ function popupContent(content, layer) {
135
+ return typeof content === 'function' ? content(layer) : content;
136
+ }
137
+
138
+ /** Leaflet popup options as sMap popup options. */
139
+ function popupOptions(o) {
140
+ if (!o) { return undefined; }
141
+ const out = {};
142
+ if (o.className !== undefined) { out.className = o.className; }
143
+ if (o.maxWidth !== undefined) { out.maxWidth = o.maxWidth; }
144
+ if (o.minWidth !== undefined) { out.minWidth = o.minWidth; }
145
+ if (o.closeButton !== undefined) { out.closeButton = o.closeButton; }
146
+ if (o.closeOnClick !== undefined) { out.closeOnClick = o.closeOnClick; }
147
+ if (o.autoPan !== undefined) { out.autoPan = o.autoPan; }
148
+ if (o.offset !== undefined) { out.offset = Array.isArray(o.offset) ? o.offset : [o.offset.x, o.offset.y]; }
149
+ return out;
150
+ }
151
+
152
+ // ------------------------------------------------------------------ layers
153
+
154
+ /**
155
+ * What a layer draws: { kind: 'points' | 'lines' | 'polygons', geometries: [GeoJSON geometry], properties, options }
156
+ * (sMap layer options). Layers whose kind and options are equal are drawn as one sMap layer.
157
+ */
158
+ class Layer extends Evented {
159
+ constructor(options) {
160
+ super();
161
+ this.options = Object.assign({}, this.constructor.defaults || {}, options || {});
162
+ this._leaflet_id = ++seq;
163
+ this._host = null; // the compat map or group drawing it
164
+ this._popup = null;
165
+ this._eventParents = [];
166
+ }
167
+ addTo(target) {
168
+ const host = hostOf(target);
169
+ if (this._host) { this.remove(); }
170
+ host.addLayer(this);
171
+ return this;
172
+ }
173
+ remove() { if (this._host) { this._host.removeLayer(this); } return this; }
174
+ removeFrom(target) { const host = hostOf(target); if (this._host === host) { host.removeLayer(this); } return this; }
175
+ bindPopup(content, options) { this._popup = { content: content, options: options }; this._changed(); return this; }
176
+ unbindPopup() { this._popup = null; this._changed(); return this; }
177
+ getPopup() { return this._popup; }
178
+ isPopupOpen() { return !!this._popupOpen; }
179
+ setPopupContent(content) { if (this._popup) { this._popup.content = content; } return this; }
180
+ /** Opens this layer's popup at `latlng` (default: the layer's own position or centre). */
181
+ openPopup(latlng) {
182
+ const map = this._mapOf();
183
+ if (!map || !this._popup) { return this; }
184
+ const at = latlng ? toLatLng(latlng) : this._anchor();
185
+ if (!at) { return this; }
186
+ map.smap.openPopup([at.lng, at.lat], popupContent(this._popup.content, this), popupOptions(this._popup.options));
187
+ return this;
188
+ }
189
+ closePopup() { const map = this._mapOf(); if (map) { map.smap.closePopup(); } return this; }
190
+ togglePopup() { return this.openPopup(); }
191
+ addEventParent(p) { this._eventParents.push(p); return this; }
192
+ removeEventParent(p) { this._eventParents = this._eventParents.filter(function (x) { return x !== p; }); return this; }
193
+ getBounds() {
194
+ const b = new LatLngBounds();
195
+ this._specs().forEach(function (s) { s.geometries.forEach(function (g) { walkCoords(g, function (c) { b.extend([c[1], c[0]]); }); }); });
196
+ return b;
197
+ }
198
+ toGeoJSON() {
199
+ const features = [];
200
+ const props = (this.feature && this.feature.properties) || {};
201
+ this._specs().forEach(function (s) { s.geometries.forEach(function (g) { features.push({ type: 'Feature', properties: props, geometry: g }); }); });
202
+ return features.length === 1 ? features[0] : { type: 'FeatureCollection', features: features };
203
+ }
204
+ setStyle(style) { Object.assign(this.options, style || {}); this._changed(); return this; }
205
+ bringToFront() { const h = this._host; if (h) { h.removeLayer(this); h.addLayer(this); } return this; }
206
+ _mapOf() { let h = this._host; while (h && !(h instanceof CompatMap)) { h = h._host; } return h || null; }
207
+ _anchor() { const b = this.getBounds(); return b.isValid() ? b.getCenter() : null; }
208
+ _changed() { if (this._host) { this._host._childChanged(this); } }
209
+ _specs() { return []; }
210
+ }
211
+
212
+ function walkCoords(g, fn) {
213
+ if (!g) { return; }
214
+ if (g.type === 'GeometryCollection') { g.geometries.forEach(function (x) { walkCoords(x, fn); }); return; }
215
+ (function walk(c) { if (typeof c[0] === 'number') { fn(c); } else { c.forEach(walk); } })(g.coordinates);
216
+ }
217
+
218
+ // Leaflet's default look (Path options).
219
+ const PATH_DEFAULTS = { stroke: true, color: '#3388ff', weight: 3, opacity: 1, fill: false, fillColor: null, fillOpacity: 0.2, dashArray: null };
220
+
221
+ function dash(o) {
222
+ if (!o.dashArray) { return undefined; }
223
+ const parts = (Array.isArray(o.dashArray) ? o.dashArray : String(o.dashArray).split(/[\s,]+/)).map(Number).filter(function (n) { return n > 0; });
224
+ if (!parts.length) { return undefined; }
225
+ // Leaflet dashes are in pixels, sMap's in line widths.
226
+ const w = o.weight || 1;
227
+ return parts.map(function (n) { return Math.round((n / w) * 100) / 100; });
228
+ }
229
+
230
+ function lineOptions(o) {
231
+ const out = { color: o.stroke === false ? TRANSPARENT : o.color, width: o.weight, opacity: o.stroke === false ? 0 : o.opacity };
232
+ const d = dash(o);
233
+ if (d) { out.dash = d; }
234
+ return out;
235
+ }
236
+
237
+ function areaOptions(o) {
238
+ const fill = o.fill === false ? TRANSPARENT : (o.fillColor || o.color);
239
+ return {
240
+ fill: fill,
241
+ opacity: o.fill === false ? 0 : o.fillOpacity,
242
+ outline: o.stroke === false ? TRANSPARENT : withAlpha(o.color, o.opacity),
243
+ outlineWidth: o.stroke === false ? 0.01 : o.weight,
244
+ };
245
+ }
246
+
247
+ /** Leaflet's default marker: a blue pin. */
248
+ const DEFAULT_PIN = { shape: 'pin', fill: '#2a81cb', border: '#3274a3', size: 26 };
249
+
250
+ function iconAnchor(icon) {
251
+ const o = icon.options || {};
252
+ if (!o.iconAnchor || !o.iconSize) { return o.iconSize ? 'center' : 'bottom'; }
253
+ const a = Array.isArray(o.iconAnchor) ? o.iconAnchor : [o.iconAnchor.x, o.iconAnchor.y];
254
+ const s = Array.isArray(o.iconSize) ? o.iconSize : [o.iconSize.x, o.iconSize.y];
255
+ const v = a[1] >= s[1] * 0.75 ? 'bottom' : (a[1] <= s[1] * 0.25 ? 'top' : '');
256
+ const h = a[0] <= s[0] * 0.25 ? 'left' : (a[0] >= s[0] * 0.75 ? 'right' : '');
257
+ return (v + (v && h ? '-' : '') + h) || 'center';
258
+ }
259
+
260
+ let warnedDivIcon = false;
261
+
262
+ export class Marker extends Layer {
263
+ constructor(latlng, options) { super(options); this._latlng = toLatLng(latlng); }
264
+ getLatLng() { return this._latlng; }
265
+ setLatLng(latlng) { this._latlng = toLatLng(latlng); this._changed(); this.fire('move', { latlng: this._latlng }); return this; }
266
+ setIcon(icon) { this.options.icon = icon; this._changed(); return this; }
267
+ setOpacity(opacity) { this.options.opacity = opacity; this._changed(); return this; }
268
+ setZIndexOffset(z) { this.options.zIndexOffset = z; this._changed(); return this; }
269
+ _anchor() { return this._latlng; }
270
+ _specs() {
271
+ if (!this._latlng) { return []; }
272
+ const o = this.options;
273
+ const icon = o.icon;
274
+ let options;
275
+ if (icon && icon.options && icon.options.iconUrl) {
276
+ options = { icon: icon.options.iconUrl, iconAnchor: iconAnchor(icon) };
277
+ } else {
278
+ if (icon && icon.options && icon.options.html !== undefined && !warnedDivIcon && typeof console !== 'undefined') {
279
+ warnedDivIcon = true;
280
+ console.warn('sMap: divIcon has no counterpart on an sMap map; the default pin is drawn instead.');
281
+ }
282
+ options = { marker: Object.assign({}, DEFAULT_PIN, o.opacity !== undefined && o.opacity !== 1 ? { opacity: o.opacity } : {}) };
283
+ }
284
+ if (o.zIndexOffset) { options.zIndex = o.zIndexOffset; }
285
+ return [{ kind: 'points', geometries: [{ type: 'Point', coordinates: [this._latlng.lng, this._latlng.lat] }], options: options }];
286
+ }
287
+ }
288
+
289
+ export class CircleMarker extends Layer {
290
+ constructor(latlng, options) { super(Object.assign({}, PATH_DEFAULTS, { fill: true, radius: 10 }, options || {})); this._latlng = toLatLng(latlng); }
291
+ getLatLng() { return this._latlng; }
292
+ setLatLng(latlng) { this._latlng = toLatLng(latlng); this._changed(); return this; }
293
+ setRadius(r) { this.options.radius = r; this._changed(); return this; }
294
+ getRadius() { return this.options.radius; }
295
+ _anchor() { return this._latlng; }
296
+ _specs() {
297
+ if (!this._latlng) { return []; }
298
+ const o = this.options;
299
+ return [{
300
+ kind: 'points',
301
+ geometries: [{ type: 'Point', coordinates: [this._latlng.lng, this._latlng.lat] }],
302
+ options: {
303
+ color: o.fill === false ? TRANSPARENT : withAlpha(o.fillColor || o.color, o.fillOpacity),
304
+ radius: o.radius,
305
+ strokeColor: o.stroke === false ? TRANSPARENT : withAlpha(o.color, o.opacity),
306
+ strokeWidth: o.stroke === false ? 0 : o.weight,
307
+ },
308
+ }];
309
+ }
310
+ }
311
+
312
+ /** A circle of a radius in metres, drawn as an area of 64 points. */
313
+ export class Circle extends Layer {
314
+ constructor(latlng, options) {
315
+ if (typeof options === 'number') { options = { radius: options }; }
316
+ super(Object.assign({}, PATH_DEFAULTS, { fill: true, radius: 10 }, options || {}));
317
+ this._latlng = toLatLng(latlng);
318
+ }
319
+ getLatLng() { return this._latlng; }
320
+ setLatLng(latlng) { this._latlng = toLatLng(latlng); this._changed(); return this; }
321
+ setRadius(r) { this.options.radius = r; this._changed(); return this; }
322
+ getRadius() { return this.options.radius; }
323
+ _anchor() { return this._latlng; }
324
+ _specs() {
325
+ if (!this._latlng) { return []; }
326
+ const R = 6378137;
327
+ const lat = this._latlng.lat * Math.PI / 180;
328
+ const ring = [];
329
+ for (let i = 0; i <= 64; i++) {
330
+ const a = (i % 64) / 64 * 2 * Math.PI;
331
+ const dLat = (this.options.radius * Math.cos(a)) / R;
332
+ const dLng = (this.options.radius * Math.sin(a)) / (R * Math.cos(lat));
333
+ ring.push([this._latlng.lng + dLng * 180 / Math.PI, this._latlng.lat + dLat * 180 / Math.PI]);
334
+ }
335
+ return [{ kind: 'polygons', geometries: [{ type: 'Polygon', coordinates: [ring] }], options: areaOptions(this.options) }];
336
+ }
337
+ }
338
+
339
+ function depth(a) { let d = 0; while (Array.isArray(a) && a.length && !isLatLngish(a)) { d += 1; a = a[0]; } return d; }
340
+
341
+ export class Polyline extends Layer {
342
+ constructor(latlngs, options) { super(Object.assign({}, PATH_DEFAULTS, options || {})); this._latlngs = latlngs || []; }
343
+ getLatLngs() { return this._latlngs; }
344
+ setLatLngs(latlngs) { this._latlngs = latlngs || []; this._changed(); return this; }
345
+ addLatLng(latlng) { if (depth(this._latlngs) <= 1) { this._latlngs.push(latlng); } this._changed(); return this; }
346
+ isEmpty() { return !this._latlngs.length; }
347
+ _geometry() {
348
+ const lls = this._latlngs;
349
+ if (!lls.length) { return null; }
350
+ if (depth(lls) <= 1) { return { type: 'LineString', coordinates: lls.map(lngLatArr) }; }
351
+ return { type: 'MultiLineString', coordinates: lls.map(function (line) { return line.map(lngLatArr); }) };
352
+ }
353
+ _specs() { const g = this._geometry(); return g ? [{ kind: 'lines', geometries: [g], options: lineOptions(this.options) }] : []; }
354
+ }
355
+
356
+ function closeRing(ring) {
357
+ const r = ring.map(lngLatArr);
358
+ if (r.length && (r[0][0] !== r[r.length - 1][0] || r[0][1] !== r[r.length - 1][1])) { r.push(r[0].slice()); }
359
+ return r;
360
+ }
361
+
362
+ export class Polygon extends Polyline {
363
+ constructor(latlngs, options) { super(latlngs, Object.assign({ fill: true }, options || {})); }
364
+ _geometry() {
365
+ const lls = this._latlngs;
366
+ if (!lls.length) { return null; }
367
+ const d = depth(lls);
368
+ if (d <= 1) { return { type: 'Polygon', coordinates: [closeRing(lls)] }; }
369
+ if (d === 2) { return { type: 'Polygon', coordinates: lls.map(closeRing) }; }
370
+ return { type: 'MultiPolygon', coordinates: lls.map(function (poly) { return poly.map(closeRing); }) };
371
+ }
372
+ _specs() { const g = this._geometry(); return g ? [{ kind: 'polygons', geometries: [g], options: areaOptions(this.options) }] : []; }
373
+ }
374
+
375
+ export class Rectangle extends Polygon {
376
+ constructor(bounds, options) { super(rectangleRing(bounds), options); }
377
+ setBounds(bounds) { return this.setLatLngs(rectangleRing(bounds)); }
378
+ }
379
+
380
+ function rectangleRing(bounds) {
381
+ const b = latLngBounds(bounds);
382
+ return [b.getSouthWest(), b.getNorthWest(), b.getNorthEast(), b.getSouthEast()];
383
+ }
384
+
385
+ // ------------------------------------------------------------------ drawing (maps and groups)
386
+
387
+ function keyOf(spec) {
388
+ return spec.kind + '|' + JSON.stringify(spec.options, function (k, v) { return typeof v === 'function' ? '[fn]' : v; });
389
+ }
390
+
391
+ /** The layers a list draws, groups opened up: [{ layer, popup }] (a layer's own popup, else its nearest group's). */
392
+ function leaves(layers, inherited, out) {
393
+ out = out || { vectors: [], tiles: [] };
394
+ layers.forEach(function (l) {
395
+ if (l instanceof LayerGroup) { leaves(l._layers, l._popup || inherited, out); return; }
396
+ if (l instanceof TileLayer) { out.tiles.push(l); return; }
397
+ out.vectors.push({ layer: l, popup: l._popup || inherited || null });
398
+ });
399
+ return out;
400
+ }
401
+
402
+ /**
403
+ * Draws layers on the sMap map under ids `<base>:<n>`: layers of one kind and look become one sMap layer, each feature
404
+ * tagged with its layer, so a click and a popup find the Leaflet layer it came from. Drawn again with the same looks,
405
+ * only the data is replaced (the sMap layers keep their place); otherwise they are added again (on top).
406
+ */
407
+ class Drawing {
408
+ constructor(base) { this.base = base; this.ids = []; this.keys = []; this.groups = []; }
409
+ draw(smap, items) {
410
+ const groups = [];
411
+ const byKey = {};
412
+ items.forEach(function (item) {
413
+ item.layer._specs().forEach(function (spec) {
414
+ const k = keyOf(spec) + (item.popup ? '|popup' : '');
415
+ let g = byKey[k];
416
+ if (!g) { g = byKey[k] = { key: k, kind: spec.kind, options: spec.options, features: [], items: [] }; groups.push(g); }
417
+ const idx = g.items.length;
418
+ g.items.push(item);
419
+ const props = Object.assign({}, (item.layer.feature && item.layer.feature.properties) || {}, { __leaflet: idx });
420
+ spec.geometries.forEach(function (geometry) { g.features.push({ type: 'Feature', properties: props, geometry: geometry }); });
421
+ });
422
+ });
423
+ const keys = groups.map(function (g) { return g.key; });
424
+ const same = keys.length === this.keys.length && keys.every(function (k, i) { return k === this.keys[i]; }, this) &&
425
+ this.ids.every(function (id) { return smap.layers().indexOf(id) >= 0; });
426
+ this.groups = groups;
427
+ if (same) {
428
+ groups.forEach(function (g, n) { smap.setData(this.ids[n], { type: 'FeatureCollection', features: g.features }); }, this);
429
+ return;
430
+ }
431
+ this.erase(smap);
432
+ this.keys = keys;
433
+ const self = this;
434
+ groups.forEach(function (g, n) {
435
+ const id = self.base + ':' + n;
436
+ const item = function (props) { const live = self.groups[n]; return live && props ? live.items[props.__leaflet] : null; };
437
+ const options = Object.assign({}, g.options, {
438
+ onClick: function (feature, e) {
439
+ const it = item(feature && feature.properties);
440
+ if (!it) { return; }
441
+ const lngLat = e && e.lngLat;
442
+ it.layer.fire('click', {
443
+ latlng: lngLat ? { lat: lngLat.lat, lng: lngLat.lng } : it.layer._anchor(),
444
+ containerPoint: e && e.point,
445
+ originalEvent: e && e.originalEvent,
446
+ layer: it.layer,
447
+ }, true);
448
+ },
449
+ });
450
+ const withPopup = g.items.find(function (it) { return !!it.popup; });
451
+ if (withPopup) {
452
+ options.popup = function (props) {
453
+ const it = item(props);
454
+ return it && it.popup ? popupContent(it.popup.content, it.layer) : null;
455
+ };
456
+ if (withPopup.popup.options) { options.popupOptions = popupOptions(withPopup.popup.options); }
457
+ }
458
+ const fc = { type: 'FeatureCollection', features: g.features };
459
+ if (g.kind === 'points') { smap.addPoints(id, fc, options); }
460
+ else if (g.kind === 'lines') { smap.addLines(id, fc, options); }
461
+ else { smap.addPolygons(id, fc, options); }
462
+ self.ids.push(id);
463
+ });
464
+ }
465
+ erase(smap) {
466
+ this.ids.forEach(function (id) { smap.removeLayer(id); });
467
+ this.ids = [];
468
+ this.keys = [];
469
+ }
470
+ }
471
+
472
+ function hostOf(target) {
473
+ if (target instanceof CompatMap || target instanceof LayerGroup) { return target; }
474
+ if (target && target.__leafletCompat) { return target.__leafletCompat.map; }
475
+ throw new Error('sMap: addTo() takes the compat map (L.map), a layer group, or an sMap map passed to createLeafletCompat()');
476
+ }
477
+
478
+ /** Raster tiles (`L.tileLayer`) on the sMap map. */
479
+ export class TileLayer extends Layer {
480
+ constructor(url, options) { super(Object.assign({ subdomains: 'abc', tileSize: 256, minZoom: 0, maxZoom: 18, zoomOffset: 0, opacity: 1 }, options || {})); this._url = url; this._rev = 0; }
481
+ setUrl(url) { this._url = url; this._rev += 1; this._changed(); return this; }
482
+ setOpacity(opacity) { this.options.opacity = opacity; this._rev += 1; this._changed(); return this; }
483
+ getAttribution() { return this.options.attribution; }
484
+ /** The tile URLs with every Leaflet placeholder filled except {z}, {x}, {y} (one per subdomain). */
485
+ tileUrls() {
486
+ const o = this.options;
487
+ const subs = typeof o.subdomains === 'string' ? o.subdomains.split('') : (o.subdomains || []);
488
+ let url = String(this._url).replace(/\{r\}/g, o.detectRetina ? '@2x' : '').replace(/\{-y\}/g, '{y}');
489
+ url = url.replace(/\{([A-Za-z_]+)\}/g, function (all, name) {
490
+ if (name === 'z' || name === 'x' || name === 'y' || name === 's') { return all; }
491
+ const v = o[name];
492
+ return v === undefined ? all : (typeof v === 'function' ? v({}) : String(v));
493
+ });
494
+ if (url.indexOf('{s}') < 0 || !subs.length) { return [url]; }
495
+ return subs.map(function (s) { return url.replace(/\{s\}/g, s); });
496
+ }
497
+ _drawSelf(smap, id) {
498
+ if (typeof smap.addRasterLayer !== 'function') { throw new Error('sMap: tileLayer needs @superrouteca/smap 1.1.0 (addRasterLayer)'); }
499
+ const o = this.options;
500
+ const spec = { tiles: this.tileUrls(), tileSize: o.tileSize };
501
+ if (o.attribution) { spec.attribution = o.attribution; }
502
+ if (o.opacity !== undefined && o.opacity !== 1) { spec.opacity = o.opacity; }
503
+ if (o.tms || /\{-y\}/.test(this._url)) { spec.scheme = 'tms'; }
504
+ if (o.minZoom) { spec.minzoom = Math.max(0, o.minZoom - 1); }
505
+ if (o.maxNativeZoom !== undefined || o.maxZoom !== undefined) { spec.maxzoom = o.maxNativeZoom !== undefined ? o.maxNativeZoom : o.maxZoom; }
506
+ smap.addRasterLayer(id, spec);
507
+ }
508
+ }
509
+
510
+ /** OGC WMS (`L.tileLayer.wms`) on the sMap map. */
511
+ export class WmsLayer extends TileLayer {
512
+ constructor(url, options) { super(url, Object.assign({ layers: '', styles: '', format: 'image/jpeg', transparent: false, version: '1.1.1' }, options || {})); }
513
+ setParams(params) { Object.assign(this.options, params); this._rev += 1; this._changed(); return this; }
514
+ _drawSelf(smap, id) {
515
+ if (typeof smap.addWmsLayer !== 'function') { throw new Error('sMap: tileLayer.wms needs @superrouteca/smap 1.1.0 (addWmsLayer)'); }
516
+ const o = this.options;
517
+ const spec = { url: this._url, layers: o.layers, styles: o.styles, format: o.format, transparent: o.transparent, version: o.version };
518
+ if (o.attribution) { spec.attribution = o.attribution; }
519
+ smap.addWmsLayer(id, spec);
520
+ }
521
+ }
522
+
523
+ /** Layers held and drawn together (`L.layerGroup`, `L.featureGroup`, `L.geoJSON`). */
524
+ export class LayerGroup extends Layer {
525
+ constructor(layers, options) {
526
+ super(options);
527
+ this._layers = [];
528
+ (layers || []).forEach(function (l) { this.addLayer(l); }, this);
529
+ }
530
+ addLayer(layer) {
531
+ if (layer._host === this) { return this; }
532
+ if (layer._host) { layer._host.removeLayer(layer); }
533
+ layer._host = this;
534
+ this._layers.push(layer);
535
+ if (this._eventsUp) { layer.addEventParent(this); }
536
+ this._changed();
537
+ return this;
538
+ }
539
+ removeLayer(layer) {
540
+ if (typeof layer === 'number') { layer = this.getLayer(layer); }
541
+ if (!layer || layer._host !== this) { return this; }
542
+ layer._host = null;
543
+ layer.removeEventParent(this);
544
+ this._layers = this._layers.filter(function (l) { return l !== layer; });
545
+ this._changed();
546
+ return this;
547
+ }
548
+ hasLayer(layer) { return this._layers.indexOf(layer) >= 0; }
549
+ clearLayers() { this._layers.slice().forEach(function (l) { this.removeLayer(l); }, this); return this; }
550
+ eachLayer(fn, ctx) { this._layers.forEach(function (l) { fn.call(ctx, l); }); return this; }
551
+ getLayers() { return this._layers.slice(); }
552
+ getLayer(id) { return this._layers.find(function (l) { return l._leaflet_id === id; }) || null; }
553
+ getLayerId(layer) { return layer._leaflet_id; }
554
+ setStyle(style) { this._layers.forEach(function (l) { if (l.setStyle) { l.setStyle(style); } }); return this; }
555
+ invoke(name) { const args = Array.prototype.slice.call(arguments, 1); this._layers.forEach(function (l) { if (typeof l[name] === 'function') { l[name].apply(l, args); } }); return this; }
556
+ _specs() { return this._layers.reduce(function (a, l) { return a.concat(l._specs()); }, []); }
557
+ _childChanged() { this._changed(); }
558
+ }
559
+
560
+ /** A layer group whose layers' events reach it (as Leaflet's FeatureGroup). */
561
+ export class FeatureGroup extends LayerGroup {
562
+ constructor(layers, options) { super([], options); this._eventsUp = true; (layers || []).forEach(function (l) { this.addLayer(l); }, this); }
563
+ bringToFront() { return Layer.prototype.bringToFront.call(this); }
564
+ }
565
+
566
+ function asFeatures(data) {
567
+ if (!data) { return []; }
568
+ if (Array.isArray(data)) { return data.reduce(function (a, d) { return a.concat(asFeatures(d)); }, []); }
569
+ if (data.type === 'FeatureCollection') { return data.features || []; }
570
+ if (data.type === 'Feature') { return [data]; }
571
+ if (data.type) { return [{ type: 'Feature', properties: {}, geometry: data }]; }
572
+ return [];
573
+ }
574
+
575
+ function swap(c) { return [c[1], c[0]]; }
576
+
577
+ /** `L.geoJSON(data, { style, pointToLayer, onEachFeature, filter })` on the sMap map. */
578
+ export class GeoJSON extends FeatureGroup {
579
+ constructor(data, options) {
580
+ super([], options);
581
+ if (data) { this.addData(data); }
582
+ }
583
+ addData(data) {
584
+ const o = this.options;
585
+ asFeatures(data).forEach(function (f) {
586
+ if (!f || !f.geometry) { return; }
587
+ if (o.filter && !o.filter(f)) { return; }
588
+ const layer = this._layerFor(f);
589
+ if (!layer) { return; }
590
+ layer.feature = f;
591
+ layer.defaultOptions = Object.assign({}, layer.options);
592
+ this._restyle(layer);
593
+ if (o.onEachFeature) { o.onEachFeature(f, layer); }
594
+ this.addLayer(layer);
595
+ }, this);
596
+ return this;
597
+ }
598
+ resetStyle(layer) {
599
+ const layers = layer ? [layer] : this._layers;
600
+ layers.forEach(function (l) { if (l.defaultOptions) { l.options = Object.assign({}, l.defaultOptions); this._restyle(l); l._changed(); } }, this);
601
+ return this;
602
+ }
603
+ setStyle(style) { this.options.style = style; this._layers.forEach(function (l) { this._restyle(l); l._changed(); }, this); return this; }
604
+ _restyle(layer) {
605
+ const s = this.options.style;
606
+ if (!s || layer instanceof Marker) { return; }
607
+ Object.assign(layer.options, typeof s === 'function' ? s(layer.feature) : s);
608
+ }
609
+ _layerFor(f) {
610
+ const g = f.geometry;
611
+ const o = this.options;
612
+ const coordsToLatLng = o.coordsToLatLng || swap;
613
+ switch (g.type) {
614
+ case 'Point': {
615
+ const ll = coordsToLatLng(g.coordinates);
616
+ return o.pointToLayer ? o.pointToLayer(f, toLatLng(ll)) : new Marker(ll, o.markersInheritOptions ? o : {});
617
+ }
618
+ case 'MultiPoint': {
619
+ const group = new FeatureGroup();
620
+ g.coordinates.forEach(function (c) {
621
+ const ll = coordsToLatLng(c);
622
+ group.addLayer(o.pointToLayer ? o.pointToLayer(f, toLatLng(ll)) : new Marker(ll));
623
+ });
624
+ return group;
625
+ }
626
+ case 'LineString': return new Polyline(g.coordinates.map(coordsToLatLng));
627
+ case 'MultiLineString': return new Polyline(g.coordinates.map(function (l) { return l.map(coordsToLatLng); }));
628
+ case 'Polygon': return new Polygon(g.coordinates.map(function (r) { return r.map(coordsToLatLng); }));
629
+ case 'MultiPolygon': return new Polygon(g.coordinates.map(function (p) { return p.map(function (r) { return r.map(coordsToLatLng); }); }));
630
+ case 'GeometryCollection': {
631
+ const group = new FeatureGroup();
632
+ g.geometries.forEach(function (x) {
633
+ const child = this._layerFor({ type: 'Feature', properties: f.properties, geometry: x });
634
+ if (child) { child.feature = f; this._restyle(child); group.addLayer(child); }
635
+ }, this);
636
+ return group;
637
+ }
638
+ default: return null;
639
+ }
640
+ }
641
+ }
642
+
643
+ // ------------------------------------------------------------------ the map
644
+
645
+ /** A Leaflet-style map over an sMap map (zoom levels as Leaflet counts them: one above the sMap map's). */
646
+ export class CompatMap extends Evented {
647
+ constructor(smap) {
648
+ super();
649
+ this.smap = smap;
650
+ this._layers = [];
651
+ this._wrapped = [];
652
+ }
653
+ get engine() { return this.smap.engine; }
654
+ addLayer(layer) {
655
+ if (layer._host === this) { return this; }
656
+ if (layer._host) { layer._host.removeLayer(layer); }
657
+ layer._host = this;
658
+ this._layers.push(layer);
659
+ this._drawLayer(layer);
660
+ layer.fire('add');
661
+ this.fire('layeradd', { layer: layer });
662
+ return this;
663
+ }
664
+ removeLayer(layer) {
665
+ if (layer._host !== this) { return this; }
666
+ layer._host = null;
667
+ this._layers = this._layers.filter(function (l) { return l !== layer; });
668
+ this._eraseLayer(layer);
669
+ layer.fire('remove');
670
+ this.fire('layerremove', { layer: layer });
671
+ return this;
672
+ }
673
+ hasLayer(layer) { return layer._host === this; }
674
+ eachLayer(fn, ctx) { this._layers.forEach(function (l) { fn.call(ctx, l); }); return this; }
675
+ // Each layer added to the map is drawn on its own, in the order added (a later layer is on top, as in Leaflet).
676
+ _drawLayer(layer) {
677
+ const smap = this.smap;
678
+ const parts = leaves([layer], null);
679
+ layer.__tiles = layer.__tiles || {};
680
+ const keep = {};
681
+ parts.tiles.forEach(function (t) {
682
+ const id = 'leaflet-' + t._leaflet_id;
683
+ keep[id] = t._rev;
684
+ if (layer.__tiles[id] === t._rev) { return; }
685
+ if (layer.__tiles[id] !== undefined) { smap.removeLayer(id); }
686
+ t._drawSelf(smap, id);
687
+ });
688
+ Object.keys(layer.__tiles).forEach(function (id) { if (keep[id] === undefined) { smap.removeLayer(id); } });
689
+ layer.__tiles = keep;
690
+ if (!layer.__drawing) { layer.__drawing = new Drawing('leaflet-' + layer._leaflet_id); }
691
+ layer.__drawing.draw(smap, parts.vectors);
692
+ }
693
+ _eraseLayer(layer) {
694
+ const smap = this.smap;
695
+ Object.keys(layer.__tiles || {}).forEach(function (id) { smap.removeLayer(id); });
696
+ layer.__tiles = {};
697
+ if (layer.__drawing) { layer.__drawing.erase(smap); }
698
+ }
699
+ _childChanged(layer) { if (layer._host === this) { this._drawLayer(layer); } }
700
+ // Camera
701
+ getCenter() { const c = this.smap.engine.getCenter(); return { lat: c.lat, lng: c.lng }; }
702
+ getZoom() { return this.smap.engine.getZoom() + 1; }
703
+ getBounds() { const b = this.smap.engine.getBounds(); return latLngBounds([[b.getSouth(), b.getWest()], [b.getNorth(), b.getEast()]]); }
704
+ getMinZoom() { return this.smap.engine.getMinZoom() + 1; }
705
+ getMaxZoom() { return this.smap.engine.getMaxZoom() + 1; }
706
+ setView(center, zoom, options) {
707
+ const ll = toLatLng(center);
708
+ const cam = { center: [ll.lng, ll.lat] };
709
+ if (zoom !== undefined) { cam.zoom = zoom - 1; }
710
+ const animate = options && options.animate;
711
+ this.smap.engine[animate ? 'easeTo' : 'jumpTo'](animate ? Object.assign(cam, { duration: ((options && options.duration) || 0.25) * 1000 }) : cam);
712
+ return this;
713
+ }
714
+ setZoom(zoom, options) { return this.setView(this.getCenter(), zoom, options); }
715
+ zoomIn(delta, options) { return this.setZoom(this.getZoom() + (delta || 1), options); }
716
+ zoomOut(delta, options) { return this.setZoom(this.getZoom() - (delta || 1), options); }
717
+ panTo(center, options) { return this.setView(center, undefined, Object.assign({ animate: true }, options)); }
718
+ panBy(offset, options) { this.smap.engine.panBy(Array.isArray(offset) ? offset : [offset.x, offset.y], options && options.animate === false ? { duration: 0 } : {}); return this; }
719
+ flyTo(center, zoom, options) {
720
+ const ll = toLatLng(center);
721
+ const cam = { center: [ll.lng, ll.lat] };
722
+ if (zoom !== undefined) { cam.zoom = zoom - 1; }
723
+ if (options && options.duration !== undefined) { cam.duration = options.duration * 1000; }
724
+ this.smap.flyTo(cam);
725
+ return this;
726
+ }
727
+ fitBounds(bounds, options) {
728
+ const b = latLngBounds(bounds);
729
+ if (!b.isValid()) { return this; }
730
+ const o = options || {};
731
+ const fit = {};
732
+ if (o.padding) { const p = Array.isArray(o.padding) ? o.padding : [o.padding.x, o.padding.y]; fit.padding = { left: p[0], right: p[0], top: p[1], bottom: p[1] }; }
733
+ if (o.paddingTopLeft || o.paddingBottomRight) {
734
+ const tl = o.paddingTopLeft || [0, 0];
735
+ const br = o.paddingBottomRight || [0, 0];
736
+ fit.padding = { left: tl[0], top: tl[1], right: br[0], bottom: br[1] };
737
+ }
738
+ if (o.maxZoom !== undefined) { fit.maxZoom = o.maxZoom - 1; }
739
+ if (o.animate === false) { fit.duration = 0; }
740
+ this.smap.engine.fitBounds(b.toLngLatArray(), fit);
741
+ return this;
742
+ }
743
+ flyToBounds(bounds, options) { return this.fitBounds(bounds, options); }
744
+ invalidateSize() { this.smap.engine.resize(); return this; }
745
+ getContainer() { return this.smap.engine.getContainer(); }
746
+ getSize() { const c = this.smap.engine.getContainer(); return { x: c.clientWidth, y: c.clientHeight }; }
747
+ project(latlng) { const ll = toLatLng(latlng); return this.smap.engine.project([ll.lng, ll.lat]); }
748
+ unproject(point) { const p = Array.isArray(point) ? point : [point.x, point.y]; const c = this.smap.engine.unproject(p); return { lat: c.lat, lng: c.lng }; }
749
+ latLngToContainerPoint(latlng) { return this.project(latlng); }
750
+ containerPointToLatLng(point) { return this.unproject(point); }
751
+ openPopup(content, latlng, options) {
752
+ if (content instanceof Popup) { content.openOn(this); return this; }
753
+ const ll = toLatLng(latlng);
754
+ this.smap.openPopup([ll.lng, ll.lat], content, popupOptions(options));
755
+ return this;
756
+ }
757
+ closePopup() { this.smap.closePopup(); return this; }
758
+ remove() { this.smap.remove(); return this; }
759
+ // Events: map mouse events carry `latlng` and `containerPoint` as in Leaflet; the others are the sMap map's own.
760
+ on(types, fn, ctx) {
761
+ if (typeof types === 'object') { return super.on(types, fn); }
762
+ const self = this;
763
+ String(types).split(/\s+/).forEach(function (type) {
764
+ const engineType = type;
765
+ const wrapped = function (e) {
766
+ const out = { type: type, target: self, originalEvent: e && e.originalEvent };
767
+ if (e && e.lngLat) { out.latlng = { lat: e.lngLat.lat, lng: e.lngLat.lng }; }
768
+ if (e && e.point) { out.containerPoint = { x: e.point.x, y: e.point.y }; }
769
+ fn.call(ctx || self, out);
770
+ };
771
+ self._wrapped.push({ type: type, fn: fn, ctx: ctx, wrapped: wrapped, engineType: engineType });
772
+ self.smap.engine.on(engineType, wrapped);
773
+ });
774
+ return this;
775
+ }
776
+ off(types, fn, ctx) {
777
+ const self = this;
778
+ String(types || '').split(/\s+/).forEach(function (type) {
779
+ self._wrapped = self._wrapped.filter(function (w) {
780
+ if (w.type !== type || (fn && w.fn !== fn) || (ctx !== undefined && w.ctx !== ctx)) { return true; }
781
+ self.smap.engine.off(w.engineType, w.wrapped);
782
+ return false;
783
+ });
784
+ });
785
+ return this;
786
+ }
787
+ }
788
+
789
+ /** `L.popup()`: a popup opened at a position on the map. */
790
+ export class Popup {
791
+ constructor(options, source) { this.options = options || {}; this._source = source; this._latlng = null; this._content = null; }
792
+ setLatLng(latlng) { this._latlng = toLatLng(latlng); return this; }
793
+ getLatLng() { return this._latlng; }
794
+ setContent(content) { this._content = content; return this; }
795
+ getContent() { return this._content; }
796
+ openOn(map) {
797
+ const m = map instanceof CompatMap ? map : hostOf(map);
798
+ m.smap.openPopup([this._latlng.lng, this._latlng.lat], popupContent(this._content, this._source), popupOptions(this.options));
799
+ this._map = m;
800
+ return this;
801
+ }
802
+ close() { if (this._map) { this._map.smap.closePopup(); } return this; }
803
+ remove() { return this.close(); }
804
+ }
805
+
806
+ /** `L.icon({ iconUrl, iconSize, iconAnchor })`. */
807
+ export class Icon { constructor(options) { this.options = Object.assign({}, options || {}); } }
808
+ /** `L.divIcon()`: kept for the call to work; an sMap map draws the default pin for it. */
809
+ export class DivIcon extends Icon {}
810
+
811
+ /**
812
+ * Leaflet-style calls on an sMap map: `L.map` is the map, `L.marker`, `L.circleMarker`, `L.circle`, `L.polyline`,
813
+ * `L.polygon`, `L.rectangle`, `L.geoJSON`, `L.tileLayer` (and `L.tileLayer.wms`), `L.layerGroup`, `L.featureGroup`,
814
+ * `L.popup`, `L.icon`, `L.latLng`, `L.latLngBounds`.
815
+ */
816
+ export function createLeafletCompat(smap) {
817
+ if (!smap || !smap.engine) { throw new Error('sMap: createLeafletCompat() takes an sMap map once it is ready (await map.ready)'); }
818
+ if (smap.__leafletCompat) { return smap.__leafletCompat; }
819
+ const map = new CompatMap(smap);
820
+ const tileLayer = function (url, options) { return new TileLayer(url, options); };
821
+ tileLayer.wms = function (url, options) { return new WmsLayer(url, options); };
822
+ const ns = {
823
+ version: '1.1.0',
824
+ map: map,
825
+ marker: function (ll, o) { return new Marker(ll, o); },
826
+ circleMarker: function (ll, o) { return new CircleMarker(ll, o); },
827
+ circle: function (ll, o) { return new Circle(ll, o); },
828
+ polyline: function (lls, o) { return new Polyline(lls, o); },
829
+ polygon: function (lls, o) { return new Polygon(lls, o); },
830
+ rectangle: function (b, o) { return new Rectangle(b, o); },
831
+ geoJSON: function (d, o) { return new GeoJSON(d, o); },
832
+ geoJson: function (d, o) { return new GeoJSON(d, o); },
833
+ tileLayer: tileLayer,
834
+ layerGroup: function (l, o) { return new LayerGroup(l, o); },
835
+ featureGroup: function (l, o) { return new FeatureGroup(l, o); },
836
+ popup: function (o, s) { return new Popup(o, s); },
837
+ icon: function (o) { return new Icon(o); },
838
+ divIcon: function (o) { return new DivIcon(o); },
839
+ latLng: function (a, b) { return b !== undefined ? { lat: +a, lng: +b } : toLatLng(a); },
840
+ latLngBounds: latLngBounds,
841
+ Marker, CircleMarker, Circle, Polyline, Polygon, Rectangle, GeoJSON, TileLayer, LayerGroup, FeatureGroup, Popup, Icon, DivIcon,
842
+ };
843
+ Object.defineProperty(smap, '__leafletCompat', { value: ns, enumerable: false, configurable: true });
844
+ return ns;
845
+ }
846
+
847
+ export default createLeafletCompat;