react-native-leaflet-kit 1.0.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.
Files changed (67) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +410 -0
  3. package/dist/components/Circle.d.ts +4 -0
  4. package/dist/components/Circle.d.ts.map +1 -0
  5. package/dist/components/Circle.js +15 -0
  6. package/dist/components/Circle.js.map +1 -0
  7. package/dist/components/GeoJSON.d.ts +4 -0
  8. package/dist/components/GeoJSON.d.ts.map +1 -0
  9. package/dist/components/GeoJSON.js +14 -0
  10. package/dist/components/GeoJSON.js.map +1 -0
  11. package/dist/components/Heatmap.d.ts +4 -0
  12. package/dist/components/Heatmap.d.ts.map +1 -0
  13. package/dist/components/Heatmap.js +14 -0
  14. package/dist/components/Heatmap.js.map +1 -0
  15. package/dist/components/MapContainer.d.ts +9 -0
  16. package/dist/components/MapContainer.d.ts.map +1 -0
  17. package/dist/components/MapContainer.js +86 -0
  18. package/dist/components/MapContainer.js.map +1 -0
  19. package/dist/components/Marker.d.ts +7 -0
  20. package/dist/components/Marker.d.ts.map +1 -0
  21. package/dist/components/Marker.js +20 -0
  22. package/dist/components/Marker.js.map +1 -0
  23. package/dist/components/MarkerCluster.d.ts +4 -0
  24. package/dist/components/MarkerCluster.d.ts.map +1 -0
  25. package/dist/components/MarkerCluster.js +14 -0
  26. package/dist/components/MarkerCluster.js.map +1 -0
  27. package/dist/components/Polygon.d.ts +4 -0
  28. package/dist/components/Polygon.d.ts.map +1 -0
  29. package/dist/components/Polygon.js +15 -0
  30. package/dist/components/Polygon.js.map +1 -0
  31. package/dist/components/Polyline.d.ts +4 -0
  32. package/dist/components/Polyline.d.ts.map +1 -0
  33. package/dist/components/Polyline.js +14 -0
  34. package/dist/components/Polyline.js.map +1 -0
  35. package/dist/components/Popup.d.ts +4 -0
  36. package/dist/components/Popup.d.ts.map +1 -0
  37. package/dist/components/Popup.js +27 -0
  38. package/dist/components/Popup.js.map +1 -0
  39. package/dist/components/TileLayer.d.ts +4 -0
  40. package/dist/components/TileLayer.d.ts.map +1 -0
  41. package/dist/components/TileLayer.js +14 -0
  42. package/dist/components/TileLayer.js.map +1 -0
  43. package/dist/components/UserMarker.d.ts +4 -0
  44. package/dist/components/UserMarker.d.ts.map +1 -0
  45. package/dist/components/UserMarker.js +15 -0
  46. package/dist/components/UserMarker.js.map +1 -0
  47. package/dist/context/MapContext.d.ts +11 -0
  48. package/dist/context/MapContext.d.ts.map +1 -0
  49. package/dist/context/MapContext.js +11 -0
  50. package/dist/context/MapContext.js.map +1 -0
  51. package/dist/index.d.ts +14 -0
  52. package/dist/index.d.ts.map +1 -0
  53. package/dist/index.js +14 -0
  54. package/dist/index.js.map +1 -0
  55. package/dist/templates/LeafletHTML.d.ts +2 -0
  56. package/dist/templates/LeafletHTML.d.ts.map +1 -0
  57. package/dist/templates/LeafletHTML.js +539 -0
  58. package/dist/templates/LeafletHTML.js.map +1 -0
  59. package/dist/types/index.d.ts +155 -0
  60. package/dist/types/index.d.ts.map +1 -0
  61. package/dist/types/index.js +15 -0
  62. package/dist/types/index.js.map +1 -0
  63. package/dist/utils/deepEqual.d.ts +2 -0
  64. package/dist/utils/deepEqual.d.ts.map +1 -0
  65. package/dist/utils/deepEqual.js +22 -0
  66. package/dist/utils/deepEqual.js.map +1 -0
  67. package/package.json +52 -0
