aviation-chart 0.2.5 → 0.3.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.
@@ -88,6 +88,1243 @@ var _mlGl = /*#__PURE__*/_mergeNamespaces({
88
88
  default: ku
89
89
  }, [_mlGlExports]);
90
90
 
91
+ const R$1 = 6371008.8;
92
+ const STROKE_DASHARRAY = {
93
+ solid: undefined,
94
+ dashed: [6, 4],
95
+ dotted: [1, 3],
96
+ "dash-dot": [8, 4, 2, 4],
97
+ "long-dash": [12, 6],
98
+ "double-dash": [6, 2, 6, 8],
99
+ };
100
+ function toRad(deg) {
101
+ return (deg * Math.PI) / 180;
102
+ }
103
+ function toDeg(rad) {
104
+ return (rad * 180) / Math.PI;
105
+ }
106
+ function haversineDistance(a, b) {
107
+ const dLat = toRad(b[1] - a[1]);
108
+ const dLon = toRad(b[0] - a[0]);
109
+ const lat1 = toRad(a[1]);
110
+ const lat2 = toRad(b[1]);
111
+ const h = Math.sin(dLat / 2) ** 2 +
112
+ Math.cos(lat1) * Math.cos(lat2) * Math.sin(dLon / 2) ** 2;
113
+ return 2 * R$1 * Math.asin(Math.sqrt(h));
114
+ }
115
+ function destinationPoint(origin, distanceMeters, bearingDeg) {
116
+ const d = distanceMeters / R$1;
117
+ const brng = toRad(bearingDeg);
118
+ const lat1 = toRad(origin[1]);
119
+ const lon1 = toRad(origin[0]);
120
+ const lat2 = Math.asin(Math.sin(lat1) * Math.cos(d) + Math.cos(lat1) * Math.sin(d) * Math.cos(brng));
121
+ const lon2 = lon1 +
122
+ Math.atan2(Math.sin(brng) * Math.sin(d) * Math.cos(lat1), Math.cos(d) - Math.sin(lat1) * Math.sin(lat2));
123
+ return [toDeg(lon2), toDeg(lat2)];
124
+ }
125
+ function circlePolygon(center, radiusMeters, steps = 64) {
126
+ const coords = [];
127
+ for (let i = 0; i <= steps; i++) {
128
+ const bearing = (360 / steps) * i;
129
+ coords.push(destinationPoint(center, radiusMeters, bearing));
130
+ }
131
+ return coords;
132
+ }
133
+ function computeBounds(coords) {
134
+ let minLng = Infinity, minLat = Infinity, maxLng = -Infinity, maxLat = -Infinity;
135
+ for (const [lng, lat] of coords) {
136
+ if (lng < minLng)
137
+ minLng = lng;
138
+ if (lng > maxLng)
139
+ maxLng = lng;
140
+ if (lat < minLat)
141
+ minLat = lat;
142
+ if (lat > maxLat)
143
+ maxLat = lat;
144
+ }
145
+ return [
146
+ [minLng, minLat],
147
+ [maxLng, maxLat],
148
+ ];
149
+ }
150
+ function flattenCoords(rings) {
151
+ const result = [];
152
+ for (const ring of rings) {
153
+ if (!ring)
154
+ continue;
155
+ for (const c of ring)
156
+ result.push(c);
157
+ }
158
+ return result;
159
+ }
160
+ function pointInPolygon(point, ring) {
161
+ const [x, y] = point;
162
+ let inside = false;
163
+ for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
164
+ const [xi, yi] = ring[i];
165
+ const [xj, yj] = ring[j];
166
+ if (yi > y !== yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi) + xi) {
167
+ inside = !inside;
168
+ }
169
+ }
170
+ return inside;
171
+ }
172
+ function polylineLength(coords) {
173
+ let total = 0;
174
+ for (let i = 1; i < coords.length; i++) {
175
+ total += haversineDistance(coords[i - 1], coords[i]);
176
+ }
177
+ return total;
178
+ }
179
+ function polygonArea(ring) {
180
+ let area = 0;
181
+ for (let i = 0; i < ring.length; i++) {
182
+ const j = (i + 1) % ring.length;
183
+ const [lng1, lat1] = ring[i];
184
+ const [lng2, lat2] = ring[j];
185
+ area += toRad(lng2 - lng1) * (2 + Math.sin(toRad(lat1)) + Math.sin(toRad(lat2)));
186
+ }
187
+ return Math.abs((area * R$1 * R$1) / 2);
188
+ }
189
+
190
+ let circleCounter = 0;
191
+ class Circle {
192
+ constructor(options) {
193
+ this._map = null;
194
+ this._visible = true;
195
+ this.id = `overlay-circle-${++circleCounter}`;
196
+ this._center = options.center;
197
+ this._radius = options.radius;
198
+ this._options = { ...options };
199
+ this._sourceId = this.id;
200
+ this._fillLayerId = `${this.id}-fill`;
201
+ this._strokeLayerId = `${this.id}-stroke`;
202
+ this._labelLayerId = `${this.id}-label`;
203
+ }
204
+ bindTo(mapOrSdk) {
205
+ const map = mapOrSdk.map ?? mapOrSdk;
206
+ this._map = map;
207
+ this._addToMap();
208
+ return this;
209
+ }
210
+ _ring() {
211
+ return circlePolygon(this._center, this._radius, this._options.steps ?? 64);
212
+ }
213
+ _geojson() {
214
+ const ring = this._ring();
215
+ return {
216
+ type: "FeatureCollection",
217
+ features: [
218
+ {
219
+ type: "Feature",
220
+ properties: { ...this._options.properties, overlayId: this.id, _label: this._options.label ?? "" },
221
+ geometry: { type: "Polygon", coordinates: [ring] },
222
+ },
223
+ {
224
+ type: "Feature",
225
+ properties: { overlayId: this.id, _label: this._options.label ?? "", _type: "center" },
226
+ geometry: { type: "Point", coordinates: this._center },
227
+ },
228
+ ],
229
+ };
230
+ }
231
+ _resolveStrokeDash() {
232
+ if (this._options.strokeLineType)
233
+ return STROKE_DASHARRAY[this._options.strokeLineType];
234
+ return this._options.strokeDasharray;
235
+ }
236
+ _addToMap() {
237
+ const map = this._map;
238
+ const o = this._options;
239
+ const before = o.beforeId;
240
+ const zoomFilter = {};
241
+ if (o.minZoom != null)
242
+ zoomFilter.minzoom = o.minZoom;
243
+ if (o.maxZoom != null)
244
+ zoomFilter.maxzoom = o.maxZoom;
245
+ map.addSource(this._sourceId, { type: "geojson", data: this._geojson() });
246
+ const fillPaint = {
247
+ "fill-color": o.color ?? "#1890ff",
248
+ "fill-opacity": o.opacity ?? 0.25,
249
+ "fill-antialias": o.antialias ?? true,
250
+ };
251
+ if (o.fillTranslate)
252
+ fillPaint["fill-translate"] = o.fillTranslate;
253
+ if (o.fillPattern)
254
+ fillPaint["fill-pattern"] = o.fillPattern;
255
+ map.addLayer({
256
+ id: this._fillLayerId,
257
+ type: "fill",
258
+ source: this._sourceId,
259
+ filter: ["==", ["geometry-type"], "Polygon"],
260
+ ...zoomFilter,
261
+ paint: fillPaint,
262
+ }, before);
263
+ const strokePaint = {
264
+ "line-color": o.strokeColor ?? o.color ?? "#1890ff",
265
+ "line-width": o.strokeWidth ?? 2,
266
+ "line-opacity": o.strokeOpacity ?? 0.8,
267
+ };
268
+ const dash = this._resolveStrokeDash();
269
+ if (dash)
270
+ strokePaint["line-dasharray"] = dash;
271
+ if (o.strokeBlur)
272
+ strokePaint["line-blur"] = o.strokeBlur;
273
+ if (o.strokeTranslate)
274
+ strokePaint["line-translate"] = o.strokeTranslate;
275
+ map.addLayer({
276
+ id: this._strokeLayerId,
277
+ type: "line",
278
+ source: this._sourceId,
279
+ filter: ["==", ["geometry-type"], "Polygon"],
280
+ ...zoomFilter,
281
+ layout: {
282
+ "line-cap": o.strokeLineCap ?? "round",
283
+ "line-join": o.strokeLineJoin ?? "round",
284
+ },
285
+ paint: strokePaint,
286
+ }, before);
287
+ if (o.label) {
288
+ map.addLayer({
289
+ id: this._labelLayerId,
290
+ type: "symbol",
291
+ source: this._sourceId,
292
+ filter: ["==", ["get", "_type"], "center"],
293
+ ...zoomFilter,
294
+ layout: {
295
+ "text-field": ["get", "_label"],
296
+ "text-size": o.labelSize ?? 14,
297
+ "text-anchor": "center",
298
+ "text-allow-overlap": true,
299
+ },
300
+ paint: {
301
+ "text-color": o.labelColor ?? "#333333",
302
+ "text-halo-color": o.labelHaloColor ?? "#ffffff",
303
+ "text-halo-width": o.labelHaloWidth ?? 1,
304
+ },
305
+ }, before);
306
+ }
307
+ if (o.cursor) {
308
+ map.on("mouseenter", this._fillLayerId, () => { map.getCanvas().style.cursor = o.cursor; });
309
+ map.on("mouseleave", this._fillLayerId, () => { map.getCanvas().style.cursor = ""; });
310
+ }
311
+ }
312
+ _updateSource() {
313
+ const src = this._map?.getSource(this._sourceId);
314
+ if (src)
315
+ src.setData(this._geojson());
316
+ }
317
+ getCenter() {
318
+ return [...this._center];
319
+ }
320
+ setCenter(center) {
321
+ this._center = center;
322
+ this._updateSource();
323
+ return this;
324
+ }
325
+ getRadius() {
326
+ return this._radius;
327
+ }
328
+ setRadius(radius) {
329
+ this._radius = radius;
330
+ this._updateSource();
331
+ return this;
332
+ }
333
+ getBounds() {
334
+ return computeBounds(this._ring());
335
+ }
336
+ contains(lnglat) {
337
+ return haversineDistance(this._center, lnglat) <= this._radius;
338
+ }
339
+ setStyle(style) {
340
+ const map = this._map;
341
+ if (!map)
342
+ return this;
343
+ if (style.color !== undefined)
344
+ map.setPaintProperty(this._fillLayerId, "fill-color", style.color);
345
+ if (style.opacity !== undefined)
346
+ map.setPaintProperty(this._fillLayerId, "fill-opacity", style.opacity);
347
+ if (style.fillTranslate !== undefined)
348
+ map.setPaintProperty(this._fillLayerId, "fill-translate", style.fillTranslate);
349
+ if (style.fillPattern !== undefined)
350
+ map.setPaintProperty(this._fillLayerId, "fill-pattern", style.fillPattern);
351
+ if (style.antialias !== undefined)
352
+ map.setPaintProperty(this._fillLayerId, "fill-antialias", style.antialias);
353
+ if (style.strokeColor !== undefined)
354
+ map.setPaintProperty(this._strokeLayerId, "line-color", style.strokeColor);
355
+ if (style.strokeWidth !== undefined)
356
+ map.setPaintProperty(this._strokeLayerId, "line-width", style.strokeWidth);
357
+ if (style.strokeOpacity !== undefined)
358
+ map.setPaintProperty(this._strokeLayerId, "line-opacity", style.strokeOpacity);
359
+ if (style.strokeLineType !== undefined || style.strokeDasharray !== undefined) {
360
+ Object.assign(this._options, style);
361
+ const d = this._resolveStrokeDash();
362
+ map.setPaintProperty(this._strokeLayerId, "line-dasharray", d ?? []);
363
+ }
364
+ if (style.strokeBlur !== undefined)
365
+ map.setPaintProperty(this._strokeLayerId, "line-blur", style.strokeBlur);
366
+ if (style.strokeTranslate !== undefined)
367
+ map.setPaintProperty(this._strokeLayerId, "line-translate", style.strokeTranslate);
368
+ if (style.strokeLineCap !== undefined)
369
+ map.setLayoutProperty(this._strokeLayerId, "line-cap", style.strokeLineCap);
370
+ if (style.strokeLineJoin !== undefined)
371
+ map.setLayoutProperty(this._strokeLayerId, "line-join", style.strokeLineJoin);
372
+ Object.assign(this._options, style);
373
+ return this;
374
+ }
375
+ setLabel(label) {
376
+ this._options.label = label;
377
+ this._updateSource();
378
+ return this;
379
+ }
380
+ show() {
381
+ this._visible = true;
382
+ const vis = "visible";
383
+ this._map?.setLayoutProperty(this._fillLayerId, "visibility", vis);
384
+ this._map?.setLayoutProperty(this._strokeLayerId, "visibility", vis);
385
+ if (this._map?.getLayer(this._labelLayerId))
386
+ this._map.setLayoutProperty(this._labelLayerId, "visibility", vis);
387
+ return this;
388
+ }
389
+ hide() {
390
+ this._visible = false;
391
+ const vis = "none";
392
+ this._map?.setLayoutProperty(this._fillLayerId, "visibility", vis);
393
+ this._map?.setLayoutProperty(this._strokeLayerId, "visibility", vis);
394
+ if (this._map?.getLayer(this._labelLayerId))
395
+ this._map.setLayoutProperty(this._labelLayerId, "visibility", vis);
396
+ return this;
397
+ }
398
+ isVisible() {
399
+ return this._visible;
400
+ }
401
+ remove() {
402
+ const map = this._map;
403
+ if (!map)
404
+ return;
405
+ for (const lid of [this._labelLayerId, this._strokeLayerId, this._fillLayerId]) {
406
+ if (map.getLayer(lid))
407
+ map.removeLayer(lid);
408
+ }
409
+ if (map.getSource(this._sourceId))
410
+ map.removeSource(this._sourceId);
411
+ this._map = null;
412
+ }
413
+ }
414
+
415
+ let textCounter = 0;
416
+ let Text$1 = class Text {
417
+ constructor(options) {
418
+ this._map = null;
419
+ this._visible = true;
420
+ this.id = `overlay-text-${++textCounter}`;
421
+ this._position = options.position;
422
+ this._text = options.text;
423
+ this._options = { ...options };
424
+ this._sourceId = this.id;
425
+ this._layerId = this.id;
426
+ }
427
+ bindTo(mapOrSdk) {
428
+ const map = mapOrSdk.map ?? mapOrSdk;
429
+ this._map = map;
430
+ this._addToMap();
431
+ return this;
432
+ }
433
+ _geojson() {
434
+ return {
435
+ type: "Feature",
436
+ properties: {
437
+ ...this._options.properties,
438
+ overlayId: this.id,
439
+ _text: this._text,
440
+ },
441
+ geometry: { type: "Point", coordinates: this._position },
442
+ };
443
+ }
444
+ _buildFont() {
445
+ const o = this._options;
446
+ if (o.fontFamily)
447
+ return o.fontFamily;
448
+ const weight = o.fontWeight === "bold" ? "Bold" : "Regular";
449
+ const style = o.fontStyle === "italic" ? " Italic" : "";
450
+ return [`Open Sans ${weight}${style}`, `Arial Unicode MS ${weight}`];
451
+ }
452
+ _addToMap() {
453
+ const map = this._map;
454
+ const o = this._options;
455
+ const before = o.beforeId;
456
+ const zoomFilter = {};
457
+ if (o.minZoom != null)
458
+ zoomFilter.minzoom = o.minZoom;
459
+ if (o.maxZoom != null)
460
+ zoomFilter.maxzoom = o.maxZoom;
461
+ map.addSource(this._sourceId, { type: "geojson", data: this._geojson() });
462
+ const layout = {
463
+ "text-field": ["get", "_text"],
464
+ "text-size": o.fontSize ?? 14,
465
+ "text-anchor": o.anchor ?? "center",
466
+ "text-rotate": o.rotation ?? 0,
467
+ "text-offset": o.offset ?? [0, 0],
468
+ "text-allow-overlap": o.allowOverlap ?? true,
469
+ "text-ignore-placement": o.ignorePlacement ?? false,
470
+ "text-max-width": o.maxWidth ?? 10,
471
+ "text-line-height": o.lineHeight ?? 1.2,
472
+ "text-letter-spacing": o.letterSpacing ?? 0,
473
+ "text-font": this._buildFont(),
474
+ };
475
+ if (o.justify)
476
+ layout["text-justify"] = o.justify;
477
+ const paint = {
478
+ "text-color": o.color ?? "#000000",
479
+ "text-opacity": o.opacity ?? 1,
480
+ "text-halo-color": o.backgroundColor ?? o.haloColor ?? "#ffffff",
481
+ "text-halo-width": o.backgroundColor ? (o.fontSize ?? 14) * 0.3 : (o.haloWidth ?? 1),
482
+ "text-halo-blur": o.haloBlur ?? 0,
483
+ };
484
+ if (o.translate)
485
+ paint["text-translate"] = o.translate;
486
+ map.addLayer({
487
+ id: this._layerId,
488
+ type: "symbol",
489
+ source: this._sourceId,
490
+ ...zoomFilter,
491
+ layout,
492
+ paint,
493
+ }, before);
494
+ if (o.cursor) {
495
+ map.on("mouseenter", this._layerId, () => { map.getCanvas().style.cursor = o.cursor; });
496
+ map.on("mouseleave", this._layerId, () => { map.getCanvas().style.cursor = ""; });
497
+ }
498
+ }
499
+ _updateSource() {
500
+ const src = this._map?.getSource(this._sourceId);
501
+ if (src)
502
+ src.setData(this._geojson());
503
+ }
504
+ getText() {
505
+ return this._text;
506
+ }
507
+ setText(text) {
508
+ this._text = text;
509
+ this._updateSource();
510
+ return this;
511
+ }
512
+ getPosition() {
513
+ return [...this._position];
514
+ }
515
+ setPosition(position) {
516
+ this._position = position;
517
+ this._updateSource();
518
+ return this;
519
+ }
520
+ setStyle(style) {
521
+ const map = this._map;
522
+ if (!map)
523
+ return this;
524
+ if (style.color !== undefined)
525
+ map.setPaintProperty(this._layerId, "text-color", style.color);
526
+ if (style.opacity !== undefined)
527
+ map.setPaintProperty(this._layerId, "text-opacity", style.opacity);
528
+ if (style.haloColor !== undefined)
529
+ map.setPaintProperty(this._layerId, "text-halo-color", style.haloColor);
530
+ if (style.haloWidth !== undefined)
531
+ map.setPaintProperty(this._layerId, "text-halo-width", style.haloWidth);
532
+ if (style.haloBlur !== undefined)
533
+ map.setPaintProperty(this._layerId, "text-halo-blur", style.haloBlur);
534
+ if (style.translate !== undefined)
535
+ map.setPaintProperty(this._layerId, "text-translate", style.translate);
536
+ if (style.fontSize !== undefined)
537
+ map.setLayoutProperty(this._layerId, "text-size", style.fontSize);
538
+ if (style.rotation !== undefined)
539
+ map.setLayoutProperty(this._layerId, "text-rotate", style.rotation);
540
+ if (style.anchor !== undefined)
541
+ map.setLayoutProperty(this._layerId, "text-anchor", style.anchor);
542
+ if (style.offset !== undefined)
543
+ map.setLayoutProperty(this._layerId, "text-offset", style.offset);
544
+ if (style.justify !== undefined)
545
+ map.setLayoutProperty(this._layerId, "text-justify", style.justify);
546
+ if (style.maxWidth !== undefined)
547
+ map.setLayoutProperty(this._layerId, "text-max-width", style.maxWidth);
548
+ if (style.lineHeight !== undefined)
549
+ map.setLayoutProperty(this._layerId, "text-line-height", style.lineHeight);
550
+ if (style.letterSpacing !== undefined)
551
+ map.setLayoutProperty(this._layerId, "text-letter-spacing", style.letterSpacing);
552
+ if (style.fontWeight !== undefined) {
553
+ this._options.fontWeight = style.fontWeight;
554
+ map.setLayoutProperty(this._layerId, "text-font", this._buildFont());
555
+ }
556
+ Object.assign(this._options, style);
557
+ return this;
558
+ }
559
+ show() {
560
+ this._visible = true;
561
+ this._map?.setLayoutProperty(this._layerId, "visibility", "visible");
562
+ return this;
563
+ }
564
+ hide() {
565
+ this._visible = false;
566
+ this._map?.setLayoutProperty(this._layerId, "visibility", "none");
567
+ return this;
568
+ }
569
+ isVisible() {
570
+ return this._visible;
571
+ }
572
+ remove() {
573
+ const map = this._map;
574
+ if (!map)
575
+ return;
576
+ if (map.getLayer(this._layerId))
577
+ map.removeLayer(this._layerId);
578
+ if (map.getSource(this._sourceId))
579
+ map.removeSource(this._sourceId);
580
+ this._map = null;
581
+ }
582
+ };
583
+
584
+ let markerCounter = 0;
585
+ class EnhancedMarker {
586
+ constructor(options) {
587
+ this._map = null;
588
+ this._wrapperEl = null;
589
+ this._labelEl = null;
590
+ this._iconEl = null;
591
+ this._listeners = new Map();
592
+ this._visible = true;
593
+ this.id = `overlay-marker-${++markerCounter}`;
594
+ this._options = { ...options };
595
+ const element = this._buildElement(options);
596
+ const markerOpts = {
597
+ draggable: options.draggable ?? false,
598
+ rotation: options.angle,
599
+ };
600
+ if (element)
601
+ markerOpts.element = element;
602
+ else
603
+ markerOpts.color = options.color ?? "#1890ff";
604
+ if (options.anchor)
605
+ markerOpts.anchor = options.anchor;
606
+ if (options.offset)
607
+ markerOpts.offset = options.offset;
608
+ if (options.scale && !element)
609
+ markerOpts.scale = options.scale;
610
+ this._marker = new _mlGlExports.Marker(markerOpts).setLngLat(options.position);
611
+ if (options.popupContent) {
612
+ this._applyPopup(options.popupContent);
613
+ }
614
+ this._setupEvents();
615
+ }
616
+ _labelPositionCSS() {
617
+ const pos = this._options.labelPosition ?? "bottom";
618
+ switch (pos) {
619
+ case "top": return "flex-direction:column-reverse;";
620
+ case "left": return "flex-direction:row-reverse;";
621
+ case "right": return "flex-direction:row;";
622
+ default: return "flex-direction:column;";
623
+ }
624
+ }
625
+ _buildElement(opts) {
626
+ const needCustom = opts.icon || opts.label || opts.className || opts.opacity != null;
627
+ if (!needCustom)
628
+ return null;
629
+ const wrapper = document.createElement("div");
630
+ wrapper.className = `aviation-marker ${opts.className ?? ""}`.trim();
631
+ wrapper.style.cssText = `display:flex;${this._labelPositionCSS()}align-items:center;cursor:${opts.cursor ?? "pointer"};opacity:${opts.opacity ?? 1};`;
632
+ this._wrapperEl = wrapper;
633
+ if (opts.icon instanceof HTMLElement) {
634
+ wrapper.appendChild(opts.icon);
635
+ this._iconEl = opts.icon;
636
+ }
637
+ else if (typeof opts.icon === "string") {
638
+ const img = document.createElement("img");
639
+ img.src = opts.icon;
640
+ img.style.cssText = `width:${opts.iconWidth ?? 24}px;height:${opts.iconHeight ?? 24}px;`;
641
+ img.draggable = false;
642
+ wrapper.appendChild(img);
643
+ this._iconEl = img;
644
+ }
645
+ if (opts.label) {
646
+ this._labelEl = this._buildLabelEl(opts);
647
+ wrapper.appendChild(this._labelEl);
648
+ }
649
+ return wrapper;
650
+ }
651
+ _buildLabelEl(opts) {
652
+ const label = document.createElement("span");
653
+ label.className = opts.labelClassName ?? "aviation-marker-label";
654
+ label.textContent = opts.label;
655
+ const lo = opts.labelOffset ?? [0, 2];
656
+ label.style.cssText = `
657
+ font-size:${opts.labelFontSize ?? 12}px;
658
+ color:${opts.labelColor ?? "#333"};
659
+ background:${opts.labelBackground ?? "rgba(255,255,255,0.85)"};
660
+ white-space:nowrap;padding:1px 6px;border-radius:3px;
661
+ margin:${lo[1]}px ${lo[0]}px;
662
+ pointer-events:none;
663
+ `;
664
+ return label;
665
+ }
666
+ _applyPopup(content) {
667
+ const popup = new _mlGlExports.Popup({
668
+ offset: this._options.popupOffset ?? 25,
669
+ maxWidth: this._options.popupMaxWidth ?? "240px",
670
+ });
671
+ if (typeof content === "string")
672
+ popup.setHTML(content);
673
+ else
674
+ popup.setDOMContent(content);
675
+ this._marker.setPopup(popup);
676
+ }
677
+ _setupEvents() {
678
+ this._marker.on("dragstart", (e) => this._emit("dragstart", e));
679
+ this._marker.on("drag", (e) => this._emit("drag", e));
680
+ this._marker.on("dragend", (e) => this._emit("dragend", e));
681
+ const el = this._marker.getElement();
682
+ el.addEventListener("click", (e) => this._emit("click", e));
683
+ el.addEventListener("dblclick", (e) => this._emit("dblclick", e));
684
+ el.addEventListener("mouseenter", (e) => this._emit("mouseenter", e));
685
+ el.addEventListener("mouseleave", (e) => this._emit("mouseleave", e));
686
+ }
687
+ bindTo(mapOrSdk) {
688
+ const map = mapOrSdk.map ?? mapOrSdk;
689
+ this._map = map;
690
+ this._marker.addTo(map);
691
+ if (this._options.popupOpen && this._marker.getPopup()) {
692
+ this._marker.togglePopup();
693
+ }
694
+ return this;
695
+ }
696
+ getPosition() {
697
+ const ll = this._marker.getLngLat();
698
+ return [ll.lng, ll.lat];
699
+ }
700
+ setPosition(position) {
701
+ this._marker.setLngLat(position);
702
+ return this;
703
+ }
704
+ getLabel() {
705
+ return this._labelEl?.textContent ?? undefined;
706
+ }
707
+ setLabel(label) {
708
+ if (this._labelEl) {
709
+ this._labelEl.textContent = label;
710
+ }
711
+ else if (this._wrapperEl) {
712
+ this._options.label = label;
713
+ this._labelEl = this._buildLabelEl(this._options);
714
+ this._wrapperEl.appendChild(this._labelEl);
715
+ }
716
+ return this;
717
+ }
718
+ setLabelStyle(style) {
719
+ if (!this._labelEl)
720
+ return this;
721
+ if (style.labelFontSize !== undefined)
722
+ this._labelEl.style.fontSize = `${style.labelFontSize}px`;
723
+ if (style.labelColor !== undefined)
724
+ this._labelEl.style.color = style.labelColor;
725
+ if (style.labelBackground !== undefined)
726
+ this._labelEl.style.background = style.labelBackground;
727
+ Object.assign(this._options, style);
728
+ return this;
729
+ }
730
+ setIcon(icon) {
731
+ if (typeof icon === "string" && this._iconEl instanceof HTMLImageElement) {
732
+ this._iconEl.src = icon;
733
+ }
734
+ else if (this._wrapperEl && this._iconEl) {
735
+ const newEl = icon instanceof HTMLElement ? icon : (() => {
736
+ const img = document.createElement("img");
737
+ img.src = icon;
738
+ img.style.cssText = `width:${this._options.iconWidth ?? 24}px;height:${this._options.iconHeight ?? 24}px;`;
739
+ img.draggable = false;
740
+ return img;
741
+ })();
742
+ this._wrapperEl.replaceChild(newEl, this._iconEl);
743
+ this._iconEl = newEl;
744
+ }
745
+ return this;
746
+ }
747
+ setIconSize(width, height) {
748
+ this._options.iconWidth = width;
749
+ this._options.iconHeight = height;
750
+ if (this._iconEl instanceof HTMLImageElement) {
751
+ this._iconEl.style.width = `${width}px`;
752
+ this._iconEl.style.height = `${height}px`;
753
+ }
754
+ return this;
755
+ }
756
+ getDraggable() {
757
+ return this._marker.isDraggable();
758
+ }
759
+ setDraggable(draggable) {
760
+ this._marker.setDraggable(draggable);
761
+ return this;
762
+ }
763
+ getAngle() {
764
+ return this._marker.getRotation();
765
+ }
766
+ setAngle(angle) {
767
+ this._marker.setRotation(angle);
768
+ return this;
769
+ }
770
+ setOpacity(opacity) {
771
+ this._options.opacity = opacity;
772
+ this._marker.getElement().style.opacity = String(opacity);
773
+ return this;
774
+ }
775
+ setPopup(content) {
776
+ this._applyPopup(content);
777
+ return this;
778
+ }
779
+ openPopup() {
780
+ const popup = this._marker.getPopup();
781
+ if (popup && !popup.isOpen())
782
+ this._marker.togglePopup();
783
+ return this;
784
+ }
785
+ closePopup() {
786
+ const popup = this._marker.getPopup();
787
+ if (popup && popup.isOpen())
788
+ this._marker.togglePopup();
789
+ return this;
790
+ }
791
+ show() {
792
+ this._visible = true;
793
+ this._marker.getElement().style.display = "";
794
+ return this;
795
+ }
796
+ hide() {
797
+ this._visible = false;
798
+ this._marker.getElement().style.display = "none";
799
+ return this;
800
+ }
801
+ isVisible() {
802
+ return this._visible;
803
+ }
804
+ on(event, fn) {
805
+ if (!this._listeners.has(event))
806
+ this._listeners.set(event, new Set());
807
+ this._listeners.get(event).add(fn);
808
+ return this;
809
+ }
810
+ off(event, fn) {
811
+ this._listeners.get(event)?.delete(fn);
812
+ return this;
813
+ }
814
+ _emit(event, data) {
815
+ this._listeners.get(event)?.forEach((fn) => fn(data));
816
+ }
817
+ remove() {
818
+ this._marker.remove();
819
+ this._listeners.clear();
820
+ this._map = null;
821
+ }
822
+ }
823
+
824
+ const LINE_DASHARRAY = {
825
+ solid: undefined,
826
+ dashed: [6, 4],
827
+ dotted: [1, 3],
828
+ "dash-dot": [8, 4, 2, 4],
829
+ "long-dash": [12, 6],
830
+ "double-dash": [6, 2, 6, 8],
831
+ };
832
+ let polylineCounter = 0;
833
+ class Polyline {
834
+ constructor(options) {
835
+ this._map = null;
836
+ this._visible = true;
837
+ this.id = `overlay-polyline-${++polylineCounter}`;
838
+ this._path = options.path.map((c) => [...c]);
839
+ this._options = { ...options };
840
+ this._sourceId = this.id;
841
+ this._borderLayerId = `${this.id}-border`;
842
+ this._layerId = this.id;
843
+ this._arrowLayerId = `${this.id}-arrow`;
844
+ this._labelLayerId = `${this.id}-label`;
845
+ }
846
+ bindTo(mapOrSdk) {
847
+ const map = mapOrSdk.map ?? mapOrSdk;
848
+ this._map = map;
849
+ this._addToMap();
850
+ return this;
851
+ }
852
+ _geojson() {
853
+ return {
854
+ type: "Feature",
855
+ properties: { ...this._options.properties, overlayId: this.id, _label: this._options.label ?? "" },
856
+ geometry: { type: "LineString", coordinates: this._path },
857
+ };
858
+ }
859
+ _resolveDasharray() {
860
+ if (this._options.lineType)
861
+ return LINE_DASHARRAY[this._options.lineType];
862
+ return this._options.dasharray;
863
+ }
864
+ _addToMap() {
865
+ const map = this._map;
866
+ const o = this._options;
867
+ const before = o.beforeId;
868
+ map.addSource(this._sourceId, { type: "geojson", data: this._geojson() });
869
+ if (o.borderWidth && o.borderWidth > 0) {
870
+ map.addLayer({
871
+ id: this._borderLayerId,
872
+ type: "line",
873
+ source: this._sourceId,
874
+ ...(o.minZoom != null ? { minzoom: o.minZoom } : {}),
875
+ ...(o.maxZoom != null ? { maxzoom: o.maxZoom } : {}),
876
+ layout: {
877
+ "line-cap": o.lineCap ?? "round",
878
+ "line-join": o.lineJoin ?? "round",
879
+ },
880
+ paint: {
881
+ "line-color": o.borderColor ?? "#000000",
882
+ "line-width": (o.width ?? 2) + (o.borderWidth ?? 0) * 2,
883
+ "line-opacity": o.opacity ?? 1,
884
+ },
885
+ }, before);
886
+ }
887
+ const paint = {
888
+ "line-color": o.color ?? "#1890ff",
889
+ "line-width": o.width ?? 2,
890
+ "line-opacity": o.opacity ?? 1,
891
+ };
892
+ const dash = this._resolveDasharray();
893
+ if (dash)
894
+ paint["line-dasharray"] = dash;
895
+ if (o.blur)
896
+ paint["line-blur"] = o.blur;
897
+ if (o.offset)
898
+ paint["line-offset"] = o.offset;
899
+ if (o.translate)
900
+ paint["line-translate"] = o.translate;
901
+ if (o.gradient)
902
+ paint["line-gradient"] = o.gradient;
903
+ const layout = {
904
+ "line-cap": o.lineCap ?? "round",
905
+ "line-join": o.lineJoin ?? "round",
906
+ };
907
+ if (o.miterLimit != null)
908
+ layout["line-miter-limit"] = o.miterLimit;
909
+ if (o.roundLimit != null)
910
+ layout["line-round-limit"] = o.roundLimit;
911
+ map.addLayer({
912
+ id: this._layerId,
913
+ type: "line",
914
+ source: this._sourceId,
915
+ ...(o.minZoom != null ? { minzoom: o.minZoom } : {}),
916
+ ...(o.maxZoom != null ? { maxzoom: o.maxZoom } : {}),
917
+ layout,
918
+ paint,
919
+ }, before);
920
+ if (o.showArrow) {
921
+ this._ensureArrowImage(map);
922
+ map.addLayer({
923
+ id: this._arrowLayerId,
924
+ type: "symbol",
925
+ source: this._sourceId,
926
+ ...(o.minZoom != null ? { minzoom: o.minZoom } : {}),
927
+ ...(o.maxZoom != null ? { maxzoom: o.maxZoom } : {}),
928
+ layout: {
929
+ "symbol-placement": "line",
930
+ "symbol-spacing": o.arrowSpacing ?? 100,
931
+ "icon-image": "__overlay_arrow__",
932
+ "icon-size": Math.max(0.6, (o.width ?? 2) / 5),
933
+ "icon-allow-overlap": true,
934
+ "icon-rotation-alignment": "map",
935
+ },
936
+ }, before);
937
+ }
938
+ if (o.label) {
939
+ map.addLayer({
940
+ id: this._labelLayerId,
941
+ type: "symbol",
942
+ source: this._sourceId,
943
+ ...(o.minZoom != null ? { minzoom: o.minZoom } : {}),
944
+ ...(o.maxZoom != null ? { maxzoom: o.maxZoom } : {}),
945
+ layout: {
946
+ "symbol-placement": "line",
947
+ "symbol-spacing": o.labelSpacing ?? 250,
948
+ "text-field": ["get", "_label"],
949
+ "text-size": o.labelSize ?? 12,
950
+ "text-offset": o.labelOffset ?? [0, -0.8],
951
+ "text-allow-overlap": false,
952
+ "text-rotation-alignment": "map",
953
+ },
954
+ paint: {
955
+ "text-color": o.labelColor ?? o.color ?? "#1890ff",
956
+ "text-halo-color": o.labelHaloColor ?? "#ffffff",
957
+ "text-halo-width": o.labelHaloWidth ?? 1,
958
+ },
959
+ }, before);
960
+ }
961
+ if (o.cursor) {
962
+ map.on("mouseenter", this._layerId, () => { map.getCanvas().style.cursor = o.cursor; });
963
+ map.on("mouseleave", this._layerId, () => { map.getCanvas().style.cursor = ""; });
964
+ }
965
+ }
966
+ _ensureArrowImage(map) {
967
+ if (map.hasImage("__overlay_arrow__"))
968
+ return;
969
+ const size = 16;
970
+ const data = new Uint8Array(size * size * 4);
971
+ for (let y = 0; y < size; y++) {
972
+ for (let x = 0; x < size; x++) {
973
+ const cx = x - size / 2, cy = y - size / 2;
974
+ const inArrow = cx >= 0 && Math.abs(cy) <= (size / 2 - cx) * 0.6;
975
+ const idx = (y * size + x) * 4;
976
+ if (inArrow) {
977
+ data[idx] = 255;
978
+ data[idx + 1] = 255;
979
+ data[idx + 2] = 255;
980
+ data[idx + 3] = 255;
981
+ }
982
+ }
983
+ }
984
+ map.addImage("__overlay_arrow__", { width: size, height: size, data }, { sdf: true });
985
+ }
986
+ _updateSource() {
987
+ const src = this._map?.getSource(this._sourceId);
988
+ if (src)
989
+ src.setData(this._geojson());
990
+ }
991
+ getPath() {
992
+ return this._path.map((c) => [...c]);
993
+ }
994
+ setPath(path) {
995
+ this._path = path.map((c) => [...c]);
996
+ this._updateSource();
997
+ return this;
998
+ }
999
+ getLength() {
1000
+ return polylineLength(this._path);
1001
+ }
1002
+ getBounds() {
1003
+ return computeBounds(this._path);
1004
+ }
1005
+ setStyle(style) {
1006
+ const map = this._map;
1007
+ if (!map)
1008
+ return this;
1009
+ if (style.color !== undefined) {
1010
+ map.setPaintProperty(this._layerId, "line-color", style.color);
1011
+ }
1012
+ if (style.width !== undefined) {
1013
+ map.setPaintProperty(this._layerId, "line-width", style.width);
1014
+ if (map.getLayer(this._borderLayerId)) {
1015
+ map.setPaintProperty(this._borderLayerId, "line-width", style.width + (this._options.borderWidth ?? 0) * 2);
1016
+ }
1017
+ }
1018
+ if (style.opacity !== undefined) {
1019
+ map.setPaintProperty(this._layerId, "line-opacity", style.opacity);
1020
+ if (map.getLayer(this._borderLayerId))
1021
+ map.setPaintProperty(this._borderLayerId, "line-opacity", style.opacity);
1022
+ }
1023
+ if (style.lineType !== undefined || style.dasharray !== undefined) {
1024
+ Object.assign(this._options, style);
1025
+ const dash = this._resolveDasharray();
1026
+ map.setPaintProperty(this._layerId, "line-dasharray", dash ?? []);
1027
+ }
1028
+ if (style.blur !== undefined)
1029
+ map.setPaintProperty(this._layerId, "line-blur", style.blur);
1030
+ if (style.offset !== undefined)
1031
+ map.setPaintProperty(this._layerId, "line-offset", style.offset);
1032
+ if (style.translate !== undefined)
1033
+ map.setPaintProperty(this._layerId, "line-translate", style.translate);
1034
+ if (style.borderColor !== undefined && map.getLayer(this._borderLayerId)) {
1035
+ map.setPaintProperty(this._borderLayerId, "line-color", style.borderColor);
1036
+ }
1037
+ if (style.lineCap !== undefined)
1038
+ map.setLayoutProperty(this._layerId, "line-cap", style.lineCap);
1039
+ if (style.lineJoin !== undefined)
1040
+ map.setLayoutProperty(this._layerId, "line-join", style.lineJoin);
1041
+ Object.assign(this._options, style);
1042
+ return this;
1043
+ }
1044
+ setLabel(label) {
1045
+ this._options.label = label;
1046
+ this._updateSource();
1047
+ return this;
1048
+ }
1049
+ show() {
1050
+ this._visible = true;
1051
+ const vis = "visible";
1052
+ this._map?.setLayoutProperty(this._layerId, "visibility", vis);
1053
+ if (this._map?.getLayer(this._borderLayerId))
1054
+ this._map.setLayoutProperty(this._borderLayerId, "visibility", vis);
1055
+ if (this._map?.getLayer(this._arrowLayerId))
1056
+ this._map.setLayoutProperty(this._arrowLayerId, "visibility", vis);
1057
+ if (this._map?.getLayer(this._labelLayerId))
1058
+ this._map.setLayoutProperty(this._labelLayerId, "visibility", vis);
1059
+ return this;
1060
+ }
1061
+ hide() {
1062
+ this._visible = false;
1063
+ const vis = "none";
1064
+ this._map?.setLayoutProperty(this._layerId, "visibility", vis);
1065
+ if (this._map?.getLayer(this._borderLayerId))
1066
+ this._map.setLayoutProperty(this._borderLayerId, "visibility", vis);
1067
+ if (this._map?.getLayer(this._arrowLayerId))
1068
+ this._map.setLayoutProperty(this._arrowLayerId, "visibility", vis);
1069
+ if (this._map?.getLayer(this._labelLayerId))
1070
+ this._map.setLayoutProperty(this._labelLayerId, "visibility", vis);
1071
+ return this;
1072
+ }
1073
+ isVisible() {
1074
+ return this._visible;
1075
+ }
1076
+ remove() {
1077
+ const map = this._map;
1078
+ if (!map)
1079
+ return;
1080
+ for (const lid of [this._labelLayerId, this._arrowLayerId, this._layerId, this._borderLayerId]) {
1081
+ if (map.getLayer(lid))
1082
+ map.removeLayer(lid);
1083
+ }
1084
+ if (map.getSource(this._sourceId))
1085
+ map.removeSource(this._sourceId);
1086
+ this._map = null;
1087
+ }
1088
+ }
1089
+
1090
+ let polygonCounter = 0;
1091
+ class EnhancedPolygon {
1092
+ constructor(options) {
1093
+ this._map = null;
1094
+ this._visible = true;
1095
+ this.id = `overlay-polygon-${++polygonCounter}`;
1096
+ this._path = options.path.map((ring) => ring.map((c) => [...c]));
1097
+ this._options = { ...options };
1098
+ this._sourceId = this.id;
1099
+ this._fillLayerId = `${this.id}-fill`;
1100
+ this._strokeLayerId = `${this.id}-stroke`;
1101
+ this._labelLayerId = `${this.id}-label`;
1102
+ }
1103
+ bindTo(mapOrSdk) {
1104
+ const map = mapOrSdk.map ?? mapOrSdk;
1105
+ this._map = map;
1106
+ this._addToMap();
1107
+ return this;
1108
+ }
1109
+ _geojson() {
1110
+ const centroid = this._centroid();
1111
+ return {
1112
+ type: "FeatureCollection",
1113
+ features: [
1114
+ {
1115
+ type: "Feature",
1116
+ properties: { ...this._options.properties, overlayId: this.id, _label: this._options.label ?? "" },
1117
+ geometry: { type: "Polygon", coordinates: this._path },
1118
+ },
1119
+ {
1120
+ type: "Feature",
1121
+ properties: { overlayId: this.id, _label: this._options.label ?? "", _type: "centroid" },
1122
+ geometry: { type: "Point", coordinates: centroid },
1123
+ },
1124
+ ],
1125
+ };
1126
+ }
1127
+ _centroid() {
1128
+ const ring = this._path[0];
1129
+ if (!ring || ring.length === 0)
1130
+ return [0, 0];
1131
+ let lngSum = 0, latSum = 0;
1132
+ for (const [lng, lat] of ring) {
1133
+ lngSum += lng;
1134
+ latSum += lat;
1135
+ }
1136
+ return [lngSum / ring.length, latSum / ring.length];
1137
+ }
1138
+ _resolveStrokeDash() {
1139
+ if (this._options.strokeLineType)
1140
+ return STROKE_DASHARRAY[this._options.strokeLineType];
1141
+ return this._options.strokeDasharray;
1142
+ }
1143
+ _addToMap() {
1144
+ const map = this._map;
1145
+ const o = this._options;
1146
+ const before = o.beforeId;
1147
+ const zoomFilter = {};
1148
+ if (o.minZoom != null)
1149
+ zoomFilter.minzoom = o.minZoom;
1150
+ if (o.maxZoom != null)
1151
+ zoomFilter.maxzoom = o.maxZoom;
1152
+ map.addSource(this._sourceId, { type: "geojson", data: this._geojson() });
1153
+ const fillPaint = {
1154
+ "fill-color": o.color ?? "#1890ff",
1155
+ "fill-opacity": o.opacity ?? 0.25,
1156
+ "fill-antialias": o.antialias ?? true,
1157
+ };
1158
+ if (o.fillTranslate)
1159
+ fillPaint["fill-translate"] = o.fillTranslate;
1160
+ if (o.fillPattern)
1161
+ fillPaint["fill-pattern"] = o.fillPattern;
1162
+ map.addLayer({
1163
+ id: this._fillLayerId,
1164
+ type: "fill",
1165
+ source: this._sourceId,
1166
+ filter: ["==", ["geometry-type"], "Polygon"],
1167
+ ...zoomFilter,
1168
+ paint: fillPaint,
1169
+ }, before);
1170
+ const strokePaint = {
1171
+ "line-color": o.strokeColor ?? o.color ?? "#1890ff",
1172
+ "line-width": o.strokeWidth ?? 2,
1173
+ "line-opacity": o.strokeOpacity ?? 0.8,
1174
+ };
1175
+ const dash = this._resolveStrokeDash();
1176
+ if (dash)
1177
+ strokePaint["line-dasharray"] = dash;
1178
+ if (o.strokeBlur)
1179
+ strokePaint["line-blur"] = o.strokeBlur;
1180
+ if (o.strokeOffset)
1181
+ strokePaint["line-offset"] = o.strokeOffset;
1182
+ if (o.strokeTranslate)
1183
+ strokePaint["line-translate"] = o.strokeTranslate;
1184
+ map.addLayer({
1185
+ id: this._strokeLayerId,
1186
+ type: "line",
1187
+ source: this._sourceId,
1188
+ filter: ["==", ["geometry-type"], "Polygon"],
1189
+ ...zoomFilter,
1190
+ layout: {
1191
+ "line-cap": o.strokeLineCap ?? "round",
1192
+ "line-join": o.strokeLineJoin ?? "round",
1193
+ },
1194
+ paint: strokePaint,
1195
+ }, before);
1196
+ if (o.label) {
1197
+ map.addLayer({
1198
+ id: this._labelLayerId,
1199
+ type: "symbol",
1200
+ source: this._sourceId,
1201
+ filter: ["==", ["get", "_type"], "centroid"],
1202
+ ...zoomFilter,
1203
+ layout: {
1204
+ "text-field": ["get", "_label"],
1205
+ "text-size": o.labelSize ?? 14,
1206
+ "text-anchor": o.labelAnchor ?? "center",
1207
+ "text-offset": o.labelOffset ?? [0, 0],
1208
+ "text-allow-overlap": true,
1209
+ },
1210
+ paint: {
1211
+ "text-color": o.labelColor ?? "#333333",
1212
+ "text-halo-color": o.labelHaloColor ?? "#ffffff",
1213
+ "text-halo-width": o.labelHaloWidth ?? 1,
1214
+ },
1215
+ }, before);
1216
+ }
1217
+ if (o.cursor) {
1218
+ map.on("mouseenter", this._fillLayerId, () => { map.getCanvas().style.cursor = o.cursor; });
1219
+ map.on("mouseleave", this._fillLayerId, () => { map.getCanvas().style.cursor = ""; });
1220
+ }
1221
+ }
1222
+ _updateSource() {
1223
+ const src = this._map?.getSource(this._sourceId);
1224
+ if (src)
1225
+ src.setData(this._geojson());
1226
+ }
1227
+ getPath() {
1228
+ return this._path.map((ring) => ring.map((c) => [...c]));
1229
+ }
1230
+ setPath(path) {
1231
+ this._path = path.map((ring) => ring.map((c) => [...c]));
1232
+ this._updateSource();
1233
+ return this;
1234
+ }
1235
+ getArea() {
1236
+ const ring = this._path[0];
1237
+ if (!ring)
1238
+ return 0;
1239
+ return polygonArea(ring);
1240
+ }
1241
+ getBounds() {
1242
+ return computeBounds(flattenCoords(this._path));
1243
+ }
1244
+ contains(lnglat) {
1245
+ const ring = this._path[0];
1246
+ if (!ring)
1247
+ return false;
1248
+ return pointInPolygon(lnglat, ring);
1249
+ }
1250
+ setStyle(style) {
1251
+ const map = this._map;
1252
+ if (!map)
1253
+ return this;
1254
+ if (style.color !== undefined)
1255
+ map.setPaintProperty(this._fillLayerId, "fill-color", style.color);
1256
+ if (style.opacity !== undefined)
1257
+ map.setPaintProperty(this._fillLayerId, "fill-opacity", style.opacity);
1258
+ if (style.fillTranslate !== undefined)
1259
+ map.setPaintProperty(this._fillLayerId, "fill-translate", style.fillTranslate);
1260
+ if (style.fillPattern !== undefined)
1261
+ map.setPaintProperty(this._fillLayerId, "fill-pattern", style.fillPattern);
1262
+ if (style.antialias !== undefined)
1263
+ map.setPaintProperty(this._fillLayerId, "fill-antialias", style.antialias);
1264
+ if (style.strokeColor !== undefined)
1265
+ map.setPaintProperty(this._strokeLayerId, "line-color", style.strokeColor);
1266
+ if (style.strokeWidth !== undefined)
1267
+ map.setPaintProperty(this._strokeLayerId, "line-width", style.strokeWidth);
1268
+ if (style.strokeOpacity !== undefined)
1269
+ map.setPaintProperty(this._strokeLayerId, "line-opacity", style.strokeOpacity);
1270
+ if (style.strokeLineType !== undefined || style.strokeDasharray !== undefined) {
1271
+ Object.assign(this._options, style);
1272
+ const dash = this._resolveStrokeDash();
1273
+ map.setPaintProperty(this._strokeLayerId, "line-dasharray", dash ?? []);
1274
+ }
1275
+ if (style.strokeBlur !== undefined)
1276
+ map.setPaintProperty(this._strokeLayerId, "line-blur", style.strokeBlur);
1277
+ if (style.strokeOffset !== undefined)
1278
+ map.setPaintProperty(this._strokeLayerId, "line-offset", style.strokeOffset);
1279
+ if (style.strokeTranslate !== undefined)
1280
+ map.setPaintProperty(this._strokeLayerId, "line-translate", style.strokeTranslate);
1281
+ if (style.strokeLineCap !== undefined)
1282
+ map.setLayoutProperty(this._strokeLayerId, "line-cap", style.strokeLineCap);
1283
+ if (style.strokeLineJoin !== undefined)
1284
+ map.setLayoutProperty(this._strokeLayerId, "line-join", style.strokeLineJoin);
1285
+ Object.assign(this._options, style);
1286
+ return this;
1287
+ }
1288
+ setLabel(label) {
1289
+ this._options.label = label;
1290
+ this._updateSource();
1291
+ return this;
1292
+ }
1293
+ show() {
1294
+ this._visible = true;
1295
+ const vis = "visible";
1296
+ this._map?.setLayoutProperty(this._fillLayerId, "visibility", vis);
1297
+ this._map?.setLayoutProperty(this._strokeLayerId, "visibility", vis);
1298
+ if (this._map?.getLayer(this._labelLayerId))
1299
+ this._map.setLayoutProperty(this._labelLayerId, "visibility", vis);
1300
+ return this;
1301
+ }
1302
+ hide() {
1303
+ this._visible = false;
1304
+ const vis = "none";
1305
+ this._map?.setLayoutProperty(this._fillLayerId, "visibility", vis);
1306
+ this._map?.setLayoutProperty(this._strokeLayerId, "visibility", vis);
1307
+ if (this._map?.getLayer(this._labelLayerId))
1308
+ this._map.setLayoutProperty(this._labelLayerId, "visibility", vis);
1309
+ return this;
1310
+ }
1311
+ isVisible() {
1312
+ return this._visible;
1313
+ }
1314
+ remove() {
1315
+ const map = this._map;
1316
+ if (!map)
1317
+ return;
1318
+ for (const lid of [this._labelLayerId, this._strokeLayerId, this._fillLayerId]) {
1319
+ if (map.getLayer(lid))
1320
+ map.removeLayer(lid);
1321
+ }
1322
+ if (map.getSource(this._sourceId))
1323
+ map.removeSource(this._sourceId);
1324
+ this._map = null;
1325
+ }
1326
+ }
1327
+
91
1328
  // AMM layer styles — multi-theme support.
