web-mojo 2.2.24 → 2.2.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/dist/admin.cjs.js +1 -1
  2. package/dist/admin.cjs.js.map +1 -1
  3. package/dist/admin.es.js +13 -802
  4. package/dist/admin.es.js.map +1 -1
  5. package/dist/auth.cjs.js +1 -1
  6. package/dist/auth.es.js +1 -1
  7. package/dist/charts.cjs.js +1 -1
  8. package/dist/charts.es.js +4 -4
  9. package/dist/chunks/{ChatView-DK692WUV.js → ChatView-ChGpB5fY.js} +2 -2
  10. package/dist/chunks/{ChatView-DK692WUV.js.map → ChatView-ChGpB5fY.js.map} +1 -1
  11. package/dist/chunks/{ChatView-WQHC44om.js → ChatView-wMhIMZ01.js} +7 -7
  12. package/dist/chunks/{ChatView-WQHC44om.js.map → ChatView-wMhIMZ01.js.map} +1 -1
  13. package/dist/chunks/{Collection-DFPQ8X0o.js → Collection-9DhgHESv.js} +2 -2
  14. package/dist/chunks/{Collection-DFPQ8X0o.js.map → Collection-9DhgHESv.js.map} +1 -1
  15. package/dist/chunks/{ContextMenu-BEFu3lOK.js → ContextMenu-fsEv-iq5.js} +3 -3
  16. package/dist/chunks/{ContextMenu-BEFu3lOK.js.map → ContextMenu-fsEv-iq5.js.map} +1 -1
  17. package/dist/chunks/{DataView-BC82eli9.js → DataView-aFvKzCsO.js} +2 -2
  18. package/dist/chunks/{DataView-BC82eli9.js.map → DataView-aFvKzCsO.js.map} +1 -1
  19. package/dist/chunks/{Dialog-C2P6rKyT.js → Dialog-2U9faiAH.js} +6 -1370
  20. package/dist/chunks/Dialog-2U9faiAH.js.map +1 -0
  21. package/dist/chunks/Dialog-t8WYyPj8.js +2 -0
  22. package/dist/chunks/Dialog-t8WYyPj8.js.map +1 -0
  23. package/dist/chunks/FormPlugins-CEjco_Hb.js +2 -0
  24. package/dist/chunks/FormPlugins-CEjco_Hb.js.map +1 -0
  25. package/dist/chunks/FormPlugins-DY6e88YT.js +124 -0
  26. package/dist/chunks/FormPlugins-DY6e88YT.js.map +1 -0
  27. package/dist/chunks/{FormView-DPqIYixn.js → FormView-D6TdblYe.js} +3 -122
  28. package/dist/chunks/FormView-D6TdblYe.js.map +1 -0
  29. package/dist/chunks/FormView-DokttDQL.js +3 -0
  30. package/dist/chunks/FormView-DokttDQL.js.map +1 -0
  31. package/dist/chunks/{ListView-Db3Qhvpx.js → ListView-Whl0135W.js} +5 -5
  32. package/dist/chunks/{ListView-Db3Qhvpx.js.map → ListView-Whl0135W.js.map} +1 -1
  33. package/dist/chunks/MetricsCountryMapView-BNpojbUy.js +1054 -0
  34. package/dist/chunks/MetricsCountryMapView-BNpojbUy.js.map +1 -0
  35. package/dist/chunks/MetricsCountryMapView-D1bXRxjZ.js +2 -0
  36. package/dist/chunks/MetricsCountryMapView-D1bXRxjZ.js.map +1 -0
  37. package/dist/chunks/MetricsMiniChartWidget-BaQjSl7x.js +2 -0
  38. package/dist/chunks/{MetricsMiniChartWidget-CQdjokTH.js.map → MetricsMiniChartWidget-BaQjSl7x.js.map} +1 -1
  39. package/dist/chunks/{MetricsMiniChartWidget-BkyY9Z4b.js → MetricsMiniChartWidget-C976DEgD.js} +4 -4
  40. package/dist/chunks/{MetricsMiniChartWidget-BkyY9Z4b.js.map → MetricsMiniChartWidget-C976DEgD.js.map} +1 -1
  41. package/dist/chunks/{PDFViewer-DvAQE5qi.js → PDFViewer-Bx7pn5kV.js} +2 -2
  42. package/dist/chunks/{PDFViewer-DvAQE5qi.js.map → PDFViewer-Bx7pn5kV.js.map} +1 -1
  43. package/dist/chunks/{PDFViewer-DQaqFVAJ.js → PDFViewer-DQwOZokX.js} +3 -3
  44. package/dist/chunks/{PDFViewer-DQaqFVAJ.js.map → PDFViewer-DQwOZokX.js.map} +1 -1
  45. package/dist/chunks/{Rest-Bqy5Cbt6.js → Rest-DnVeH4wg.js} +5 -5
  46. package/dist/chunks/{Rest-Bqy5Cbt6.js.map → Rest-DnVeH4wg.js.map} +1 -1
  47. package/dist/chunks/TokenManager-Bwdnkh5h.js +2 -0
  48. package/dist/chunks/{TokenManager-DuTYWpFy.js.map → TokenManager-Bwdnkh5h.js.map} +1 -1
  49. package/dist/chunks/{TokenManager-B_Su1An2.js → TokenManager-EiNkojsp.js} +5 -5
  50. package/dist/chunks/{TokenManager-B_Su1An2.js.map → TokenManager-EiNkojsp.js.map} +1 -1
  51. package/dist/chunks/WebApp-D1ob7GxI.js +2 -0
  52. package/dist/chunks/WebApp-D1ob7GxI.js.map +1 -0
  53. package/dist/chunks/WebApp-DEo7MILL.js +1364 -0
  54. package/dist/chunks/WebApp-DEo7MILL.js.map +1 -0
  55. package/dist/chunks/{WebSocketClient-Dz0AiiM-.js → WebSocketClient-D6kP3imj.js} +2 -2
  56. package/dist/chunks/{WebSocketClient-Dz0AiiM-.js.map → WebSocketClient-D6kP3imj.js.map} +1 -1
  57. package/dist/chunks/{version-Bu21rfOy.js → version-CbWgDs2g.js} +4 -4
  58. package/dist/chunks/{version-Bu21rfOy.js.map → version-CbWgDs2g.js.map} +1 -1
  59. package/dist/chunks/{version-1GKnq64r.js → version-DGV8FEbm.js} +2 -2
  60. package/dist/chunks/{version-1GKnq64r.js.map → version-DGV8FEbm.js.map} +1 -1
  61. package/dist/css/web-mojo.css +1 -1
  62. package/dist/docit.cjs.js +1 -1
  63. package/dist/docit.es.js +6 -6
  64. package/dist/index.cjs.js +1 -1
  65. package/dist/index.cjs.js.map +1 -1
  66. package/dist/index.es.js +28 -27
  67. package/dist/index.es.js.map +1 -1
  68. package/dist/lightbox.cjs.js +1 -1
  69. package/dist/lightbox.cjs.js.map +1 -1
  70. package/dist/lightbox.es.js +5 -5
  71. package/dist/map.cjs.js +1 -1
  72. package/dist/map.cjs.js.map +1 -1
  73. package/dist/map.es.js +995 -229
  74. package/dist/map.es.js.map +1 -1
  75. package/dist/timeline.es.js +4 -4
  76. package/package.json +1 -1
  77. package/dist/chunks/Dialog-C2P6rKyT.js.map +0 -1
  78. package/dist/chunks/Dialog-CA4DXjJ5.js +0 -2
  79. package/dist/chunks/Dialog-CA4DXjJ5.js.map +0 -1
  80. package/dist/chunks/FormView-BVWavB_q.js +0 -3
  81. package/dist/chunks/FormView-BVWavB_q.js.map +0 -1
  82. package/dist/chunks/FormView-DPqIYixn.js.map +0 -1
  83. package/dist/chunks/MetricsMiniChartWidget-CQdjokTH.js +0 -2
  84. package/dist/chunks/TokenManager-DuTYWpFy.js +0 -2