@@ -0,0 +1,539 @@
1
+ export const LEAFLET_HTML_CONTENT = `<!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
6
+ <title>Leaflet Map</title>
7
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.css" />
8
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/1.5.3/MarkerCluster.css" />
9
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/1.5.3/MarkerCluster.Default.css" />
10
+ <style>
11
+ :root {
12
+ --theme-bg: #ffffff;
13
+ --theme-color: #333333;
14
+ }
15
+
16
+ #map.dark-mode-tiles {
17
+ --theme-bg: #1a1a1a;
18
+ --theme-color: #ffffff;
19
+ }
20
+
21
+ body {
22
+ margin: 0;
23
+ padding: 0;
24
+ font-family: Arial, sans-serif;
25
+ background-color: var(--theme-bg);
26
+ }
27
+
28
+ #map {
29
+ height: 100vh;
30
+ width: 100vw;
31
+ background-color: var(--theme-bg);
32
+ }
33
+
34
+ .leaflet-container {
35
+ background: none !important;
36
+ outline: 0;
37
+ }
38
+
39
+ .dark-mode-tiles .leaflet-tile-pane {
40
+ filter: brightness(0.6) invert(1) contrast(3) hue-rotate(200deg) saturate(0.3) brightness(0.7);
41
+ }
42
+
43
+ .custom-div-icon { background: none; border: none; }
44
+ .pulse-marker {
45
+ width: var(--user-marker-size, 12px);
46
+ height: var(--user-marker-size, 12px);
47
+ border-radius: 50%;
48
+ background: var(--user-marker-color, #1169C2);
49
+ border: 3px solid white;
50
+ box-shadow: 0 0 8px var(--user-marker-shadow, rgba(66, 133, 244, 0.7));
51
+ position: absolute;
52
+ top: 50%;
53
+ left: 50%;
54
+ margin-top: calc(var(--user-marker-size, 12px) / -2 - 3px);
55
+ margin-left: calc(var(--user-marker-size, 12px) / -2 - 3px);
56
+ z-index: 2;
57
+ display: var(--pulse-display, block);
58
+ }
59
+ .pulse-marker::before {
60
+ content: '';
61
+ position: absolute;
62
+ top: 0;
63
+ left: 0;
64
+ width: 100%;
65
+ height: 100%;
66
+ border-radius: 50%;
67
+ background: var(--user-marker-color, #1169C2);
68
+ animation: pulse var(--user-marker-pulse-duration, 2.5s) ease-out infinite;
69
+ pointer-events: none;
70
+ display: var(--pulse-animation-display, block);
71
+ }
72
+ @keyframes pulse {
73
+ 0% { transform: scale(0.8); opacity: 0.7; }
74
+ 50% { opacity: 0.4; }
75
+ 100% { transform: scale(var(--user-marker-pulse-max-scale, 2.5)); opacity: 0; }
76
+ }
77
+ .accuracy-circle {
78
+ stroke: var(--user-marker-color, #1169C2);
79
+ stroke-width: 2;
80
+ fill: var(--accuracy-circle-color, rgba(66, 133, 244, 0.1));
81
+ }
82
+ .direction-cone {
83
+ position: absolute;
84
+ width: var(--direction-cone-width, 60px);
85
+ height: var(--direction-cone-height, 50px);
86
+ left: 50%;
87
+ top: 50%;
88
+ margin-left: calc(var(--direction-cone-width, 60px) / -2);
89
+ margin-top: calc(var(--direction-cone-height, 50px) * -1);
90
+ transform-origin: center bottom;
91
+ background: linear-gradient(to top, var(--direction-cone-color, rgba(66, 133, 244, 0.6)), transparent);
92
+ clip-path: polygon(50% 100%, 0% 0%, 100% 0%);
93
+ transition: transform 0.8s cubic-bezier(0.4, 0, 0.2, 1);
94
+ pointer-events: none;
95
+ z-index: 1;
96
+ display: var(--direction-cone-display, block);
97
+ }
98
+ .leaflet-control-zoom { visibility: hidden; }
99
+
100
+ @keyframes flow {
101
+ from { stroke-dashoffset: 20; }
102
+ to { stroke-dashoffset: 0; }
103
+ }
104
+ .animated-polyline {
105
+ stroke-dasharray: 10, 10;
106
+ animation: flow 1s linear infinite;
107
+ }
108
+
109
+ .custom-popup .leaflet-popup-content-wrapper {
110
+ background: var(--theme-bg);
111
+ color: var(--theme-color);
112
+ border-radius: 12px;
113
+ padding: 0;
114
+ box-shadow: 0 3px 14px rgba(0,0,0,0.4);
115
+ }
116
+ .custom-popup .leaflet-popup-content {
117
+ margin: 12px;
118
+ line-height: 1.4;
119
+ }
120
+ .custom-popup .leaflet-popup-tip {
121
+ background: var(--theme-bg);
122
+ }
123
+ .custom-popup .leaflet-popup-close-button {
124
+ top: 10px !important;
125
+ right: 12px !important;
126
+ font-size: 20px !important;
127
+ font-weight: normal;
128
+ color: var(--theme-color);
129
+ padding: 0;
130
+ width: 24px;
131
+ height: 24px;
132
+ line-height: 24px;
133
+ text-align: center;
134
+ z-index: 1000;
135
+ }
136
+ </style>
137
+ </head>
138
+ <body>
139
+ <div id="map"></div>
140
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.js"></script>
141
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/1.5.3/leaflet.markercluster.js"></script>
142
+ <script src="https://cdn.jsdelivr.net/npm/leaflet.heat@0.2.0/dist/leaflet-heat.js"></script>
143
+ <script>
144
+ const svg = '<svg xmlns="http://www.w3.org/2000/svg" width="256" height="256"><rect width="100%" height="100%" fill="#f4f4f4"/><g transform="translate(100, 100) scale(0.30)"><path d="M0 16 L40 0 L88 16 L128 0 L128 112 L88 128 L40 112 L0 128 Z" fill="none" stroke="#888" stroke-width="3"/><line x1="40" y1="0" x2="40" y2="112" stroke="#888" stroke-width="3"/><line x1="88" y1="16" x2="88" y2="128" stroke="#888" stroke-width="3"/></g><text x="47%" y="60%" text-anchor="middle" font-size="9" fill="#888" font-family="system-ui, -apple-system, BlinkMacSystemFont">Offline</text></svg>';
145
+ const OFFLINE_TILE = 'data:image/svg+xml;charset=UTF-8,' + encodeURIComponent(svg);
146
+
147
+ let map, bounds = null, isReady = false, dragEnabled = true, zoomEnabled = true, isAutoFitEnabled = false, hasInitialFitPerformed = false, fitTimeout = null;
148
+ const markers = new Map(), polylines = new Map(), layers = new Map(), circles = new Map(), polygons = new Map();
149
+ const geojsonLayers = new Map(), heatmaps = new Map();
150
+ let markerClusterGroup = null;
151
+ let ownPositionMarker = null, accuracyCircle = null, directionCone = null, currentHeadingValue = 0;
152
+
153
+ const sendMessage = (message) => {
154
+ const msgStr = JSON.stringify(message);
155
+ if (window.ReactNativeWebView) window.ReactNativeWebView.postMessage(msgStr);
156
+ };
157
+
158
+ const hexToRgba = (hex, alpha) => {
159
+ const r = parseInt(hex.slice(1, 3), 16), g = parseInt(hex.slice(3, 5), 16), b = parseInt(hex.slice(5, 7), 16);
160
+ return 'rgba(' + r + ', ' + g + ', ' + b + ', ' + alpha + ')';
161
+ };
162
+
163
+ const createIcon = (iconData, size = [32, 32]) => {
164
+ if (!iconData) return null;
165
+ if (typeof iconData === 'string' && (iconData.startsWith('http') || iconData.includes('.'))) {
166
+ return L.icon({ iconUrl: iconData, iconSize: size, iconAnchor: [size[0]/2, size[1]], popupAnchor: [0, -size[1]] });
167
+ }
168
+ return L.divIcon({
169
+ className: 'custom-div-icon',
170
+ html: '<div style="font-size:' + Math.round(size[0]/2) + 'px;text-align:center;line-height:' + size[1] + 'px">' + iconData + '</div>',
171
+ iconSize: size, iconAnchor: [Math.round(size[0]/2), Math.round(size[1]/2)]
172
+ });
173
+ };
174
+
175
+ const addPopupStyle = (data) => {
176
+ const styleId = 'style-popup-' + data.id;
177
+ let styleEl = document.getElementById(styleId);
178
+ if (!styleEl) {
179
+ styleEl = document.createElement('style');
180
+ styleEl.id = styleId;
181
+ document.head.appendChild(styleEl);
182
+ }
183
+
184
+ const s = data.style || {};
185
+ styleEl.textContent =
186
+ '.custom-popup-' + data.id + ' .leaflet-popup-content-wrapper {' +
187
+ (s.backgroundColor ? 'background: ' + s.backgroundColor + ' !important;' : '') +
188
+ (s.textColor ? 'color: ' + s.textColor + ' !important;' : '') +
189
+ (s.borderRadius !== undefined ? 'border-radius: ' + s.borderRadius + 'px !important;' : '') +
190
+ '}' +
191
+ '.custom-popup-' + data.id + ' .leaflet-popup-content {' +
192
+ (s.padding !== undefined ? 'padding: ' + s.padding + 'px !important;' : '') +
193
+ (s.fontSize !== undefined ? 'font-size: ' + s.fontSize + 'px !important;' : '') +
194
+ (s.fontWeight !== undefined ? 'font-weight: ' + s.fontWeight + ' !important;' : '') +
195
+ '}' +
196
+ '.custom-popup-' + data.id + ' .leaflet-popup-tip {' +
197
+ (s.backgroundColor ? 'background: ' + s.backgroundColor + ' !important;' : '') +
198
+ '}' +
199
+ '.custom-popup-' + data.id + ' .leaflet-popup-close-button {' +
200
+ (s.closeButtonColor ? 'color: ' + s.closeButtonColor + ' !important;' : '') +
201
+ '}';
202
+ };
203
+
204
+ const updateMarkers = (markerData) => {
205
+ if (!markers.has(markerData.id)) {
206
+ const icon = markerData.icon ? createIcon(markerData.icon, markerData.size) : null;
207
+ const marker = icon ? L.marker(markerData.position, { icon }) : L.marker(markerData.position);
208
+ if (markerData.title || markerData.content) {
209
+ const popupOptions = {
210
+ className: 'custom-popup custom-popup-' + markerData.id,
211
+ maxWidth: (markerData.style && markerData.style.maxWidth) || 300,
212
+ minWidth: (markerData.style && markerData.style.minWidth) || 50,
213
+ offset: markerData.offset || [0, 7],
214
+ autoPan: markerData.autoPan !== undefined ? markerData.autoPan : true
215
+ };
216
+ marker.bindPopup(markerData.content || markerData.title, popupOptions);
217
+ addPopupStyle(markerData);
218
+ }
219
+ marker.on('click', () => sendMessage({ event: 'ON_MARKER_CLICK', payload: { id: markerData.id } }));
220
+
221
+ if (markerClusterGroup) {
222
+ markerClusterGroup.addLayer(marker);
223
+ } else {
224
+ marker.addTo(map);
225
+ }
226
+ markers.set(markerData.id, marker);
227
+ } else {
228
+ const marker = markers.get(markerData.id);
229
+ marker.setLatLng(markerData.position);
230
+ if (markerData.content || markerData.title) {
231
+ marker.setPopupContent(markerData.content || markerData.title);
232
+ addPopupStyle(markerData);
233
+ }
234
+ }
235
+ updateBounds();
236
+ };
237
+
238
+ const updatePolylines = (data) => {
239
+ const options = {
240
+ color: data.color || '#3388ff',
241
+ weight: data.weight || 3,
242
+ opacity: data.opacity || 1,
243
+ dashArray: data.dashArray,
244
+ className: data.isAnimated ? 'animated-polyline' : ''
245
+ };
246
+
247
+ if (!polylines.has(data.id)) {
248
+ const poly = L.polyline(data.positions, options).addTo(map);
249
+ polylines.set(data.id, poly);
250
+ } else {
251
+ const poly = polylines.get(data.id);
252
+ poly.setLatLngs(data.positions);
253
+ poly.setStyle(options);
254
+ }
255
+ updateBounds();
256
+ };
257
+
258
+ const updateCircles = (data) => {
259
+ const options = {
260
+ color: data.color || '#3388ff',
261
+ fillColor: data.fillColor || data.color || '#3388ff',
262
+ fillOpacity: data.fillOpacity || 0.2,
263
+ weight: data.weight || 2
264
+ };
265
+ if (!circles.has(data.id)) {
266
+ const circle = L.circle(data.center, { radius: data.radius, ...options }).addTo(map);
267
+ circles.set(data.id, circle);
268
+ } else {
269
+ const circle = circles.get(data.id);
270
+ circle.setLatLng(data.center);
271
+ circle.setRadius(data.radius);
272
+ circle.setStyle(options);
273
+ }
274
+ updateBounds();
275
+ };
276
+
277
+ const updatePolygons = (data) => {
278
+ const options = {
279
+ color: data.color || '#3388ff',
280
+ fillColor: data.fillColor || data.color || '#3388ff',
281
+ fillOpacity: data.fillOpacity || 0.2,
282
+ weight: data.weight || 2
283
+ };
284
+ if (!polygons.has(data.id)) {
285
+ const polygon = L.polygon(data.positions, options).addTo(map);
286
+ polygons.set(data.id, polygon);
287
+ } else {
288
+ const polygon = polygons.get(data.id);
289
+ polygon.setLatLngs(data.positions);
290
+ polygon.setStyle(options);
291
+ }
292
+ updateBounds();
293
+ };
294
+
295
+ const updateGeoJSON = (data) => {
296
+ if (geojsonLayers.has(data.id)) {
297
+ map.removeLayer(geojsonLayers.get(data.id));
298
+ }
299
+ const layer = L.geoJSON(data.data, {
300
+ style: data.style,
301
+ onEachFeature: (feature, layer) => {
302
+ layer.on('click', () => {
303
+ sendMessage({ event: 'ON_GEOJSON_CLICK', payload: { id: data.id, feature } });
304
+ });
305
+ }
306
+ }).addTo(map);
307
+ geojsonLayers.set(data.id, layer);
308
+ updateBounds();
309
+ };
310
+
311
+ const updateHeatmap = (data) => {
312
+ if (heatmaps.has(data.id)) {
313
+ map.removeLayer(heatmaps.get(data.id));
314
+ }
315
+ const heatPoints = data.points.map(p => [p.lat, p.lng, p.intensity]);
316
+ const layer = L.heatLayer(heatPoints, {
317
+ radius: data.radius || 25,
318
+ blur: data.blur || 15,
319
+ max: data.max || 1.0
320
+ }).addTo(map);
321
+ heatmaps.set(data.id, layer);
322
+ };
323
+
324
+ const toggleCluster = (enabled, options = {}) => {
325
+ if (enabled && !markerClusterGroup) {
326
+ markerClusterGroup = L.markerClusterGroup(options);
327
+ markers.forEach(m => {
328
+ map.removeLayer(m);
329
+ markerClusterGroup.addLayer(m);
330
+ });
331
+ map.addLayer(markerClusterGroup);
332
+ } else if (!enabled && markerClusterGroup) {
333
+ map.removeLayer(markerClusterGroup);
334
+ markers.forEach(m => m.addTo(map));
335
+ markerClusterGroup = null;
336
+ }
337
+ };
338
+
339
+ const updateOwnPositionMarker = (markerData) => {
340
+ if (!markerData || !markerData.position) {
341
+ if (ownPositionMarker) { map.removeLayer(ownPositionMarker); ownPositionMarker = null; }
342
+ if (accuracyCircle) { map.removeLayer(accuracyCircle); accuracyCircle = null; }
343
+ if (directionCone) { map.removeLayer(directionCone); directionCone = null; }
344
+ return;
345
+ }
346
+ const { lat, lng } = markerData.position;
347
+ const markerColor = markerData.markerColor || '#1169C2';
348
+ const style = markerData.style || {};
349
+ const root = document.documentElement;
350
+
351
+ root.style.setProperty('--user-marker-size', (style.markerSize || 12) + 'px');
352
+ root.style.setProperty('--user-marker-color', markerColor);
353
+ root.style.setProperty('--user-marker-shadow', hexToRgba(markerColor, 0.5));
354
+ root.style.setProperty('--accuracy-circle-color', hexToRgba(markerData.accuracyCircleColor || markerColor, 0.1));
355
+
356
+ root.style.setProperty('--pulse-display', (style.showPulse !== false) ? 'block' : 'none');
357
+ root.style.setProperty('--user-marker-pulse-max-scale', style.pulseMaxScale || 2.5);
358
+ root.style.setProperty('--user-marker-pulse-duration', style.pulseDuration || '2.5s');
359
+
360
+ root.style.setProperty('--direction-cone-display', (style.showDirectionCone !== false) ? 'block' : 'none');
361
+ root.style.setProperty('--direction-cone-width', (style.coneWidth || 60) + 'px');
362
+ root.style.setProperty('--direction-cone-height', (style.coneHeight || 50) + 'px');
363
+
364
+ const newLatLng = L.latLng(lat, lng);
365
+ if (!ownPositionMarker) {
366
+ ownPositionMarker = L.marker(newLatLng, { icon: L.divIcon({ className: 'custom-div-icon', html: '<div class="pulse-marker"></div>', iconSize: [30, 30], iconAnchor: [15, 15] }) }).addTo(map);
367
+ } else if (!ownPositionMarker.getLatLng().equals(newLatLng, 0.00001)) {
368
+ animateMarker(ownPositionMarker, ownPositionMarker.getLatLng(), newLatLng, 1000);
369
+ }
370
+
371
+ if (markerData.accuracy > 0) {
372
+ if (!accuracyCircle) accuracyCircle = L.circle(newLatLng, { radius: markerData.accuracy, className: 'accuracy-circle', fillOpacity: 0.1, weight: 2 }).addTo(map);
373
+ else { accuracyCircle.setLatLng(newLatLng); accuracyCircle.setRadius(markerData.accuracy); }
374
+ }
375
+
376
+ if (markerData.heading !== undefined && markerData.heading !== null) {
377
+ if (!directionCone) directionCone = L.marker(newLatLng, { icon: L.divIcon({ className: 'custom-div-icon', html: '<div class="direction-cone"></div>', iconSize: [30, 30], iconAnchor: [15, 15] }), zIndexOffset: -100 }).addTo(map);
378
+ else directionCone.setLatLng(newLatLng);
379
+
380
+ const coneDiv = directionCone.getElement()?.querySelector('.direction-cone');
381
+ if (coneDiv) {
382
+ let diff = (markerData.heading - (currentHeadingValue % 360));
383
+ if (diff > 180) diff -= 360; else if (diff < -180) diff += 360;
384
+ currentHeadingValue += diff;
385
+ coneDiv.style.transform = 'rotate(' + currentHeadingValue + 'deg)';
386
+ document.documentElement.style.setProperty('--direction-cone-color', hexToRgba(markerColor, style.coneOpacity || 0.6));
387
+ }
388
+ } else if (directionCone) { map.removeLayer(directionCone); directionCone = null; }
389
+ updateBounds();
390
+ };
391
+
392
+ const animateMarker = (marker, from, to, duration) => {
393
+ const start = Date.now();
394
+ const animate = () => {
395
+ const progress = Math.min((Date.now() - start) / duration, 1);
396
+ const ease = 1 - Math.pow(1 - progress, 3);
397
+ const cur = [from.lat + (to.lat - from.lat) * ease, from.lng + (to.lng - from.lng) * ease];
398
+ marker.setLatLng(cur);
399
+ if (accuracyCircle) accuracyCircle.setLatLng(cur);
400
+ if (directionCone) directionCone.setLatLng(cur);
401
+ if (progress < 1) requestAnimationFrame(animate);
402
+ };
403
+ requestAnimationFrame(animate);
404
+ };
405
+
406
+ window.addEventListener('message', (event) => {
407
+ let data = event.data;
408
+ if (typeof data === 'string') {
409
+ try { data = JSON.parse(data); } catch (e) { return; }
410
+ }
411
+ if (!data) return;
412
+
413
+ if (data.type === 'init') {
414
+ if (data.center) map.setView(data.center, data.zoom || 13);
415
+ if (data.isDark) document.getElementById('map').classList.add('dark-mode-tiles');
416
+ if (data.fitBounds) isAutoFitEnabled = true;
417
+ }
418
+ if (data.type === 'fit_bounds_toggle') {
419
+ isAutoFitEnabled = !!data.enabled;
420
+ if (isAutoFitEnabled) hasInitialFitPerformed = false; // Reset to allow re-fit
421
+ }
422
+ if (data.type === 'marker') updateMarkers(data);
423
+ if (data.type === 'remove_marker') {
424
+ if (markers.has(data.id)) {
425
+ map.removeLayer(markers.get(data.id));
426
+ markers.delete(data.id);
427
+ const styleEl = document.getElementById('style-popup-' + data.id);
428
+ if (styleEl) styleEl.remove();
429
+ }
430
+ }
431
+ if (data.type === 'polyline') updatePolylines(data);
432
+ if (data.type === 'remove_polyline') { if (polylines.has(data.id)) { map.removeLayer(polylines.get(data.id)); polylines.delete(data.id); } }
433
+ if (data.type === 'circle') updateCircles(data);
434
+ if (data.type === 'remove_circle') { if (circles.has(data.id)) { map.removeLayer(circles.get(data.id)); circles.delete(data.id); } }
435
+ if (data.type === 'polygon') updatePolygons(data);
436
+ if (data.type === 'remove_polygon') { if (polygons.has(data.id)) { map.removeLayer(polygons.get(data.id)); polygons.delete(data.id); } }
437
+ if (data.type === 'geojson') updateGeoJSON(data);
438
+ if (data.type === 'remove_geojson') { if (geojsonLayers.has(data.id)) { map.removeLayer(geojsonLayers.get(data.id)); geojsonLayers.delete(data.id); } }
439
+ if (data.type === 'heatmap') updateHeatmap(data);
440
+ if (data.type === 'remove_heatmap') { if (heatmaps.has(data.id)) { map.removeLayer(heatmaps.get(data.id)); heatmaps.delete(data.id); } }
441
+ if (data.type === 'cluster') toggleCluster(data.enabled, data.options);
442
+ if (data.type === 'userMarker') updateOwnPositionMarker(data);
443
+ if (data.type === 'center') {
444
+ isAutoFitEnabled = false; // Disable auto-fit if specifically centering
445
+ map.setView(data.position, data.zoom || map.getZoom());
446
+ }
447
+ if (data.type === 'tile') {
448
+ if (layers.has(data.id)) map.removeLayer(layers.get(data.id));
449
+ const layer = L.tileLayer(data.url, { attribution: data.attribution }).addTo(map);
450
+ layers.set(data.id, layer);
451
+ }
452
+ if (data.type === 'theme') {
453
+ document.documentElement.style.setProperty('--theme-bg', data.background);
454
+ if (data.isDark) document.getElementById('map').classList.add('dark-mode-tiles');
455
+ else document.getElementById('map').classList.remove('dark-mode-tiles');
456
+ }
457
+ if (data.type === 'fitBounds') {
458
+ const options = data.options || { padding: [50, 50], maxZoom: 15 };
459
+ if (bounds && bounds.isValid()) map.fitBounds(bounds, options);
460
+ }
461
+ });
462
+
463
+ const updateBounds = () => {
464
+ const routeBounds = L.latLngBounds();
465
+ let hasRouteData = false;
466
+
467
+ // Collect Route Elements (Markers, Polylines, etc.)
468
+ markers.forEach(m => { routeBounds.extend(m.getLatLng()); hasRouteData = true; });
469
+ polylines.forEach(p => { routeBounds.extend(p.getBounds()); hasRouteData = true; });
470
+ geojsonLayers.forEach(g => { routeBounds.extend(g.getBounds()); hasRouteData = true; });
471
+ circles.forEach(c => { routeBounds.extend(c.getBounds()); hasRouteData = true; });
472
+ polygons.forEach(p => { routeBounds.extend(p.getBounds()); hasRouteData = true; });
473
+
474
+ // Global bounds (used for manual fitBounds/Recenter, includes User)
475
+ bounds = L.latLngBounds();
476
+ if (hasRouteData) bounds.extend(routeBounds);
477
+ if (ownPositionMarker) bounds.extend(ownPositionMarker.getLatLng());
478
+
479
+ if (isAutoFitEnabled && !hasInitialFitPerformed) {
480
+ if (fitTimeout) clearTimeout(fitTimeout);
481
+ fitTimeout = setTimeout(() => {
482
+ if (hasRouteData && routeBounds.isValid()) {
483
+ // Priority 1: Focus on the Route context (Hero view)
484
+ map.fitBounds(routeBounds, { padding: [50, 50], maxZoom: 15 });
485
+ hasInitialFitPerformed = true;
486
+ } else if (ownPositionMarker) {
487
+ // Priority 2: Focus on User if no route markers are present
488
+ map.setView(ownPositionMarker.getLatLng(), 15);
489
+ hasInitialFitPerformed = true;
490
+ }
491
+ }, 200); // Wait for all components to register through the bridge
492
+ }
493
+ };
494
+
495
+ const initMap = () => {
496
+ try {
497
+ if (map) return;
498
+ map = L.map('map', { center: [28.7041, 77.1025], zoom: 13, zoomControl: false });
499
+ bounds = L.latLngBounds();
500
+ map.on('moveend', () => {
501
+ const center = map.getCenter();
502
+ sendMessage({ event: 'ON_MOVE_END', payload: { mapCenterPosition: center, zoom: map.getZoom(), bounds: map.getBounds() } });
503
+ });
504
+ map.on('click', (e) => sendMessage({ event: 'ON_MAP_CLICK', payload: { latlng: e.latlng } }));
505
+
506
+ // Gesture Detection
507
+ const onUserInteraction = () => {
508
+ if (isAutoFitEnabled) {
509
+ isAutoFitEnabled = false;
510
+ sendMessage({ event: 'ON_USER_GESTURE' });
511
+ }
512
+ };
513
+
514
+ map.on('dragstart', onUserInteraction);
515
+ map.on('zoomstart', onUserInteraction);
516
+ map.on('touchstart', onUserInteraction);
517
+ map.on('mousedown', onUserInteraction);
518
+
519
+ isReady = true;
520
+ // Tiny delay to ensure bridge is fully established
521
+ setTimeout(() => {
522
+ sendMessage({ event: 'MAP_READY' });
523
+ }, 100);
524
+ } catch (err) {
525
+ sendMessage({ event: 'ON_MAP_ERROR', msg: err.message });
526
+ }
527
+ };
528
+
529
+ window.onerror = (msg, url, line) => {
530
+ sendMessage({ event: 'ON_MAP_ERROR', msg: msg + ' at ' + line });
531
+ return false;
532
+ };
533
+
534
+ document.addEventListener('DOMContentLoaded', initMap);
535
+ setTimeout(initMap, 500); // Fallback if DOMContentLoaded already fired
536
+ </script>
537
+ </body>
538
+ </html>`;
539
+ //# sourceMappingURL=LeafletHTML.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LeafletHTML.js","sourceRoot":"","sources":["../../src/templates/LeafletHTML.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,oBAAoB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAyhB5B,CAAC"}