adt-js-components 1.9.6 → 1.10.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 +2 -1
- package/src/Map/index.js +256 -221
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "adt-js-components",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.10.0",
|
|
4
4
|
"description": "JavaScript components for Nette framework",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
"select2": "^4.0.13",
|
|
15
15
|
"select2-bootstrap-5-theme": "^1.1.1",
|
|
16
16
|
"autonumeric": "^4.6.0",
|
|
17
|
+
"@here/flexpolyline": "^0.1.0",
|
|
17
18
|
"flatpickr": "^4.6.3",
|
|
18
19
|
"script-loader": "^0.7.2",
|
|
19
20
|
"timepicker": "^1.13.4",
|
package/src/Map/index.js
CHANGED
|
@@ -3,10 +3,12 @@ import 'leaflet/dist/leaflet.css';
|
|
|
3
3
|
import "leaflet.markercluster";
|
|
4
4
|
import "leaflet.markercluster/dist/MarkerCluster.css";
|
|
5
5
|
import "leaflet.markercluster/dist/MarkerCluster.Default.css";
|
|
6
|
+
import { decode as decodeFlexPolyline } from '@here/flexpolyline';
|
|
6
7
|
import {RouteSetting, defaultRouteSettings} from './route.types.js';
|
|
7
8
|
|
|
8
9
|
let siteKey;
|
|
9
10
|
let markerImg;
|
|
11
|
+
let mapProvider;
|
|
10
12
|
const svgCache = new Map();
|
|
11
13
|
const mapInstances = new WeakMap();
|
|
12
14
|
const selectedMarkers = new WeakMap();
|
|
@@ -25,9 +27,15 @@ const DEPOT_TYPE = {
|
|
|
25
27
|
END: 'depot-end'
|
|
26
28
|
};
|
|
27
29
|
|
|
30
|
+
const MAP_PROVIDER = {
|
|
31
|
+
MAPY_CZ: 'mapy.cz',
|
|
32
|
+
HERE: 'here',
|
|
33
|
+
};
|
|
34
|
+
|
|
28
35
|
async function run(options) {
|
|
29
36
|
siteKey = options.siteKey;
|
|
30
37
|
markerImg = options.markerImg;
|
|
38
|
+
mapProvider = options.mapProvider ?? MAP_PROVIDER.MAPY_CZ;
|
|
31
39
|
|
|
32
40
|
function applyEventHandlers(el) {
|
|
33
41
|
const {
|
|
@@ -47,11 +55,11 @@ async function run(options) {
|
|
|
47
55
|
onAfterRouteCalculation = null,
|
|
48
56
|
} = JSON.parse(el.dataset.adtMap);
|
|
49
57
|
|
|
50
|
-
/** @type {RouteSetting} */
|
|
51
58
|
const routeSettings = {
|
|
52
59
|
...defaultRouteSettings,
|
|
53
60
|
...route,
|
|
54
|
-
customMarkers
|
|
61
|
+
customMarkers,
|
|
62
|
+
mapProvider,
|
|
55
63
|
};
|
|
56
64
|
|
|
57
65
|
if (mapInstances.has(el)) {
|
|
@@ -71,28 +79,39 @@ async function run(options) {
|
|
|
71
79
|
onBeforeRouteCalculationMap.set(map, onBeforeRouteCalculation);
|
|
72
80
|
onAfterRouteCalculationMap.set(map, onAfterRouteCalculation);
|
|
73
81
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
82
|
+
if (mapProvider === MAP_PROVIDER.HERE) {
|
|
83
|
+
L.tileLayer(
|
|
84
|
+
`https://maps.hereapi.com/v3/base/mc/{z}/{x}/{y}/png8?style=explore.day&apiKey=${siteKey}`,
|
|
85
|
+
{
|
|
86
|
+
minZoom: 0,
|
|
87
|
+
maxZoom: 20,
|
|
88
|
+
attribution: '© <a href="https://www.here.com" target="_blank">HERE</a>',
|
|
89
|
+
}
|
|
90
|
+
).addTo(map);
|
|
91
|
+
} else {
|
|
92
|
+
L.tileLayer(
|
|
93
|
+
`https://api.mapy.cz/v1/maptiles/basic/256/{z}/{x}/{y}?apikey=${siteKey}`,
|
|
94
|
+
{
|
|
95
|
+
minZoom: 0,
|
|
96
|
+
maxZoom: 19,
|
|
97
|
+
attribution: '<a href="https://api.mapy.cz/copyright" target="_blank">© Seznam.cz a.s. a další</a>',
|
|
98
|
+
}
|
|
99
|
+
).addTo(map);
|
|
100
|
+
|
|
101
|
+
const LogoControl = L.Control.extend({
|
|
102
|
+
options: { position: 'bottomleft' },
|
|
103
|
+
onAdd: function () {
|
|
104
|
+
const container = L.DomUtil.create('div');
|
|
105
|
+
const link = L.DomUtil.create('a', '', container);
|
|
106
|
+
link.setAttribute('href', 'http://mapy.cz/');
|
|
107
|
+
link.setAttribute('target', '_blank');
|
|
108
|
+
link.innerHTML = '<img src="https://api.mapy.cz/img/api/logo.svg" />';
|
|
109
|
+
L.DomEvent.disableClickPropagation(link);
|
|
110
|
+
return container;
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
new LogoControl().addTo(map);
|
|
114
|
+
}
|
|
96
115
|
|
|
97
116
|
if (position.length) {
|
|
98
117
|
if (zoom) {
|
|
@@ -100,6 +119,13 @@ async function run(options) {
|
|
|
100
119
|
} else {
|
|
101
120
|
map.fitBounds([position]);
|
|
102
121
|
}
|
|
122
|
+
} else if (!markers.length) {
|
|
123
|
+
const depot = routeSettings.startPoint ?? routeSettings.endPoint;
|
|
124
|
+
if (depot) {
|
|
125
|
+
map.setView([depot.lat, depot.lon], zoom ?? 12);
|
|
126
|
+
} else {
|
|
127
|
+
map.setView([50.0755, 14.4378], 7);
|
|
128
|
+
}
|
|
103
129
|
}
|
|
104
130
|
|
|
105
131
|
map.scrollWheelZoom.disable();
|
|
@@ -109,7 +135,6 @@ async function run(options) {
|
|
|
109
135
|
map.dragging.disable();
|
|
110
136
|
}
|
|
111
137
|
|
|
112
|
-
|
|
113
138
|
if (selectable) {
|
|
114
139
|
enableRectangleSelection(map, onSelectionChange, showSelectionOrder);
|
|
115
140
|
}
|
|
@@ -142,10 +167,7 @@ async function run(options) {
|
|
|
142
167
|
if (markers.length) {
|
|
143
168
|
addMarkers(map, markers, markerOptions, customMarkerOptions, position, selectable, onSelectionChange, showSelectionOrder, markerInfoCallback);
|
|
144
169
|
} else if (showDefaultMarker) {
|
|
145
|
-
createMarker({
|
|
146
|
-
id: 0,
|
|
147
|
-
position: position
|
|
148
|
-
}, markerOptions, customMarkerOptions, null, selectable, onSelectionChange, map, showSelectionOrder, markerInfoCallback).addTo(map);
|
|
170
|
+
createMarker({ id: 0, position }, markerOptions, customMarkerOptions, null, selectable, onSelectionChange, map, showSelectionOrder, markerInfoCallback).addTo(map);
|
|
149
171
|
}
|
|
150
172
|
};
|
|
151
173
|
} else {
|
|
@@ -154,10 +176,7 @@ async function run(options) {
|
|
|
154
176
|
if (markers.length) {
|
|
155
177
|
addMarkers(map, markers, markerOptions, customMarkerOptions, position, selectable, onSelectionChange, showSelectionOrder, markerInfoCallback);
|
|
156
178
|
} else if (showDefaultMarker) {
|
|
157
|
-
createMarker({
|
|
158
|
-
id: 0,
|
|
159
|
-
position: position
|
|
160
|
-
}, markerOptions, customMarkerOptions, null, selectable, onSelectionChange, map, showSelectionOrder, markerInfoCallback).addTo(map);
|
|
179
|
+
createMarker({ id: 0, position }, markerOptions, customMarkerOptions, null, selectable, onSelectionChange, map, showSelectionOrder, markerInfoCallback).addTo(map);
|
|
161
180
|
}
|
|
162
181
|
}
|
|
163
182
|
};
|
|
@@ -183,14 +202,10 @@ async function run(options) {
|
|
|
183
202
|
if (node.hasAttribute("data-adt-map")) {
|
|
184
203
|
applyEventHandlers(node);
|
|
185
204
|
}
|
|
186
|
-
|
|
187
|
-
node.querySelectorAll?.('[data-adt-map]').forEach(el => {
|
|
188
|
-
applyEventHandlers(el);
|
|
189
|
-
});
|
|
205
|
+
node.querySelectorAll?.('[data-adt-map]').forEach(el => applyEventHandlers(el));
|
|
190
206
|
}
|
|
191
207
|
});
|
|
192
208
|
}
|
|
193
|
-
|
|
194
209
|
if (mutation.type === "attributes" && mutation.attributeName === "data-adt-map") {
|
|
195
210
|
applyEventHandlers(mutation.target);
|
|
196
211
|
}
|
|
@@ -204,9 +219,7 @@ async function run(options) {
|
|
|
204
219
|
attributeFilter: ["data-adt-map"]
|
|
205
220
|
});
|
|
206
221
|
|
|
207
|
-
document.querySelectorAll('[data-adt-map]').forEach(
|
|
208
|
-
applyEventHandlers(el);
|
|
209
|
-
});
|
|
222
|
+
document.querySelectorAll('[data-adt-map]').forEach(el => applyEventHandlers(el));
|
|
210
223
|
}
|
|
211
224
|
|
|
212
225
|
function enableRectangleSelection(map, onSelectionChange, showSelectionOrder) {
|
|
@@ -218,13 +231,7 @@ function enableRectangleSelection(map, onSelectionChange, showSelectionOrder) {
|
|
|
218
231
|
if (e.originalEvent.ctrlKey && e.originalEvent.shiftKey) {
|
|
219
232
|
isDrawing = true;
|
|
220
233
|
startPoint = e.latlng;
|
|
221
|
-
|
|
222
|
-
rectangle = L.rectangle([startPoint, startPoint], {
|
|
223
|
-
color: '#3388ff',
|
|
224
|
-
weight: 2,
|
|
225
|
-
fillOpacity: 0.1
|
|
226
|
-
}).addTo(map);
|
|
227
|
-
|
|
234
|
+
rectangle = L.rectangle([startPoint, startPoint], { color: '#3388ff', weight: 2, fillOpacity: 0.1 }).addTo(map);
|
|
228
235
|
map.dragging.disable();
|
|
229
236
|
e.originalEvent.preventDefault();
|
|
230
237
|
}
|
|
@@ -246,10 +253,8 @@ function enableRectangleSelection(map, onSelectionChange, showSelectionOrder) {
|
|
|
246
253
|
const markerMap = markerInstances.get(map);
|
|
247
254
|
const selectedInArea = [];
|
|
248
255
|
|
|
249
|
-
markerMap.forEach((markerInstance
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
if (bounds.contains(latLng)) {
|
|
256
|
+
markerMap.forEach((markerInstance) => {
|
|
257
|
+
if (bounds.contains(markerInstance.getLatLng())) {
|
|
253
258
|
selectedInArea.push(markerInstance);
|
|
254
259
|
}
|
|
255
260
|
});
|
|
@@ -268,9 +273,7 @@ function enableRectangleSelection(map, onSelectionChange, showSelectionOrder) {
|
|
|
268
273
|
|
|
269
274
|
if (onSelectionChange && window[onSelectionChange]) {
|
|
270
275
|
const order = selectionOrder.get(map);
|
|
271
|
-
const orderedIds = Array.from(order.entries())
|
|
272
|
-
.sort((a, b) => a[1] - b[1])
|
|
273
|
-
.map(entry => entry[0]);
|
|
276
|
+
const orderedIds = Array.from(order.entries()).sort((a, b) => a[1] - b[1]).map(e => e[0]);
|
|
274
277
|
window[onSelectionChange](orderedIds);
|
|
275
278
|
}
|
|
276
279
|
|
|
@@ -290,21 +293,12 @@ function addMarkers(map, markers, options, selectedOptions, position, selectable
|
|
|
290
293
|
spiderfyOnMaxZoom: true,
|
|
291
294
|
showCoverageOnHover: false,
|
|
292
295
|
zoomToBoundsOnClick: true,
|
|
293
|
-
|
|
294
296
|
iconCreateFunction: function (cluster) {
|
|
295
297
|
const childCount = cluster.getChildCount();
|
|
296
|
-
|
|
297
|
-
if (childCount < 10) {
|
|
298
|
-
c += 'small';
|
|
299
|
-
} else if (childCount < 100) {
|
|
300
|
-
c += 'medium';
|
|
301
|
-
} else {
|
|
302
|
-
c += 'large';
|
|
303
|
-
}
|
|
304
|
-
|
|
298
|
+
const c = childCount < 10 ? 'small' : childCount < 100 ? 'medium' : 'large';
|
|
305
299
|
return new L.DivIcon({
|
|
306
300
|
html: '<div><span>' + childCount + '</span></div>',
|
|
307
|
-
className: 'marker-cluster' + c,
|
|
301
|
+
className: 'marker-cluster marker-cluster-' + c,
|
|
308
302
|
iconSize: new L.Point(40, 40)
|
|
309
303
|
});
|
|
310
304
|
}
|
|
@@ -326,7 +320,6 @@ function addMarkers(map, markers, options, selectedOptions, position, selectable
|
|
|
326
320
|
iconAnchor: [markerImage.width / 2, markerImage.height]
|
|
327
321
|
});
|
|
328
322
|
createMarker(marker, markerOptions, selectedOptions, cluster, selectable, onSelectionChange, map, showSelectionOrder, markerInfoCallback);
|
|
329
|
-
|
|
330
323
|
loadedCount++;
|
|
331
324
|
if (loadedCount === totalMarkers) {
|
|
332
325
|
checkAndApplyPreselection(map, markers, showSelectionOrder, onSelectionChange, selectable);
|
|
@@ -364,11 +357,6 @@ function createMarker(marker, options, selectedOptions, cluster = null, selectab
|
|
|
364
357
|
mapMarker._selectedIcon = selectedOptions.icon;
|
|
365
358
|
mapMarker._markerData = marker;
|
|
366
359
|
|
|
367
|
-
const markerElement = mapMarker.getElement();
|
|
368
|
-
if (markerElement && markerElement.parentElement) {
|
|
369
|
-
markerElement.parentElement.style.pointerEvents = 'visible';
|
|
370
|
-
}
|
|
371
|
-
|
|
372
360
|
if (map) {
|
|
373
361
|
const markers = markerInstances.get(map);
|
|
374
362
|
markers.set(marker.id, mapMarker);
|
|
@@ -377,7 +365,6 @@ function createMarker(marker, options, selectedOptions, cluster = null, selectab
|
|
|
377
365
|
const el = mapMarker.getElement();
|
|
378
366
|
if (el) {
|
|
379
367
|
el.style.cursor = 'pointer';
|
|
380
|
-
|
|
381
368
|
const parent = el.parentElement;
|
|
382
369
|
if (parent) {
|
|
383
370
|
parent.style.pointerEvents = 'all';
|
|
@@ -390,14 +377,14 @@ function createMarker(marker, options, selectedOptions, cluster = null, selectab
|
|
|
390
377
|
|
|
391
378
|
if (selectable && map) {
|
|
392
379
|
mapMarker.on('click', function (e) {
|
|
393
|
-
if (e.originalEvent.shiftKey && markerInfoCallback && window[markerInfoCallback]) {
|
|
380
|
+
if (e.originalEvent.shiftKey && !e.originalEvent.ctrlKey && markerInfoCallback && window[markerInfoCallback]) {
|
|
394
381
|
window[markerInfoCallback](marker);
|
|
395
382
|
L.DomEvent.stopPropagation(e);
|
|
383
|
+
L.DomEvent.preventDefault(e);
|
|
396
384
|
return;
|
|
397
385
|
}
|
|
398
386
|
|
|
399
387
|
const selected = selectedMarkers.get(map);
|
|
400
|
-
|
|
401
388
|
if (selected.has(marker.id)) {
|
|
402
389
|
deselectMarker(mapMarker, map, showSelectionOrder);
|
|
403
390
|
} else {
|
|
@@ -406,9 +393,7 @@ function createMarker(marker, options, selectedOptions, cluster = null, selectab
|
|
|
406
393
|
|
|
407
394
|
if (onSelectionChange && window[onSelectionChange]) {
|
|
408
395
|
const order = selectionOrder.get(map);
|
|
409
|
-
const orderedIds = Array.from(order.entries())
|
|
410
|
-
.sort((a, b) => a[1] - b[1])
|
|
411
|
-
.map(entry => entry[0]);
|
|
396
|
+
const orderedIds = Array.from(order.entries()).sort((a, b) => a[1] - b[1]).map(e => e[0]);
|
|
412
397
|
window[onSelectionChange](orderedIds);
|
|
413
398
|
}
|
|
414
399
|
|
|
@@ -416,11 +401,9 @@ function createMarker(marker, options, selectedOptions, cluster = null, selectab
|
|
|
416
401
|
if (settings && settings.enabled) {
|
|
417
402
|
calculateRoute(map);
|
|
418
403
|
}
|
|
419
|
-
|
|
420
404
|
if (originalCallback && window[originalCallback]) {
|
|
421
405
|
window[originalCallback](e);
|
|
422
406
|
}
|
|
423
|
-
|
|
424
407
|
L.DomEvent.stopPropagation(e);
|
|
425
408
|
});
|
|
426
409
|
} else if (originalCallback) {
|
|
@@ -443,9 +426,7 @@ function createMarker(marker, options, selectedOptions, cluster = null, selectab
|
|
|
443
426
|
async function selectMarker(marker, map, showSelectionOrder) {
|
|
444
427
|
const selected = selectedMarkers.get(map);
|
|
445
428
|
const order = selectionOrder.get(map);
|
|
446
|
-
|
|
447
429
|
selected.add(marker.options.id);
|
|
448
|
-
|
|
449
430
|
const maxOrder = order.size > 0 ? Math.max(...order.values()) : 0;
|
|
450
431
|
const newOrder = maxOrder + 1;
|
|
451
432
|
order.set(marker.options.id, newOrder);
|
|
@@ -453,14 +434,13 @@ async function selectMarker(marker, map, showSelectionOrder) {
|
|
|
453
434
|
if (marker._selectedIcon) {
|
|
454
435
|
marker.setIcon(marker._selectedIcon);
|
|
455
436
|
}
|
|
456
|
-
|
|
457
437
|
const icon = marker.getElement();
|
|
458
438
|
if (icon) {
|
|
459
439
|
icon.classList.add('marker-selected');
|
|
460
440
|
}
|
|
461
441
|
|
|
462
442
|
if (showSelectionOrder) {
|
|
463
|
-
const newIcon = await createMarkerIcon(map, marker.options.icon.options.iconUrl, newOrder)
|
|
443
|
+
const newIcon = await createMarkerIcon(map, marker.options.icon.options.iconUrl, newOrder);
|
|
464
444
|
marker.setIcon(newIcon);
|
|
465
445
|
}
|
|
466
446
|
}
|
|
@@ -472,11 +452,7 @@ function deselectMarker(marker, map, showSelectionOrder) {
|
|
|
472
452
|
|
|
473
453
|
selected.delete(marker.options.id);
|
|
474
454
|
order.delete(marker.options.id);
|
|
475
|
-
order.forEach((value, key) => {
|
|
476
|
-
if (value > removedOrder) {
|
|
477
|
-
order.set(key, value - 1);
|
|
478
|
-
}
|
|
479
|
-
});
|
|
455
|
+
order.forEach((value, key) => { if (value > removedOrder) order.set(key, value - 1); });
|
|
480
456
|
|
|
481
457
|
if (showSelectionOrder) {
|
|
482
458
|
updateMarkerOrderDisplay(map, marker, null, false);
|
|
@@ -500,22 +476,16 @@ function deselectMarker(marker, map, showSelectionOrder) {
|
|
|
500
476
|
}
|
|
501
477
|
}
|
|
502
478
|
|
|
503
|
-
|
|
504
479
|
async function updateMarkerOrderDisplay(map, marker, orderNumber, isSelected, color = null) {
|
|
505
480
|
if (!marker._normalIcon || !marker._normalIcon.options) return;
|
|
506
|
-
|
|
507
|
-
const iconUrl = isSelected && marker._selectedIcon ?
|
|
508
|
-
marker._selectedIcon.options.iconUrl :
|
|
509
|
-
marker._normalIcon.options.iconUrl;
|
|
481
|
+
const iconUrl = isSelected && marker._selectedIcon ? marker._selectedIcon.options.iconUrl : marker._normalIcon.options.iconUrl;
|
|
510
482
|
const newIcon = await createMarkerIcon(map, iconUrl, orderNumber, color);
|
|
511
|
-
|
|
512
483
|
marker.setIcon(newIcon);
|
|
513
484
|
}
|
|
514
485
|
|
|
515
486
|
async function createMarkerIcon(map, iconUrl, orderNumber, color = null) {
|
|
516
487
|
let inlineStyle = null;
|
|
517
488
|
const settings = routeSettingsMap.get(map);
|
|
518
|
-
|
|
519
489
|
if ((settings && settings.enabled) || color) {
|
|
520
490
|
inlineStyle = `--marker-fill: ${color ?? settings.color};`;
|
|
521
491
|
}
|
|
@@ -546,12 +516,10 @@ function applyPreselectedMarkers(map, markersData, showSelectionOrder, onSelecti
|
|
|
546
516
|
const markerMap = markerInstances.get(map);
|
|
547
517
|
const order = selectionOrder.get(map);
|
|
548
518
|
const preselected = markersData
|
|
549
|
-
.filter(m =>
|
|
550
|
-
return m.selected === true;
|
|
551
|
-
})
|
|
519
|
+
.filter(m => m.selected === true)
|
|
552
520
|
.sort((a, b) => (a.selectionOrder || 0) - (b.selectionOrder || 0));
|
|
553
521
|
|
|
554
|
-
preselected.forEach((markerData
|
|
522
|
+
preselected.forEach((markerData) => {
|
|
555
523
|
const markerInstance = markerMap.get(markerData.id);
|
|
556
524
|
if (markerInstance) {
|
|
557
525
|
selectMarker(markerInstance, map, showSelectionOrder);
|
|
@@ -561,10 +529,7 @@ function applyPreselectedMarkers(map, markersData, showSelectionOrder, onSelecti
|
|
|
561
529
|
});
|
|
562
530
|
|
|
563
531
|
if (onSelectionChange && window[onSelectionChange] && order.size > 0) {
|
|
564
|
-
const orderedIds = Array.from(order.entries())
|
|
565
|
-
.sort((a, b) => a[1] - b[1])
|
|
566
|
-
.map(entry => entry[0]);
|
|
567
|
-
|
|
532
|
+
const orderedIds = Array.from(order.entries()).sort((a, b) => a[1] - b[1]).map(e => e[0]);
|
|
568
533
|
window[onSelectionChange](orderedIds);
|
|
569
534
|
}
|
|
570
535
|
|
|
@@ -586,24 +551,22 @@ async function calculateRoute(map) {
|
|
|
586
551
|
routePolylines.set(map, null);
|
|
587
552
|
}
|
|
588
553
|
|
|
589
|
-
if (!routeSettings || !routeSettings.enabled)
|
|
590
|
-
return;
|
|
591
|
-
}
|
|
554
|
+
if (!routeSettings || !routeSettings.enabled) return;
|
|
592
555
|
|
|
593
556
|
const hasCustomStart = routeSettings.startPoint !== null && routeSettings.startPoint !== undefined;
|
|
594
557
|
const hasCustomEnd = routeSettings.endPoint !== null && routeSettings.endPoint !== undefined;
|
|
595
558
|
|
|
596
|
-
if (hasCustomStart)
|
|
597
|
-
|
|
559
|
+
if (hasCustomStart) {
|
|
560
|
+
addDepotMarker(map, routeSettings.startPoint, DEPOT_TYPE.START);
|
|
561
|
+
}
|
|
562
|
+
if (hasCustomEnd) {
|
|
563
|
+
addDepotMarker(map, routeSettings.endPoint, DEPOT_TYPE.END);
|
|
564
|
+
}
|
|
598
565
|
|
|
599
566
|
if (!selectedSet || selectedSet.size === 0) return;
|
|
600
567
|
|
|
601
|
-
const orderedIds = Array.from(order.entries())
|
|
602
|
-
|
|
603
|
-
.map(entry => entry[0]);
|
|
604
|
-
const routeMarkers = orderedIds
|
|
605
|
-
.map(id => markers.find(m => m.id === id))
|
|
606
|
-
.filter(m => m !== undefined);
|
|
568
|
+
const orderedIds = Array.from(order.entries()).sort((a, b) => a[1] - b[1]).map(e => e[0]);
|
|
569
|
+
const routeMarkers = orderedIds.map(id => markers.find(m => m.id === id)).filter(m => m !== undefined);
|
|
607
570
|
|
|
608
571
|
if (routeMarkers.length < 2) return;
|
|
609
572
|
|
|
@@ -612,86 +575,25 @@ async function calculateRoute(map) {
|
|
|
612
575
|
window[beforeCallback]();
|
|
613
576
|
}
|
|
614
577
|
|
|
615
|
-
|
|
616
|
-
|
|
578
|
+
const isHere = routeSettings.mapProvider === MAP_PROVIDER.HERE;
|
|
579
|
+
const startPoint = hasCustomStart ? routeSettings.startPoint : routeMarkers[0].position;
|
|
580
|
+
const endPoint = hasCustomEnd ? routeSettings.endPoint : routeMarkers[routeMarkers.length - 1].position;
|
|
617
581
|
|
|
618
|
-
const WAYPOINTS_LIMIT = 15;
|
|
619
582
|
const allCoords = [];
|
|
620
583
|
const allParts = [];
|
|
621
|
-
let totalDuration = 0;
|
|
622
|
-
let totalLength = 0;
|
|
623
584
|
|
|
624
585
|
try {
|
|
625
|
-
if (
|
|
626
|
-
|
|
627
|
-
start: `${startPoint.lon},${startPoint.lat}`,
|
|
628
|
-
end: `${endPoint.lon},${endPoint.lat}`,
|
|
629
|
-
routeType: routeSettings.routeType,
|
|
630
|
-
apikey: siteKey
|
|
631
|
-
});
|
|
632
|
-
routeMarkers.forEach(m => params.append('waypoints', `${m.position.lon},${m.position.lat}`));
|
|
633
|
-
|
|
634
|
-
const response = await fetch(`https://api.mapy.cz/v1/routing/route?${params.toString()}`);
|
|
635
|
-
const data = await response.json();
|
|
636
|
-
|
|
637
|
-
if (data.geometry?.geometry?.coordinates) {
|
|
638
|
-
allCoords.push(...data.geometry.geometry.coordinates.map(c => [c[1], c[0]]));
|
|
639
|
-
}
|
|
640
|
-
if (data.parts) {
|
|
641
|
-
allParts.push(...data.parts);
|
|
642
|
-
}
|
|
643
|
-
if (data.duration) {
|
|
644
|
-
totalDuration += data.duration;
|
|
645
|
-
}
|
|
646
|
-
if (data.length) {
|
|
647
|
-
totalLength += data.length;
|
|
648
|
-
}
|
|
586
|
+
if (isHere) {
|
|
587
|
+
await calculateRouteHere({ routeMarkers, startPoint, endPoint, routeSettings, allCoords, allParts });
|
|
649
588
|
} else {
|
|
650
|
-
|
|
651
|
-
for (let i = 0; i < routeMarkers.length; i += WAYPOINTS_LIMIT) {
|
|
652
|
-
chunks.push(routeMarkers.slice(i, i + WAYPOINTS_LIMIT));
|
|
653
|
-
}
|
|
654
|
-
|
|
655
|
-
for (let i = 0; i < chunks.length; i++) {
|
|
656
|
-
const chunk = chunks[i];
|
|
657
|
-
const isFirstChunk = i === 0;
|
|
658
|
-
const isLastChunk = i === chunks.length - 1;
|
|
659
|
-
|
|
660
|
-
const chunkStart = isFirstChunk ? startPoint : chunks[i - 1][chunks[i - 1].length - 1].position;
|
|
661
|
-
const chunkEnd = isLastChunk ? endPoint : chunk[chunk.length - 1].position;
|
|
662
|
-
|
|
663
|
-
const params = new URLSearchParams({
|
|
664
|
-
start: `${chunkStart.lon},${chunkStart.lat}`,
|
|
665
|
-
end: `${chunkEnd.lon},${chunkEnd.lat}`,
|
|
666
|
-
routeType: routeSettings.routeType,
|
|
667
|
-
apikey: siteKey
|
|
668
|
-
});
|
|
669
|
-
|
|
670
|
-
const markersToAdd = isFirstChunk ? chunk : chunk.slice(1);
|
|
671
|
-
markersToAdd.forEach(m => params.append('waypoints', `${m.position.lon},${m.position.lat}`));
|
|
672
|
-
|
|
673
|
-
const response = await fetch(`https://api.mapy.cz/v1/routing/route?${params.toString()}`);
|
|
674
|
-
const data = await response.json();
|
|
675
|
-
|
|
676
|
-
if (data.geometry?.geometry?.coordinates) {
|
|
677
|
-
allCoords.push(...data.geometry.geometry.coordinates.map(c => [c[1], c[0]]));
|
|
678
|
-
}
|
|
679
|
-
if (data.parts) {
|
|
680
|
-
allParts.push(...data.parts);
|
|
681
|
-
}
|
|
682
|
-
if (data.duration) {
|
|
683
|
-
totalDuration += data.duration;
|
|
684
|
-
}
|
|
685
|
-
if (data.length) {
|
|
686
|
-
totalLength += data.length;
|
|
687
|
-
}
|
|
688
|
-
}
|
|
589
|
+
await calculateRouteMapy({ routeMarkers, startPoint, endPoint, routeSettings, allCoords, allParts });
|
|
689
590
|
}
|
|
690
591
|
} catch (error) {
|
|
691
592
|
console.error('Error calculating route:', error);
|
|
692
593
|
const afterCallback = onAfterRouteCalculationMap.get(map);
|
|
693
|
-
if (afterCallback && window[afterCallback])
|
|
694
|
-
|
|
594
|
+
if (afterCallback && window[afterCallback]) {
|
|
595
|
+
window[afterCallback]({}, 0, 0);
|
|
596
|
+
}
|
|
695
597
|
return;
|
|
696
598
|
}
|
|
697
599
|
|
|
@@ -704,20 +606,103 @@ async function calculateRoute(map) {
|
|
|
704
606
|
routePolylines.set(map, polyline);
|
|
705
607
|
}
|
|
706
608
|
|
|
707
|
-
|
|
609
|
+
const totalDuration = allParts.reduce((s, p) => s + (p.duration || 0), 0);
|
|
610
|
+
const totalLength = allParts.reduce((s, p) => s + (p.length || 0), 0);
|
|
611
|
+
|
|
708
612
|
const routeParts = {};
|
|
709
613
|
allParts.forEach((part, index) => {
|
|
710
614
|
if (index < orderedIds.length) {
|
|
711
|
-
|
|
712
|
-
routeParts[markerId] = {
|
|
713
|
-
duration: part.duration,
|
|
714
|
-
length: part.length,
|
|
715
|
-
};
|
|
615
|
+
routeParts[orderedIds[index]] = { duration: part.duration, length: part.length };
|
|
716
616
|
}
|
|
717
617
|
});
|
|
718
618
|
|
|
719
619
|
const afterCallback = onAfterRouteCalculationMap.get(map);
|
|
720
|
-
if (afterCallback && window[afterCallback])
|
|
620
|
+
if (afterCallback && window[afterCallback]) {
|
|
621
|
+
window[afterCallback](routeParts, totalLength, totalDuration);
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
async function calculateRouteMapy({ routeMarkers, startPoint, endPoint, routeSettings, allCoords, allParts }) {
|
|
626
|
+
const WAYPOINTS_LIMIT = 15;
|
|
627
|
+
|
|
628
|
+
const chunks = [];
|
|
629
|
+
for (let i = 0; i < routeMarkers.length; i += WAYPOINTS_LIMIT) chunks.push(routeMarkers.slice(i, i + WAYPOINTS_LIMIT));
|
|
630
|
+
|
|
631
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
632
|
+
const chunk = chunks[i];
|
|
633
|
+
const isFirstChunk = i === 0;
|
|
634
|
+
const isLastChunk = i === chunks.length - 1;
|
|
635
|
+
const chunkStart = isFirstChunk ? startPoint : chunks[i - 1][chunks[i - 1].length - 1].position;
|
|
636
|
+
const chunkEnd = isLastChunk ? endPoint : chunk[chunk.length - 1].position;
|
|
637
|
+
|
|
638
|
+
const params = new URLSearchParams({
|
|
639
|
+
start: `${chunkStart.lon},${chunkStart.lat}`,
|
|
640
|
+
end: `${chunkEnd.lon},${chunkEnd.lat}`,
|
|
641
|
+
routeType: routeSettings.routeType,
|
|
642
|
+
apikey: siteKey
|
|
643
|
+
});
|
|
644
|
+
|
|
645
|
+
const markersToAdd = isFirstChunk ? chunk : chunk.slice(1);
|
|
646
|
+
markersToAdd.forEach(m => params.append('waypoints', `${m.position.lon},${m.position.lat}`));
|
|
647
|
+
|
|
648
|
+
const response = await fetch(`https://api.mapy.cz/v1/routing/route?${params.toString()}`);
|
|
649
|
+
const data = await response.json();
|
|
650
|
+
|
|
651
|
+
if (data.geometry?.geometry?.coordinates) {
|
|
652
|
+
allCoords.push(...data.geometry.geometry.coordinates.map(c => [c[1], c[0]]));
|
|
653
|
+
}
|
|
654
|
+
if (data.parts) {
|
|
655
|
+
allParts.push(...data.parts);
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
async function calculateRouteHere({ routeMarkers, startPoint, endPoint, routeSettings, allCoords, allParts }) {
|
|
661
|
+
const WAYPOINTS_LIMIT = 98;
|
|
662
|
+
|
|
663
|
+
const chunks = [];
|
|
664
|
+
for (let i = 0; i < routeMarkers.length; i += WAYPOINTS_LIMIT) chunks.push(routeMarkers.slice(i, i + WAYPOINTS_LIMIT));
|
|
665
|
+
|
|
666
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
667
|
+
const chunk = chunks[i];
|
|
668
|
+
const isFirstChunk = i === 0;
|
|
669
|
+
const isLastChunk = i === chunks.length - 1;
|
|
670
|
+
const chunkStart = isFirstChunk ? startPoint : chunks[i - 1][chunks[i - 1].length - 1].position;
|
|
671
|
+
const chunkEnd = isLastChunk ? endPoint : chunk[chunk.length - 1].position;
|
|
672
|
+
|
|
673
|
+
const params = new URLSearchParams({
|
|
674
|
+
origin: `${chunkStart.lat},${chunkStart.lon}`,
|
|
675
|
+
destination: `${chunkEnd.lat},${chunkEnd.lon}`,
|
|
676
|
+
transportMode: routeSettings.routeType,
|
|
677
|
+
return: 'polyline,summary',
|
|
678
|
+
apiKey: siteKey,
|
|
679
|
+
});
|
|
680
|
+
|
|
681
|
+
if (routeSettings.departureTime) {
|
|
682
|
+
params.set('departureTime', routeSettings.departureTime);
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
const viaMarkers = isFirstChunk ? chunk : chunk.slice(1);
|
|
686
|
+
viaMarkers.forEach(m => params.append('via', `${m.position.lat},${m.position.lon}`));
|
|
687
|
+
|
|
688
|
+
const response = await fetch(`https://router.hereapi.com/v8/routes?${params.toString()}`);
|
|
689
|
+
const data = await response.json();
|
|
690
|
+
|
|
691
|
+
if (!data.routes || data.routes.length === 0) {
|
|
692
|
+
console.warn('HERE routing: žádná trasa nenalezena', data);
|
|
693
|
+
continue;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
for (const section of data.routes[0].sections) {
|
|
697
|
+
if (section.polyline) {
|
|
698
|
+
const decoded = decodeFlexPolyline(section.polyline);
|
|
699
|
+
allCoords.push(...decoded.polyline);
|
|
700
|
+
}
|
|
701
|
+
if (section.summary) {
|
|
702
|
+
allParts.push({ duration: section.summary.duration, length: section.summary.length });
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
}
|
|
721
706
|
}
|
|
722
707
|
|
|
723
708
|
function addDepotMarker(map, position, depotType) {
|
|
@@ -728,53 +713,35 @@ function addDepotMarker(map, position, depotType) {
|
|
|
728
713
|
const img = new Image();
|
|
729
714
|
img.src = iconUrl;
|
|
730
715
|
img.onload = function () {
|
|
731
|
-
const icon = L.icon({
|
|
732
|
-
|
|
733
|
-
iconSize: [img.width, img.height],
|
|
734
|
-
iconAnchor: [img.width / 2, img.height]
|
|
735
|
-
});
|
|
736
|
-
|
|
737
|
-
L.marker(position, {icon: icon}).addTo(map);
|
|
716
|
+
const icon = L.icon({ iconUrl, iconSize: [img.width, img.height], iconAnchor: [img.width / 2, img.height] });
|
|
717
|
+
L.marker(position, { icon }).addTo(map);
|
|
738
718
|
};
|
|
739
719
|
}
|
|
740
720
|
|
|
741
721
|
function getSelectedMarkers(mapElement) {
|
|
742
722
|
const map = mapInstances.get(mapElement);
|
|
743
723
|
if (!map) return [];
|
|
744
|
-
|
|
745
724
|
const order = selectionOrder.get(map);
|
|
746
|
-
return Array.from(order.entries())
|
|
747
|
-
.sort((a, b) => a[1] - b[1])
|
|
748
|
-
.map(entry => entry[0]);
|
|
725
|
+
return Array.from(order.entries()).sort((a, b) => a[1] - b[1]).map(e => e[0]);
|
|
749
726
|
}
|
|
750
727
|
|
|
751
728
|
function clearSelection(mapElement) {
|
|
752
729
|
const map = mapInstances.get(mapElement);
|
|
753
730
|
if (!map) return;
|
|
754
|
-
|
|
755
731
|
const selected = selectedMarkers.get(map);
|
|
756
732
|
const order = selectionOrder.get(map);
|
|
757
733
|
const markers = markerInstances.get(map);
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
deselectMarker(markerInstance, map, true);
|
|
762
|
-
}
|
|
763
|
-
});
|
|
764
|
-
|
|
734
|
+
markers.forEach((markerInstance) => { if (selected.has(markerInstance.options.id)) {
|
|
735
|
+
deselectMarker(markerInstance, map, true);
|
|
736
|
+
} });
|
|
765
737
|
selected.clear();
|
|
766
738
|
order.clear();
|
|
767
739
|
}
|
|
768
740
|
|
|
769
|
-
function getOnSelectionChange(map) {
|
|
770
|
-
return onSelectionChangeMap.get(map);
|
|
771
|
-
}
|
|
772
|
-
|
|
773
741
|
function toggleMarker(mapElement, markerId, selected) {
|
|
774
742
|
const map = mapInstances.get(mapElement);
|
|
775
743
|
const markers = markerInstances.get(map);
|
|
776
744
|
const marker = markers?.get(markerId);
|
|
777
|
-
|
|
778
745
|
if (!marker) return;
|
|
779
746
|
|
|
780
747
|
const selectedSet = selectedMarkers.get(map);
|
|
@@ -802,16 +769,13 @@ function toggleMarker(mapElement, markerId, selected) {
|
|
|
802
769
|
function setOrder(mapElement, markerId, orderNumber) {
|
|
803
770
|
let color = null;
|
|
804
771
|
const map = mapInstances.get(mapElement);
|
|
805
|
-
const settings = $(mapElement).data('adt-map')
|
|
772
|
+
const settings = $(mapElement).data('adt-map');
|
|
806
773
|
const markers = markerInstances.get(map);
|
|
807
774
|
const marker = markers?.get(markerId);
|
|
808
|
-
|
|
809
775
|
if (settings && settings.route && settings.route.enabled) {
|
|
810
776
|
color = settings.route.color;
|
|
811
777
|
}
|
|
812
|
-
|
|
813
778
|
if (!marker) return;
|
|
814
|
-
|
|
815
779
|
updateMarkerOrderDisplay(mapElement, marker, orderNumber, true, color);
|
|
816
780
|
}
|
|
817
781
|
|
|
@@ -833,6 +797,76 @@ function recalculateRoute(mapElement) {
|
|
|
833
797
|
calculateRoute(map);
|
|
834
798
|
}
|
|
835
799
|
|
|
800
|
+
|
|
801
|
+
function addMarkerAndSelect(mapElement, markerData) {
|
|
802
|
+
const map = mapInstances.get(mapElement);
|
|
803
|
+
if (!map) return;
|
|
804
|
+
|
|
805
|
+
const markers = markerInstances.get(map);
|
|
806
|
+
const routeSettings = routeSettingsMap.get(map);
|
|
807
|
+
const markersData = markersDataMap.get(map);
|
|
808
|
+
const cluster = markerClusters.get(map);
|
|
809
|
+
|
|
810
|
+
if (markers.has(markerData.id)) {
|
|
811
|
+
const existing = markers.get(markerData.id);
|
|
812
|
+
selectMarker(existing, map, true);
|
|
813
|
+
return;
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
const normalIconUrl = routeSettings?.customMarkers?.normal || markerImg;
|
|
817
|
+
const selectedIconUrl = routeSettings?.customMarkers?.selected || normalIconUrl;
|
|
818
|
+
|
|
819
|
+
const normalImg = new Image();
|
|
820
|
+
normalImg.src = normalIconUrl;
|
|
821
|
+
normalImg.onload = function () {
|
|
822
|
+
const normalIcon = L.icon({
|
|
823
|
+
iconUrl: normalIconUrl,
|
|
824
|
+
iconSize: [normalImg.width, normalImg.height],
|
|
825
|
+
iconAnchor: [normalImg.width / 2, normalImg.height],
|
|
826
|
+
});
|
|
827
|
+
|
|
828
|
+
const loadSelectedIcon = (callback) => {
|
|
829
|
+
if (selectedIconUrl === normalIconUrl) {
|
|
830
|
+
callback(normalIcon);
|
|
831
|
+
return;
|
|
832
|
+
}
|
|
833
|
+
const selectedImgEl = new Image();
|
|
834
|
+
selectedImgEl.src = selectedIconUrl;
|
|
835
|
+
selectedImgEl.onload = function () {
|
|
836
|
+
callback(L.icon({
|
|
837
|
+
iconUrl: selectedIconUrl,
|
|
838
|
+
iconSize: [selectedImgEl.width, selectedImgEl.height],
|
|
839
|
+
iconAnchor: [selectedImgEl.width / 2, selectedImgEl.height],
|
|
840
|
+
}));
|
|
841
|
+
};
|
|
842
|
+
};
|
|
843
|
+
|
|
844
|
+
loadSelectedIcon((selectedIcon) => {
|
|
845
|
+
const newMarker = createMarker(
|
|
846
|
+
markerData,
|
|
847
|
+
{ icon: normalIcon },
|
|
848
|
+
{ icon: selectedIcon },
|
|
849
|
+
cluster || null,
|
|
850
|
+
true,
|
|
851
|
+
onSelectionChangeMap.get(map),
|
|
852
|
+
map,
|
|
853
|
+
true,
|
|
854
|
+
null
|
|
855
|
+
);
|
|
856
|
+
|
|
857
|
+
if (!cluster) {
|
|
858
|
+
newMarker.addTo(map);
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
markersData.push(markerData);
|
|
862
|
+
selectMarker(newMarker, map, true);
|
|
863
|
+
|
|
864
|
+
if (routeSettings?.enabled) {
|
|
865
|
+
calculateRoute(map);
|
|
866
|
+
}
|
|
867
|
+
});
|
|
868
|
+
};
|
|
869
|
+
}
|
|
836
870
|
export default {
|
|
837
871
|
run,
|
|
838
872
|
getSelectedMarkers,
|
|
@@ -842,4 +876,5 @@ export default {
|
|
|
842
876
|
onBeforeRouteCalculation,
|
|
843
877
|
onAfterRouteCalculation,
|
|
844
878
|
recalculateRoute,
|
|
845
|
-
|
|
879
|
+
addMarkerAndSelect,
|
|
880
|
+
}
|