smap-leaflet 0.0.0-stage → 2.6.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.
@@ -0,0 +1,2381 @@
1
+ import * as o from "leaflet";
2
+ import "proj4";
3
+ import "proj4leaflet";
4
+ const _ = o;
5
+ _.Proj && (o.CRS.Baidu = new _.Proj.CRS(
6
+ "EPSG:900913",
7
+ "+proj=merc +a=6378206 +b=6356584.314245179 +lat_ts=0.0 +lon_0=0.0 +x_0=0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs",
8
+ {
9
+ resolutions: (() => {
10
+ const t = [];
11
+ t[0] = Math.pow(2, 18);
12
+ for (let e = 1; e < 19; e++)
13
+ t[e] = Math.pow(2, 18 - e);
14
+ return t;
15
+ })(),
16
+ origin: [0, 0],
17
+ bounds: o.bounds([20037508342789244e-9, 0], [0, 20037508342789244e-9])
18
+ }
19
+ ));
20
+ const N = {
21
+ TianDiTu: {
22
+ Normal: {
23
+ Map: "https://t{s}.tianditu.gov.cn/DataServer?T=vec_w&X={x}&Y={y}&L={z}&tk={key}",
24
+ Annotion: "https://t{s}.tianditu.gov.cn/DataServer?T=cva_w&X={x}&Y={y}&L={z}&tk={key}"
25
+ },
26
+ Satellite: {
27
+ Map: "https://t{s}.tianditu.gov.cn/DataServer?T=img_w&X={x}&Y={y}&L={z}&tk={key}",
28
+ Annotion: "https://t{s}.tianditu.gov.cn/DataServer?T=cia_w&X={x}&Y={y}&L={z}&tk={key}"
29
+ },
30
+ Terrain: {
31
+ Map: "https://t{s}.tianditu.gov.cn/DataServer?T=ter_w&X={x}&Y={y}&L={z}&tk={key}",
32
+ Annotion: "https://t{s}.tianditu.gov.cn/DataServer?T=cta_w&X={x}&Y={y}&L={z}&tk={key}"
33
+ },
34
+ Subdomains: ["0", "1", "2", "3", "4", "5", "6", "7"]
35
+ },
36
+ GaoDe: {
37
+ Normal: {
38
+ Map: "https://webrd0{s}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}"
39
+ },
40
+ Satellite: {
41
+ Map: "https://webst0{s}.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}",
42
+ Annotion: "https://webst0{s}.is.autonavi.com/appmaptile?style=8&x={x}&y={y}&z={z}"
43
+ },
44
+ Brief: {
45
+ Map: "https://webrd0{s}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=7&x={x}&y={y}&z={z}"
46
+ },
47
+ Subdomains: ["1", "2", "3", "4"]
48
+ },
49
+ Google: {
50
+ Normal: {
51
+ Map: "https://www.google.cn/maps/vt?lyrs=m@189&gl=cn&x={x}&y={y}&z={z}"
52
+ },
53
+ Satellite: {
54
+ Map: "https://www.google.cn/maps/vt?lyrs=s@189&gl=cn&x={x}&y={y}&z={z}",
55
+ Annotion: "https://www.google.cn/maps/vt?lyrs=y@189&gl=cn&x={x}&y={y}&z={z}"
56
+ },
57
+ Subdomains: []
58
+ },
59
+ Geoq: {
60
+ Normal: {
61
+ Map: "https://map.geoq.cn/ArcGIS/rest/services/ChinaOnlineCommunity/MapServer/tile/{z}/{y}/{x}",
62
+ PurplishBlue: "https://map.geoq.cn/ArcGIS/rest/services/ChinaOnlineStreetPurplishBlue/MapServer/tile/{z}/{y}/{x}",
63
+ Gray: "https://map.geoq.cn/ArcGIS/rest/services/ChinaOnlineStreetGray/MapServer/tile/{z}/{y}/{x}",
64
+ Warm: "https://map.geoq.cn/ArcGIS/rest/services/ChinaOnlineStreetWarm/MapServer/tile/{z}/{y}/{x}"
65
+ },
66
+ Theme: {
67
+ Hydro: "https://thematic.geoq.cn/arcgis/rest/services/ThematicMaps/WorldHydroMap/MapServer/tile/{z}/{y}/{x}"
68
+ },
69
+ Subdomains: []
70
+ },
71
+ OSM: {
72
+ Normal: {
73
+ Map: "https://{s}.tile.osm.org/{z}/{x}/{y}.png"
74
+ },
75
+ Subdomains: ["a", "b", "c"]
76
+ },
77
+ Baidu: {
78
+ Normal: {
79
+ Map: "https://online{s}.map.bdimg.com/onlinelabel/?qt=tile&x={x}&y={y}&z={z}&styles=pl&scaler=1&p=1"
80
+ },
81
+ Satellite: {
82
+ Map: "https://shangetu{s}.map.bdimg.com/it/u=x={x};y={y};z={z};v=009;type=sate&fm=46",
83
+ Annotion: "https://online{s}.map.bdimg.com/tile/?qt=tile&x={x}&y={y}&z={z}&styles=sl&v=020"
84
+ },
85
+ Subdomains: "0123456789".split(""),
86
+ tms: !0
87
+ },
88
+ BaiduV3: {
89
+ Normal: {
90
+ Map: "https://maponline{s}.bdimg.com/tile/?qt=vtile&x={x}&y={y}&z={z}&styles=pl&scaler=2&udt=&from=jsapi3_0"
91
+ },
92
+ Subdomains: "012".split(""),
93
+ tms: !0
94
+ },
95
+ Tencent: {
96
+ Normal: {
97
+ Map: "https://rt{s}.map.gtimg.com/tile?z={z}&x={x}&y={-y}&type=vector&styleid=3"
98
+ },
99
+ Satellite: {
100
+ Map: "https://p{s}.map.gtimg.com/sateTiles/{z}/{sx}/{sy}/{x}_{-y}.jpg"
101
+ },
102
+ Terrain: {
103
+ Map: "https://p{s}.map.gtimg.com/demTiles/{z}/{sx}/{sy}/{x}_{-y}.jpg"
104
+ },
105
+ Subdomains: "0123".split("")
106
+ },
107
+ Mapbox: {
108
+ Satellite: {
109
+ Map: "https://api.mapbox.com/v4/mapbox.satellite/{z}/{x}/{y}.webp?access_token={key}"
110
+ },
111
+ Subdomains: ["0"]
112
+ }
113
+ }, P = {
114
+ GaoDe: "gcj02",
115
+ Geoq: "gcj02",
116
+ Google: "gcj02",
117
+ Tencent: "gcj02",
118
+ Baidu: "bd09",
119
+ BaiduV3: "bd09"
120
+ };
121
+ function mt(i) {
122
+ return P[i] || "wgs84";
123
+ }
124
+ const ye = [
125
+ "TianDiTu.Normal.Map",
126
+ "TianDiTu.Normal.Annotion",
127
+ "TianDiTu.Satellite.Map",
128
+ "TianDiTu.Satellite.Annotion",
129
+ "TianDiTu.Terrain.Map",
130
+ "TianDiTu.Terrain.Annotion",
131
+ "GaoDe.Normal.Map",
132
+ "GaoDe.Satellite.Map",
133
+ "GaoDe.Satellite.Annotion",
134
+ "GaoDe.Brief.Map",
135
+ "Google.Normal.Map",
136
+ "Google.Satellite.Map",
137
+ "Google.Satellite.Annotion",
138
+ "Geoq.Normal.Map",
139
+ "Geoq.Normal.PurplishBlue",
140
+ "Geoq.Normal.Gray",
141
+ "Geoq.Normal.Warm",
142
+ "Geoq.Theme.Hydro",
143
+ "OSM.Normal.Map",
144
+ "Baidu.Normal.Map",
145
+ "Baidu.Satellite.Map",
146
+ "Baidu.Satellite.Annotion",
147
+ "BaiduV3.Normal.Map",
148
+ "Tencent.Normal.Map",
149
+ "Tencent.Satellite.Map",
150
+ "Tencent.Terrain.Map",
151
+ "Mapbox.Satellite.Map"
152
+ ], Y = ["Subdomains", "tms", "key"];
153
+ function ve(i, t) {
154
+ if (!i || i.includes("."))
155
+ throw new Error(`Invalid tile provider name: "${i}"`);
156
+ for (const e of Object.keys(t.layers))
157
+ if (e.includes(".") || Y.includes(e))
158
+ throw new Error(`Invalid tile group name: "${e}"`);
159
+ N[i] = {
160
+ ...t.layers,
161
+ Subdomains: t.subdomains ?? [],
162
+ ...t.tms ? { tms: !0 } : {},
163
+ ...t.key ? { key: t.key } : {}
164
+ }, t.coordType && t.coordType !== "wgs84" ? P[i] = t.coordType : delete P[i];
165
+ }
166
+ function we() {
167
+ const i = [];
168
+ for (const [t, e] of Object.entries(N))
169
+ for (const [s, r] of Object.entries(e))
170
+ if (!(Y.includes(s) || typeof r != "object" || !r))
171
+ for (const n of Object.keys(r))
172
+ i.push(`${t}.${s}.${n}`);
173
+ return i;
174
+ }
175
+ function R(i, t = {}) {
176
+ var d;
177
+ const e = i.split("."), s = e[0], r = e[1], n = e[2], a = N[s];
178
+ if (!((d = a == null ? void 0 : a[r]) != null && d[n]))
179
+ throw new Error(`Unknown tile provider: ${i}`);
180
+ const l = a[r][n], h = {
181
+ subdomains: a.Subdomains || [],
182
+ ...t,
183
+ key: t.key || a.key || "",
184
+ corrdType: mt(s)
185
+ };
186
+ a.tms && (h.tms = !0);
187
+ const c = o.TileLayer.extend({
188
+ getTileUrl(p) {
189
+ const g = {
190
+ s: this._getSubdomain(p),
191
+ x: p.x,
192
+ y: p.y,
193
+ z: this._getZoomForUrl()
194
+ };
195
+ if (this._map && !this._map.options.crs.infinite) {
196
+ const v = this._globalTileRange.max.y - p.y;
197
+ this.options.tms && (g.y = v), g["-y"] = v;
198
+ }
199
+ return g.sx = g.x >> 4, g.sy = (1 << g.z) - g.y >> 4, o.Util.template(this._url, o.Util.extend(g, this.options));
200
+ }
201
+ });
202
+ return new c(l, h);
203
+ }
204
+ const f = 3.141592653589793, U = 6378245, j = 0.006693421622965943, x = f * 3e3 / 180;
205
+ function gt(i, t) {
206
+ let e = -100 + 2 * i + 3 * t + 0.2 * t * t + 0.1 * i * t + 0.2 * Math.sqrt(Math.abs(i));
207
+ return e += (20 * Math.sin(6 * i * f) + 20 * Math.sin(2 * i * f)) * 2 / 3, e += (20 * Math.sin(t * f) + 40 * Math.sin(t / 3 * f)) * 2 / 3, e += (160 * Math.sin(t / 12 * f) + 320 * Math.sin(t * f / 30)) * 2 / 3, e;
208
+ }
209
+ function ft(i, t) {
210
+ let e = 300 + i + 2 * t + 0.1 * i * i + 0.1 * i * t + 0.1 * Math.sqrt(Math.abs(i));
211
+ return e += (20 * Math.sin(6 * i * f) + 20 * Math.sin(2 * i * f)) * 2 / 3, e += (20 * Math.sin(i * f) + 40 * Math.sin(i / 3 * f)) * 2 / 3, e += (150 * Math.sin(i / 12 * f) + 300 * Math.sin(i / 30 * f)) * 2 / 3, e;
212
+ }
213
+ function X(i, t) {
214
+ return t < 72.004 || t > 137.8347 || i < 0.8293 || i > 55.8271;
215
+ }
216
+ function Q(i, t) {
217
+ let e = gt(i - 105, t - 35), s = ft(i - 105, t - 35);
218
+ const r = t / 180 * f;
219
+ let n = Math.sin(r);
220
+ n = 1 - j * n * n;
221
+ const a = Math.sqrt(n);
222
+ return e = e * 180 / (U * (1 - j) / (n * a) * f), s = s * 180 / (U / a * Math.cos(r) * f), { lat: t + e, lng: i + s };
223
+ }
224
+ function C(i, t) {
225
+ return X(t, i) ? { lng: i, lat: t } : Q(i, t);
226
+ }
227
+ function tt(i, t) {
228
+ if (X(t, i)) return { lng: i, lat: t };
229
+ const e = Q(i, t);
230
+ return { lng: i * 2 - e.lng, lat: t * 2 - e.lat };
231
+ }
232
+ function et(i, t) {
233
+ const e = Math.sqrt(i * i + t * t) + 2e-5 * Math.sin(t * x), s = Math.atan2(t, i) + 3e-6 * Math.cos(i * x);
234
+ return { lng: e * Math.cos(s) + 65e-4, lat: e * Math.sin(s) + 6e-3 };
235
+ }
236
+ function st(i, t) {
237
+ const e = i - 65e-4, s = t - 6e-3, r = Math.sqrt(e * e + s * s) - 2e-5 * Math.sin(s * x), n = Math.atan2(s, e) - 3e-6 * Math.cos(e * x);
238
+ return { lng: r * Math.cos(n), lat: r * Math.sin(n) };
239
+ }
240
+ function A(i, t) {
241
+ const e = C(i, t);
242
+ return et(e.lng, e.lat);
243
+ }
244
+ function yt(i, t) {
245
+ const e = st(i, t);
246
+ return tt(e.lng, e.lat);
247
+ }
248
+ const vt = {
249
+ "wgs84>gcj02": C,
250
+ "gcj02>wgs84": tt,
251
+ "gcj02>bd09": et,
252
+ "bd09>gcj02": st,
253
+ "wgs84>bd09": A,
254
+ "bd09>wgs84": yt
255
+ };
256
+ function wt(i, t, e, s) {
257
+ if (e === s) return { lng: i, lat: t };
258
+ const r = vt[`${e}>${s}`];
259
+ if (!r)
260
+ throw new Error(`Unsupported coordinate conversion: ${e} → ${s}`);
261
+ return r(i, t);
262
+ }
263
+ function be(i, t, e) {
264
+ const s = JSON.parse(JSON.stringify(i));
265
+ if (t === e) return s;
266
+ const r = (a) => {
267
+ if (!Array.isArray(a)) return a;
268
+ if (typeof a[0] == "number") {
269
+ const { lng: l, lat: h } = wt(a[0], a[1], t, e);
270
+ return [l, h, ...a.slice(2)];
271
+ }
272
+ return a.map(r);
273
+ }, n = (a) => {
274
+ var l, h;
275
+ if (!(!a || typeof a != "object")) {
276
+ switch (a.type) {
277
+ case "FeatureCollection":
278
+ (l = a.features) == null || l.forEach(n);
279
+ break;
280
+ case "Feature":
281
+ n(a.geometry);
282
+ break;
283
+ case "GeometryCollection":
284
+ (h = a.geometries) == null || h.forEach(n);
285
+ break;
286
+ default:
287
+ a.coordinates && (a.coordinates = r(a.coordinates));
288
+ }
289
+ delete a.bbox;
290
+ }
291
+ };
292
+ return n(s), s;
293
+ }
294
+ function bt() {
295
+ const i = o.GridLayer.prototype;
296
+ i._setZoomTransform = function(t, e, s) {
297
+ let r = e;
298
+ r && this.options && (this.options.corrdType === "gcj02" ? r = C(e.lng, e.lat) : this.options.corrdType === "bd09" && (r = A(e.lng, e.lat)));
299
+ const n = this._map.getZoomScale(s, t.zoom), a = t.origin.multiplyBy(n).subtract(this._map._getNewPixelOrigin(r, s)).round();
300
+ o.Browser.any3d ? o.DomUtil.setTransform(t.el, a, n) : o.DomUtil.setPosition(t.el, a);
301
+ }, i._getTiledPixelBounds = function(t) {
302
+ let e = t;
303
+ e && this.options && (this.options.corrdType === "gcj02" ? e = C(t.lng, t.lat) : this.options.corrdType === "bd09" && (e = A(t.lng, t.lat)));
304
+ const s = this._map, r = s._animatingZoom ? Math.max(s._animateToZoom, s.getZoom()) : s.getZoom(), n = s.getZoomScale(r, this._tileZoom), a = s.project(e, this._tileZoom).floor(), l = s.getSize().divideBy(n * 2);
305
+ return new o.Bounds(a.subtract(l), a.add(l));
306
+ };
307
+ }
308
+ function Lt() {
309
+ const i = o.Canvas.prototype, t = i._redraw;
310
+ i._redraw = function() {
311
+ if (!this._ctx) {
312
+ this._redrawRequest = null;
313
+ return;
314
+ }
315
+ t.call(this);
316
+ };
317
+ }
318
+ function z(i) {
319
+ i.dataset.nogap || (i.dataset.nogap = "1", i.style.border = "none");
320
+ }
321
+ function kt(i) {
322
+ i.querySelectorAll(".leaflet-tile").forEach(z);
323
+ }
324
+ function Tt() {
325
+ const i = o.GridLayer.prototype._initTile;
326
+ o.GridLayer.prototype._initTile = function(t) {
327
+ i.call(this, t), t.style.border = "none", t.dataset.nogap = "1";
328
+ };
329
+ }
330
+ function Mt(i) {
331
+ kt(i);
332
+ const t = new MutationObserver((e) => {
333
+ for (const s of e)
334
+ for (const r of s.addedNodes)
335
+ r instanceof HTMLElement && (r.classList.contains("leaflet-tile") ? z(r) : r.querySelectorAll(".leaflet-tile").forEach(z));
336
+ });
337
+ return t.observe(i, { childList: !0, subtree: !0 }), t;
338
+ }
339
+ function xt(i) {
340
+ return i >= 1e4 ? `${Math.round(i / 1e3)}k` : i >= 1e3 ? `${(i / 1e3).toFixed(1)}k` : String(i);
341
+ }
342
+ function Ct(i) {
343
+ const t = i < 10 ? "s" : i < 100 ? "m" : "l", e = { s: 32, m: 38, l: 46 }[t];
344
+ return o.divIcon({
345
+ className: `smap-cluster smap-cluster--${t}`,
346
+ html: `<span>${xt(i)}</span>`,
347
+ iconSize: [e, e]
348
+ });
349
+ }
350
+ class St extends o.FeatureGroup {
351
+ constructor(t, e = {}, s = {}) {
352
+ super(), this.items = [], this.clusterOptions = e, this.canvas = s, this.items = this.index(t);
353
+ }
354
+ /** Replace the data */
355
+ setPoints(t) {
356
+ return this.items = this.index(t), this.refresh(), this;
357
+ }
358
+ /** Bounds of all points, not just the ones currently drawn */
359
+ getBounds() {
360
+ return o.latLngBounds(this.items.map((t) => t.latlng));
361
+ }
362
+ onAdd(t) {
363
+ return super.onAdd(t), t.on("zoomend moveend", this.refresh, this), this.refresh(), this;
364
+ }
365
+ onRemove(t) {
366
+ return t.off("zoomend moveend", this.refresh, this), super.onRemove(t);
367
+ }
368
+ index(t) {
369
+ return t.map((e) => ({ point: e, latlng: o.latLng(e) }));
370
+ }
371
+ refresh() {
372
+ const t = this._map;
373
+ if (!t) return;
374
+ this.clearLayers();
375
+ const e = t.getZoom(), s = this.clusterOptions, r = s.clusterRadius ?? 60, n = e < (s.disableClusteringAtZoom ?? 1 / 0), a = t.getBounds().pad(0.2), l = /* @__PURE__ */ new Map();
376
+ this.items.forEach((h, c) => {
377
+ if (!a.contains(h.latlng)) return;
378
+ let d = `#${c}`;
379
+ if (n) {
380
+ const g = t.project(h.latlng, e);
381
+ d = `${Math.floor(g.x / r)}:${Math.floor(g.y / r)}`;
382
+ }
383
+ let p = l.get(d);
384
+ p || l.set(d, p = { items: [], lat: 0, lng: 0 }), p.items.push(h), p.lat += h.latlng.lat, p.lng += h.latlng.lng;
385
+ });
386
+ for (const h of l.values()) {
387
+ const c = h.items.length;
388
+ this.addLayer(
389
+ c === 1 ? this.pointMarker(h.items[0]) : this.clusterMarker(h, o.latLng(h.lat / c, h.lng / c))
390
+ );
391
+ }
392
+ }
393
+ pointMarker({ point: t, latlng: e }) {
394
+ const { style: s, tooltip: r, onClick: n } = this.clusterOptions, a = o.circleMarker(e, {
395
+ radius: this.clusterOptions.radius ?? 5,
396
+ weight: 1,
397
+ color: "#fff",
398
+ fillColor: "#1f6feb",
399
+ fillOpacity: 0.9,
400
+ interactive: !!(r || n),
401
+ ...typeof s == "function" ? s(t, 0) : s,
402
+ ...this.canvas
403
+ });
404
+ return r && a.bindTooltip(() => r(t)), n && a.on("click", (l) => n(t, l)), a;
405
+ }
406
+ clusterMarker(t, e) {
407
+ const s = o.marker(e, { icon: Ct(t.items.length), keyboard: !1 });
408
+ return s.on("click", (r) => {
409
+ const n = t.items.map((l) => l.point);
410
+ if (this.clusterOptions.onClusterClick) {
411
+ this.clusterOptions.onClusterClick(n, r);
412
+ return;
413
+ }
414
+ const a = this._map;
415
+ a.fitBounds(o.latLngBounds(t.items.map((l) => l.latlng)), {
416
+ padding: [48, 48],
417
+ maxZoom: a.getMaxZoom()
418
+ });
419
+ }), s;
420
+ }
421
+ }
422
+ const Et = [
423
+ [-90, -360],
424
+ [90, -360],
425
+ [90, 360],
426
+ [-90, 360]
427
+ ];
428
+ function Dt(i) {
429
+ const t = [], e = (r) => t.push(r.map(([n, a]) => [a, n])), s = (r) => {
430
+ switch (r == null ? void 0 : r.type) {
431
+ case "FeatureCollection":
432
+ r.features.forEach(s);
433
+ break;
434
+ case "Feature":
435
+ s(r.geometry);
436
+ break;
437
+ case "GeometryCollection":
438
+ r.geometries.forEach(s);
439
+ break;
440
+ case "Polygon":
441
+ e(r.coordinates[0]);
442
+ break;
443
+ case "MultiPolygon":
444
+ r.coordinates.forEach((n) => e(n[0]));
445
+ break;
446
+ }
447
+ };
448
+ return s(i), t;
449
+ }
450
+ class Ot {
451
+ constructor(t) {
452
+ this.registry = /* @__PURE__ */ new Map(), this.ownCanvas = null, this.listeners = [], this.map = t;
453
+ }
454
+ // ============ Registry ============
455
+ /** Be told when a layer is registered, removed, shown or hidden */
456
+ onChange(t) {
457
+ this.listeners.push(t);
458
+ }
459
+ changed() {
460
+ this.listeners.forEach((t) => t());
461
+ }
462
+ /**
463
+ * Put a layer under management and add it to the map.
464
+ * An existing layer with the same id is removed first.
465
+ */
466
+ add(t, e, s = {}) {
467
+ return this.remove(t), this.registry.set(t, e), s.visible !== !1 && e.addTo(this.map), this.changed(), e;
468
+ }
469
+ get(t) {
470
+ return this.registry.get(t);
471
+ }
472
+ has(t) {
473
+ return this.registry.has(t);
474
+ }
475
+ /** Ids of all managed layers, in insertion order */
476
+ ids() {
477
+ return [...this.registry.keys()];
478
+ }
479
+ isVisible(t) {
480
+ const e = this.registry.get(t);
481
+ return !!e && this.map.hasLayer(e);
482
+ }
483
+ /** Show a managed layer. Returns false when the id is unknown */
484
+ show(t) {
485
+ const e = this.registry.get(t);
486
+ return e ? (e.addTo(this.map), this.changed(), !0) : !1;
487
+ }
488
+ /** Hide a managed layer without forgetting it. Returns false when the id is unknown */
489
+ hide(t) {
490
+ const e = this.registry.get(t);
491
+ return e ? (e.remove(), this.changed(), !0) : !1;
492
+ }
493
+ /** Flip (or set) visibility. Returns the resulting visibility */
494
+ toggle(t, e) {
495
+ return e ?? !this.isVisible(t) ? this.show(t) : (this.hide(t), !1);
496
+ }
497
+ /** Remove a managed layer from the map and forget it. Returns false when the id is unknown */
498
+ remove(t) {
499
+ const e = this.registry.get(t);
500
+ return e ? (e.remove(), this.registry.delete(t), this.changed(), !0) : !1;
501
+ }
502
+ /** Remove every managed layer */
503
+ clear() {
504
+ for (const t of this.registry.values())
505
+ t.remove();
506
+ this.registry.clear(), this.changed();
507
+ }
508
+ /** Release everything, including the shared canvas. Called by `smap.destroy()` */
509
+ destroy() {
510
+ var t;
511
+ this.clear(), this.listeners = [], (t = this.ownCanvas) == null || t.remove(), this.ownCanvas = null;
512
+ }
513
+ /**
514
+ * Renderer option for vector layers created here.
515
+ *
516
+ * Everything must end up on ONE canvas: Leaflet stacks a full-size <canvas> per
517
+ * renderer and only the top one receives mouse events, and a renderer is never
518
+ * removed from the map when its layers are. So: reuse the map's own canvas when
519
+ * it has one (`preferCanvas`, the default), otherwise share a single canvas.
520
+ */
521
+ canvas() {
522
+ return this.map.options.preferCanvas ? {} : (this.ownCanvas ?? (this.ownCanvas = o.canvas({ padding: 0.5 })), { renderer: this.ownCanvas });
523
+ }
524
+ place(t, e) {
525
+ return e ? this.add(e, t) : t.addTo(this.map);
526
+ }
527
+ // ============ WFS / GeoJSON ============
528
+ /**
529
+ * Fetch GeoJSON from a GeoServer WFS endpoint
530
+ */
531
+ async loadWFS(t) {
532
+ const e = new URLSearchParams({
533
+ service: "WFS",
534
+ version: "1.1.0",
535
+ request: "GetFeature",
536
+ typeName: t.layer,
537
+ outputFormat: t.outputFormat || "application/json"
538
+ });
539
+ for (const [n, a] of Object.entries(t))
540
+ !["url", "layer", "style", "outputFormat", "id"].includes(n) && a != null && e.set(n, String(a));
541
+ const s = `${t.url}?${e.toString()}`, r = await fetch(s);
542
+ if (!r.ok)
543
+ throw new Error(`WFS request failed: ${r.status} ${r.statusText}`);
544
+ return r.json();
545
+ }
546
+ /**
547
+ * Create a GeoJSON layer from data with optional styling
548
+ */
549
+ createGeoJsonLayer(t, e) {
550
+ return o.geoJSON(t, {
551
+ style: e ? { ...e, ...this.canvas() } : void 0
552
+ });
553
+ }
554
+ /**
555
+ * Load WFS data and add to map as a GeoJSON layer
556
+ */
557
+ async addWFS(t) {
558
+ const e = await this.loadWFS(t);
559
+ return this.place(this.createGeoJsonLayer(e, t.style), t.id);
560
+ }
561
+ // ============ WMS ============
562
+ /**
563
+ * Create a WMS tile layer
564
+ */
565
+ createWMS(t) {
566
+ const { url: e, layer: s, id: r, ...n } = t;
567
+ return o.tileLayer.wms(e, {
568
+ layers: s,
569
+ format: n.format || "image/png",
570
+ transparent: n.transparent !== !1,
571
+ crs: n.crs || o.CRS.EPSG4326,
572
+ ...n
573
+ });
574
+ }
575
+ /**
576
+ * Create a WMS tile layer and add to map
577
+ */
578
+ addWMS(t) {
579
+ return this.place(this.createWMS(t), t.id);
580
+ }
581
+ // ============ Mask ============
582
+ /**
583
+ * Build a mask that dims everything outside the given polygon(s).
584
+ * `getBounds()` of the result is the bounds of the highlighted region.
585
+ */
586
+ createMask(t, e = {}) {
587
+ const s = Dt(t);
588
+ if (!s.length)
589
+ throw new Error("createMask() needs a GeoJSON Polygon or MultiPolygon");
590
+ const n = [o.polygon([Et, ...s], {
591
+ stroke: !1,
592
+ fillColor: e.fillColor ?? "#000",
593
+ fillOpacity: e.fillOpacity ?? 0.5,
594
+ interactive: !1
595
+ })];
596
+ e.outline !== !1 && n.push(
597
+ o.polyline(
598
+ s.map((h) => [...h, h[0]]),
599
+ { color: e.color ?? "#3388ff", weight: e.weight ?? 2, interactive: !1 }
600
+ )
601
+ );
602
+ const a = o.featureGroup(n), l = o.latLngBounds(s.flat());
603
+ return a.getBounds = () => l, a;
604
+ }
605
+ /**
606
+ * Add a mask to the map. By default the view is fitted to the region.
607
+ */
608
+ addMask(t, e = {}) {
609
+ const s = this.createMask(t, e);
610
+ if (e.restrict) {
611
+ const r = this.map.options.maxBounds;
612
+ s.once("remove", () => this.map.setMaxBounds(r)), this.map.setMaxBounds(s.getBounds());
613
+ }
614
+ return this.place(s, e.id), e.fit !== !1 && this.map.fitBounds(s.getBounds()), s;
615
+ }
616
+ // ============ Points ============
617
+ /**
618
+ * Build a layer of many points, drawn on canvas.
619
+ * Suitable for tens of thousands of points, where one marker per point would be too slow.
620
+ */
621
+ createPointLayer(t, e = {}) {
622
+ const s = this.canvas(), { style: r, tooltip: n, onClick: a } = e, l = !!(n || a), h = o.featureGroup();
623
+ return t.forEach((c, d) => {
624
+ const p = o.circleMarker(o.latLng(c), {
625
+ radius: e.radius ?? 4,
626
+ weight: 1,
627
+ color: "#fff",
628
+ fillColor: "#3388ff",
629
+ fillOpacity: 0.9,
630
+ interactive: l,
631
+ ...typeof r == "function" ? r(c, d) : r,
632
+ ...s
633
+ });
634
+ n && p.bindTooltip(() => n(c)), a && p.on("click", (g) => a(c, g)), h.addLayer(p);
635
+ }), h;
636
+ }
637
+ /**
638
+ * Add a layer of many points to the map
639
+ */
640
+ addPoints(t, e = {}) {
641
+ return this.place(this.createPointLayer(t, e), e.id);
642
+ }
643
+ // ============ Clusters ============
644
+ /**
645
+ * Build a layer of points that merge into counted bubbles when zoomed out.
646
+ * Use it when there are too many points to tell apart at low zoom.
647
+ */
648
+ createCluster(t, e = {}) {
649
+ return new St(t, e, this.canvas());
650
+ }
651
+ /**
652
+ * Add a clustered point layer to the map
653
+ */
654
+ addCluster(t, e = {}) {
655
+ return this.place(this.createCluster(t, e), e.id);
656
+ }
657
+ }
658
+ const Pt = (i, t) => i.length === t.length && i.every((e, s) => e === t[s]);
659
+ class At {
660
+ constructor(t, e, s) {
661
+ this.controls = /* @__PURE__ */ new Map(), this.refreshLayers = null, this.refreshOverlays = null, this.map = t, this.host = e, this.layers = s, e == null || e.onTileChange(() => {
662
+ var r;
663
+ return (r = this.refreshLayers) == null ? void 0 : r.call(this);
664
+ }), s == null || s.onChange(() => {
665
+ var r;
666
+ return (r = this.refreshOverlays) == null ? void 0 : r.call(this);
667
+ });
668
+ }
669
+ add(t, e) {
670
+ this.remove(t);
671
+ let s;
672
+ switch (t) {
673
+ case "attribution": {
674
+ const r = o.control.attribution({ prefix: (e == null ? void 0 : e.prefix) ?? "" });
675
+ r.addAttribution(
676
+ (e == null ? void 0 : e.content) ?? 'smap-leaflet &copy; <a href="https://github.com">SMap</a>'
677
+ ), s = r;
678
+ break;
679
+ }
680
+ case "zoom": {
681
+ s = o.control.zoom({
682
+ position: (e == null ? void 0 : e.position) ?? "topright",
683
+ ...e
684
+ });
685
+ break;
686
+ }
687
+ case "scale": {
688
+ s = o.control.scale({
689
+ position: (e == null ? void 0 : e.position) ?? "bottomleft",
690
+ ...e
691
+ });
692
+ break;
693
+ }
694
+ case "layers": {
695
+ s = this.createLayersControl(e);
696
+ break;
697
+ }
698
+ case "overlays": {
699
+ s = this.createOverlaysControl(e ?? {});
700
+ break;
701
+ }
702
+ default:
703
+ throw new Error(`Unknown control type: ${t}`);
704
+ }
705
+ return s.addTo(this.map), this.controls.set(t, s), s;
706
+ }
707
+ /** Base-map switcher: one button per entry, the current one highlighted */
708
+ createLayersControl(t) {
709
+ var n;
710
+ const e = this.host;
711
+ if (!e)
712
+ throw new Error('The "layers" control is only available through smap.control');
713
+ if (!((n = t == null ? void 0 : t.options) != null && n.length))
714
+ throw new Error('The "layers" control needs a non-empty `options` list');
715
+ const s = t.options.map((a) => ({
716
+ label: a.label,
717
+ types: Array.isArray(a.tileType) ? a.tileType : [a.tileType]
718
+ })), r = new o.Control({ position: t.position ?? "topright" });
719
+ return r.onAdd = () => {
720
+ const a = o.DomUtil.create("div", "smap-layers leaflet-bar");
721
+ a.setAttribute("role", "group"), o.DomEvent.disableClickPropagation(a), o.DomEvent.disableScrollPropagation(a);
722
+ const l = s.map((h) => {
723
+ const c = o.DomUtil.create("button", "smap-layers-item", a);
724
+ return c.type = "button", c.textContent = h.label, c.addEventListener("click", () => e.setTileLayer(h.types)), c;
725
+ });
726
+ return this.refreshLayers = () => {
727
+ const h = e.getTileType();
728
+ l.forEach((c, d) => {
729
+ const p = Pt(s[d].types, h);
730
+ c.classList.toggle("is-active", p), c.setAttribute("aria-pressed", String(p));
731
+ });
732
+ }, this.refreshLayers(), a;
733
+ }, r.onRemove = () => {
734
+ this.refreshLayers = null;
735
+ }, r;
736
+ }
737
+ /** Switches for the layers registered in `smap.layer` */
738
+ createOverlaysControl(t) {
739
+ const e = this.layers;
740
+ if (!e)
741
+ throw new Error('The "overlays" control is only available through smap.control');
742
+ const s = new o.Control({ position: t.position ?? "topright" });
743
+ return s.onAdd = () => {
744
+ const r = o.DomUtil.create("div", "smap-overlays leaflet-bar");
745
+ o.DomEvent.disableClickPropagation(r), o.DomEvent.disableScrollPropagation(r), t.title && (o.DomUtil.create("div", "smap-overlays-title", r).textContent = t.title);
746
+ const n = o.DomUtil.create("div", "smap-overlays-list", r);
747
+ return this.refreshOverlays = () => {
748
+ n.textContent = "";
749
+ const a = t.items ?? e.ids().map((l) => ({ id: l, label: l }));
750
+ for (const l of a) {
751
+ const h = o.DomUtil.create("label", "smap-overlays-item", n), c = o.DomUtil.create("input", "", h);
752
+ c.type = "checkbox", c.checked = e.isVisible(l.id), c.disabled = !e.has(l.id), c.addEventListener("change", () => e.toggle(l.id, c.checked)), o.DomUtil.create("span", "", h).textContent = l.label;
753
+ }
754
+ r.classList.toggle("is-empty", !a.length);
755
+ }, this.refreshOverlays(), r;
756
+ }, s.onRemove = () => {
757
+ this.refreshOverlays = null;
758
+ }, s;
759
+ }
760
+ /**
761
+ * Remove a control by type
762
+ */
763
+ remove(t) {
764
+ const e = this.controls.get(t);
765
+ e && (e.remove(), this.controls.delete(t));
766
+ }
767
+ /**
768
+ * Remove all managed controls
769
+ */
770
+ removeAll() {
771
+ for (const [, t] of this.controls)
772
+ t.remove();
773
+ this.controls.clear();
774
+ }
775
+ }
776
+ const k = "https://api.tianditu.gov.cn";
777
+ class zt {
778
+ constructor(t = {}) {
779
+ this.context = t;
780
+ }
781
+ async search(t, e) {
782
+ const s = e ?? t, r = e ? t : this.context.map;
783
+ let { level: n, mapBound: a } = s;
784
+ if (r) {
785
+ const h = r.getBounds();
786
+ n ?? (n = r.getZoom()), a ?? (a = [h.getWest(), h.getSouth(), h.getEast(), h.getNorth()].join(
787
+ ","
788
+ ));
789
+ }
790
+ if (n == null || !a)
791
+ throw new Error("search() needs a map, or both `level` and `mapBound`");
792
+ const l = JSON.stringify({
793
+ level: n,
794
+ mapBound: a,
795
+ queryType: s.queryType ?? 1,
796
+ start: s.start ?? 0,
797
+ count: s.count ?? 10,
798
+ keyWord: s.keyword
799
+ });
800
+ return this.request(`${k}/v2/search`, {
801
+ postStr: l,
802
+ type: "query",
803
+ tk: this.resolveKey(s.tk)
804
+ });
805
+ }
806
+ /**
807
+ * Geocoding: address → coordinates
808
+ */
809
+ async geocode(t) {
810
+ const { tk: e, ...s } = t;
811
+ return this.request(`${k}/geocoder`, {
812
+ ds: JSON.stringify(s),
813
+ tk: this.resolveKey(e)
814
+ });
815
+ }
816
+ /**
817
+ * Reverse geocoding: coordinates → address
818
+ */
819
+ async reverseGeocode(t) {
820
+ const { tk: e, ...s } = t;
821
+ return this.request(`${k}/geocoder`, {
822
+ type: "geocode",
823
+ postStr: JSON.stringify({ ...s, ver: s.ver ?? 1 }),
824
+ tk: this.resolveKey(e)
825
+ });
826
+ }
827
+ /**
828
+ * Administrative district query (TianDiTu v2 API)
829
+ */
830
+ async getAdministrative(t) {
831
+ const e = t.keyword ?? t.searchWord;
832
+ if (!e)
833
+ throw new Error("getAdministrative() needs a `keyword`");
834
+ return this.request(`${k}/v2/administrative`, {
835
+ keyword: e,
836
+ childLevel: String(t.childLevel ?? 0),
837
+ extensions: String(t.extensions ?? !1),
838
+ tk: this.resolveKey(t.tk)
839
+ });
840
+ }
841
+ /**
842
+ * Get location by IP (no key required)
843
+ */
844
+ async getLocationByIp() {
845
+ const t = await fetch("https://map.tianditu.gov.cn/data/getCityName");
846
+ if (!t.ok)
847
+ throw new Error(`IP location request failed: ${t.status}`);
848
+ return t.json();
849
+ }
850
+ resolveKey(t) {
851
+ const e = this.context.key, s = t || (typeof e == "function" ? e() : e);
852
+ if (!s)
853
+ throw new Error("TianDiTu key is missing: pass `tk`, or set `tdtKey` on the map");
854
+ return s;
855
+ }
856
+ async request(t, e) {
857
+ const s = new URLSearchParams(e), r = `${t}?${s.toString()}`, n = await fetch(r);
858
+ if (!n.ok)
859
+ throw new Error(`API request failed: ${n.status} ${n.statusText}`);
860
+ return n.json();
861
+ }
862
+ }
863
+ class Nt {
864
+ constructor(t) {
865
+ this.mapItems = null, this.bound = /* @__PURE__ */ new Map(), this.el = null, this.onPointerDown = (e) => {
866
+ this.el && !this.el.contains(e.target) && this.hide();
867
+ }, this.onKeyDown = (e) => {
868
+ e.key === "Escape" && this.hide();
869
+ }, this.map = t, this.map.on("click movestart zoomstart resize", this.hide, this), document.addEventListener("pointerdown", this.onPointerDown, !0), document.addEventListener("keydown", this.onKeyDown);
870
+ }
871
+ /** Set the menu shown when right-clicking the map itself. Pass null to remove it */
872
+ setItems(t) {
873
+ this.map.off("contextmenu", this.onMapContextMenu, this), this.mapItems = t, t && this.map.on("contextmenu", this.onMapContextMenu, this);
874
+ }
875
+ /** Give a layer its own menu. Returns a function that removes it again */
876
+ bind(t, e) {
877
+ this.unbind(t);
878
+ const s = (r) => {
879
+ var n;
880
+ o.DomEvent.stopPropagation(r), (n = r.originalEvent) == null || n.preventDefault(), this.open(e, { latlng: r.latlng, containerPoint: r.containerPoint, layer: t });
881
+ };
882
+ return t.on("contextmenu", s), this.bound.set(t, s), () => this.unbind(t);
883
+ }
884
+ unbind(t) {
885
+ const e = this.bound.get(t);
886
+ e && (t.off("contextmenu", e), this.bound.delete(t));
887
+ }
888
+ /** Close the menu if it is open */
889
+ hide() {
890
+ var t;
891
+ (t = this.el) == null || t.remove(), this.el = null;
892
+ }
893
+ destroy() {
894
+ this.hide(), this.setItems(null);
895
+ for (const t of [...this.bound.keys()])
896
+ this.unbind(t);
897
+ this.map.off("click movestart zoomstart resize", this.hide, this), document.removeEventListener("pointerdown", this.onPointerDown, !0), document.removeEventListener("keydown", this.onKeyDown);
898
+ }
899
+ onMapContextMenu(t) {
900
+ this.mapItems && this.open(this.mapItems, { latlng: t.latlng, containerPoint: t.containerPoint });
901
+ }
902
+ open(t, e) {
903
+ this.hide();
904
+ const s = { ...e, map: this.map }, r = typeof t == "function" ? t(s) : t;
905
+ if (!r.length) return;
906
+ const n = o.DomUtil.create("div", "smap-contextmenu");
907
+ n.setAttribute("role", "menu"), o.DomEvent.disableClickPropagation(n), o.DomEvent.disableScrollPropagation(n), n.addEventListener("contextmenu", (c) => c.preventDefault()), r.forEach((c) => n.appendChild(this.renderItem(c, s)));
908
+ const a = this.map.getContainer();
909
+ a.appendChild(n), this.el = n;
910
+ const l = Math.max(0, Math.min(e.containerPoint.x, a.clientWidth - n.offsetWidth)), h = Math.max(0, Math.min(e.containerPoint.y, a.clientHeight - n.offsetHeight));
911
+ n.style.left = `${l}px`, n.style.top = `${h}px`;
912
+ }
913
+ renderItem(t, e) {
914
+ if (t === "-") {
915
+ const r = o.DomUtil.create("div", "smap-contextmenu-separator");
916
+ return r.setAttribute("role", "separator"), r;
917
+ }
918
+ const s = o.DomUtil.create("button", "smap-contextmenu-item");
919
+ return s.type = "button", s.setAttribute("role", "menuitem"), s.textContent = t.text, s.disabled = !!t.disabled, t.danger && s.classList.add("is-danger"), s.addEventListener("click", () => {
920
+ var r;
921
+ this.hide(), (r = t.onClick) == null || r.call(t, e);
922
+ }), s;
923
+ }
924
+ }
925
+ const Bt = {
926
+ timeout: 3e3,
927
+ enableHighAccuracy: !1
928
+ };
929
+ function It(i) {
930
+ const { timeout: t, enableHighAccuracy: e } = { ...Bt, ...i };
931
+ return new Promise((s, r) => {
932
+ if (!navigator.geolocation) {
933
+ r(new Error("浏览器不支持 HTML5 定位"));
934
+ return;
935
+ }
936
+ let n = -1;
937
+ n = navigator.geolocation.watchPosition(
938
+ (a) => {
939
+ navigator.geolocation.clearWatch(n);
940
+ const { latitude: l, longitude: h, accuracy: c } = a.coords;
941
+ s({ latitude: l, longitude: h, accuracy: c });
942
+ },
943
+ (a) => {
944
+ navigator.geolocation.clearWatch(n);
945
+ const l = {
946
+ [a.PERMISSION_DENIED]: "定位权限被拒绝",
947
+ [a.POSITION_UNAVAILABLE]: "位置信息不可用",
948
+ [a.TIMEOUT]: "定位超时"
949
+ };
950
+ r(new Error(l[a.code] || "定位未知错误"));
951
+ },
952
+ { enableHighAccuracy: e, timeout: t, maximumAge: 0 }
953
+ );
954
+ });
955
+ }
956
+ function F(i) {
957
+ const t = (e) => new Promise((s, r) => {
958
+ const n = new Image();
959
+ n.crossOrigin = "anonymous", n.onload = () => s(n), n.onerror = () => r(new Error(i)), n.src = e;
960
+ });
961
+ return t(i).catch(
962
+ () => t(`${i}${i.includes("?") ? "&" : "?"}_cors=${Date.now()}`)
963
+ );
964
+ }
965
+ function $t(i) {
966
+ try {
967
+ return new URL(i).host;
968
+ } catch {
969
+ return i;
970
+ }
971
+ }
972
+ const Gt = [".smap-measure-label", ".smap-cluster", ".smap-draw-marker"], _t = ".smap-measure-remove";
973
+ function q(i) {
974
+ return !i || i === "transparent" || /,\s*0\)$|\/\s*0\)$/.test(i);
975
+ }
976
+ function W(i, t, e, s, r, n) {
977
+ const a = Math.max(0, Math.min(n, s / 2, r / 2));
978
+ i.beginPath(), i.moveTo(t + a, e), i.arcTo(t + s, e, t + s, e + r, a), i.arcTo(t + s, e + r, t, e + r, a), i.arcTo(t, e + r, t, e, a), i.arcTo(t, e, t + s, e, a), i.closePath();
979
+ }
980
+ function it(i, t, e) {
981
+ var l;
982
+ const s = getComputedStyle(t);
983
+ if (s.display === "none" || s.visibility === "hidden" || Number(s.opacity) === 0)
984
+ return;
985
+ const r = t.getBoundingClientRect(), n = r.left - e.left, a = r.top - e.top;
986
+ if (r.width > 0 && r.height > 0) {
987
+ const h = s.borderTopLeftRadius, c = h.endsWith("%") ? Math.min(r.width, r.height) * parseFloat(h) / 100 : parseFloat(h) || 0;
988
+ q(s.backgroundColor) || (W(i, n, a, r.width, r.height, c), i.fillStyle = s.backgroundColor, i.fill());
989
+ const d = parseFloat(s.borderTopWidth) || 0;
990
+ d > 0 && s.borderTopStyle !== "none" && !q(s.borderTopColor) && (W(
991
+ i,
992
+ n + d / 2,
993
+ a + d / 2,
994
+ r.width - d,
995
+ r.height - d,
996
+ c - d / 2
997
+ ), i.lineWidth = d, i.strokeStyle = s.borderTopColor, i.stroke());
998
+ }
999
+ for (const h of t.childNodes)
1000
+ if (h.nodeType === Node.TEXT_NODE) {
1001
+ const c = (l = h.textContent) == null ? void 0 : l.trim();
1002
+ if (!c) continue;
1003
+ const d = document.createRange();
1004
+ d.selectNodeContents(h);
1005
+ const p = d.getBoundingClientRect();
1006
+ i.font = `${s.fontStyle} ${s.fontWeight} ${s.fontSize} ${s.fontFamily}`, i.fillStyle = s.color, i.textAlign = "center", i.textBaseline = "middle", i.fillText(
1007
+ c,
1008
+ p.left - e.left + p.width / 2,
1009
+ p.top - e.top + p.height / 2
1010
+ );
1011
+ } else h instanceof Element && !h.matches(_t) && it(i, h, e);
1012
+ }
1013
+ function Rt(i, t) {
1014
+ const e = [];
1015
+ return i.eachLayer((s) => {
1016
+ s instanceof o.GridLayer && s.isLoading() && e.push(new Promise((r) => s.once("load", () => r())));
1017
+ }), e.length ? Promise.race([
1018
+ Promise.all(e).then(() => {
1019
+ }),
1020
+ new Promise((s) => setTimeout(s, t))
1021
+ ]) : Promise.resolve();
1022
+ }
1023
+ function Ut(i, t) {
1024
+ for (let e = i; e && e !== t; e = e.parentElement) {
1025
+ const s = Number(e.style.zIndex);
1026
+ if (s) return s;
1027
+ }
1028
+ return 0;
1029
+ }
1030
+ async function jt(i, t = {}) {
1031
+ var v;
1032
+ await Rt(i, t.timeout ?? 8e3);
1033
+ const e = i.getContainer(), s = e.getBoundingClientRect(), r = i.getSize(), n = t.scale ?? Math.min(window.devicePixelRatio || 1, 2), a = document.createElement("canvas");
1034
+ a.width = Math.round(r.x * n), a.height = Math.round(r.y * n);
1035
+ const l = a.getContext("2d");
1036
+ if (!l) throw new Error("Canvas is not available in this environment");
1037
+ l.scale(n, n), l.fillStyle = t.background ?? "#ffffff", l.fillRect(0, 0, r.x, r.y);
1038
+ const h = (u) => {
1039
+ const m = u.getBoundingClientRect();
1040
+ return { x: m.left - s.left, y: m.top - s.top, w: m.width, h: m.height };
1041
+ }, c = (u) => u.w > 0 && u.h > 0 && u.x < r.x && u.y < r.y && u.x + u.w > 0 && u.y + u.h > 0, d = [...e.querySelectorAll("img.leaflet-tile-loaded")].map((u, m) => ({ img: u, order: m, box: h(u), z: Ut(u, e) })).filter((u) => c(u.box)).sort((u, m) => u.z - m.z || u.order - m.order), p = await Promise.all(
1042
+ d.map(
1043
+ (u) => F(u.img.src).catch(() => {
1044
+ throw new Error(
1045
+ `Cannot export the map: tiles from ${$t(u.img.src)} do not allow cross-origin reading`
1046
+ );
1047
+ })
1048
+ )
1049
+ );
1050
+ d.forEach(({ img: u, box: m }, w) => {
1051
+ const b = u.closest(".leaflet-layer");
1052
+ l.globalAlpha = Number((b == null ? void 0 : b.style.opacity) || 1), l.drawImage(p[w], m.x, m.y, m.w, m.h);
1053
+ }), l.globalAlpha = 1, i.eachLayer((u) => {
1054
+ const m = u;
1055
+ u instanceof o.Canvas && m._redrawRequest && m._redraw();
1056
+ });
1057
+ for (const u of e.querySelectorAll(
1058
+ ".leaflet-pane > canvas, .leaflet-pane > svg"
1059
+ )) {
1060
+ const m = h(u);
1061
+ if (c(m))
1062
+ if (u instanceof HTMLCanvasElement)
1063
+ l.drawImage(u, m.x, m.y, m.w, m.h);
1064
+ else {
1065
+ const w = new XMLSerializer().serializeToString(u), b = URL.createObjectURL(new Blob([w], { type: "image/svg+xml" }));
1066
+ try {
1067
+ l.drawImage(await F(b), m.x, m.y, m.w, m.h);
1068
+ } finally {
1069
+ URL.revokeObjectURL(b);
1070
+ }
1071
+ }
1072
+ }
1073
+ const g = [...t.labels === !1 ? [] : Gt, ...t.include ?? []];
1074
+ if (g.length)
1075
+ for (const u of e.querySelectorAll(g.join(",")))
1076
+ (v = u.parentElement) != null && v.closest(g.join(",")) || c(h(u)) && it(l, u, s);
1077
+ return new Promise((u, m) => {
1078
+ a.toBlob(
1079
+ (w) => w ? u(w) : m(new Error("Failed to encode the image")),
1080
+ t.type ?? "image/png",
1081
+ t.quality
1082
+ );
1083
+ });
1084
+ }
1085
+ function Ft(i, t) {
1086
+ const e = URL.createObjectURL(i), s = document.createElement("a");
1087
+ s.href = e, s.download = t, s.click(), setTimeout(() => URL.revokeObjectURL(e), 1e3);
1088
+ }
1089
+ const H = 6378137, O = Math.PI / 180;
1090
+ function qt(i) {
1091
+ const t = i.length;
1092
+ if (t < 3) return 0;
1093
+ let e = 0;
1094
+ for (let s = 0; s < t; s++) {
1095
+ const r = i[s], n = i[(s + 1) % t];
1096
+ e += (n.lng - r.lng) * O * (2 + Math.sin(r.lat * O) + Math.sin(n.lat * O));
1097
+ }
1098
+ return Math.abs(e * H * H / 2);
1099
+ }
1100
+ function rt(i) {
1101
+ let t = 0;
1102
+ for (let e = 1; e < i.length; e++)
1103
+ t += i[e - 1].distanceTo(i[e]);
1104
+ return t;
1105
+ }
1106
+ const Wt = 2e3 / 3;
1107
+ function nt(i, t = "auto") {
1108
+ return t === "km" || t === "auto" && i >= 1e3 ? `${(i / 1e3).toFixed(2)} km` : `${i.toFixed(1)} m`;
1109
+ }
1110
+ function Ht(i, t = "auto") {
1111
+ switch (t) {
1112
+ case "ha":
1113
+ return `${(i / 1e4).toFixed(2)} 公顷`;
1114
+ case "mu":
1115
+ return `${(i / Wt).toFixed(2)} 亩`;
1116
+ case "km2":
1117
+ return `${(i / 1e6).toFixed(2)} km²`;
1118
+ case "m2":
1119
+ return `${i.toFixed(1)} m²`;
1120
+ default:
1121
+ return i >= 1e6 ? `${(i / 1e6).toFixed(2)} km²` : `${i.toFixed(1)} m²`;
1122
+ }
1123
+ }
1124
+ const y = {
1125
+ marker: {
1126
+ start: "单击地图放置标记"
1127
+ },
1128
+ polyline: {
1129
+ start: "单击开始绘制线",
1130
+ next: "单击继续绘制",
1131
+ finish: "再次单击最后一个点完成"
1132
+ },
1133
+ polygon: {
1134
+ start: "单击开始绘制多边形",
1135
+ next: "单击继续绘制",
1136
+ finish: "单击第一个点闭合"
1137
+ },
1138
+ rectangle: {
1139
+ start: "按住拖动绘制矩形,或单击确定第一个角",
1140
+ finish: "松开完成,或再次单击确定对角"
1141
+ },
1142
+ circle: {
1143
+ start: "按住拖动绘制圆,或单击确定圆心",
1144
+ finish: "松开完成,或再次单击确定半径",
1145
+ radius: "半径"
1146
+ },
1147
+ /** {n} is replaced by the number of points required */
1148
+ tooFewPoints: "至少需要 {n} 个点",
1149
+ cancel: "按 Esc 取消",
1150
+ edit: "拖动圆点调整形状;单击顶点可删除"
1151
+ }, Zt = 8, Kt = 6;
1152
+ function B(i = "vertex") {
1153
+ return o.divIcon({
1154
+ className: `smap-vertex smap-vertex--${i}`,
1155
+ iconSize: [14, 14],
1156
+ iconAnchor: [7, 7]
1157
+ });
1158
+ }
1159
+ class I {
1160
+ constructor(t) {
1161
+ this.snapMark = null, this.host = t, this.map = t.map, this.scratch = o.featureGroup();
1162
+ }
1163
+ enable() {
1164
+ this.scratch.addTo(this.map), this.map.getContainer().classList.add("smap-drawing"), this.map.on("mousemove", this.trackHint, this), this.start();
1165
+ }
1166
+ disable() {
1167
+ this.stop(), this.map.off("mousemove", this.trackHint, this), this.map.getContainer().classList.remove("smap-drawing"), this.scratch.remove();
1168
+ }
1169
+ get shape() {
1170
+ return this.host.options.shapeOptions ?? {};
1171
+ }
1172
+ /** Style of the not-yet-committed part of a shape */
1173
+ get ghost() {
1174
+ return { ...this.shape, dashArray: "4 6", opacity: 0.75, interactive: !1 };
1175
+ }
1176
+ /** The position an event stands for: snapped to nearby geometry when there is some */
1177
+ resolve(t) {
1178
+ var s, r;
1179
+ const e = ((r = (s = this.host.options).snap) == null ? void 0 : r.call(s, t.latlng)) ?? t.latlng;
1180
+ return this.markSnap(e !== t.latlng ? e : null), e;
1181
+ }
1182
+ markSnap(t) {
1183
+ var e;
1184
+ t ? this.snapMark ? this.snapMark.setLatLng(t) : this.snapMark = o.marker(t, {
1185
+ icon: B("snap"),
1186
+ interactive: !1,
1187
+ keyboard: !1
1188
+ }).addTo(this.scratch) : ((e = this.snapMark) == null || e.remove(), this.snapMark = null);
1189
+ }
1190
+ trackHint(t) {
1191
+ this.host.hint.move(t.containerPoint), this.host.options.snap && this.resolve(t);
1192
+ }
1193
+ }
1194
+ class Vt extends I {
1195
+ start() {
1196
+ this.host.hint.set(y.marker.start, y.cancel), this.map.on("click", this.onClick, this);
1197
+ }
1198
+ stop() {
1199
+ this.map.off("click", this.onClick, this);
1200
+ }
1201
+ onClick(t) {
1202
+ const e = this.host.options.markerIcon;
1203
+ this.host.finish(o.marker(this.resolve(t), e ? { icon: e } : {}));
1204
+ }
1205
+ }
1206
+ class Z extends I {
1207
+ constructor(t, e) {
1208
+ super(t), this.points = [], this.fill = null, this.handles = o.layerGroup(), this.hadDoubleClickZoom = !1, this.onKey = (s) => {
1209
+ s.key === "Enter" ? this.tryFinish() : s.key === "Backspace" && this.undo();
1210
+ }, this.closed = e;
1211
+ }
1212
+ get text() {
1213
+ return this.closed ? y.polygon : y.polyline;
1214
+ }
1215
+ /** Fewest points that make a shape */
1216
+ get min() {
1217
+ return this.closed ? 3 : 2;
1218
+ }
1219
+ start() {
1220
+ this.line = o.polyline([], { ...this.shape, fill: !1, interactive: !1 }), this.guide = o.polyline([], { ...this.ghost, fill: !1 }), this.scratch.addLayer(this.line).addLayer(this.guide).addLayer(this.handles), this.closed && (this.fill = o.polygon([], { ...this.shape, stroke: !1, interactive: !1 }), this.scratch.addLayer(this.fill)), this.hadDoubleClickZoom = this.map.doubleClickZoom.enabled(), this.map.doubleClickZoom.disable(), this.map.on("click", this.onClick, this), this.map.on("mousemove", this.onMove, this), document.addEventListener("keydown", this.onKey), this.host.hint.set(this.text.start, y.cancel);
1221
+ }
1222
+ stop() {
1223
+ this.map.off("click", this.onClick, this), this.map.off("mousemove", this.onMove, this), document.removeEventListener("keydown", this.onKey), this.hadDoubleClickZoom && this.map.doubleClickZoom.enable();
1224
+ }
1225
+ near(t, e) {
1226
+ return this.map.latLngToContainerPoint(e).distanceTo(t) <= Zt;
1227
+ }
1228
+ onClick(t) {
1229
+ const { points: e } = this, s = this.resolve(t), r = (n) => this.near(t.containerPoint, n) || s.equals(n);
1230
+ if (e.length) {
1231
+ if (r(e[e.length - 1])) return this.tryFinish();
1232
+ if (this.closed && r(e[0])) return this.tryFinish();
1233
+ }
1234
+ this.add(s);
1235
+ }
1236
+ add(t) {
1237
+ this.points.push(t), this.redraw(), this.host.vertex([...this.points]);
1238
+ }
1239
+ undo() {
1240
+ this.points.length && (this.points.pop(), this.guide.setLatLngs([]), this.redraw(), this.host.vertex([...this.points]));
1241
+ }
1242
+ tryFinish() {
1243
+ if (this.points.length < this.min) {
1244
+ this.host.hint.set(y.tooFewPoints.replace("{n}", String(this.min)), "", !0);
1245
+ return;
1246
+ }
1247
+ const t = { ...this.shape };
1248
+ this.host.finish(
1249
+ this.closed ? o.polygon(this.points, t) : o.polyline(this.points, t)
1250
+ );
1251
+ }
1252
+ redraw() {
1253
+ const { points: t } = this;
1254
+ this.line.setLatLngs(t), this.handles.clearLayers();
1255
+ const e = this.host.options.vertexIcon ?? B();
1256
+ t.forEach((s, r) => {
1257
+ const n = r === 0, a = r === t.length - 1, l = o.marker(s, {
1258
+ icon: e,
1259
+ // Only the vertices that end the shape react to the mouse
1260
+ interactive: a || this.closed && n,
1261
+ keyboard: !1
1262
+ });
1263
+ (a || this.closed && n) && l.on("click", () => this.tryFinish()), this.handles.addLayer(l);
1264
+ }), t.length ? t.length < this.min ? this.host.hint.set(this.text.next, y.cancel) : this.host.hint.set(this.text.next, this.text.finish) : this.host.hint.set(this.text.start, y.cancel);
1265
+ }
1266
+ onMove(t) {
1267
+ var n;
1268
+ const { points: e } = this;
1269
+ if (!e.length) return;
1270
+ const s = e[e.length - 1], r = this.resolve(t);
1271
+ this.guide.setLatLngs(this.closed && e.length > 1 ? [s, r, e[0]] : [s, r]), (n = this.fill) == null || n.setLatLngs([...e, r]);
1272
+ }
1273
+ }
1274
+ class at extends I {
1275
+ constructor() {
1276
+ super(...arguments), this.origin = null, this.originPoint = null, this.pressing = !1, this.dragged = !1, this.armed = !1, this.hadDragging = !1;
1277
+ }
1278
+ start() {
1279
+ this.hadDragging = this.map.dragging.enabled(), this.map.dragging.disable(), this.map.on("mousedown", this.onDown, this), this.map.on("mousemove", this.onMove, this), this.map.on("mouseup", this.onUp, this), this.map.on("click", this.onClick, this), this.host.hint.set(this.text.start, y.cancel);
1280
+ }
1281
+ stop() {
1282
+ this.map.off("mousedown", this.onDown, this), this.map.off("mousemove", this.onMove, this), this.map.off("mouseup", this.onUp, this), this.map.off("click", this.onClick, this), this.hadDragging && this.map.dragging.enable();
1283
+ }
1284
+ setOrigin(t) {
1285
+ this.origin = this.resolve(t), this.originPoint = t.containerPoint, this.begin(this.origin), this.host.hint.set(this.text.finish, y.cancel);
1286
+ }
1287
+ onDown(t) {
1288
+ this.origin || (this.setOrigin(t), this.pressing = !0, this.dragged = !1);
1289
+ }
1290
+ onMove(t) {
1291
+ this.origin && (this.update(this.origin, this.resolve(t)), this.pressing && this.originPoint.distanceTo(t.containerPoint) > Kt && (this.dragged = !0));
1292
+ }
1293
+ onUp(t) {
1294
+ const e = this.pressing && this.dragged;
1295
+ this.pressing = !1, e && this.complete(this.resolve(t));
1296
+ }
1297
+ onClick(t) {
1298
+ this.origin ? this.armed ? this.complete(this.resolve(t)) : this.armed = !0 : (this.setOrigin(t), this.armed = !0);
1299
+ }
1300
+ complete(t) {
1301
+ const e = this.build(this.origin, t);
1302
+ e && this.host.finish(e);
1303
+ }
1304
+ }
1305
+ class Jt extends at {
1306
+ constructor() {
1307
+ super(...arguments), this.preview = null;
1308
+ }
1309
+ get text() {
1310
+ return y.rectangle;
1311
+ }
1312
+ begin(t) {
1313
+ this.preview = o.rectangle(o.latLngBounds(t, t), {
1314
+ ...this.shape,
1315
+ interactive: !1
1316
+ }), this.scratch.addLayer(this.preview);
1317
+ }
1318
+ update(t, e) {
1319
+ var s;
1320
+ (s = this.preview) == null || s.setBounds(o.latLngBounds(t, e));
1321
+ }
1322
+ build(t, e) {
1323
+ return t.lat === e.lat || t.lng === e.lng ? null : o.rectangle(o.latLngBounds(t, e), { ...this.shape });
1324
+ }
1325
+ }
1326
+ class Yt extends at {
1327
+ constructor() {
1328
+ super(...arguments), this.preview = null;
1329
+ }
1330
+ get text() {
1331
+ return y.circle;
1332
+ }
1333
+ begin(t) {
1334
+ this.preview = o.circle(t, { ...this.shape, radius: 0, interactive: !1 }), this.scratch.addLayer(this.preview);
1335
+ }
1336
+ update(t, e) {
1337
+ var r;
1338
+ const s = t.distanceTo(e);
1339
+ (r = this.preview) == null || r.setRadius(s), this.host.hint.set(this.text.finish, `${y.circle.radius} ${nt(s)}`);
1340
+ }
1341
+ build(t, e) {
1342
+ const s = t.distanceTo(e);
1343
+ return s > 0 ? o.circle(t, { ...this.shape, radius: s }) : null;
1344
+ }
1345
+ }
1346
+ function Xt(i, t) {
1347
+ switch (i) {
1348
+ case "marker":
1349
+ return new Vt(t);
1350
+ case "polyline":
1351
+ return new Z(t, !1);
1352
+ case "polygon":
1353
+ return new Z(t, !0);
1354
+ case "rectangle":
1355
+ return new Jt(t);
1356
+ case "circle":
1357
+ return new Yt(t);
1358
+ default:
1359
+ throw new Error(`Unknown draw type: ${i}`);
1360
+ }
1361
+ }
1362
+ class Qt {
1363
+ constructor(t) {
1364
+ this.el = o.DomUtil.create("div", "smap-draw-hint", t.getContainer()), this.main = o.DomUtil.create("div", "smap-draw-hint-main", this.el), this.sub = o.DomUtil.create("div", "smap-draw-hint-sub", this.el), this.el.style.display = "none";
1365
+ }
1366
+ set(t, e = "", s = !1) {
1367
+ this.main.textContent = t, this.sub.textContent = e, this.sub.style.display = e ? "" : "none", this.el.classList.toggle("is-error", s);
1368
+ }
1369
+ move(t) {
1370
+ this.el.style.display = "", this.el.style.transform = `translate(${Math.round(t.x) + 16}px, ${Math.round(t.y) + 16}px)`;
1371
+ }
1372
+ remove() {
1373
+ this.el.remove();
1374
+ }
1375
+ }
1376
+ const E = "#1f6feb";
1377
+ function ot(i, t) {
1378
+ i.getContainer().style.setProperty("--smap-accent", t || E);
1379
+ }
1380
+ function S() {
1381
+ return Promise.resolve();
1382
+ }
1383
+ const T = /* @__PURE__ */ new WeakMap();
1384
+ class lt {
1385
+ constructor(t, e) {
1386
+ this.drawer = null, this.hint = null, this.type = null, this.onKey = (s) => {
1387
+ s.key === "Escape" && this.cancel();
1388
+ }, this.map = t, this.hooks = e;
1389
+ }
1390
+ /** Type being drawn, or null when idle */
1391
+ get active() {
1392
+ return this.type;
1393
+ }
1394
+ /** Start drawing. A drawing already in progress on this map is cancelled first */
1395
+ start(t, e, s) {
1396
+ var n;
1397
+ (n = T.get(this.map)) == null || n.cancel(), ot(this.map, s);
1398
+ const r = new Qt(this.map);
1399
+ this.hint = r, this.type = t, this.drawer = Xt(t, {
1400
+ map: this.map,
1401
+ options: e,
1402
+ hint: r,
1403
+ finish: (a) => this.end(!0, a),
1404
+ vertex: (a) => {
1405
+ var l, h;
1406
+ return (h = (l = this.hooks).vertex) == null ? void 0 : h.call(l, a, t);
1407
+ }
1408
+ }), T.set(this.map, this), document.addEventListener("keydown", this.onKey), this.drawer.enable();
1409
+ }
1410
+ /** Abandon the drawing in progress */
1411
+ cancel() {
1412
+ this.end(!1);
1413
+ }
1414
+ destroy() {
1415
+ this.cancel();
1416
+ }
1417
+ end(t, e) {
1418
+ var n;
1419
+ const { type: s, drawer: r } = this;
1420
+ !s || !r || (this.type = null, this.drawer = null, r.disable(), (n = this.hint) == null || n.remove(), this.hint = null, document.removeEventListener("keydown", this.onKey), T.get(this.map) === this && T.delete(this.map), t && e && this.hooks.created(e, s), this.hooks.stop(s, t));
1421
+ }
1422
+ }
1423
+ function te(i) {
1424
+ return { all: i = i || /* @__PURE__ */ new Map(), on: function(t, e) {
1425
+ var s = i.get(t);
1426
+ s ? s.push(e) : i.set(t, [e]);
1427
+ }, off: function(t, e) {
1428
+ var s = i.get(t);
1429
+ s && (e ? s.splice(s.indexOf(e) >>> 0, 1) : i.set(t, []));
1430
+ }, emit: function(t, e) {
1431
+ var s = i.get(t);
1432
+ s && s.slice().map(function(r) {
1433
+ r(e);
1434
+ }), (s = i.get("*")) && s.slice().map(function(r) {
1435
+ r(t, e);
1436
+ });
1437
+ } };
1438
+ }
1439
+ function $() {
1440
+ return te();
1441
+ }
1442
+ let K = !1;
1443
+ function ee() {
1444
+ K || (bt(), Tt(), Lt(), K = !0);
1445
+ }
1446
+ class Le {
1447
+ constructor(t, e = {}) {
1448
+ this.tileLayers = [], this.tileTypes = [], this.tileChangeHandlers = [], this.drawTools = /* @__PURE__ */ new Set(), this.locationLayer = null, this.measureTools = /* @__PURE__ */ new Set(), this.sharedMeasures = /* @__PURE__ */ new Map(), this.emitter = $(), this.tileObserver = null, this.destroyed = !1, ee(), this.options = e;
1449
+ const s = typeof t == "string" && t.startsWith("#") ? t.slice(1) : t, { tileType: r, tdtKey: n, mapboxToken: a, container: l, ...h } = e;
1450
+ this.instance = o.map(s, {
1451
+ attributionControl: !1,
1452
+ zoomControl: !1,
1453
+ center: e.center,
1454
+ zoom: e.zoom ?? 12,
1455
+ minZoom: e.minZoom,
1456
+ maxZoom: e.maxZoom,
1457
+ maxNativeZoom: e.maxNativeZoom,
1458
+ preferCanvas: e.preferCanvas ?? !0,
1459
+ ...h
1460
+ }), this.layer = new Ot(this.instance), this.control = new At(
1461
+ this.instance,
1462
+ {
1463
+ setTileLayer: (c) => this.setTileLayer(c),
1464
+ getTileType: () => this.getTileType(),
1465
+ onTileChange: (c) => this.tileChangeHandlers.push(c)
1466
+ },
1467
+ this.layer
1468
+ ), this.contextMenu = new Nt(this.instance), this.service = new zt({
1469
+ map: this.instance,
1470
+ key: () => this.options.tdtKey
1471
+ }), r && this.setTileLayer(r), this.tileObserver = Mt(this.instance.getContainer()), queueMicrotask(() => {
1472
+ this.destroyed || (this.emitter.emit("loaded", this.instance), this.tileLayers.length && this.emitter.emit("tileLoaded", this.tileLayers));
1473
+ });
1474
+ }
1475
+ // ============ Tile Layer ============
1476
+ /**
1477
+ * Replace current tile layers with new type(s)
1478
+ */
1479
+ setTileLayer(t) {
1480
+ const e = Array.isArray(t) ? t : [t], s = e.map(
1481
+ (r, n) => R(r, { ...this.resolveKey(r), zIndex: n })
1482
+ );
1483
+ return this.tileLayers.forEach((r) => r.remove()), s.forEach((r) => r.addTo(this.instance)), this.tileLayers = s, this.tileTypes = [...e], this.notifyTileChange(), this.emitter.emit("tileLoaded", this.tileLayers), this.tileLayers;
1484
+ }
1485
+ /**
1486
+ * Add additional tile layer(s) without removing existing ones
1487
+ */
1488
+ addTileLayer(t) {
1489
+ const e = Array.isArray(t) ? t : [t], s = e.map(
1490
+ (r, n) => R(r, {
1491
+ ...this.resolveKey(r),
1492
+ zIndex: this.tileLayers.length + n
1493
+ })
1494
+ );
1495
+ return s.forEach((r) => r.addTo(this.instance)), this.tileLayers.push(...s), this.tileTypes.push(...e), this.notifyTileChange(), s;
1496
+ }
1497
+ notifyTileChange() {
1498
+ this.tileChangeHandlers.forEach((t) => t());
1499
+ }
1500
+ /**
1501
+ * Pick the credential that belongs to the tile provider
1502
+ * (TianDiTu → tdtKey, Mapbox → mapboxToken, others → provider default)
1503
+ */
1504
+ resolveKey(t) {
1505
+ const e = t.split(".")[0], s = e === "Mapbox" ? this.options.mapboxToken : e === "TianDiTu" ? this.options.tdtKey : void 0;
1506
+ return s ? { key: s } : {};
1507
+ }
1508
+ /**
1509
+ * Remove all tile layers
1510
+ */
1511
+ clearTileLayers() {
1512
+ this.tileLayers.forEach((t) => t.remove()), this.tileLayers = [], this.tileTypes = [], this.notifyTileChange();
1513
+ }
1514
+ /**
1515
+ * Types of the current tile layers, bottom first
1516
+ */
1517
+ getTileType() {
1518
+ return [...this.tileTypes];
1519
+ }
1520
+ /**
1521
+ * Get current tile layers
1522
+ */
1523
+ getTileLayers() {
1524
+ return [...this.tileLayers];
1525
+ }
1526
+ // ============ Measure ============
1527
+ /**
1528
+ * Create a new measure tool.
1529
+ *
1530
+ * Every call creates another tool; keep the one you get and reuse it, or call
1531
+ * its `destroy()` when done. For one shared tool per type use `getMeasure()`.
1532
+ */
1533
+ async createMeasure(t, e) {
1534
+ await S();
1535
+ const s = await import("./measure-DJVSnHDg.js"), r = {
1536
+ polyline: s.PolylineMeasure,
1537
+ polygon: s.PolygonMeasure,
1538
+ circle: s.CircleMeasure,
1539
+ rectangle: s.RectangleMeasure
1540
+ }[t];
1541
+ if (!r) throw new Error(`Unknown measure type: ${t}`);
1542
+ const n = new r(this.instance, e);
1543
+ return n.on("start", (a) => this.emitter.emit("measure:start", a)), n.on("stop", (a) => this.emitter.emit("measure:stop", a)), n.on("created", (a) => this.emitter.emit("measure:created", a)), n.on("removed", (a) => this.emitter.emit("measure:removed", a)), n.on("updating", (a) => this.emitter.emit("measure:updating", a)), n.on("updated", (a) => this.emitter.emit("measure:updated", a)), n.on("destroyed", () => this.measureTools.delete(n)), this.measureTools.add(n), n;
1544
+ }
1545
+ /**
1546
+ * The map's shared measure tool of a type, created on first use.
1547
+ * `options` only apply when it is created.
1548
+ */
1549
+ getMeasure(t, e) {
1550
+ let s = this.sharedMeasures.get(t);
1551
+ return s || (s = this.createMeasure(t, e).then((r) => (r.on("destroyed", () => this.sharedMeasures.delete(t)), r)), s.catch(() => this.sharedMeasures.delete(t)), this.sharedMeasures.set(t, s)), s;
1552
+ }
1553
+ /**
1554
+ * Destroy all measure tools
1555
+ */
1556
+ clearMeasures() {
1557
+ for (const t of [...this.measureTools])
1558
+ t.destroy();
1559
+ this.measureTools.clear(), this.sharedMeasures.clear();
1560
+ }
1561
+ // ============ Draw ============
1562
+ /**
1563
+ * Create a tool for drawing and editing shapes (loads leaflet-draw on first call)
1564
+ */
1565
+ async createDraw(t) {
1566
+ await S();
1567
+ const { DrawTool: e } = await Promise.resolve().then(() => ue), s = new e(this.instance, t);
1568
+ return this.drawTools.add(s), s;
1569
+ }
1570
+ // ============ Location ============
1571
+ /**
1572
+ * Locate the user with the browser's geolocation, show the position and move there.
1573
+ * Rejects when permission is denied or the position is unavailable.
1574
+ */
1575
+ async locate(t = {}) {
1576
+ const e = await It(t), s = o.latLng(e.latitude, e.longitude);
1577
+ return this.destroyed ? { ...e, latlng: s } : (this.clearLocation(), t.marker !== !1 && (this.locationLayer = o.featureGroup([
1578
+ o.circle(s, {
1579
+ radius: e.accuracy,
1580
+ weight: 1,
1581
+ color: "#2a7fff",
1582
+ fillOpacity: 0.12,
1583
+ interactive: !1
1584
+ }),
1585
+ o.circleMarker(s, {
1586
+ radius: 6,
1587
+ weight: 2,
1588
+ color: "#fff",
1589
+ fillColor: "#2a7fff",
1590
+ fillOpacity: 1,
1591
+ interactive: !1
1592
+ })
1593
+ ]).addTo(this.instance)), t.setView !== !1 && this.instance.setView(s, t.zoom ?? Math.max(this.instance.getZoom(), 16)), { ...e, latlng: s });
1594
+ }
1595
+ /** Remove the position shown by `locate()` */
1596
+ clearLocation() {
1597
+ var t;
1598
+ (t = this.locationLayer) == null || t.remove(), this.locationLayer = null;
1599
+ }
1600
+ // ============ Export ============
1601
+ /**
1602
+ * The map as currently shown, as an image.
1603
+ *
1604
+ * Contains the base map, vector shapes (lines, areas, circles, point layers) and
1605
+ * the library's own labels: measurement labels, cluster bubbles, drawn markers.
1606
+ * Other HTML — custom marker icons, popups, controls — is not part of it unless
1607
+ * named in `include`. Rejects if a tile server forbids cross-origin reading.
1608
+ */
1609
+ exportImage(t) {
1610
+ return jt(this.instance, t);
1611
+ }
1612
+ /** Export the map and save it as a file */
1613
+ async downloadImage(t = "map.png", e) {
1614
+ Ft(await this.exportImage(e), t);
1615
+ }
1616
+ // ============ View ============
1617
+ /**
1618
+ * Fit map to bounds of a layer
1619
+ */
1620
+ fitToLayer(t) {
1621
+ "getBounds" in t && typeof t.getBounds == "function" && this.instance.fitBounds(t.getBounds());
1622
+ }
1623
+ /**
1624
+ * Set map view
1625
+ */
1626
+ setView(t, e) {
1627
+ this.instance.setView(t, e);
1628
+ }
1629
+ // ============ Events ============
1630
+ on(t, e) {
1631
+ this.emitter.on(t, e);
1632
+ }
1633
+ off(t, e) {
1634
+ this.emitter.off(t, e);
1635
+ }
1636
+ // ============ Lifecycle ============
1637
+ /**
1638
+ * Destroy the map instance and clean up all resources
1639
+ */
1640
+ destroy() {
1641
+ var t;
1642
+ this.destroyed || (this.destroyed = !0, this.clearMeasures(), this.drawTools.forEach((e) => e.destroy()), this.drawTools.clear(), this.clearLocation(), this.contextMenu.destroy(), this.layer.destroy(), this.tileChangeHandlers = [], this.control.removeAll(), this.clearTileLayers(), this.emitter.all.clear(), (t = this.tileObserver) == null || t.disconnect(), this.tileObserver = null, this.instance.stop(), this.instance.eachLayer((e) => {
1643
+ e instanceof o.Renderer || e.remove();
1644
+ }), this.instance.remove());
1645
+ }
1646
+ }
1647
+ const V = /* @__PURE__ */ new Set(), J = /* @__PURE__ */ new Set();
1648
+ function ke(i) {
1649
+ return V.has(i) ? Promise.resolve() : new Promise((t, e) => {
1650
+ const s = document.createElement("script");
1651
+ s.type = "text/javascript", s.src = i, s.onload = () => {
1652
+ V.add(i), t();
1653
+ }, s.onerror = () => e(new Error(`Failed to load script: ${i}`)), document.head.appendChild(s);
1654
+ });
1655
+ }
1656
+ function Te(i) {
1657
+ if (J.has(i)) return;
1658
+ const t = document.createElement("link");
1659
+ t.type = "text/css", t.rel = "stylesheet", t.href = i, document.head.appendChild(t), J.add(i);
1660
+ }
1661
+ function L(i, t) {
1662
+ return o.marker(i, {
1663
+ icon: B(t),
1664
+ draggable: !0,
1665
+ keyboard: !1,
1666
+ // Above the shapes and the app's own markers
1667
+ zIndexOffset: 1e3
1668
+ });
1669
+ }
1670
+ class D {
1671
+ constructor(t) {
1672
+ this.changed = !1, this.onChange = null, this.onBegin = null, this.snap = null, this.handles = o.layerGroup(), this.enabled = !1, this.map = t;
1673
+ }
1674
+ enable() {
1675
+ this.initial = this.capture(), this.enabled = !0, this.handles.addTo(this.map), this.build();
1676
+ }
1677
+ disable() {
1678
+ this.enabled = !1, this.handles.remove(), this.handles.clearLayers(), this.cleanup();
1679
+ }
1680
+ /** Put the shape back as it was when editing started */
1681
+ revert() {
1682
+ this.restore(this.initial);
1683
+ }
1684
+ /** Undo what `build` did to the layer itself */
1685
+ cleanup() {
1686
+ }
1687
+ /** Recreate the handles after the shape changed under them */
1688
+ refresh() {
1689
+ this.enabled && (this.handles.clearLayers(), this.build());
1690
+ }
1691
+ begin() {
1692
+ var t;
1693
+ (t = this.onBegin) == null || t.call(this);
1694
+ }
1695
+ touch() {
1696
+ var t;
1697
+ this.changed = !0, (t = this.onChange) == null || t.call(this);
1698
+ }
1699
+ /** Where a dragged handle should count as being; moves the handle there if it snapped */
1700
+ position(t) {
1701
+ const e = t.getLatLng(), s = this.snap ? this.snap(e) : e;
1702
+ return s !== e && t.setLatLng(s), s;
1703
+ }
1704
+ }
1705
+ class se extends D {
1706
+ constructor(t, e) {
1707
+ super(t), this.wasDraggable = !1, this.layer = e;
1708
+ }
1709
+ capture() {
1710
+ return this.layer.getLatLng();
1711
+ }
1712
+ restore(t) {
1713
+ this.layer.setLatLng(t);
1714
+ }
1715
+ build() {
1716
+ var e;
1717
+ const { dragging: t } = this.layer;
1718
+ this.wasDraggable = !!(t != null && t.enabled()), t == null || t.enable(), this.layer.on("dragstart", this.begin, this), this.layer.on("drag dragend", this.touch, this), (e = this.layer.getElement()) == null || e.classList.add("smap-marker-editing");
1719
+ }
1720
+ cleanup() {
1721
+ var t, e;
1722
+ this.wasDraggable || (t = this.layer.dragging) == null || t.disable(), this.layer.off("dragstart", this.begin, this), this.layer.off("drag dragend", this.touch, this), (e = this.layer.getElement()) == null || e.classList.remove("smap-marker-editing");
1723
+ }
1724
+ }
1725
+ function M(i) {
1726
+ return Array.isArray(i) ? i.map(M) : o.latLng(i.lat, i.lng);
1727
+ }
1728
+ function ht(i) {
1729
+ return Array.isArray(i[0]) ? i.flatMap(ht) : [i];
1730
+ }
1731
+ class ie extends D {
1732
+ constructor(t, e) {
1733
+ super(t), this.layer = e, this.closed = e instanceof o.Polygon, this.current = M(e.getLatLngs()), this.originalDash = e.options.dashArray;
1734
+ }
1735
+ get min() {
1736
+ return this.closed ? 3 : 2;
1737
+ }
1738
+ capture() {
1739
+ return M(this.current);
1740
+ }
1741
+ restore(t) {
1742
+ this.current = M(t), this.layer.setLatLngs(this.current), this.refresh();
1743
+ }
1744
+ apply() {
1745
+ this.layer.setLatLngs(this.current), this.touch();
1746
+ }
1747
+ enable() {
1748
+ super.enable(), this.layer.setStyle({ dashArray: "6 6" });
1749
+ }
1750
+ cleanup() {
1751
+ this.layer.setStyle({ dashArray: this.originalDash });
1752
+ }
1753
+ build() {
1754
+ for (const t of ht(this.current)) {
1755
+ t.forEach((s, r) => this.addVertex(t, r, s));
1756
+ const e = this.closed ? t.length : t.length - 1;
1757
+ for (let s = 0; s < e; s++) this.addMidpoint(t, s);
1758
+ }
1759
+ }
1760
+ addVertex(t, e, s) {
1761
+ const r = L(s, "vertex");
1762
+ let n = !1;
1763
+ r.on("dragstart", () => {
1764
+ n = !0, this.begin();
1765
+ }), r.on("drag", () => {
1766
+ t[e] = this.position(r), this.apply();
1767
+ }), r.on("dragend", () => this.refresh()), r.on("click", () => {
1768
+ if (n) return void (n = !1);
1769
+ t.length <= this.min || (this.begin(), t.splice(e, 1), this.apply(), this.refresh());
1770
+ }), this.handles.addLayer(r);
1771
+ }
1772
+ addMidpoint(t, e) {
1773
+ const s = t[e], r = t[(e + 1) % t.length], n = L([(s.lat + r.lat) / 2, (s.lng + r.lng) / 2], "mid");
1774
+ n.on("dragstart", () => {
1775
+ this.begin(), t.splice(e + 1, 0, n.getLatLng());
1776
+ }), n.on("drag", () => {
1777
+ t[e + 1] = this.position(n), this.apply();
1778
+ }), n.on("dragend", () => this.refresh()), this.handles.addLayer(n);
1779
+ }
1780
+ }
1781
+ class re extends D {
1782
+ constructor(t, e) {
1783
+ super(t), this.layer = e;
1784
+ }
1785
+ capture() {
1786
+ const t = this.layer.getBounds();
1787
+ return o.latLngBounds(t.getSouthWest(), t.getNorthEast());
1788
+ }
1789
+ restore(t) {
1790
+ this.layer.setBounds(t), this.refresh();
1791
+ }
1792
+ build() {
1793
+ const t = this.layer.getBounds(), e = [
1794
+ t.getSouthWest(),
1795
+ t.getNorthWest(),
1796
+ t.getNorthEast(),
1797
+ t.getSouthEast()
1798
+ ];
1799
+ e.forEach((r, n) => {
1800
+ const a = e[(n + 2) % 4], l = L(r, "resize");
1801
+ l.on("dragstart", this.begin, this), l.on("drag", () => {
1802
+ this.layer.setBounds(o.latLngBounds(this.position(l), a)), this.touch();
1803
+ }), l.on("dragend", () => this.refresh()), this.handles.addLayer(l);
1804
+ });
1805
+ const s = L(t.getCenter(), "move");
1806
+ s.on("dragstart", this.begin, this), s.on("drag", () => {
1807
+ const r = this.layer.getBounds().getCenter(), n = s.getLatLng(), a = n.lat - r.lat, l = n.lng - r.lng, h = this.layer.getBounds();
1808
+ this.layer.setBounds(
1809
+ o.latLngBounds(
1810
+ [h.getSouth() + a, h.getWest() + l],
1811
+ [h.getNorth() + a, h.getEast() + l]
1812
+ )
1813
+ ), this.touch();
1814
+ }), s.on("dragend", () => this.refresh()), this.handles.addLayer(s);
1815
+ }
1816
+ }
1817
+ class ne extends D {
1818
+ constructor(t, e) {
1819
+ super(t), this.layer = e;
1820
+ }
1821
+ capture() {
1822
+ return { center: this.layer.getLatLng(), radius: this.layer.getRadius() };
1823
+ }
1824
+ restore(t) {
1825
+ const { center: e, radius: s } = t;
1826
+ this.layer.setLatLng(e), this.layer.setRadius(s), this.refresh();
1827
+ }
1828
+ /** The point due east of the centre, on the circle */
1829
+ edge() {
1830
+ const t = this.layer.getLatLng();
1831
+ return o.latLng(t.lat, this.layer.getBounds().getEast());
1832
+ }
1833
+ build() {
1834
+ const t = L(this.layer.getLatLng(), "move"), e = L(this.edge(), "resize");
1835
+ t.on("dragstart", this.begin, this), t.on("drag", () => {
1836
+ this.layer.setLatLng(this.position(t)), e.setLatLng(this.edge()), this.touch();
1837
+ }), e.on("dragstart", this.begin, this), e.on("drag", () => {
1838
+ this.layer.setRadius(this.layer.getLatLng().distanceTo(this.position(e))), this.touch();
1839
+ }), e.on("dragend", () => e.setLatLng(this.edge())), this.handles.addLayer(t).addLayer(e);
1840
+ }
1841
+ }
1842
+ function ae(i, t) {
1843
+ return t instanceof o.Rectangle ? new re(i, t) : t instanceof o.Polyline ? new ie(i, t) : t instanceof o.Circle ? new ne(i, t) : t instanceof o.Marker ? new se(i, t) : null;
1844
+ }
1845
+ class ct {
1846
+ constructor(t, e, s = {}) {
1847
+ this.editors = /* @__PURE__ */ new Map(), this.history = [], this.onKey = (n) => {
1848
+ var l;
1849
+ if (n.key.toLowerCase() !== "z" || !(n.ctrlKey || n.metaKey) || n.shiftKey) return;
1850
+ const a = n.target;
1851
+ (l = a == null ? void 0 : a.closest) != null && l.call(a, "input, textarea, [contenteditable]") || this.undo() && n.preventDefault();
1852
+ }, this.map = t, this.onChange = s.onChange;
1853
+ const { snap: r } = s;
1854
+ for (const n of e) {
1855
+ const a = ae(t, n);
1856
+ a && (a.onChange = () => {
1857
+ var l;
1858
+ return (l = this.onChange) == null ? void 0 : l.call(this, n);
1859
+ }, a.onBegin = () => this.history.push({ editor: a, layer: n, state: a.capture() }), r && (a.snap = (l) => r(l, n)), this.editors.set(n, a));
1860
+ }
1861
+ }
1862
+ enable() {
1863
+ this.map.getContainer().classList.add("smap-editing"), this.editors.forEach((t) => t.enable()), document.addEventListener("keydown", this.onKey);
1864
+ }
1865
+ /** Layers that were changed */
1866
+ changed() {
1867
+ return [...this.editors].filter(([, t]) => t.changed).map(([t]) => t);
1868
+ }
1869
+ get canUndo() {
1870
+ return this.history.length > 0;
1871
+ }
1872
+ /** Take back the last drag, insertion or deletion. Returns false when there is none */
1873
+ undo() {
1874
+ var e;
1875
+ const t = this.history.pop();
1876
+ return t ? (t.editor.restore(t.state), t.editor.changed = this.history.some((s) => s.editor === t.editor), (e = this.onChange) == null || e.call(this, t.layer), !0) : !1;
1877
+ }
1878
+ /** Undo every change */
1879
+ revert() {
1880
+ this.editors.forEach((t) => {
1881
+ t.changed && t.revert();
1882
+ }), this.history = [];
1883
+ }
1884
+ disable() {
1885
+ document.removeEventListener("keydown", this.onKey), this.editors.forEach((t) => t.disable()), this.map.getContainer().classList.remove("smap-editing");
1886
+ }
1887
+ }
1888
+ function ut(i, t, e) {
1889
+ if (i !== t)
1890
+ if (i instanceof o.Polyline) {
1891
+ const s = i instanceof o.Polygon, r = (n) => {
1892
+ if (Array.isArray(n[0])) return n.forEach(r);
1893
+ const a = n;
1894
+ e.vertices.push(...a), e.paths.push(s && a.length ? [...a, a[0]] : a);
1895
+ };
1896
+ r(i.getLatLngs());
1897
+ } else i instanceof o.CircleMarker || i instanceof o.Marker ? e.vertices.push(i.getLatLng()) : i instanceof o.LayerGroup && i.eachLayer((s) => ut(s, t, e));
1898
+ }
1899
+ function oe(i, t, e = 12) {
1900
+ return (s, r) => {
1901
+ const n = { vertices: [], paths: [] };
1902
+ for (const d of t()) ut(d, r, n);
1903
+ const a = i.project(s);
1904
+ let l = null, h = e;
1905
+ for (const d of n.vertices) {
1906
+ const p = i.project(d).distanceTo(a);
1907
+ p <= h && (l = d, h = p);
1908
+ }
1909
+ if (l) return o.latLng(l.lat, l.lng);
1910
+ let c = null;
1911
+ for (const d of n.paths)
1912
+ for (let p = 1; p < d.length; p++) {
1913
+ const g = o.LineUtil.closestPointOnSegment(
1914
+ a,
1915
+ i.project(d[p - 1]),
1916
+ i.project(d[p])
1917
+ ), v = g.distanceTo(a);
1918
+ v <= h && (c = g, h = v);
1919
+ }
1920
+ return c ? i.unproject(c) : s;
1921
+ };
1922
+ }
1923
+ function dt(i, t, e) {
1924
+ if (!t) return null;
1925
+ const { distance: s, layers: r } = t === !0 ? {} : t, n = () => typeof r == "function" ? r() : r ?? [];
1926
+ return oe(i, () => [...e(), ...n()], s);
1927
+ }
1928
+ const le = {
1929
+ color: E,
1930
+ weight: 3,
1931
+ lineCap: "round",
1932
+ lineJoin: "round",
1933
+ fillOpacity: 0.15
1934
+ };
1935
+ function he() {
1936
+ return o.divIcon({ className: "smap-draw-marker", iconSize: [16, 16], iconAnchor: [8, 8] });
1937
+ }
1938
+ class ce {
1939
+ constructor(t, e = {}) {
1940
+ this.emitter = $(), this.editor = null, this.map = t, this.options = e, this.group = o.featureGroup().addTo(t), this.snapper = dt(t, e.snap, () => this.getLayers()), this.session = new lt(t, {
1941
+ created: (s, r) => {
1942
+ this.group.addLayer(s), this.emitter.emit("created", { layer: s, type: r }), this.emitChange();
1943
+ },
1944
+ stop: (s) => this.emitter.emit("drawstop", { type: s })
1945
+ });
1946
+ }
1947
+ /** @deprecated Nothing needs loading any more. Kept so existing calls keep working */
1948
+ static preload() {
1949
+ return S();
1950
+ }
1951
+ // ============ Drawing ============
1952
+ /** Shape currently being drawn, or null */
1953
+ get drawing() {
1954
+ return this.session.active;
1955
+ }
1956
+ /** Start drawing one shape. Drawing ends by itself when the shape is finished */
1957
+ draw(t) {
1958
+ this.finishEdit(!0);
1959
+ const e = this.shapeOptions(), { snapper: s } = this;
1960
+ this.session.start(
1961
+ t,
1962
+ {
1963
+ shapeOptions: e,
1964
+ markerIcon: this.markerIcon(),
1965
+ snap: s ? (r) => s(r) : void 0
1966
+ },
1967
+ e.color
1968
+ ), this.emitter.emit("drawstart", { type: t });
1969
+ }
1970
+ /** Abandon the shape being drawn */
1971
+ cancel() {
1972
+ this.session.cancel();
1973
+ }
1974
+ // ============ Editing ============
1975
+ /** True while shapes can be dragged and reshaped */
1976
+ get editing() {
1977
+ return !!this.editor;
1978
+ }
1979
+ /** Make every shape editable: drag vertices, move markers, resize rectangles and circles */
1980
+ startEdit() {
1981
+ this.editor || (this.cancel(), ot(this.map, this.shapeOptions().color), this.editor = new ct(this.map, this.getLayers(), {
1982
+ snap: this.snapper,
1983
+ onChange: (t) => this.emitter.emit("editing", { layer: t })
1984
+ }), this.editor.enable());
1985
+ }
1986
+ /** True when there is a change to take back in edit mode */
1987
+ get canUndo() {
1988
+ var t;
1989
+ return ((t = this.editor) == null ? void 0 : t.canUndo) ?? !1;
1990
+ }
1991
+ /** Take back the last change made in edit mode (also Ctrl/Cmd+Z). Returns false when there is none */
1992
+ undo() {
1993
+ var t;
1994
+ return ((t = this.editor) == null ? void 0 : t.undo()) ?? !1;
1995
+ }
1996
+ /** Leave edit mode, keeping (`save = true`) or discarding the changes */
1997
+ finishEdit(t = !0) {
1998
+ const e = this.editor;
1999
+ if (!e) return;
2000
+ this.editor = null;
2001
+ const s = t ? e.changed() : [];
2002
+ t || e.revert(), e.disable(), s.length && (this.emitter.emit("edited", { layers: s }), this.emitChange());
2003
+ }
2004
+ // ============ Content ============
2005
+ getLayers() {
2006
+ return this.group.getLayers();
2007
+ }
2008
+ /** Remove one shape */
2009
+ remove(t) {
2010
+ this.group.hasLayer(t) && (this.group.removeLayer(t), this.emitter.emit("removed", { layers: [t] }), this.emitChange());
2011
+ }
2012
+ /** Remove every shape */
2013
+ clear() {
2014
+ const t = this.getLayers();
2015
+ t.length && (this.finishEdit(!1), this.group.clearLayers(), this.emitter.emit("removed", { layers: t }), this.emitChange());
2016
+ }
2017
+ /**
2018
+ * Export everything as GeoJSON (WGS-84).
2019
+ * A circle becomes a Point with `properties.radius` in metres.
2020
+ */
2021
+ toGeoJSON() {
2022
+ return { type: "FeatureCollection", features: this.getLayers().map((e) => {
2023
+ const s = e.toGeoJSON();
2024
+ return e instanceof o.Circle && (s.properties = { ...s.properties, radius: e.getRadius() }), s;
2025
+ }) };
2026
+ }
2027
+ /**
2028
+ * Load shapes from GeoJSON so they can be shown and edited.
2029
+ * A Point with `properties.radius` becomes a circle.
2030
+ */
2031
+ load(t, e = {}) {
2032
+ this.finishEdit(!1), e.replace !== !1 && this.group.clearLayers(), o.geoJSON(t, {
2033
+ style: () => this.shapeOptions(),
2034
+ pointToLayer: (r, n) => {
2035
+ var l;
2036
+ const a = Number((l = r.properties) == null ? void 0 : l.radius);
2037
+ return a > 0 ? o.circle(n, { ...this.shapeOptions(), radius: a }) : o.marker(n, { icon: this.markerIcon() });
2038
+ }
2039
+ }).eachLayer((r) => this.group.addLayer(r)), this.emitChange();
2040
+ }
2041
+ // ============ Events / lifecycle ============
2042
+ on(t, e) {
2043
+ this.emitter.on(t, e);
2044
+ }
2045
+ off(t, e) {
2046
+ this.emitter.off(t, e);
2047
+ }
2048
+ destroy() {
2049
+ this.session.destroy(), this.finishEdit(!1), this.emitter.all.clear(), this.group.remove();
2050
+ }
2051
+ emitChange() {
2052
+ this.emitter.emit("change", this.toGeoJSON());
2053
+ }
2054
+ shapeOptions() {
2055
+ return { ...le, ...this.options.shapeOptions };
2056
+ }
2057
+ markerIcon() {
2058
+ return this.options.markerIcon ?? he();
2059
+ }
2060
+ }
2061
+ const ue = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
2062
+ __proto__: null,
2063
+ DrawTool: ce
2064
+ }, Symbol.toStringTag, { value: "Module" })), de = {
2065
+ stroke: !0,
2066
+ color: E,
2067
+ weight: 3,
2068
+ opacity: 1,
2069
+ lineCap: "round",
2070
+ lineJoin: "round",
2071
+ fillOpacity: 0.12
2072
+ };
2073
+ let pe = 0;
2074
+ function me() {
2075
+ return `measure_${++pe}_${Date.now()}`;
2076
+ }
2077
+ class G {
2078
+ constructor(t, e = {}) {
2079
+ this.entries = /* @__PURE__ */ new Map(), this.draft = null, this.emitter = $(), this.editor = null, this.destroyed = !1, this.map = t, this.options = { ...e }, this.layerGroup = o.featureGroup().addTo(t), this.snapper = dt(t, e.snap, () => this.layerGroup.getLayers()), this.session = new lt(t, {
2080
+ created: (s) => this.handleCreated(s),
2081
+ vertex: (s) => this.handleVertex(s),
2082
+ stop: (s, r) => {
2083
+ this.setDraft(null), this.emitter.emit("stop", { type: s, completed: r });
2084
+ }
2085
+ }), this.clickHandler = (s) => {
2086
+ var n;
2087
+ const r = s.target;
2088
+ if ((n = r.classList) != null && n.contains("smap-measure-remove")) {
2089
+ const a = r.dataset.measureId;
2090
+ a && this.remove(a);
2091
+ }
2092
+ }, t.getContainer().addEventListener("click", this.clickHandler);
2093
+ }
2094
+ /** @deprecated Nothing needs loading any more. Kept so existing calls keep working */
2095
+ static preload() {
2096
+ return S();
2097
+ }
2098
+ /** Labels to show while drawing; only the distance tool has any */
2099
+ draftLabels(t) {
2100
+ return [];
2101
+ }
2102
+ /** Labels of a finished measurement. By default just the result label */
2103
+ resultLabels(t) {
2104
+ return [{ latlng: this.anchor(t), html: this.resultHtml(t) }];
2105
+ }
2106
+ // ============ Public API ============
2107
+ get type() {
2108
+ return this.drawType;
2109
+ }
2110
+ get measuring() {
2111
+ return this.session.active !== null;
2112
+ }
2113
+ enable() {
2114
+ this.finishEdit(!0);
2115
+ const t = this.getShapeOptions(), { snapper: e } = this;
2116
+ this.session.start(
2117
+ this.drawType,
2118
+ {
2119
+ shapeOptions: t,
2120
+ vertexIcon: this.options.icon,
2121
+ snap: e ? (s) => e(s) : void 0
2122
+ },
2123
+ t.color
2124
+ ), this.emitter.emit("start", { type: this.drawType });
2125
+ }
2126
+ disable() {
2127
+ this.session.cancel();
2128
+ }
2129
+ // ============ Editing ============
2130
+ get editing() {
2131
+ return !!this.editor;
2132
+ }
2133
+ startEdit() {
2134
+ if (this.editor) return;
2135
+ this.disable();
2136
+ const t = new Map([...this.entries.values()].map((e) => [e.result.layer, e]));
2137
+ this.editor = new ct(this.map, [...t.keys()], {
2138
+ snap: this.snapper,
2139
+ onChange: (e) => {
2140
+ const s = t.get(e);
2141
+ s && (this.refresh(s), this.emitter.emit("updating", s.result));
2142
+ }
2143
+ }), this.editor.enable();
2144
+ }
2145
+ undo() {
2146
+ var t;
2147
+ return ((t = this.editor) == null ? void 0 : t.undo()) ?? !1;
2148
+ }
2149
+ finishEdit(t = !0) {
2150
+ const e = this.editor;
2151
+ if (!e) return;
2152
+ this.editor = null;
2153
+ const s = e.changed();
2154
+ t || e.revert(), e.disable();
2155
+ for (const r of this.entries.values())
2156
+ s.includes(r.result.layer) && (this.refresh(r), t && this.emitter.emit("updated", r.result));
2157
+ }
2158
+ /** Read the numbers off the shape again and redraw its labels */
2159
+ refresh(t) {
2160
+ Object.assign(t.result, this.measure(t.result.layer)), t.labels.remove(), t.labels = this.renderLabels(this.options.showMarker ? this.resultLabels(t.result) : []);
2161
+ }
2162
+ setOptions(t) {
2163
+ Object.assign(this.options, t);
2164
+ for (const e of this.entries.values()) this.refresh(e);
2165
+ }
2166
+ getResults() {
2167
+ return [...this.entries.values()].map((t) => t.result);
2168
+ }
2169
+ remove(t) {
2170
+ const e = this.entries.get(t);
2171
+ e && (this.finishEdit(!0), e.labels.remove(), this.layerGroup.removeLayer(e.result.layer), this.entries.delete(t), this.emitter.emit("removed", { id: t, type: this.drawType }));
2172
+ }
2173
+ clearAll() {
2174
+ for (const t of [...this.entries.keys()])
2175
+ this.remove(t);
2176
+ }
2177
+ on(t, e) {
2178
+ this.emitter.on(t, e);
2179
+ }
2180
+ off(t, e) {
2181
+ this.emitter.off(t, e);
2182
+ }
2183
+ destroy() {
2184
+ this.destroyed || (this.destroyed = !0, this.session.destroy(), this.finishEdit(!1), this.setDraft(null), this.clearAll(), this.layerGroup.remove(), this.map.getContainer().removeEventListener("click", this.clickHandler), this.emitter.emit("destroyed", { type: this.drawType }), this.emitter.all.clear());
2185
+ }
2186
+ // ============ Drawing ============
2187
+ handleVertex(t) {
2188
+ if (!this.options.showMarker) return;
2189
+ const e = this.draftLabels(t);
2190
+ e.length && this.setDraft(this.renderLabels(e));
2191
+ }
2192
+ handleCreated(t) {
2193
+ const e = me();
2194
+ this.layerGroup.addLayer(t);
2195
+ const s = { id: e, type: this.drawType, layer: t, ...this.measure(t) };
2196
+ this.setDraft(null);
2197
+ const r = this.renderLabels(this.options.showMarker ? this.resultLabels(s) : []);
2198
+ this.entries.set(e, { result: s, labels: r }), this.emitter.emit("created", s);
2199
+ }
2200
+ setDraft(t) {
2201
+ var e;
2202
+ (e = this.draft) == null || e.remove(), this.draft = t;
2203
+ }
2204
+ /** Put labels on the map. A label is a permanent tooltip on an invisible marker */
2205
+ renderLabels(t) {
2206
+ const e = o.featureGroup();
2207
+ for (const { latlng: s, html: r } of t)
2208
+ o.marker(s, { icon: o.divIcon({ className: "measure-div-icon" }), interactive: !1 }).bindTooltip(r, {
2209
+ permanent: !0,
2210
+ direction: "right",
2211
+ offset: [6, 0],
2212
+ className: "measure-tooltip"
2213
+ }).addTo(e);
2214
+ return e.addTo(this.map);
2215
+ }
2216
+ // ============ Helpers for concrete tools ============
2217
+ getShapeOptions() {
2218
+ return { ...de, ...this.options.shapeOptions };
2219
+ }
2220
+ /** Text of a label: `formatLabel`, else the deprecated `valueFormatter`, else the default */
2221
+ text(t, e = "") {
2222
+ return this.options.formatLabel ? this.options.formatLabel(t) : this.options.valueFormatter ? e + this.options.valueFormatter(this.legacyValue(t)) : this.defaultText(t);
2223
+ }
2224
+ /** Plain label, used for intermediate values */
2225
+ labelHtml(t) {
2226
+ return `<div class="smap-measure-label" style="${this.accentStyle()}">${t}</div>`;
2227
+ }
2228
+ /** Emphasised label of a finished measurement, with the button that removes it */
2229
+ resultHtml(t, e = "") {
2230
+ const { id: s, layer: r, ...n } = t, a = this.text({ ...n, partial: !1 }, e), l = `<button type="button" class="smap-measure-remove" data-measure-id="${t.id}" title="删除" aria-label="删除">×</button>`;
2231
+ return `<div class="smap-measure-label smap-measure-label--result" style="${this.accentStyle()}"><span>${a}</span>${l}</div>`;
2232
+ }
2233
+ /** Labels take the colour of this tool's lines */
2234
+ accentStyle() {
2235
+ return `--smap-accent:${this.getShapeOptions().color || E}`;
2236
+ }
2237
+ formatLength(t) {
2238
+ return nt(t, this.options.lengthUnit);
2239
+ }
2240
+ formatArea(t) {
2241
+ return Ht(t, this.options.areaUnit);
2242
+ }
2243
+ /** Length of a path in metres */
2244
+ pathLength(t) {
2245
+ return rt(t);
2246
+ }
2247
+ }
2248
+ class Me extends G {
2249
+ constructor() {
2250
+ super(...arguments), this.drawType = "polyline";
2251
+ }
2252
+ measure(t) {
2253
+ const e = t.getLatLngs();
2254
+ return { latlngs: e, distance: this.pathLength(e) };
2255
+ }
2256
+ anchor(t) {
2257
+ return t.latlngs[t.latlngs.length - 1];
2258
+ }
2259
+ defaultText(t) {
2260
+ const e = this.formatLength(t.distance ?? 0);
2261
+ return t.partial ? e : `共 ${e}`;
2262
+ }
2263
+ legacyValue(t) {
2264
+ return t.distance ?? 0;
2265
+ }
2266
+ draftLabels(t) {
2267
+ return this.nodeLabels(t);
2268
+ }
2269
+ resultLabels(t) {
2270
+ return [
2271
+ ...this.nodeLabels(t.latlngs.slice(0, -1)),
2272
+ // The deprecated formatter only returned the number, so it keeps its "共" prefix
2273
+ { latlng: this.anchor(t), html: this.resultHtml(t, "共 ") }
2274
+ ];
2275
+ }
2276
+ /** "起点" on the first vertex, the distance so far on the others */
2277
+ nodeLabels(t) {
2278
+ return t.map((e, s) => {
2279
+ if (s === 0) return { latlng: e, html: this.labelHtml("起点") };
2280
+ const r = t.slice(0, s + 1), n = this.text({
2281
+ type: "polyline",
2282
+ latlngs: r,
2283
+ distance: this.pathLength(r),
2284
+ partial: !0
2285
+ });
2286
+ return { latlng: e, html: this.labelHtml(n) };
2287
+ });
2288
+ }
2289
+ }
2290
+ class pt extends G {
2291
+ measure(t) {
2292
+ const e = t.getLatLngs()[0];
2293
+ return {
2294
+ latlngs: e,
2295
+ area: qt(e),
2296
+ perimeter: e.length ? rt([...e, e[0]]) : 0
2297
+ };
2298
+ }
2299
+ anchor(t) {
2300
+ return t.latlngs[0];
2301
+ }
2302
+ defaultText(t) {
2303
+ return this.formatArea(t.area ?? 0);
2304
+ }
2305
+ legacyValue(t) {
2306
+ return t.latlngs;
2307
+ }
2308
+ }
2309
+ class xe extends pt {
2310
+ constructor() {
2311
+ super(...arguments), this.drawType = "polygon";
2312
+ }
2313
+ }
2314
+ class Ce extends G {
2315
+ constructor() {
2316
+ super(...arguments), this.drawType = "circle";
2317
+ }
2318
+ measure(t) {
2319
+ const e = t.getRadius(), s = t.getLatLng();
2320
+ return {
2321
+ latlngs: [s],
2322
+ center: s,
2323
+ radius: e,
2324
+ area: Math.PI * e * e,
2325
+ perimeter: 2 * Math.PI * e
2326
+ };
2327
+ }
2328
+ anchor(t) {
2329
+ return t.center ?? t.latlngs[0];
2330
+ }
2331
+ defaultText(t) {
2332
+ return this.formatArea(t.area ?? 0);
2333
+ }
2334
+ legacyValue(t) {
2335
+ return t.radius ?? 0;
2336
+ }
2337
+ }
2338
+ class Se extends pt {
2339
+ constructor() {
2340
+ super(...arguments), this.drawType = "rectangle";
2341
+ }
2342
+ }
2343
+ export {
2344
+ ye as BUILTIN_TILE_TYPES,
2345
+ G as BaseMeasureTool,
2346
+ Ce as CircleMeasure,
2347
+ St as ClusterLayer,
2348
+ Nt as ContextMenu,
2349
+ At as ControlManager,
2350
+ ce as DrawTool,
2351
+ Ot as LayerManager,
2352
+ xe as PolygonMeasure,
2353
+ Me as PolylineMeasure,
2354
+ Se as RectangleMeasure,
2355
+ Le as SMap,
2356
+ zt as ServiceClient,
2357
+ st as bd09ToGcj02,
2358
+ yt as bd09ToWgs84,
2359
+ R as createChinaTileLayer,
2360
+ oe as createSnapper,
2361
+ Ht as formatArea,
2362
+ nt as formatLength,
2363
+ et as gcj02ToBd09,
2364
+ tt as gcj02ToWgs84,
2365
+ qt as geodesicArea,
2366
+ mt as getCoordType,
2367
+ It as getLocation,
2368
+ we as getTileTypes,
2369
+ S as loadLeafletDraw,
2370
+ ke as loadScript,
2371
+ Te as loadStyle,
2372
+ rt as pathLength,
2373
+ N as providers,
2374
+ ve as registerProvider,
2375
+ y as sketchText,
2376
+ wt as transformCoord,
2377
+ be as transformGeoJSON,
2378
+ A as wgs84ToBd09,
2379
+ C as wgs84ToGcj02
2380
+ };
2381
+ //# sourceMappingURL=smap-leaflet.mjs.map