adt-js-components 1.8.2 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/Map/index.js +541 -20
- package/src/Map/route.types.js +18 -0
package/package.json
CHANGED
package/src/Map/index.js
CHANGED
|
@@ -1,20 +1,47 @@
|
|
|
1
1
|
import L from 'leaflet';
|
|
2
2
|
import 'leaflet/dist/leaflet.css';
|
|
3
|
-
|
|
4
3
|
import "leaflet.markercluster";
|
|
5
4
|
import "leaflet.markercluster/dist/MarkerCluster.css";
|
|
6
5
|
import "leaflet.markercluster/dist/MarkerCluster.Default.css";
|
|
6
|
+
import {RouteSetting, defaultRouteSettings} from './route.types.js';
|
|
7
7
|
|
|
8
8
|
let siteKey;
|
|
9
9
|
let markerImg;
|
|
10
10
|
const mapInstances = new WeakMap();
|
|
11
|
+
const selectedMarkers = new WeakMap();
|
|
12
|
+
const selectionOrder = new WeakMap();
|
|
13
|
+
const markerInstances = new WeakMap();
|
|
14
|
+
const routePolylines = new WeakMap();
|
|
15
|
+
const routeSettingsMap = new WeakMap();
|
|
16
|
+
const markersDataMap = new WeakMap();
|
|
17
|
+
const markerClusters = new WeakMap();
|
|
18
|
+
const onSelectionChangeMap = new WeakMap();
|
|
11
19
|
|
|
12
20
|
async function run(options) {
|
|
13
21
|
siteKey = options.siteKey;
|
|
14
22
|
markerImg = options.markerImg;
|
|
15
23
|
|
|
16
24
|
function applyEventHandlers(el) {
|
|
17
|
-
const {
|
|
25
|
+
const {
|
|
26
|
+
position = [],
|
|
27
|
+
zoom,
|
|
28
|
+
hideControl = false,
|
|
29
|
+
markers = [],
|
|
30
|
+
route = {},
|
|
31
|
+
showDefaultMarker = true,
|
|
32
|
+
callback,
|
|
33
|
+
selectable = false,
|
|
34
|
+
onSelectionChange = null,
|
|
35
|
+
customMarkers = {},
|
|
36
|
+
showSelectionOrder = false,
|
|
37
|
+
markerInfoCallback = null,
|
|
38
|
+
} = JSON.parse(el.dataset.adtMap);
|
|
39
|
+
|
|
40
|
+
/** @type {RouteSetting} */
|
|
41
|
+
const routeSettings = {
|
|
42
|
+
...defaultRouteSettings,
|
|
43
|
+
...route,
|
|
44
|
+
};
|
|
18
45
|
|
|
19
46
|
if (mapInstances.has(el)) {
|
|
20
47
|
mapInstances.get(el).remove();
|
|
@@ -23,12 +50,20 @@ async function run(options) {
|
|
|
23
50
|
|
|
24
51
|
const map = L.map(el);
|
|
25
52
|
mapInstances.set(el, map);
|
|
53
|
+
selectedMarkers.set(map, new Set());
|
|
54
|
+
selectionOrder.set(map, new Map());
|
|
55
|
+
markerInstances.set(map, new Map());
|
|
56
|
+
routePolylines.set(map, null);
|
|
57
|
+
routeSettingsMap.set(map, routeSettings);
|
|
58
|
+
markersDataMap.set(map, markers);
|
|
59
|
+
onSelectionChangeMap.set(map, onSelectionChange);
|
|
26
60
|
|
|
27
61
|
L.tileLayer("https://api.mapy.cz/v1/maptiles/basic/256/{z}/{x}/{y}?apikey=" + siteKey, {
|
|
28
62
|
minZoom: 0,
|
|
29
63
|
maxZoom: 19,
|
|
30
64
|
attribution: '<a href="https://api.mapy.cz/copyright" target="_blank">© Seznam.cz a.s. a další</a>',
|
|
31
65
|
}).addTo(map);
|
|
66
|
+
|
|
32
67
|
const LogoControl = L.Control.extend({
|
|
33
68
|
options: {
|
|
34
69
|
position: 'bottomleft',
|
|
@@ -40,6 +75,7 @@ async function run(options) {
|
|
|
40
75
|
link.setAttribute('target', '_blank');
|
|
41
76
|
link.innerHTML = '<img src="https://api.mapy.cz/img/api/logo.svg" />';
|
|
42
77
|
L.DomEvent.disableClickPropagation(link);
|
|
78
|
+
|
|
43
79
|
return container;
|
|
44
80
|
},
|
|
45
81
|
});
|
|
@@ -60,24 +96,66 @@ async function run(options) {
|
|
|
60
96
|
map.dragging.disable();
|
|
61
97
|
}
|
|
62
98
|
|
|
99
|
+
|
|
100
|
+
if (selectable) {
|
|
101
|
+
enableRectangleSelection(map, onSelectionChange, showSelectionOrder);
|
|
102
|
+
}
|
|
103
|
+
|
|
63
104
|
const markerOptions = {};
|
|
64
|
-
|
|
105
|
+
const customMarkerOptions = {};
|
|
106
|
+
const normalImg = customMarkers.normal || markerImg;
|
|
107
|
+
const selectedImg = customMarkers.selected || markerImg;
|
|
108
|
+
|
|
109
|
+
if (normalImg) {
|
|
65
110
|
const img = new Image();
|
|
66
|
-
img.src =
|
|
111
|
+
img.src = normalImg;
|
|
67
112
|
img.onload = function () {
|
|
68
113
|
markerOptions.icon = L.icon({
|
|
69
|
-
iconUrl:
|
|
114
|
+
iconUrl: normalImg,
|
|
70
115
|
iconSize: [img.width, img.height],
|
|
71
116
|
iconAnchor: [img.width / 2, img.height]
|
|
72
117
|
});
|
|
73
|
-
|
|
74
|
-
|
|
118
|
+
|
|
119
|
+
if (selectedImg && selectedImg !== normalImg) {
|
|
120
|
+
const selectedImgEl = new Image();
|
|
121
|
+
selectedImgEl.src = selectedImg;
|
|
122
|
+
selectedImgEl.onload = function () {
|
|
123
|
+
customMarkerOptions.icon = L.icon({
|
|
124
|
+
iconUrl: selectedImg,
|
|
125
|
+
iconSize: [selectedImgEl.width, selectedImgEl.height],
|
|
126
|
+
iconAnchor: [selectedImgEl.width / 2, selectedImgEl.height]
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
if (markers.length) {
|
|
130
|
+
addMarkers(map, markers, markerOptions, customMarkerOptions, position, selectable, onSelectionChange, showSelectionOrder, markerInfoCallback);
|
|
131
|
+
} else if (showDefaultMarker) {
|
|
132
|
+
createMarker({
|
|
133
|
+
id: 0,
|
|
134
|
+
position: position
|
|
135
|
+
}, markerOptions, customMarkerOptions, null, selectable, onSelectionChange, map, showSelectionOrder, markerInfoCallback).addTo(map);
|
|
136
|
+
}
|
|
137
|
+
};
|
|
75
138
|
} else {
|
|
76
|
-
|
|
139
|
+
customMarkerOptions.icon = markerOptions.icon;
|
|
140
|
+
|
|
141
|
+
if (markers.length) {
|
|
142
|
+
addMarkers(map, markers, markerOptions, customMarkerOptions, position, selectable, onSelectionChange, showSelectionOrder, markerInfoCallback);
|
|
143
|
+
} else if (showDefaultMarker) {
|
|
144
|
+
createMarker({
|
|
145
|
+
id: 0,
|
|
146
|
+
position: position
|
|
147
|
+
}, markerOptions, customMarkerOptions, null, selectable, onSelectionChange, map, showSelectionOrder, markerInfoCallback).addTo(map);
|
|
148
|
+
}
|
|
77
149
|
}
|
|
78
150
|
};
|
|
79
151
|
}
|
|
80
152
|
|
|
153
|
+
if (routeSettings.enabled) {
|
|
154
|
+
setTimeout(() => {
|
|
155
|
+
calculateRoute(map);
|
|
156
|
+
}, 500);
|
|
157
|
+
}
|
|
158
|
+
|
|
81
159
|
if (callback) {
|
|
82
160
|
map.on('zoomend', window[callback]);
|
|
83
161
|
map.on('moveend', window[callback]);
|
|
@@ -90,8 +168,15 @@ async function run(options) {
|
|
|
90
168
|
mutations.forEach(mutation => {
|
|
91
169
|
if (mutation.type === "childList") {
|
|
92
170
|
mutation.addedNodes.forEach(node => {
|
|
93
|
-
if (node.nodeType === 1
|
|
94
|
-
|
|
171
|
+
if (node.nodeType === 1) {
|
|
172
|
+
// Zkontroluj samotný node
|
|
173
|
+
if (node.hasAttribute("data-adt-map")) {
|
|
174
|
+
applyEventHandlers(node);
|
|
175
|
+
}
|
|
176
|
+
// Zkontroluj všechny potomky
|
|
177
|
+
node.querySelectorAll?.('[data-adt-map]').forEach(el => {
|
|
178
|
+
applyEventHandlers(el);
|
|
179
|
+
});
|
|
95
180
|
}
|
|
96
181
|
});
|
|
97
182
|
}
|
|
@@ -109,16 +194,116 @@ async function run(options) {
|
|
|
109
194
|
attributeFilter: ["data-adt-map"]
|
|
110
195
|
});
|
|
111
196
|
|
|
112
|
-
document.querySelectorAll('[data-adt-map]').forEach(function(el) {
|
|
197
|
+
document.querySelectorAll('[data-adt-map]').forEach(function (el) {
|
|
113
198
|
applyEventHandlers(el);
|
|
114
199
|
});
|
|
115
200
|
}
|
|
116
201
|
|
|
117
|
-
function
|
|
202
|
+
function enableRectangleSelection(map, onSelectionChange, showSelectionOrder) {
|
|
203
|
+
let isDrawing = false;
|
|
204
|
+
let startPoint = null;
|
|
205
|
+
let rectangle = null;
|
|
206
|
+
|
|
207
|
+
map.on('mousedown', (e) => {
|
|
208
|
+
if (e.originalEvent.ctrlKey && e.originalEvent.shiftKey) {
|
|
209
|
+
isDrawing = true;
|
|
210
|
+
startPoint = e.latlng;
|
|
211
|
+
|
|
212
|
+
rectangle = L.rectangle([startPoint, startPoint], {
|
|
213
|
+
color: '#3388ff',
|
|
214
|
+
weight: 2,
|
|
215
|
+
fillOpacity: 0.1
|
|
216
|
+
}).addTo(map);
|
|
217
|
+
|
|
218
|
+
map.dragging.disable();
|
|
219
|
+
e.originalEvent.preventDefault();
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
map.on('mousemove', (e) => {
|
|
224
|
+
if (isDrawing && rectangle) {
|
|
225
|
+
rectangle.setBounds([startPoint, e.latlng]);
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
map.on('mouseup', (e) => {
|
|
230
|
+
if (isDrawing) {
|
|
231
|
+
isDrawing = false;
|
|
232
|
+
map.dragging.enable();
|
|
233
|
+
|
|
234
|
+
if (rectangle) {
|
|
235
|
+
const bounds = rectangle.getBounds();
|
|
236
|
+
const markerMap = markerInstances.get(map);
|
|
237
|
+
const selectedInArea = [];
|
|
238
|
+
|
|
239
|
+
markerMap.forEach((markerInstance, markerId) => {
|
|
240
|
+
const latLng = markerInstance.getLatLng();
|
|
241
|
+
|
|
242
|
+
if (bounds.contains(latLng)) {
|
|
243
|
+
selectedInArea.push(markerInstance);
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
const selected = selectedMarkers.get(map);
|
|
248
|
+
selectedInArea.forEach(marker => {
|
|
249
|
+
if (selected.has(marker.options.id)) {
|
|
250
|
+
deselectMarker(marker, map, showSelectionOrder);
|
|
251
|
+
} else {
|
|
252
|
+
selectMarker(marker, map, showSelectionOrder);
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
map.removeLayer(rectangle);
|
|
257
|
+
rectangle = null;
|
|
258
|
+
|
|
259
|
+
if (onSelectionChange && window[onSelectionChange]) {
|
|
260
|
+
const order = selectionOrder.get(map);
|
|
261
|
+
const orderedIds = Array.from(order.entries())
|
|
262
|
+
.sort((a, b) => a[1] - b[1])
|
|
263
|
+
.map(entry => entry[0]);
|
|
264
|
+
window[onSelectionChange](orderedIds);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
const settings = routeSettingsMap.get(map);
|
|
268
|
+
if (settings && settings.enabled) {
|
|
269
|
+
calculateRoute(map);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
function addMarkers(map, markers, options, selectedOptions, position, selectable, onSelectionChange, showSelectionOrder, markerInfoCallback) {
|
|
118
277
|
const positionsOfMarkers = [];
|
|
119
278
|
const cluster = L.markerClusterGroup({
|
|
120
|
-
disableClusteringAtZoom:
|
|
279
|
+
disableClusteringAtZoom: 18,
|
|
280
|
+
spiderfyOnMaxZoom: true,
|
|
281
|
+
showCoverageOnHover: false,
|
|
282
|
+
zoomToBoundsOnClick: true,
|
|
283
|
+
|
|
284
|
+
iconCreateFunction: function (cluster) {
|
|
285
|
+
const childCount = cluster.getChildCount();
|
|
286
|
+
let c = ' marker-cluster-';
|
|
287
|
+
if (childCount < 10) {
|
|
288
|
+
c += 'small';
|
|
289
|
+
} else if (childCount < 100) {
|
|
290
|
+
c += 'medium';
|
|
291
|
+
} else {
|
|
292
|
+
c += 'large';
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
return new L.DivIcon({
|
|
296
|
+
html: '<div><span>' + childCount + '</span></div>',
|
|
297
|
+
className: 'marker-cluster' + c,
|
|
298
|
+
iconSize: new L.Point(40, 40)
|
|
299
|
+
});
|
|
300
|
+
}
|
|
121
301
|
});
|
|
302
|
+
|
|
303
|
+
markerClusters.set(map, cluster);
|
|
304
|
+
let loadedCount = 0;
|
|
305
|
+
const totalMarkers = markers.length;
|
|
306
|
+
|
|
122
307
|
for (const marker of markers) {
|
|
123
308
|
if (marker.img) {
|
|
124
309
|
let markerOptions = options;
|
|
@@ -130,10 +315,16 @@ function addMarkers(map, markers, options, position) {
|
|
|
130
315
|
iconSize: [markerImage.width, markerImage.height],
|
|
131
316
|
iconAnchor: [markerImage.width / 2, markerImage.height]
|
|
132
317
|
});
|
|
133
|
-
createMarker(marker, markerOptions, cluster);
|
|
318
|
+
createMarker(marker, markerOptions, selectedOptions, cluster, selectable, onSelectionChange, map, showSelectionOrder, markerInfoCallback);
|
|
319
|
+
|
|
320
|
+
loadedCount++;
|
|
321
|
+
if (loadedCount === totalMarkers) {
|
|
322
|
+
checkAndApplyPreselection(map, markers, showSelectionOrder, onSelectionChange, selectable);
|
|
323
|
+
}
|
|
134
324
|
};
|
|
135
325
|
} else {
|
|
136
|
-
createMarker(marker, options, cluster);
|
|
326
|
+
createMarker(marker, options, selectedOptions, cluster, selectable, onSelectionChange, map, showSelectionOrder, markerInfoCallback);
|
|
327
|
+
loadedCount++;
|
|
137
328
|
}
|
|
138
329
|
|
|
139
330
|
if (!marker.excludeFromBoundary) {
|
|
@@ -141,26 +332,356 @@ function addMarkers(map, markers, options, position) {
|
|
|
141
332
|
}
|
|
142
333
|
}
|
|
143
334
|
|
|
144
|
-
if (!position.length) {
|
|
335
|
+
if (!position.length && positionsOfMarkers.length) {
|
|
145
336
|
map.fitBounds(positionsOfMarkers);
|
|
146
337
|
}
|
|
147
338
|
map.addLayer(cluster);
|
|
339
|
+
|
|
340
|
+
if (loadedCount === totalMarkers) {
|
|
341
|
+
setTimeout(() => {
|
|
342
|
+
checkAndApplyPreselection(map, markers, showSelectionOrder, onSelectionChange, selectable);
|
|
343
|
+
}, 200);
|
|
344
|
+
}
|
|
148
345
|
}
|
|
149
346
|
|
|
150
|
-
function
|
|
347
|
+
function checkAndApplyPreselection(map, markers, showSelectionOrder, onSelectionChange, selectable) {
|
|
348
|
+
if (selectable && showSelectionOrder) {
|
|
349
|
+
applyPreselectedMarkers(map, markers, showSelectionOrder, onSelectionChange);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
function createMarker(marker, options, selectedOptions, cluster = null, selectable = false, onSelectionChange = null, map = null, showSelectionOrder = false, markerInfoCallback = null) {
|
|
151
354
|
const mapMarker = L.marker(marker.position, {...options, id: marker.id});
|
|
152
|
-
|
|
153
|
-
|
|
355
|
+
mapMarker._normalIcon = options.icon;
|
|
356
|
+
mapMarker._selectedIcon = selectedOptions.icon;
|
|
357
|
+
mapMarker._markerData = marker;
|
|
358
|
+
|
|
359
|
+
if (map) {
|
|
360
|
+
const markers = markerInstances.get(map);
|
|
361
|
+
markers.set(marker.id, mapMarker);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
const originalCallback = marker.callback;
|
|
365
|
+
|
|
366
|
+
if (selectable && map) {
|
|
367
|
+
mapMarker.on('click', function (e) {
|
|
368
|
+
if (e.originalEvent.shiftKey && markerInfoCallback && window[markerInfoCallback]) {
|
|
369
|
+
window[markerInfoCallback](marker);
|
|
370
|
+
L.DomEvent.stopPropagation(e);
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
const selected = selectedMarkers.get(map);
|
|
375
|
+
|
|
376
|
+
if (selected.has(marker.id)) {
|
|
377
|
+
deselectMarker(mapMarker, map, showSelectionOrder);
|
|
378
|
+
} else {
|
|
379
|
+
selectMarker(mapMarker, map, showSelectionOrder);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
if (onSelectionChange && window[onSelectionChange]) {
|
|
383
|
+
const order = selectionOrder.get(map);
|
|
384
|
+
const orderedIds = Array.from(order.entries())
|
|
385
|
+
.sort((a, b) => a[1] - b[1])
|
|
386
|
+
.map(entry => entry[0]);
|
|
387
|
+
window[onSelectionChange](orderedIds);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
const settings = routeSettingsMap.get(map);
|
|
391
|
+
if (settings && settings.enabled) {
|
|
392
|
+
calculateRoute(map);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
if (originalCallback && window[originalCallback]) {
|
|
396
|
+
window[originalCallback](e);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
L.DomEvent.stopPropagation(e);
|
|
400
|
+
});
|
|
401
|
+
} else if (originalCallback) {
|
|
402
|
+
mapMarker.on('click', window[originalCallback]);
|
|
154
403
|
}
|
|
404
|
+
|
|
155
405
|
if (marker.popup) {
|
|
156
406
|
mapMarker.bindPopup(marker.popup);
|
|
157
407
|
} else if (marker.popupCallback) {
|
|
158
408
|
mapMarker.bindPopup(() => window[marker.popupCallback](mapMarker));
|
|
159
409
|
}
|
|
410
|
+
|
|
160
411
|
if (cluster) {
|
|
161
412
|
cluster.addLayer(mapMarker);
|
|
162
413
|
}
|
|
414
|
+
|
|
163
415
|
return mapMarker;
|
|
164
416
|
}
|
|
165
417
|
|
|
166
|
-
|
|
418
|
+
async function selectMarker(marker, map, showSelectionOrder) {
|
|
419
|
+
const selected = selectedMarkers.get(map);
|
|
420
|
+
const order = selectionOrder.get(map);
|
|
421
|
+
|
|
422
|
+
selected.add(marker.options.id);
|
|
423
|
+
|
|
424
|
+
const maxOrder = order.size > 0 ? Math.max(...order.values()) : 0;
|
|
425
|
+
const newOrder = maxOrder + 1;
|
|
426
|
+
order.set(marker.options.id, newOrder);
|
|
427
|
+
|
|
428
|
+
if (marker._selectedIcon) {
|
|
429
|
+
marker.setIcon(marker._selectedIcon);
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
const icon = marker.getElement();
|
|
433
|
+
if (icon) {
|
|
434
|
+
icon.classList.add('marker-selected');
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
if (showSelectionOrder) {
|
|
438
|
+
const newIcon = await createMarkerIcon(map, marker.options.icon.options.iconUrl, newOrder)
|
|
439
|
+
marker.setIcon(newIcon);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
function deselectMarker(marker, map, showSelectionOrder) {
|
|
444
|
+
const selected = selectedMarkers.get(map);
|
|
445
|
+
const order = selectionOrder.get(map);
|
|
446
|
+
const removedOrder = order.get(marker.options.id);
|
|
447
|
+
|
|
448
|
+
selected.delete(marker.options.id);
|
|
449
|
+
order.delete(marker.options.id);
|
|
450
|
+
order.forEach((value, key) => {
|
|
451
|
+
if (value > removedOrder) {
|
|
452
|
+
order.set(key, value - 1);
|
|
453
|
+
}
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
if (showSelectionOrder) {
|
|
457
|
+
updateMarkerOrderDisplay(map, marker, null, false);
|
|
458
|
+
} else if (marker._normalIcon) {
|
|
459
|
+
marker.setIcon(marker._normalIcon);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
const icon = marker.getElement();
|
|
463
|
+
if (icon) {
|
|
464
|
+
icon.classList.remove('marker-selected');
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
if (showSelectionOrder) {
|
|
468
|
+
const markers = markerInstances.get(map);
|
|
469
|
+
markers.forEach((markerInstance) => {
|
|
470
|
+
const newOrder = order.get(markerInstance.options.id);
|
|
471
|
+
if (newOrder) {
|
|
472
|
+
updateMarkerOrderDisplay(map, markerInstance, newOrder, true);
|
|
473
|
+
}
|
|
474
|
+
});
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
|
|
479
|
+
async function updateMarkerOrderDisplay(map, marker, orderNumber, isSelected, color = null) {
|
|
480
|
+
if (!marker._normalIcon || !marker._normalIcon.options) return;
|
|
481
|
+
|
|
482
|
+
const iconUrl = isSelected && marker._selectedIcon ?
|
|
483
|
+
marker._selectedIcon.options.iconUrl :
|
|
484
|
+
marker._normalIcon.options.iconUrl;
|
|
485
|
+
const newIcon = await createMarkerIcon(map, iconUrl, orderNumber, color);
|
|
486
|
+
|
|
487
|
+
marker.setIcon(newIcon);
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
async function createMarkerIcon(map, iconUrl, orderNumber, color = null) {
|
|
491
|
+
let inlineStyle = null;
|
|
492
|
+
const response = await fetch(iconUrl);
|
|
493
|
+
const svg = await response.text();
|
|
494
|
+
const settings = routeSettingsMap.get(map);
|
|
495
|
+
|
|
496
|
+
if ((settings && settings.enabled) || color) {
|
|
497
|
+
inlineStyle = `--marker-fill: ${color ?? settings.color};`;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
return L.divIcon({
|
|
501
|
+
className: 'marker-icon-wrapper',
|
|
502
|
+
html: `
|
|
503
|
+
<div class="marker-icon" style="${inlineStyle}">
|
|
504
|
+
${svg}
|
|
505
|
+
${orderNumber ? `<span class="selection-order-label">${orderNumber}</span>` : ''}
|
|
506
|
+
</div>
|
|
507
|
+
`,
|
|
508
|
+
iconSize: [43, 58],
|
|
509
|
+
iconAnchor: [21, 58]
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
function applyPreselectedMarkers(map, markersData, showSelectionOrder, onSelectionChange) {
|
|
514
|
+
const markerMap = markerInstances.get(map);
|
|
515
|
+
const order = selectionOrder.get(map);
|
|
516
|
+
const preselected = markersData
|
|
517
|
+
.filter(m => {
|
|
518
|
+
return m.selected === true;
|
|
519
|
+
})
|
|
520
|
+
.sort((a, b) => (a.selectionOrder || 0) - (b.selectionOrder || 0));
|
|
521
|
+
|
|
522
|
+
preselected.forEach((markerData, index) => {
|
|
523
|
+
const markerInstance = markerMap.get(markerData.id);
|
|
524
|
+
if (markerInstance) {
|
|
525
|
+
selectMarker(markerInstance, map, showSelectionOrder);
|
|
526
|
+
} else {
|
|
527
|
+
console.warn('Marker instance NOT found for ID:', markerData.id);
|
|
528
|
+
}
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
if (onSelectionChange && window[onSelectionChange] && order.size > 0) {
|
|
532
|
+
const orderedIds = Array.from(order.entries())
|
|
533
|
+
.sort((a, b) => a[1] - b[1])
|
|
534
|
+
.map(entry => entry[0]);
|
|
535
|
+
|
|
536
|
+
window[onSelectionChange](orderedIds);
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
const settings = routeSettingsMap.get(map);
|
|
540
|
+
if (settings && settings.enabled && order.size >= 2) {
|
|
541
|
+
calculateRoute(map);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
async function calculateRoute(map) {
|
|
546
|
+
const selectedSet = selectedMarkers.get(map);
|
|
547
|
+
const order = selectionOrder.get(map);
|
|
548
|
+
const markers = markersDataMap.get(map);
|
|
549
|
+
const routeSettings = routeSettingsMap.get(map);
|
|
550
|
+
const oldPolyline = routePolylines.get(map);
|
|
551
|
+
|
|
552
|
+
if (oldPolyline) {
|
|
553
|
+
map.removeLayer(oldPolyline);
|
|
554
|
+
routePolylines.set(map, null);
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
if (!routeSettings || !routeSettings.enabled) {
|
|
558
|
+
return;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
if (selectedSet && selectedSet.size > 0) {
|
|
562
|
+
const orderedIds = Array.from(order.entries())
|
|
563
|
+
.sort((a, b) => a[1] - b[1])
|
|
564
|
+
.map(entry => entry[0]);
|
|
565
|
+
const routeMarkers = orderedIds
|
|
566
|
+
.map(id => markers.find(m => m.id === id))
|
|
567
|
+
.filter(m => m !== undefined);
|
|
568
|
+
|
|
569
|
+
if (routeMarkers.length < 2) {
|
|
570
|
+
return;
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
const waypoints = routeMarkers.map(m => `${m.position['lon']},${m.position['lat']}`).join('|');
|
|
574
|
+
|
|
575
|
+
try {
|
|
576
|
+
const response = await fetch(
|
|
577
|
+
`https://api.mapy.cz/v1/routing/route?` + new URLSearchParams({
|
|
578
|
+
start: waypoints.split('|')[0],
|
|
579
|
+
end: waypoints.split('|')[waypoints.split('|').length - 1],
|
|
580
|
+
routeType: routeSettings.routeType,
|
|
581
|
+
waypoints: waypoints.split('|').slice(1, -1).join('|'),
|
|
582
|
+
apikey: siteKey,
|
|
583
|
+
})
|
|
584
|
+
);
|
|
585
|
+
|
|
586
|
+
const data = await response.json();
|
|
587
|
+
|
|
588
|
+
if (data.geometry?.geometry?.coordinates) {
|
|
589
|
+
const coords = data.geometry.geometry.coordinates.map(c => [c[1], c[0]]);
|
|
590
|
+
const polyline = L.polyline(coords, {
|
|
591
|
+
color: routeSettings.color,
|
|
592
|
+
weight: routeSettings.weight,
|
|
593
|
+
opacity: routeSettings.opacity
|
|
594
|
+
}).addTo(map);
|
|
595
|
+
|
|
596
|
+
routePolylines.set(map, polyline);
|
|
597
|
+
}
|
|
598
|
+
} catch (error) {
|
|
599
|
+
console.error('Error calculating route:', error);
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
function getSelectedMarkers(mapElement) {
|
|
605
|
+
const map = mapInstances.get(mapElement);
|
|
606
|
+
if (!map) return [];
|
|
607
|
+
|
|
608
|
+
const order = selectionOrder.get(map);
|
|
609
|
+
return Array.from(order.entries())
|
|
610
|
+
.sort((a, b) => a[1] - b[1])
|
|
611
|
+
.map(entry => entry[0]);
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
function clearSelection(mapElement) {
|
|
615
|
+
const map = mapInstances.get(mapElement);
|
|
616
|
+
if (!map) return;
|
|
617
|
+
|
|
618
|
+
const selected = selectedMarkers.get(map);
|
|
619
|
+
const order = selectionOrder.get(map);
|
|
620
|
+
const markers = markerInstances.get(map);
|
|
621
|
+
|
|
622
|
+
markers.forEach((markerInstance) => {
|
|
623
|
+
if (selected.has(markerInstance.options.id)) {
|
|
624
|
+
deselectMarker(markerInstance, map, true);
|
|
625
|
+
}
|
|
626
|
+
});
|
|
627
|
+
|
|
628
|
+
selected.clear();
|
|
629
|
+
order.clear();
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
function getOnSelectionChange(map) {
|
|
633
|
+
return onSelectionChangeMap.get(map);
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
function toggleMarker(mapElement, markerId, selected) {
|
|
637
|
+
const map = mapInstances.get(mapElement);
|
|
638
|
+
const markers = markerInstances.get(map);
|
|
639
|
+
const marker = markers?.get(markerId);
|
|
640
|
+
|
|
641
|
+
if (!marker) return;
|
|
642
|
+
|
|
643
|
+
const selectedSet = selectedMarkers.get(map);
|
|
644
|
+
const isSelected = selectedSet.has(markerId);
|
|
645
|
+
|
|
646
|
+
if (selected && !isSelected) {
|
|
647
|
+
selectMarker(marker, map, true);
|
|
648
|
+
} else if (!selected && isSelected) {
|
|
649
|
+
deselectMarker(marker, map, true);
|
|
650
|
+
} else {
|
|
651
|
+
return;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
const cluster = markerClusters.get(map);
|
|
655
|
+
if (cluster) {
|
|
656
|
+
cluster.refreshClusters(marker);
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
const settings = routeSettingsMap.get(map);
|
|
660
|
+
if (settings && settings.enabled) {
|
|
661
|
+
calculateRoute(map);
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
function setOrder(mapElement, markerId, orderNumber) {
|
|
666
|
+
let color = null;
|
|
667
|
+
const map = mapInstances.get(mapElement);
|
|
668
|
+
const settings = $(mapElement).data('adt-map')
|
|
669
|
+
const markers = markerInstances.get(map);
|
|
670
|
+
const marker = markers?.get(markerId);
|
|
671
|
+
|
|
672
|
+
if (settings && settings.route && settings.route.enabled) {
|
|
673
|
+
color = settings.route.color;
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
if (!marker) return;
|
|
677
|
+
|
|
678
|
+
updateMarkerOrderDisplay(mapElement, marker, orderNumber, true, color);
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
export default {
|
|
682
|
+
run,
|
|
683
|
+
getSelectedMarkers,
|
|
684
|
+
clearSelection,
|
|
685
|
+
toggleMarker,
|
|
686
|
+
setOrder,
|
|
687
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export const defaultRouteSettings = {
|
|
2
|
+
enabled: false,
|
|
3
|
+
color: 'blue',
|
|
4
|
+
weight: 4,
|
|
5
|
+
opacity: 0.7,
|
|
6
|
+
routeType: 'car_fast'
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* TODO - interface
|
|
11
|
+
*
|
|
12
|
+
* @typedef {Object} RouteSetting
|
|
13
|
+
* @property {boolean} [enabled]
|
|
14
|
+
* @property {string} [color]
|
|
15
|
+
* @property {number} [weight]
|
|
16
|
+
* @property {number} [opacity]
|
|
17
|
+
* @property {string} [routeType]
|
|
18
|
+
*/
|