92
1329
 
93
1330
  // ── Light theme colors ────────────────────────────────────────────────────────
@@ -4073,7 +5310,7 @@ function buildLayersLight() {
4073
5310
  "text-anchor": "bottom",
4074
5311
  "text-justify": "center",
4075
5312
  "text-size": ["interpolate", ["linear"], ["zoom"], 4, 0, 5, 12],
4076
- "text-offset": ["interpolate", ["linear"], ["zoom"], 4, ["literal", [0, -1.2]], 5, ["literal", [0, -0.6]]],
5313
+ "text-offset": [0, -1.2],
4077
5314
  "icon-allow-overlap": true,
4078
5315
  "icon-ignore-placement": true,
4079
5316
  "text-allow-overlap": true,
@@ -5210,6 +6447,21 @@ class MapSDK {
5210
6447
  addGeoJSON(sourceId, geojson, props) {
5211
6448
  return this.geoJSONManager.addGeoJSON(sourceId, geojson, props);
5212
6449
  }
6450
+ createCircle(options) {
6451
+ return new Circle(options).bindTo(this);
6452
+ }
6453
+ createText(options) {
6454
+ return new Text$1(options).bindTo(this);
6455
+ }
6456
+ createMarker(options) {
6457
+ return new EnhancedMarker(options).bindTo(this);
6458
+ }
6459
+ createPolyline(options) {
6460
+ return new Polyline(options).bindTo(this);
6461
+ }
6462
+ createPolygon(options) {
6463
+ return new EnhancedPolygon(options).bindTo(this);
6464
+ }
5213
6465
  addLayer(layerConfig) {
5214
6466
  this.layerManager.addLayer(layerConfig);
5215
6467
  }
@@ -27034,4 +28286,4 @@ var LngLat = _mlGlExports.LngLat;
27034
28286
  var LngLatBounds = _mlGlExports.LngLatBounds;
27035
28287
  var Marker = _mlGlExports.Marker;
27036
28288
  var Popup = _mlGlExports.Popup;
27037
- export { API, MapSDK as AviationChart, CHART_THEMES, DEFAULT_LAYER_VISIBILITY, DrawPlugin, ErrorManager, GROUP_ALIASES, GeoJSONManager, LAYER_GROUPS, LAYER_LABELS, LayerManager, LngLat, LngLatBounds, _mlGl as MapEngine, MapSDK, Marker, MeasurePlugin, NOTAM, PerformanceManager, PluginManager, Popup, TYPEMAP, WindManager, MapSDK as default, globalConfig };
28289
+ export { API, MapSDK as AviationChart, CHART_THEMES, Circle, DEFAULT_LAYER_VISIBILITY, DrawPlugin, EnhancedMarker, EnhancedPolygon, ErrorManager, GROUP_ALIASES, GeoJSONManager, LAYER_GROUPS, LAYER_LABELS, LayerManager, LngLat, LngLatBounds, _mlGl as MapEngine, MapSDK, Marker, MeasurePlugin, NOTAM, PerformanceManager, PluginManager, Polyline, Popup, TYPEMAP, Text$1 as Text, WindManager, MapSDK as default, globalConfig };