@@ -0,0 +1,1054 @@
1
+ import { V as View } from "./Rest-DnVeH4wg.js";
2
+ class MapView extends View {
3
+ constructor(options = {}) {
4
+ super({
5
+ className: "map-view",
6
+ ...options
7
+ });
8
+ this.markers = options.markers || [];
9
+ this.center = options.center || null;
10
+ this.zoom = options.zoom || 13;
11
+ this.height = options.height || 400;
12
+ this.showZoomControl = options.showZoomControl !== false;
13
+ this.tileLayer = options.tileLayer || "osm";
14
+ this.showLeafletBranding = options.showLeafletBranding === true;
15
+ this.showLayerControl = options.showLayerControl === true;
16
+ this.layerOptions = options.layerOptions || {
17
+ osm: "OSM",
18
+ satellite: "Satellite",
19
+ terrain: "Terrain",
20
+ dark: "Dark",
21
+ light: "Light",
22
+ watercolor: "Watercolor",
23
+ bw: "B/W",
24
+ streets: "Streets"
25
+ };
26
+ this.map = null;
27
+ this.leafletMarkers = [];
28
+ this._tileLayer = null;
29
+ this.template = `
30
+ <div class="map-container">
31
+ <div id="map-{{id}}" style="height: {{height}}px; width: 100%; border-radius: 0.375rem; border: 1px solid #dee2e6;"></div>
32
+ </div>
33
+ `;
34
+ }
35
+ async onAfterRender() {
36
+ await this.loadLeaflet();
37
+ await this.initializeMap();
38
+ }
39
+ async loadLeaflet() {
40
+ if (window.L) return;
41
+ const cssLoaded = new Promise((resolve) => {
42
+ const link = document.createElement("link");
43
+ link.rel = "stylesheet";
44
+ link.href = "https://unpkg.com/leaflet@1.9.4/dist/leaflet.css";
45
+ link.onload = resolve;
46
+ link.onerror = resolve;
47
+ document.head.appendChild(link);
48
+ });
49
+ const jsLoaded = new Promise((resolve, reject) => {
50
+ const script = document.createElement("script");
51
+ script.src = "https://unpkg.com/leaflet@1.9.4/dist/leaflet.js";
52
+ script.onload = resolve;
53
+ script.onerror = reject;
54
+ document.head.appendChild(script);
55
+ });
56
+ await Promise.all([cssLoaded, jsLoaded]);
57
+ }
58
+ getTileLayerUrl() {
59
+ const tileLayers = {
60
+ // Standard street maps
61
+ osm: {
62
+ url: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
63
+ attribution: "© OpenStreetMap contributors",
64
+ maxZoom: 19
65
+ },
66
+ // Satellite imagery
67
+ satellite: {
68
+ url: "https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}",
69
+ attribution: "© Esri",
70
+ maxZoom: 19
71
+ },
72
+ // Terrain and topographic
73
+ terrain: {
74
+ url: "https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png",
75
+ attribution: "© OpenTopoMap contributors",
76
+ maxZoom: 17
77
+ },
78
+ // Dark mode styles
79
+ dark: {
80
+ url: "https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png",
81
+ attribution: "© OpenStreetMap contributors © CARTO",
82
+ maxZoom: 20
83
+ },
84
+ // Light/minimal styles
85
+ light: {
86
+ url: "https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png",
87
+ attribution: "© OpenStreetMap contributors © CARTO",
88
+ maxZoom: 20
89
+ },
90
+ // Watercolor artistic style
91
+ watercolor: {
92
+ url: "https://tiles.stadiamaps.com/tiles/stamen_watercolor/{z}/{x}/{y}.jpg",
93
+ attribution: "© Stadia Maps © Stamen Design © OpenStreetMap contributors",
94
+ maxZoom: 16
95
+ },
96
+ // Black and white
97
+ bw: {
98
+ url: "https://{s}.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}{r}.png",
99
+ attribution: "© OpenStreetMap contributors © CARTO",
100
+ maxZoom: 20
101
+ },
102
+ // Streets with labels
103
+ streets: {
104
+ url: "https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png",
105
+ attribution: "© OpenStreetMap contributors © CARTO",
106
+ maxZoom: 20
107
+ }
108
+ };
109
+ return tileLayers[this.tileLayer] || tileLayers.osm;
110
+ }
111
+ async initializeMap() {
112
+ const mapElement = this.element.querySelector(`#map-${this.id}`);
113
+ if (!mapElement || !window.L) return;
114
+ let mapCenter = this.center;
115
+ if (!mapCenter && this.markers.length > 0) {
116
+ mapCenter = [this.markers[0].lat, this.markers[0].lng];
117
+ }
118
+ if (!mapCenter) {
119
+ mapCenter = [0, 0];
120
+ }
121
+ this.map = window.L.map(mapElement, {
122
+ center: mapCenter,
123
+ zoom: this.zoom,
124
+ zoomControl: this.showZoomControl
125
+ });
126
+ if (this.map && this.map.attributionControl && this.showLeafletBranding === false) {
127
+ try {
128
+ this.map.attributionControl.setPrefix("");
129
+ } catch (e) {
130
+ }
131
+ }
132
+ const tileConfig = this.getTileLayerUrl();
133
+ this._tileLayer = window.L.tileLayer(tileConfig.url, {
134
+ attribution: tileConfig.attribution,
135
+ maxZoom: tileConfig.maxZoom
136
+ }).addTo(this.map);
137
+ if (this.showLayerControl) {
138
+ const container = mapElement.parentElement || this.element.querySelector(".map-container");
139
+ if (container) {
140
+ container.style.position = container.style.position || "relative";
141
+ const selector = document.createElement("select");
142
+ selector.className = "form-select form-select-sm";
143
+ selector.style.position = "absolute";
144
+ selector.style.top = "8px";
145
+ selector.style.right = "8px";
146
+ selector.style.zIndex = "1000";
147
+ selector.style.maxWidth = "180px";
148
+ selector.setAttribute("aria-label", "Map tile layer");
149
+ Object.entries(this.layerOptions || {}).forEach(([key, label]) => {
150
+ const opt = document.createElement("option");
151
+ opt.value = key;
152
+ opt.textContent = label;
153
+ if (key === this.tileLayer) opt.selected = true;
154
+ selector.appendChild(opt);
155
+ });
156
+ selector.addEventListener("change", () => this.setTileLayer(selector.value));
157
+ container.appendChild(selector);
158
+ }
159
+ }
160
+ this.addMarkers(this.markers);
161
+ if (this.markers.length > 1) {
162
+ this.fitBounds();
163
+ }
164
+ setTimeout(() => {
165
+ if (this.map) {
166
+ this.map.invalidateSize();
167
+ }
168
+ }, 300);
169
+ }
170
+ addMarkers(markers) {
171
+ if (!this.map || !Array.isArray(markers)) return;
172
+ markers.forEach((markerData) => {
173
+ const { lat, lng, popup, icon } = markerData;
174
+ if (!lat || !lng) return;
175
+ const markerOptions = {};
176
+ if (icon) {
177
+ markerOptions.icon = window.L.icon(icon);
178
+ }
179
+ const marker = window.L.marker([lat, lng], markerOptions).addTo(this.map);
180
+ if (popup) {
181
+ marker.bindPopup(popup);
182
+ }
183
+ this.leafletMarkers.push(marker);
184
+ });
185
+ }
186
+ fitBounds() {
187
+ if (!this.map || this.leafletMarkers.length === 0) return;
188
+ const group = new window.L.featureGroup(this.leafletMarkers);
189
+ this.map.fitBounds(group.getBounds().pad(0.1));
190
+ }
191
+ updateMarkers(newMarkers) {
192
+ this.clearMarkers();
193
+ this.markers = newMarkers;
194
+ this.addMarkers(newMarkers);
195
+ if (newMarkers.length > 1) {
196
+ this.fitBounds();
197
+ } else if (newMarkers.length === 1) {
198
+ this.map.setView([newMarkers[0].lat, newMarkers[0].lng], this.zoom);
199
+ }
200
+ }
201
+ clearMarkers() {
202
+ this.leafletMarkers.forEach((marker) => {
203
+ this.map.removeLayer(marker);
204
+ });
205
+ this.leafletMarkers = [];
206
+ }
207
+ setView(lat, lng, zoom = null) {
208
+ if (!this.map) return;
209
+ this.map.setView([lat, lng], zoom || this.zoom);
210
+ }
211
+ setZoom(zoom) {
212
+ if (!this.map) return;
213
+ this.map.setZoom(zoom);
214
+ }
215
+ setTileLayer(key) {
216
+ if (!this.map) return;
217
+ const original = this.tileLayer;
218
+ this.tileLayer = key || this.tileLayer;
219
+ const tileConfig = this.getTileLayerUrl();
220
+ try {
221
+ if (this._tileLayer) {
222
+ this.map.removeLayer(this._tileLayer);
223
+ }
224
+ } catch (e) {
225
+ }
226
+ this._tileLayer = window.L.tileLayer(tileConfig.url, {
227
+ attribution: tileConfig.attribution,
228
+ maxZoom: tileConfig.maxZoom
229
+ }).addTo(this.map);
230
+ this.tileLayer = key || original;
231
+ setTimeout(() => {
232
+ try {
233
+ this.map.invalidateSize();
234
+ } catch (e) {
235
+ }
236
+ }, 150);
237
+ }
238
+ async onBeforeDestroy() {
239
+ if (this.map) {
240
+ this.map.remove();
241
+ this.map = null;
242
+ }
243
+ await super.onBeforeDestroy();
244
+ }
245
+ static async showAsDialog(options = {}) {
246
+ const view = new MapView(options);
247
+ const dopts = options.dialogOptions || {};
248
+ const dialogOptions = {
249
+ title: "Map View",
250
+ header: true,
251
+ body: view,
252
+ size: "lg",
253
+ centered: false,
254
+ ...dopts
255
+ };
256
+ await view.init();
257
+ await view.getApp().showDialog(dialogOptions);
258
+ }
259
+ }
260
+ class MapLibreView extends View {
261
+ constructor(options = {}) {
262
+ super({
263
+ className: "maplibre-view",
264
+ ...options
265
+ });
266
+ this.markers = options.markers || [];
267
+ this.center = options.center || null;
268
+ this.zoom = options.zoom || 13;
269
+ this.height = options.height || 400;
270
+ this.pitch = options.pitch || 0;
271
+ this.bearing = options.bearing || 0;
272
+ this.mapStyle = options.style || "streets";
273
+ this.showNavigationControl = options.showNavigationControl !== false;
274
+ this.autoFitBounds = options.autoFitBounds !== false;
275
+ this.map = null;
276
+ this.mapMarkers = [];
277
+ this.pendingMarkers = [...this.markers];
278
+ this.lineSources = options.lineSources || [];
279
+ this.pendingLineData = /* @__PURE__ */ new Map();
280
+ this.template = `
281
+ <div class="maplibre-container">
282
+ <div id="maplibre-{{id}}" style="height: {{height}}px; width: 100%; border-radius: 0.375rem; border: 1px solid #dee2e6;"></div>
283
+ </div>
284
+ `;
285
+ }
286
+ async onAfterRender() {
287
+ await this.loadMapLibre();
288
+ await this.initializeMap();
289
+ }
290
+ async loadMapLibre() {
291
+ if (window.maplibregl) return;
292
+ const link = document.createElement("link");
293
+ link.rel = "stylesheet";
294
+ link.href = "https://unpkg.com/maplibre-gl@4.7.1/dist/maplibre-gl.css";
295
+ document.head.appendChild(link);
296
+ return new Promise((resolve, reject) => {
297
+ const script = document.createElement("script");
298
+ script.src = "https://unpkg.com/maplibre-gl@4.7.1/dist/maplibre-gl.js";
299
+ script.onload = resolve;
300
+ script.onerror = reject;
301
+ document.head.appendChild(script);
302
+ });
303
+ }
304
+ getMapStyle() {
305
+ const styles = {
306
+ streets: "https://demotiles.maplibre.org/style.json",
307
+ dark: {
308
+ version: 8,
309
+ sources: {
310
+ osm: {
311
+ type: "raster",
312
+ tiles: ["https://a.tile.openstreetmap.org/{z}/{x}/{y}.png"],
313
+ tileSize: 256,
314
+ attribution: "© OpenStreetMap contributors"
315
+ }
316
+ },
317
+ layers: [{
318
+ id: "osm",
319
+ type: "raster",
320
+ source: "osm"
321
+ }],
322
+ glyphs: "https://demotiles.maplibre.org/font/{fontstack}/{range}.pbf"
323
+ },
324
+ light: {
325
+ version: 8,
326
+ sources: {
327
+ osm: {
328
+ type: "raster",
329
+ tiles: ["https://a.tile.openstreetmap.org/{z}/{x}/{y}.png"],
330
+ tileSize: 256,
331
+ attribution: "© OpenStreetMap contributors"
332
+ }
333
+ },
334
+ layers: [{
335
+ id: "osm",
336
+ type: "raster",
337
+ source: "osm"
338
+ }],
339
+ glyphs: "https://demotiles.maplibre.org/font/{fontstack}/{range}.pbf"
340
+ },
341
+ satellite: {
342
+ version: 8,
343
+ sources: {
344
+ satellite: {
345
+ type: "raster",
346
+ tiles: ["https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}"],
347
+ tileSize: 256,
348
+ attribution: "© Esri"
349
+ }
350
+ },
351
+ layers: [{
352
+ id: "satellite",
353
+ type: "raster",
354
+ source: "satellite"
355
+ }],
356
+ glyphs: "https://demotiles.maplibre.org/font/{fontstack}/{range}.pbf"
357
+ },
358
+ terrain: {
359
+ version: 8,
360
+ sources: {
361
+ terrain: {
362
+ type: "raster",
363
+ tiles: ["https://a.tile.opentopomap.org/{z}/{x}/{y}.png"],
364
+ tileSize: 256,
365
+ attribution: "© OpenTopoMap contributors"
366
+ }
367
+ },
368
+ layers: [{
369
+ id: "terrain",
370
+ type: "raster",
371
+ source: "terrain"
372
+ }],
373
+ glyphs: "https://demotiles.maplibre.org/font/{fontstack}/{range}.pbf"
374
+ }
375
+ };
376
+ return styles[this.mapStyle] || styles.streets;
377
+ }
378
+ async initializeMap() {
379
+ const mapElement = this.element.querySelector(`#maplibre-${this.id}`);
380
+ if (!mapElement || !window.maplibregl) return;
381
+ let mapCenter = this.center;
382
+ if (!mapCenter && this.markers.length > 0) {
383
+ mapCenter = [this.markers[0].lng, this.markers[0].lat];
384
+ }
385
+ if (!mapCenter) {
386
+ mapCenter = [0, 0];
387
+ }
388
+ this.map = new window.maplibregl.Map({
389
+ container: mapElement,
390
+ style: this.getMapStyle(),
391
+ center: mapCenter,
392
+ zoom: this.zoom,
393
+ pitch: this.pitch,
394
+ bearing: this.bearing
395
+ });
396
+ if (this.showNavigationControl) {
397
+ this.map.addControl(new window.maplibregl.NavigationControl(), "top-right");
398
+ }
399
+ this.map.on("load", () => {
400
+ const initialMarkers = this.pendingMarkers.length ? this.pendingMarkers : this.markers;
401
+ this.updateMarkers(initialMarkers);
402
+ this.lineSources.forEach((source) => this.addLineSource(source));
403
+ this.pendingLineData.forEach((source) => this.addLineSource(source));
404
+ this.pendingLineData.clear();
405
+ });
406
+ }
407
+ addMarkers(markers) {
408
+ if (!this.map || !Array.isArray(markers)) {
409
+ this.pendingMarkers = Array.isArray(markers) ? markers : [];
410
+ return;
411
+ }
412
+ markers.forEach((markerData) => {
413
+ const { lng, lat, popup, color, icon, size } = markerData;
414
+ if (!lng || !lat) return;
415
+ const el = document.createElement("div");
416
+ el.className = "maplibre-marker";
417
+ const markerSize = Number(size) || 30;
418
+ el.style.width = `${markerSize}px`;
419
+ el.style.height = `${markerSize}px`;
420
+ el.style.borderRadius = "50%";
421
+ el.style.backgroundColor = color || "#3b82f6";
422
+ el.style.border = "3px solid white";
423
+ el.style.boxShadow = "0 2px 4px rgba(0,0,0,0.3)";
424
+ el.style.cursor = "pointer";
425
+ el.style.display = "flex";
426
+ el.style.alignItems = "center";
427
+ el.style.justifyContent = "center";
428
+ if (icon) {
429
+ el.innerHTML = `<i class="${icon}" style="color: white;"></i>`;
430
+ }
431
+ const marker = new window.maplibregl.Marker({ element: el }).setLngLat([lng, lat]).addTo(this.map);
432
+ if (popup) {
433
+ const mapPopup = new window.maplibregl.Popup({ offset: 25 }).setHTML(popup);
434
+ marker.setPopup(mapPopup);
435
+ }
436
+ this.mapMarkers.push(marker);
437
+ });
438
+ }
439
+ fitBounds() {
440
+ if (!this.map || this.markers.length === 0) return;
441
+ const bounds = new window.maplibregl.LngLatBounds();
442
+ this.markers.forEach((marker) => {
443
+ bounds.extend([marker.lng, marker.lat]);
444
+ });
445
+ this.map.fitBounds(bounds, {
446
+ padding: 50,
447
+ maxZoom: 15
448
+ });
449
+ }
450
+ updateMarkers(newMarkers) {
451
+ const markers = Array.isArray(newMarkers) ? newMarkers : [];
452
+ this.markers = markers;
453
+ this.pendingMarkers = markers;
454
+ if (!this.map) return;
455
+ this.clearMarkers();
456
+ this.addMarkers(markers);
457
+ if (this.autoFitBounds && markers.length > 1) {
458
+ this.fitBounds();
459
+ } else if (markers.length === 1 && this.map) {
460
+ this.map.flyTo({
461
+ center: [markers[0].lng, markers[0].lat],
462
+ zoom: this.zoom
463
+ });
464
+ }
465
+ }
466
+ clearMarkers() {
467
+ this.mapMarkers.forEach((marker) => {
468
+ marker.remove();
469
+ });
470
+ this.mapMarkers = [];
471
+ }
472
+ addLineSource({ id, data, paint, layout }) {
473
+ if (!id || !data) return;
474
+ const sourceId = `${id}-source`;
475
+ if (!this.map) {
476
+ this.pendingLineData.set(id, { id, data, paint, layout });
477
+ return;
478
+ }
479
+ if (this.map.getLayer(id)) {
480
+ this.map.removeLayer(id);
481
+ }
482
+ if (this.map.getSource(sourceId)) {
483
+ this.map.removeSource(sourceId);
484
+ }
485
+ this.map.addSource(sourceId, {
486
+ type: "geojson",
487
+ data
488
+ });
489
+ this.map.addLayer({
490
+ id,
491
+ type: "line",
492
+ source: sourceId,
493
+ paint: {
494
+ "line-color": "#3b82f6",
495
+ "line-width": 2,
496
+ "line-opacity": 0.6,
497
+ ...paint
498
+ },
499
+ layout: {
500
+ "line-cap": "round",
501
+ "line-join": "round",
502
+ ...layout
503
+ }
504
+ });
505
+ }
506
+ updateLineSource(id, { data, paint, layout } = {}) {
507
+ if (!id || !data) return;
508
+ const sourceId = `${id}-source`;
509
+ if (!this.map) {
510
+ this.pendingLineData.set(id, { id, data, paint, layout });
511
+ return;
512
+ }
513
+ if (this.map.getSource(sourceId)) {
514
+ this.map.getSource(sourceId).setData(data);
515
+ if (paint || layout) {
516
+ if (paint) {
517
+ Object.entries(paint).forEach(([key, value]) => {
518
+ this.map.setPaintProperty(id, key, value);
519
+ });
520
+ }
521
+ if (layout) {
522
+ Object.entries(layout).forEach(([key, value]) => {
523
+ this.map.setLayoutProperty(id, key, value);
524
+ });
525
+ }
526
+ }
527
+ } else {
528
+ this.addLineSource({ id, data, paint, layout });
529
+ }
530
+ }
531
+ setView(lng, lat, zoom = null) {
532
+ if (!this.map) return;
533
+ this.map.flyTo({
534
+ center: [lng, lat],
535
+ zoom: zoom || this.zoom
536
+ });
537
+ }
538
+ setZoom(zoom) {
539
+ if (!this.map) return;
540
+ this.map.setZoom(zoom);
541
+ }
542
+ setPitch(pitch) {
543
+ if (!this.map) return;
544
+ this.map.setPitch(pitch);
545
+ }
546
+ setBearing(bearing) {
547
+ if (!this.map) return;
548
+ this.map.setBearing(bearing);
549
+ }
550
+ async onBeforeDestroy() {
551
+ if (this.map) {
552
+ this.map.remove();
553
+ this.map = null;
554
+ }
555
+ await super.onBeforeDestroy();
556
+ }
557
+ }
558
+ const COUNTRY_CENTROIDS = {
559
+ "AD": { name: "Andorra", lat: 42.54859834854764, lng: 1.5802243611232873 },
560
+ "AE": { name: "United Arab Emirates", lat: 24.18250292309135, lng: 54.27920525789581 },
561
+ "AF": { name: "Afghanistan", lat: 34.13402601376932, lng: 66.59216131095278 },
562
+ "AG": { name: "Antigua and Barbuda", lat: 17.07146759372967, lng: -61.78530823226373 },
563
+ "AI": { name: "Anguilla", lat: 18.222874004219086, lng: -63.06008343771806 },
564
+ "AL": { name: "Albania", lat: 41.14165894891656, lng: 20.061082767269493 },
565
+ "AM": { name: "Armenia", lat: 40.17841274230679, lng: 45.05490831965259 },
566
+ "AO": { name: "Angola", lat: -12.167424062667942, lng: 17.651768783079 },
567
+ "AQ": { name: "Antarctica", lat: -77.16987521415838, lng: -177.56451613408842 },
568
+ "AR": { name: "Argentina", lat: -35.697270518120085, lng: -64.53238503843076 },
569
+ "AS": { name: "American Samoa", lat: -14.305711987770538, lng: -170.7007316174498 },
570
+ "AT": { name: "Austria", lat: 47.631858269895794, lng: 13.797778364631036 },
571
+ "AU": { name: "Australia", lat: -25.697337673983082, lng: 134.02277170916162 },
572
+ "AW": { name: "Aruba", lat: 12.515625722992898, lng: -69.97564014284046 },
573
+ "AZ": { name: "Azerbaijan", lat: 40.3920509942049, lng: 48.634592670644324 },
574
+ "BA": { name: "Bosnia and Herzegovina", lat: 44.14415356126429, lng: 17.83467240787538 },
575
+ "BB": { name: "Barbados", lat: 13.183219369337529, lng: -59.557383949150285 },
576
+ "BD": { name: "Bangladesh", lat: 23.673728665121, lng: 90.43212562608613 },
577
+ "BE": { name: "Belgium", lat: 50.6182138854095, lng: 4.675010154696485 },
578
+ "BF": { name: "Burkina Faso", lat: 12.108709036312737, lng: -1.6932816211842325 },
579
+ "BG": { name: "Bulgaria", lat: 42.82043677302438, lng: 25.251739122561908 },
580
+ "BH": { name: "Bahrain", lat: 26.04798501537066, lng: 50.540695402276775 },
581
+ "BI": { name: "Burundi", lat: -3.261251993278643, lng: 29.88518227845293 },
582
+ "BJ": { name: "Benin", lat: 9.503013199615893, lng: 2.305714528830206 },
583
+ "BL": { name: "Saint Barthelemy", lat: 17.90561691241738, lng: -62.83051610005156 },
584
+ "BM": { name: "Bermuda", lat: 32.315067430740726, lng: -64.7458500599169 },
585
+ "BN": { name: "Brunei Darussalam", lat: 4.543205889917609, lng: 114.6430958360464 },
586
+ "BO": { name: "Bolivia", lat: -16.7312488393574, lng: -64.45209597511206 },
587
+ "BQ": { name: "Bonaire", lat: 12.180844982440338, lng: -68.29350445958761 },
588
+ "BQ": { name: "Saba", lat: 17.632512616389718, lng: -63.23739481909494 },
589
+ "BQ": { name: "Saint Eustatius", lat: 17.4919042294197, lng: -62.978230589445026 },
590
+ "BR": { name: "Brazil", lat: -11.524630416426652, lng: -54.355206608256424 },
591
+ "BS": { name: "Bahamas", lat: 24.72162633646784, lng: -78.07275370060313 },
592
+ "BT": { name: "Bhutan", lat: 27.42163933959824, lng: 90.46716647173861 },
593
+ "BV": { name: "Bouvet Island", lat: -54.42316679395248, lng: 3.411969465057627 },
594
+ "BW": { name: "Botswana", lat: -22.236609002062902, lng: 23.85779956995608 },
595
+ "BY": { name: "Belarus", lat: 53.46791374543163, lng: 27.964252054715104 },
596
+ "BZ": { name: "Belize", lat: 17.24252476647155, lng: -88.68273510023441 },
597
+ "CA": { name: "Canada", lat: 57.550480044655636, lng: -98.41680517868062 },
598
+ "CC": { name: "Cocos Islands", lat: -12.171249450199545, lng: 96.83688767323002 },
599
+ "CD": { name: "Congo DRC", lat: -3.338629596207896, lng: 23.419827574282188 },
600
+ "CF": { name: "Central African Republic", lat: 6.331390033944319, lng: 20.520743419397256 },
601
+ "CG": { name: "Congo", lat: -0.7294391595233845, lng: 14.879732849491393 },
602
+ "CH": { name: "Switzerland", lat: 46.73678128684938, lng: 8.286928794895285 },
603
+ "CI": { name: "Côte d'Ivoire", lat: 7.536779279421307, lng: -5.571710194917734 },
604
+ "CK": { name: "Cook Islands", lat: -21.222613253399842, lng: -159.78768870952257 },
605
+ "CL": { name: "Chile", lat: -37.82938283049967, lng: -70.76863431739216 },
606
+ "CM": { name: "Cameroon", lat: 6.294168487480992, lng: 12.948474142398263 },
607
+ "CN": { name: "China", lat: 38.07325481105728, lng: 104.69113855849604 },
608
+ "CO": { name: "Colombia", lat: 4.187753877352739, lng: -72.6445066243485 },
609
+ "CR": { name: "Costa Rica", lat: 9.863467407406214, lng: -84.14673625701816 },
610
+ "CU": { name: "Cuba", lat: 21.476176522869448, lng: -79.69817857618705 },
611
+ "CV": { name: "Cabo Verde", lat: 15.076411518651643, lng: -23.63401005900474 },
612
+ "CW": { name: "Curacao", lat: 12.199996647939832, lng: -68.96939768599042 },
613
+ "CX": { name: "Christmas Island", lat: -10.446440802183416, lng: 105.70209512200549 },
614
+ "CY": { name: "Cyprus", lat: 35.11700416345239, lng: 33.375346009199205 },
615
+ "CZ": { name: "Czech Republic", lat: 49.74917370930982, lng: 15.383273292023533 },
616
+ "DE": { name: "Germany", lat: 51.08304539800482, lng: 10.426171427430804 },
617
+ "DJ": { name: "Djibouti", lat: 11.750235727618804, lng: 42.613496898789506 },
618
+ "DK": { name: "Denmark", lat: 56.00118817971057, lng: 9.378670542409406 },
619
+ "DM": { name: "Dominica", lat: 15.429269860940513, lng: -61.360471946942994 },
620
+ "DO": { name: "Dominican Republic", lat: 18.77954818522993, lng: -70.43495198520012 },
621
+ "DZ": { name: "Algeria", lat: 28.350969744889056, lng: 2.6558464719769135 },
622
+ "EC": { name: "Ecuador", lat: -1.5642721388853116, lng: -78.4630326109714 },
623
+ "EE": { name: "Estonia", lat: 58.648108311231034, lng: 25.916870250633806 },
624
+ "EG": { name: "Egypt", lat: 26.60517034450628, lng: 30.240135435012338 },
625
+ "ER": { name: "Eritrea", lat: 15.005533147667684, lng: 39.2672401449901 },
626
+ "ES": { name: "Spain", lat: 40.365008336683836, lng: -3.6516251409956983 },
627
+ "ES": { name: "Canarias", lat: 28.297665106525546, lng: -16.53799441021647 },
628
+ "ET": { name: "Ethiopia", lat: 8.729389557048396, lng: 39.914902886544276 },
629
+ "FI": { name: "Finland", lat: 65.01578959749911, lng: 25.65738433454702 },
630
+ "FJ": { name: "Fiji", lat: -17.822470952336204, lng: 177.98144613732626 },
631
+ "FK": { name: "Falkland Islands", lat: -51.75901312766726, lng: -58.746646363799854 },
632
+ "FM": { name: "Micronesia", lat: 6.8789448129255435, lng: 158.2291899444527 },
633
+ "FO": { name: "Faroe Islands", lat: 62.130896281495346, lng: -6.9811060913122835 },
634
+ "FR": { name: "France", lat: 46.6423682169416, lng: 2.1940236627886227 },
635
+ "GA": { name: "Gabon", lat: -0.628448459921234, lng: 11.839410898545754 },
636
+ "GB": { name: "United Kingdom", lat: 53.97844735080214, lng: -2.852943909329258 },
637
+ "GD": { name: "Grenada", lat: 12.112926656338907, lng: -61.67937937204098 },
638
+ "GE": { name: "Georgia", lat: 42.17986277737226, lng: 43.378866534112234 },
639
+ "GF": { name: "French Guiana", lat: 3.857429742497078, lng: -53.32232307156624 },
640
+ "GG": { name: "Guernsey", lat: 49.45870771378872, lng: -2.576392582891568 },
641
+ "GH": { name: "Ghana", lat: 7.94530467243628, lng: -1.219233362526581 },
642
+ "GI": { name: "Gibraltar", lat: 36.14022671336082, lng: -5.345549484594358 },
643
+ "GL": { name: "Greenland", lat: 74.16847218965994, lng: -42.07567788066985 },
644
+ "GM": { name: "Gambia", lat: 13.428617959189328, lng: -15.383380385869662 },
645
+ "GN": { name: "Guinea", lat: 10.255986541378112, lng: -10.986948848040218 },
646
+ "GP": { name: "Guadeloupe", lat: 16.24420002705553, lng: -61.54382262282755 },
647
+ "GQ": { name: "Equatorial Guinea", lat: 1.5954643936590733, lng: 10.425456672353823 },
648
+ "GR": { name: "Greece", lat: 39.42012261727978, lng: 23.110368936161876 },
649
+ "GS": { name: "South Georgia and South Sandwich Islands", lat: -54.37666443862139, lng: -36.77509575898928 },
650
+ "GT": { name: "Guatemala", lat: 15.820878515352684, lng: -90.31219349119617 },
651
+ "GU": { name: "Guam", lat: 13.445430479945276, lng: 144.78024458298802 },
652
+ "GW": { name: "Guinea-Bissau", lat: 11.980075324820504, lng: -14.980186756910847 },
653
+ "GY": { name: "Guyana", lat: 4.68211981385056, lng: -58.91352612754667 },
654
+ "HM": { name: "Heard Island and McDonald Islands", lat: -53.084170035513736, lng: 73.49298560844045 },
655
+ "HN": { name: "Honduras", lat: 14.740370695750006, lng: -86.49251679006962 },
656
+ "HR": { name: "Croatia", lat: 44.91192100856702, lng: 16.625761129583374 },
657
+ "HT": { name: "Haiti", lat: 18.883520486983567, lng: -72.89291379842 },
658
+ "HU": { name: "Hungary", lat: 47.22527332486294, lng: 19.39620048366142 },
659
+ "ID": { name: "Indonesia", lat: 0.15591979959037652, lng: 113.96538246847302 },
660
+ "IE": { name: "Ireland", lat: 53.30489539816495, lng: -8.241128545554096 },
661
+ "IL": { name: "Israel", lat: 31.513542220043195, lng: 35.027923472437024 },
662
+ "IM": { name: "Isle of Man", lat: 54.22855301008011, lng: -4.532995055468449 },
663
+ "IN": { name: "India", lat: 23.586300567746722, lng: 81.17300408530181 },
664
+ "IO": { name: "British Indian Ocean Territory", lat: -7.323548444385743, lng: 72.43501618476016 },
665
+ "IQ": { name: "Iraq", lat: 33.105075667527906, lng: 43.832529181056884 },
666
+ "IR": { name: "Iran", lat: 32.906023742890056, lng: 54.237077001065444 },
667
+ "IS": { name: "Iceland", lat: 65.12360920205514, lng: -19.05682967106099 },
668
+ "IT": { name: "Italy", lat: 42.98201127614267, lng: 12.763657166123137 },
669
+ "JE": { name: "Jersey", lat: 49.215396925724306, lng: -2.1291601162653575 },
670
+ "JM": { name: "Jamaica", lat: 18.12207889341651, lng: -77.30358894542778 },
671
+ "JO": { name: "Jordan", lat: 31.387064884449156, lng: 36.95728884547246 },
672
+ "JP": { name: "Japan", lat: 36.76738832597829, lng: 137.46934234351835 },
673
+ "KE": { name: "Kenya", lat: 0.6899182318376179, lng: 37.95309411262371 },
674
+ "KG": { name: "Kyrgyzstan", lat: 41.35698905438358, lng: 74.17532903468319 },
675
+ "KH": { name: "Cambodia", lat: 12.699186865507775, lng: 105.03973078680701 },
676
+ "KI": { name: "Kiribati", lat: 1.8676673749241066, lng: -157.39024189323504 },
677
+ "KM": { name: "Comoros", lat: -11.658861474508491, lng: 43.34826587429403 },
678
+ "KN": { name: "Saint Kitts and Nevis", lat: 17.314736299587768, lng: -62.74560385895787 },
679
+ "KP": { name: "North Korea", lat: 40.19198091470839, lng: 127.3379805653744 },
680
+ "KR": { name: "South Korea", lat: 36.402386712544114, lng: 127.76224551357649 },
681
+ "KW": { name: "Kuwait", lat: 29.281360965443092, lng: 47.56311109320184 },
682
+ "KY": { name: "Cayman Islands", lat: 19.311231805620288, lng: -81.25203208977878 },
683
+ "KZ": { name: "Kazakhstan", lat: 47.641465195176835, lng: 66.3759193479301 },
684
+ "LA": { name: "Laos", lat: 18.117282736873282, lng: 103.76375899026448 },
685
+ "LB": { name: "Lebanon", lat: 33.91160170722086, lng: 35.89651946324749 },
686
+ "LC": { name: "Saint Lucia", lat: 13.895749185129906, lng: -60.9689510935251 },
687
+ "LI": { name: "Liechtenstein", lat: 47.14627562133036, lng: 9.547674672376376 },
688
+ "LK": { name: "Sri Lanka", lat: 7.696630939329944, lng: 80.66931169770622 },
689
+ "LR": { name: "Liberia", lat: 6.52012979398834, lng: -9.258988935497618 },
690
+ "LS": { name: "Lesotho", lat: -29.60168116924817, lng: 28.24475317864227 },
691
+ "LT": { name: "Lithuania", lat: 55.29437393417175, lng: 23.946021605013534 },
692
+ "LU": { name: "Luxembourg", lat: 49.77523454542369, lng: 6.103230338458876 },
693
+ "LV": { name: "Latvia", lat: 56.813853047554154, lng: 24.693671325654403 },
694
+ "LY": { name: "Libya", lat: 27.202915771690794, lng: 17.91133392454237 },
695
+ "MA": { name: "Morocco", lat: 28.687598134979325, lng: -8.817212587250811 },
696
+ "MC": { name: "Monaco", lat: 43.74798224995656, lng: 7.412820873271196 },
697
+ "MD": { name: "Moldova", lat: 47.0725674580696, lng: 28.391111865941348 },
698
+ "ME": { name: "Montenegro", lat: 42.73694835210454, lng: 19.29505087156758 },
699
+ "MF": { name: "Saint Martin", lat: 18.078012113224464, lng: -63.06678525361946 },
700
+ "MG": { name: "Madagascar", lat: -19.04163612493041, lng: 46.68493466832544 },
701
+ "MH": { name: "Marshall Islands", lat: 7.307929900994344, lng: 168.72016025351076 },
702
+ "MK": { name: "North Macedonia", lat: 41.59402890143112, lng: 21.70998923872772 },
703
+ "ML": { name: "Mali", lat: 17.168146208584837, lng: -4.346399841781153 },
704
+ "MM": { name: "Myanmar", lat: 19.901227931399873, lng: 97.08892285397344 },
705
+ "MN": { name: "Mongolia", lat: 47.08644454604851, lng: 103.3987360327455 },
706
+ "MP": { name: "Northern Mariana Islands", lat: 15.178063516432115, lng: 145.74119737203134 },
707
+ "MQ": { name: "Martinique", lat: 14.642697353597645, lng: -61.01432380875083 },
708
+ "MR": { name: "Mauritania", lat: 20.466731212820022, lng: -10.495079045035716 },
709
+ "MS": { name: "Montserrat", lat: 16.735363391460357, lng: -62.18693281256255 },
710
+ "MT": { name: "Malta", lat: 35.890522650899314, lng: 14.441922442508494 },
711
+ "MU": { name: "Mauritius", lat: -20.28142317475198, lng: 57.56415671066546 },
712
+ "MV": { name: "Maldives", lat: -0.6065577168009924, lng: 73.10076245140479 },
713
+ "MW": { name: "Malawi", lat: -13.128986464184024, lng: 34.23441182298881 },
714
+ "MX": { name: "Mexico", lat: 23.87436068093592, lng: -101.55399731630118 },
715
+ "MY": { name: "Malaysia", lat: 3.6716608556387857, lng: 114.63330303992869 },
716
+ "MZ": { name: "Mozambique", lat: -17.525230309488748, lng: 35.208577031290176 },
717
+ "NA": { name: "Namibia", lat: -21.90858163281473, lng: 18.16451345845268 },
718
+ "NC": { name: "New Caledonia", lat: -21.33003372660827, lng: 165.50767040438612 },
719
+ "NE": { name: "Niger", lat: 17.08105392407292, lng: 8.86863247002646 },
720
+ "NF": { name: "Norfolk Island", lat: -29.037654445046282, lng: 167.95259597483337 },
721
+ "NG": { name: "Nigeria", lat: 9.61029352034213, lng: 8.147714845256194 },
722
+ "NI": { name: "Nicaragua", lat: 12.893566631930554, lng: -85.016088327669 },
723
+ "NL": { name: "Netherlands", lat: 52.134054128923886, lng: 5.554136426128487 },
724
+ "NO": { name: "Norway", lat: 64.97775882947745, lng: 16.670259272390894 },
725
+ "NP": { name: "Nepal", lat: 28.300920699755657, lng: 84.1338898313567 },
726
+ "NR": { name: "Nauru", lat: -0.5221021440668993, lng: 166.92937633139178 },
727
+ "NU": { name: "Niue", lat: -19.05230921680393, lng: -169.86878106699083 },
728
+ "NZ": { name: "New Zealand", lat: -43.82765432544426, lng: 170.69035541428696 },
729
+ "OM": { name: "Oman", lat: 20.7242833183209, lng: 55.841088119829 },
730
+ "PA": { name: "Panama", lat: 8.439536749576892, lng: -80.14428761482796 },
731
+ "PE": { name: "Peru", lat: -8.522717984240291, lng: -74.11416196781884 },
732
+ "PF": { name: "French Polynesia", lat: -17.674684080120677, lng: -149.40041671099763 },
733
+ "PG": { name: "Papua New Guinea", lat: -7.156912819152135, lng: 144.8348942994695 },
734
+ "PH": { name: "Philippines", lat: 15.586542251094242, lng: 121.82208941416745 },
735
+ "PK": { name: "Pakistan", lat: 30.116188371410882, lng: 69.08835090769651 },
736
+ "PL": { name: "Poland", lat: 52.06848055692473, lng: 19.43573279234468 },
737
+ "PM": { name: "Saint Pierre and Miquelon", lat: 46.95153913615198, lng: -56.32465353437558 },
738
+ "PN": { name: "Pitcairn", lat: -24.366121747565458, lng: -128.3149848627581 },
739
+ "PR": { name: "Puerto Rico", lat: 18.216224086610914, lng: -66.49425339593509 },
740
+ "PS": { name: "Palestinian Territory", lat: 31.930818736453883, lng: 35.24251184154588 },
741
+ "PT": { name: "Portugal", lat: 39.67529214702138, lng: -7.933662183874006 },
742
+ "PW": { name: "Palau", lat: 7.534775852547396, lng: 134.57965086721052 },
743
+ "PY": { name: "Paraguay", lat: -23.42190559259428, lng: -58.38906357428651 },
744
+ "QA": { name: "Qatar", lat: 25.318528486425386, lng: 51.19794918743203 },
745
+ "RE": { name: "Réunion", lat: -21.119825460665105, lng: 55.54393506194689 },
746
+ "RO": { name: "Romania", lat: 45.82454894397586, lng: 25.094158201563292 },
747
+ "RS": { name: "Serbia", lat: 44.02679870131969, lng: 20.85677444395745 },
748
+ "RU": { name: "Russian Federation", lat: 59.039434214106194, lng: 98.6704990698032 },
749
+ "RW": { name: "Rwanda", lat: -2.014687460047154, lng: 29.919439681764082 },
750
+ "SA": { name: "Saudi Arabia", lat: 24.136038144757897, lng: 44.600958178225596 },
751
+ "SB": { name: "Solomon Islands", lat: -9.613104734596515, lng: 160.16475795033884 },
752
+ "SC": { name: "Seychelles", lat: -4.660002318822744, lng: 55.47250789595527 },
753
+ "SD": { name: "Sudan", lat: 15.67060230984256, lng: 29.951458283594064 },
754
+ "SE": { name: "Sweden", lat: 62.73420986108448, lng: 17.062431988004956 },
755
+ "SG": { name: "Singapore", lat: 1.3528251890006349, lng: 103.81025757634053 },
756
+ "SH": { name: "Saint Helena", lat: -15.962963318340398, lng: -5.717391620813109 },
757
+ "SI": { name: "Slovenia", lat: 46.13759229564504, lng: 14.890636899973781 },
758
+ "SJ": { name: "Svalbard", lat: 78.57318936469626, lng: 16.036378851505283 },
759
+ "SK": { name: "Slovakia", lat: 48.69808390520484, lng: 19.581015362490966 },
760
+ "SL": { name: "Sierra Leone", lat: 8.561330384750587, lng: -11.78656695731115 },
761
+ "SM": { name: "San Marino", lat: 43.942820729097896, lng: 12.461278349581722 },
762
+ "SN": { name: "Senegal", lat: 14.228861491763402, lng: -14.610875368352305 },
763
+ "SO": { name: "Somalia", lat: 6.524534573103924, lng: 45.40037867243972 },
764
+ "SR": { name: "Suriname", lat: 4.098723595920171, lng: -55.855514311561286 },
765
+ "SS": { name: "South Sudan", lat: 7.657782041763295, lng: 30.3851856901788 },
766
+ "ST": { name: "Sao Tome and Principe", lat: 0.22744704294793774, lng: 6.606158796857607 },
767
+ "SV": { name: "El Salvador", lat: 13.758041517055418, lng: -88.85911489238985 },
768
+ "SX": { name: "Sint Maarten", lat: 18.03942608463078, lng: -63.06883135915303 },
769
+ "SY": { name: "Syria", lat: 35.09751106058316, lng: 38.5117323139514 },
770
+ "SZ": { name: "Eswatini", lat: -26.562540935608702, lng: 31.510685746082007 },
771
+ "TC": { name: "Turks and Caicos Islands", lat: 21.799865427483745, lng: -71.74058946811508 },
772
+ "TD": { name: "Chad", lat: 15.283493546654503, lng: 18.427113900363025 },
773
+ "TF": { name: "Juan De Nova Island", lat: -17.06449193630804, lng: 42.74374761089645 },
774
+ "TF": { name: "French Southern Territories", lat: -49.26329687105643, lng: 69.54686984724839 },
775
+ "TF": { name: "Glorioso Islands", lat: -11.566224871643417, lng: 47.290948081543384 },
776
+ "TG": { name: "Togo", lat: 8.660743037717811, lng: 0.8990857571109684 },
777
+ "TH": { name: "Thailand", lat: 13.66222784745538, lng: 101.08675116214552 },
778
+ "TJ": { name: "Tajikistan", lat: 38.56933138382972, lng: 70.94215281065698 },
779
+ "TK": { name: "Tokelau", lat: -9.195174767256544, lng: -171.85265950722743 },
780
+ "TL": { name: "Timor-Leste", lat: -8.809894630601962, lng: 125.95024049562659 },
781
+ "TM": { name: "Turkmenistan", lat: 39.06069118001429, lng: 58.4577357627054 },
782
+ "TN": { name: "Tunisia", lat: 34.08636179565723, lng: 9.65587551697984 },
783
+ "TO": { name: "Tonga", lat: -21.15927212823853, lng: -175.20415878511247 },
784
+ "TR": { name: "Turkey", lat: 38.93207363123396, lng: 35.56886764076691 },
785
+ "TT": { name: "Trinidad and Tobago", lat: 10.415515638298093, lng: -61.37236579976247 },
786
+ "TV": { name: "Tuvalu", lat: -8.514701506447222, lng: 179.217833977593 },
787
+ "TZ": { name: "Tanzania", lat: -6.355794440041147, lng: 34.81832206060381 },
788
+ "UA": { name: "Ukraine", lat: 48.657532515563794, lng: 31.27377208442636 },
789
+ "UG": { name: "Uganda", lat: 1.2821729218416205, lng: 32.34371768463123 },
790
+ "UM": { name: "United States Minor Outlying Islands", lat: 19.302045812215958, lng: 166.63800339749642 },
791
+ "US": { name: "United States", lat: 38.8208089190304, lng: -96.33161660829639 },
792
+ "UY": { name: "Uruguay", lat: -32.78195043831093, lng: -56.01919523458085 },
793
+ "UZ": { name: "Uzbekistan", lat: 41.4879065244633, lng: 63.8548297593985 },
794
+ "VA": { name: "Vatican City", lat: 41.90402351316735, lng: 12.451312917026133 },
795
+ "VC": { name: "Saint Vincent and the Grenadines", lat: 13.254808122970651, lng: -61.193766354393034 },
796
+ "VE": { name: "Venezuela", lat: 7.148324760507107, lng: -66.36492135985132 },
797
+ "VG": { name: "British Virgin Islands", lat: 18.42195819619707, lng: -64.62406519257699 },
798
+ "VI": { name: "US Virgin Islands", lat: 17.738009708772523, lng: -64.76155341409797 },
799
+ "VN": { name: "Vietnam", lat: 16.517347170839393, lng: 105.91338832758704 },
800
+ "VU": { name: "Vanuatu", lat: -15.189132121699332, lng: 166.84912735669738 },
801
+ "WF": { name: "Wallis and Futuna", lat: -14.283442307826677, lng: -178.12735555777184 },
802
+ "WS": { name: "Samoa", lat: -13.634252953274622, lng: -172.44107655740137 },
803
+ "YE": { name: "Yemen", lat: 16.001392616307445, lng: 47.46815793206386 },
804
+ "YT": { name: "Mayotte", lat: -12.824468416301052, lng: 45.128142327031064 },
805
+ "ZA": { name: "South Africa", lat: -28.55361930679731, lng: 24.75252746489084 },
806
+ "ZM": { name: "Zambia", lat: -13.162832953186246, lng: 27.75521363430896 },
807
+ "ZW": { name: "Zimbabwe", lat: -18.92700121981475, lng: 29.717829640720844 }
808
+ };
809
+ class MetricsCountryMapView extends View {
810
+ constructor(options = {}) {
811
+ const mapHeight = options.height || 320;
812
+ super({
813
+ className: "metrics-country-map-view",
814
+ ...options
815
+ });
816
+ this.endpoint = options.endpoint || "/api/metrics/fetch";
817
+ this.account = options.account || "global";
818
+ this.category = options.category || null;
819
+ this.slugs = options.slugs || null;
820
+ this.granularity = options.granularity || "days";
821
+ this.maxCountries = options.maxCountries || 12;
822
+ this.metricLabel = options.metricLabel || "Events";
823
+ this.height = mapHeight;
824
+ this.mapStyle = options.mapStyle || "dark";
825
+ this.mapOptions = options.mapOptions || {};
826
+ this.showRoutes = options.showRoutes !== false;
827
+ this.routeOrigin = options.routeOrigin || { lng: -77.346, lat: 38.958, name: "Reston, VA" };
828
+ this._refreshing = false;
829
+ }
830
+ async getTemplate() {
831
+ return `
832
+ <div class="metrics-country-map">
833
+ <div class="map-container mb-3" data-container="${this.id}-map" style="height:${this.height}px"></div>
834
+ <div class="map-legend small" data-region="legend"></div>
835
+ </div>
836
+ `;
837
+ }
838
+ async onInit() {
839
+ this.statusEl = document.createElement("div");
840
+ this.statusEl.className = "text-muted small px-3 pb-2";
841
+ this.element.appendChild(this.statusEl);
842
+ this.mapView = new MapLibreView({
843
+ containerId: `${this.id}-map`,
844
+ height: this.height,
845
+ style: this.mapStyle,
846
+ zoom: this.mapOptions.zoom ?? 1.3,
847
+ center: this.mapOptions.center || [10, 20],
848
+ pitch: this.mapOptions.pitch ?? 20,
849
+ bearing: this.mapOptions.bearing ?? 0,
850
+ showNavigationControl: this.mapOptions.showNavigationControl ?? true,
851
+ autoFitBounds: this.mapOptions.autoFitBounds ?? false
852
+ });
853
+ this.addChild(this.mapView);
854
+ await this.refresh();
855
+ }
856
+ async refresh() {
857
+ if (this._refreshing) return;
858
+ this._refreshing = true;
859
+ this.setStatus("Loading hotspots…");
860
+ try {
861
+ const metrics = await this.fetchMetrics();
862
+ await this.applyMetrics(metrics);
863
+ this.setStatus("");
864
+ } catch (error) {
865
+ console.error("MetricsCountryMapView refresh error", error);
866
+ this.setStatus("Unable to load country metrics.");
867
+ } finally {
868
+ this._refreshing = false;
869
+ }
870
+ }
871
+ async fetchMetrics() {
872
+ const rest = this.getApp()?.rest;
873
+ if (!rest) {
874
+ throw new Error("REST client unavailable");
875
+ }
876
+ const params = {
877
+ account: this.account,
878
+ granularity: this.granularity,
879
+ with_labels: true
880
+ };
881
+ if (this.category) params.category = this.category;
882
+ if (this.slugs) {
883
+ const slugsArray = Array.isArray(this.slugs) ? this.slugs : [this.slugs];
884
+ params["slugs[]"] = slugsArray;
885
+ }
886
+ const response = await rest.GET(this.endpoint, params);
887
+ if (!response.success || !response.data?.status) {
888
+ throw new Error(response.data?.error || "Metrics API error");
889
+ }
890
+ return response.data.data;
891
+ }
892
+ async applyMetrics(data) {
893
+ const metrics = data?.data || {};
894
+ const labels = data?.labels || [];
895
+ const entries = [];
896
+ Object.entries(metrics).forEach(([iso, series]) => {
897
+ const total = series.reduce((sum, value) => sum + (Number(value) || 0), 0);
898
+ if (!total) return;
899
+ const centroid = COUNTRY_CENTROIDS[iso.toUpperCase()];
900
+ if (!centroid) return;
901
+ entries.push({
902
+ code: iso.toUpperCase(),
903
+ total,
904
+ values: series,
905
+ centroid
906
+ });
907
+ });
908
+ if (!entries.length) {
909
+ this.mapView.updateMarkers([]);
910
+ this.renderLegend([]);
911
+ this.setStatus("No country data available for the selected range.");
912
+ return;
913
+ }
914
+ entries.sort((a, b) => b.total - a.total);
915
+ const topEntries = entries.slice(0, this.maxCountries);
916
+ const maxValue = topEntries[0]?.total || 1;
917
+ const markers = topEntries.map((entry) => {
918
+ const intensity = entry.total / maxValue;
919
+ const markerSize = Math.round(18 + intensity * 24);
920
+ return {
921
+ lng: entry.centroid.lng,
922
+ lat: entry.centroid.lat,
923
+ size: markerSize,
924
+ color: this.getMarkerColor(intensity),
925
+ popup: `
926
+ <div class="text-center">
927
+ <strong>${entry.centroid.name}</strong><br/>
928
+ <span class="text-muted">${entry.total.toLocaleString()} ${this.metricLabel}</span>
929
+ </div>
930
+ `
931
+ };
932
+ });
933
+ if (this.showRoutes && this.routeOrigin?.lng && this.routeOrigin?.lat) {
934
+ markers.push({
935
+ lng: this.routeOrigin.lng,
936
+ lat: this.routeOrigin.lat,
937
+ size: 26,
938
+ color: "#0d6efd",
939
+ icon: "bi bi-broadcast-pin",
940
+ popup: `
941
+ <div class="text-center">
942
+ <strong>${this.routeOrigin.name || "Operations Hub"}</strong><br/>
943
+ <span class="text-muted">Origin</span>
944
+ </div>
945
+ `
946
+ });
947
+ }
948
+ this.mapView.updateMarkers(markers);
949
+ this.renderLegend(topEntries, labels);
950
+ if (this.showRoutes) {
951
+ this.renderRoutes(topEntries, maxValue);
952
+ }
953
+ }
954
+ getMarkerColor(intensity) {
955
+ const start = [32, 201, 151];
956
+ const end = [255, 193, 7];
957
+ const mix = start.map(
958
+ (value, idx) => Math.round(value + (end[idx] - value) * intensity)
959
+ );
960
+ return `rgba(${mix[0]}, ${mix[1]}, ${mix[2]}, 0.9)`;
961
+ }
962
+ renderLegend(entries) {
963
+ const legendEl = this.element.querySelector('[data-region="legend"]');
964
+ if (!legendEl) return;
965
+ if (!entries.length) {
966
+ legendEl.innerHTML = "";
967
+ return;
968
+ }
969
+ const maxValue = entries[0]?.total || 1;
970
+ const rows = entries.map((entry) => {
971
+ const percent = (entry.total / maxValue * 100).toFixed(0);
972
+ return `
973
+ <div class="d-flex justify-content-between align-items-center py-1 border-top">
974
+ <div>
975
+ <span class="fw-semibold">${entry.centroid.name}</span>
976
+ <span class="text-muted ms-1">(${entry.code})</span>
977
+ </div>
978
+ <div class="text-end">
979
+ <div class="fw-semibold">${entry.total.toLocaleString()}</div>
980
+ <small class="text-muted">${percent}% of top</small>
981
+ </div>
982
+ </div>
983
+ `;
984
+ }).join("");
985
+ legendEl.innerHTML = rows;
986
+ }
987
+ renderRoutes(entries, maxValue) {
988
+ const origin = this.routeOrigin || null;
989
+ if (!origin || !origin.lng || !origin.lat || !this.mapView) return;
990
+ const features = entries.map((entry) => ({
991
+ type: "Feature",
992
+ geometry: {
993
+ type: "LineString",
994
+ coordinates: [
995
+ [origin.lng, origin.lat],
996
+ [entry.centroid.lng, entry.centroid.lat]
997
+ ]
998
+ },
999
+ properties: {
1000
+ total: entry.total,
1001
+ intensity: entry.total / maxValue
1002
+ }
1003
+ }));
1004
+ const geojson = {
1005
+ type: "FeatureCollection",
1006
+ features
1007
+ };
1008
+ const paint = {
1009
+ "line-color": [
1010
+ "interpolate",
1011
+ ["linear"],
1012
+ ["get", "intensity"],
1013
+ 0,
1014
+ "rgba(32, 201, 151, 0.6)",
1015
+ 1,
1016
+ "rgba(255, 193, 7, 0.95)"
1017
+ ],
1018
+ "line-width": [
1019
+ "interpolate",
1020
+ ["linear"],
1021
+ ["get", "intensity"],
1022
+ 0,
1023
+ 1.75,
1024
+ 1,
1025
+ 6
1026
+ ],
1027
+ "line-opacity": [
1028
+ "interpolate",
1029
+ ["linear"],
1030
+ ["get", "intensity"],
1031
+ 0,
1032
+ 0.45,
1033
+ 1,
1034
+ 0.95
1035
+ ]
1036
+ };
1037
+ this.mapView.lineSources = this.mapView.lineSources.filter((src) => src.id !== `${this.id}-routes`);
1038
+ this.mapView.updateLineSource(`${this.id}-routes`, {
1039
+ data: geojson,
1040
+ paint
1041
+ });
1042
+ }
1043
+ setStatus(message) {
1044
+ if (!this.statusEl) return;
1045
+ this.statusEl.textContent = message || "";
1046
+ this.statusEl.style.display = message ? "block" : "none";
1047
+ }
1048
+ }
1049
+ export {
1050
+ MapView as M,
1051
+ MetricsCountryMapView as a,
1052
+ MapLibreView as b
1053
+ };
1054
+ //# sourceMappingURL=MetricsCountryMapView-BNpojbUy.js.map