adt-js-components 1.9.3 → 1.9.5
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 +162 -66
package/package.json
CHANGED
package/src/Map/index.js
CHANGED
|
@@ -7,6 +7,7 @@ import {RouteSetting, defaultRouteSettings} from './route.types.js';
|
|
|
7
7
|
|
|
8
8
|
let siteKey;
|
|
9
9
|
let markerImg;
|
|
10
|
+
const svgCache = new Map();
|
|
10
11
|
const mapInstances = new WeakMap();
|
|
11
12
|
const selectedMarkers = new WeakMap();
|
|
12
13
|
const selectionOrder = new WeakMap();
|
|
@@ -16,6 +17,8 @@ const routeSettingsMap = new WeakMap();
|
|
|
16
17
|
const markersDataMap = new WeakMap();
|
|
17
18
|
const markerClusters = new WeakMap();
|
|
18
19
|
const onSelectionChangeMap = new WeakMap();
|
|
20
|
+
const onBeforeRouteCalculationMap = new WeakMap();
|
|
21
|
+
const onAfterRouteCalculationMap = new WeakMap();
|
|
19
22
|
|
|
20
23
|
const DEPOT_TYPE = {
|
|
21
24
|
START: 'depot-start',
|
|
@@ -40,6 +43,8 @@ async function run(options) {
|
|
|
40
43
|
customMarkers = {},
|
|
41
44
|
showSelectionOrder = false,
|
|
42
45
|
markerInfoCallback = null,
|
|
46
|
+
onBeforeRouteCalculation = null,
|
|
47
|
+
onAfterRouteCalculation = null,
|
|
43
48
|
} = JSON.parse(el.dataset.adtMap);
|
|
44
49
|
|
|
45
50
|
/** @type {RouteSetting} */
|
|
@@ -63,6 +68,8 @@ async function run(options) {
|
|
|
63
68
|
routeSettingsMap.set(map, routeSettings);
|
|
64
69
|
markersDataMap.set(map, markers);
|
|
65
70
|
onSelectionChangeMap.set(map, onSelectionChange);
|
|
71
|
+
onBeforeRouteCalculationMap.set(map, onBeforeRouteCalculation);
|
|
72
|
+
onAfterRouteCalculationMap.set(map, onAfterRouteCalculation);
|
|
66
73
|
|
|
67
74
|
L.tileLayer("https://api.mapy.cz/v1/maptiles/basic/256/{z}/{x}/{y}?apikey=" + siteKey, {
|
|
68
75
|
minZoom: 0,
|
|
@@ -157,9 +164,7 @@ async function run(options) {
|
|
|
157
164
|
}
|
|
158
165
|
|
|
159
166
|
if (routeSettings.enabled) {
|
|
160
|
-
|
|
161
|
-
calculateRoute(map);
|
|
162
|
-
}, 500);
|
|
167
|
+
calculateRoute(map);
|
|
163
168
|
}
|
|
164
169
|
|
|
165
170
|
if (callback) {
|
|
@@ -175,11 +180,10 @@ async function run(options) {
|
|
|
175
180
|
if (mutation.type === "childList") {
|
|
176
181
|
mutation.addedNodes.forEach(node => {
|
|
177
182
|
if (node.nodeType === 1) {
|
|
178
|
-
// Zkontroluj samotný node
|
|
179
183
|
if (node.hasAttribute("data-adt-map")) {
|
|
180
184
|
applyEventHandlers(node);
|
|
181
185
|
}
|
|
182
|
-
|
|
186
|
+
|
|
183
187
|
node.querySelectorAll?.('[data-adt-map]').forEach(el => {
|
|
184
188
|
applyEventHandlers(el);
|
|
185
189
|
});
|
|
@@ -344,9 +348,7 @@ function addMarkers(map, markers, options, selectedOptions, position, selectable
|
|
|
344
348
|
map.addLayer(cluster);
|
|
345
349
|
|
|
346
350
|
if (loadedCount === totalMarkers) {
|
|
347
|
-
|
|
348
|
-
checkAndApplyPreselection(map, markers, showSelectionOrder, onSelectionChange, selectable);
|
|
349
|
-
}, 200);
|
|
351
|
+
checkAndApplyPreselection(map, markers, showSelectionOrder, onSelectionChange, selectable);
|
|
350
352
|
}
|
|
351
353
|
}
|
|
352
354
|
|
|
@@ -371,7 +373,7 @@ function createMarker(marker, options, selectedOptions, cluster = null, selectab
|
|
|
371
373
|
const markers = markerInstances.get(map);
|
|
372
374
|
markers.set(marker.id, mapMarker);
|
|
373
375
|
|
|
374
|
-
mapMarker.on('add', function() {
|
|
376
|
+
mapMarker.on('add', function () {
|
|
375
377
|
const el = mapMarker.getElement();
|
|
376
378
|
if (el) {
|
|
377
379
|
el.style.cursor = 'pointer';
|
|
@@ -512,22 +514,29 @@ async function updateMarkerOrderDisplay(map, marker, orderNumber, isSelected, co
|
|
|
512
514
|
|
|
513
515
|
async function createMarkerIcon(map, iconUrl, orderNumber, color = null) {
|
|
514
516
|
let inlineStyle = null;
|
|
515
|
-
const response = await fetch(iconUrl);
|
|
516
|
-
const svg = await response.text();
|
|
517
517
|
const settings = routeSettingsMap.get(map);
|
|
518
518
|
|
|
519
519
|
if ((settings && settings.enabled) || color) {
|
|
520
520
|
inlineStyle = `--marker-fill: ${color ?? settings.color};`;
|
|
521
521
|
}
|
|
522
522
|
|
|
523
|
+
let svg;
|
|
524
|
+
if (svgCache.has(iconUrl)) {
|
|
525
|
+
svg = svgCache.get(iconUrl);
|
|
526
|
+
} else {
|
|
527
|
+
const response = await fetch(iconUrl);
|
|
528
|
+
svg = await response.text();
|
|
529
|
+
svgCache.set(iconUrl, svg);
|
|
530
|
+
}
|
|
531
|
+
|
|
523
532
|
return L.divIcon({
|
|
524
533
|
className: 'marker-icon-wrapper',
|
|
525
534
|
html: `
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
535
|
+
<div class="marker-icon" style="${inlineStyle}">
|
|
536
|
+
${svg}
|
|
537
|
+
${orderNumber ? `<span class="selection-order-label">${orderNumber}</span>` : ''}
|
|
538
|
+
</div>
|
|
539
|
+
`,
|
|
531
540
|
iconSize: [43, 58],
|
|
532
541
|
iconAnchor: [21, 58]
|
|
533
542
|
});
|
|
@@ -581,68 +590,134 @@ async function calculateRoute(map) {
|
|
|
581
590
|
return;
|
|
582
591
|
}
|
|
583
592
|
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
.sort((a, b) => a[1] - b[1])
|
|
587
|
-
.map(entry => entry[0]);
|
|
588
|
-
const routeMarkers = orderedIds
|
|
589
|
-
.map(id => markers.find(m => m.id === id))
|
|
590
|
-
.filter(m => m !== undefined);
|
|
593
|
+
const hasCustomStart = routeSettings.startPoint !== null && routeSettings.startPoint !== undefined;
|
|
594
|
+
const hasCustomEnd = routeSettings.endPoint !== null && routeSettings.endPoint !== undefined;
|
|
591
595
|
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
}
|
|
596
|
+
if (hasCustomStart) addDepotMarker(map, routeSettings.startPoint, DEPOT_TYPE.START);
|
|
597
|
+
if (hasCustomEnd) addDepotMarker(map, routeSettings.endPoint, DEPOT_TYPE.END);
|
|
595
598
|
|
|
596
|
-
|
|
597
|
-
const hasCustomStart = routeSettings.startPoint !== null && routeSettings.startPoint !== undefined;
|
|
598
|
-
if (hasCustomStart) {
|
|
599
|
-
startPoint = routeSettings.startPoint;
|
|
600
|
-
}
|
|
599
|
+
if (!selectedSet || selectedSet.size === 0) return;
|
|
601
600
|
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
601
|
+
const orderedIds = Array.from(order.entries())
|
|
602
|
+
.sort((a, b) => a[1] - b[1])
|
|
603
|
+
.map(entry => entry[0]);
|
|
604
|
+
const routeMarkers = orderedIds
|
|
605
|
+
.map(id => markers.find(m => m.id === id))
|
|
606
|
+
.filter(m => m !== undefined);
|
|
607
607
|
|
|
608
|
-
|
|
609
|
-
addDepotMarker(map, startPoint, DEPOT_TYPE.START);
|
|
610
|
-
}
|
|
611
|
-
if (hasCustomEnd) {
|
|
612
|
-
addDepotMarker(map, endPoint, DEPOT_TYPE.END);
|
|
613
|
-
}
|
|
608
|
+
if (routeMarkers.length < 2) return;
|
|
614
609
|
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
apikey: siteKey
|
|
620
|
-
});
|
|
610
|
+
const beforeCallback = onBeforeRouteCalculationMap.get(map);
|
|
611
|
+
if (beforeCallback && window[beforeCallback]) {
|
|
612
|
+
window[beforeCallback]();
|
|
613
|
+
}
|
|
621
614
|
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
615
|
+
let startPoint = hasCustomStart ? routeSettings.startPoint : routeMarkers[0].position;
|
|
616
|
+
let endPoint = hasCustomEnd ? routeSettings.endPoint : routeMarkers[routeMarkers.length - 1].position;
|
|
617
|
+
|
|
618
|
+
const WAYPOINTS_LIMIT = 15;
|
|
619
|
+
const allCoords = [];
|
|
620
|
+
const allParts = [];
|
|
621
|
+
let totalDuration = 0;
|
|
622
|
+
let totalLength = 0;
|
|
623
|
+
|
|
624
|
+
try {
|
|
625
|
+
if (routeMarkers.length <= WAYPOINTS_LIMIT) {
|
|
626
|
+
const params = new URLSearchParams({
|
|
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}`));
|
|
625
633
|
|
|
626
|
-
|
|
627
|
-
const response = await fetch(
|
|
628
|
-
`https://api.mapy.cz/v1/routing/route?${params.toString()}`
|
|
629
|
-
);
|
|
634
|
+
const response = await fetch(`https://api.mapy.cz/v1/routing/route?${params.toString()}`);
|
|
630
635
|
const data = await response.json();
|
|
631
636
|
|
|
632
637
|
if (data.geometry?.geometry?.coordinates) {
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
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
|
+
}
|
|
649
|
+
} else {
|
|
650
|
+
const chunks = [];
|
|
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
|
+
}
|
|
641
688
|
}
|
|
642
|
-
} catch (error) {
|
|
643
|
-
console.error('Error calculating route:', error);
|
|
644
689
|
}
|
|
690
|
+
} catch (error) {
|
|
691
|
+
console.error('Error calculating route:', error);
|
|
692
|
+
const afterCallback = onAfterRouteCalculationMap.get(map);
|
|
693
|
+
if (afterCallback && window[afterCallback]) window[afterCallback]({}, 0, 0);
|
|
694
|
+
|
|
695
|
+
return;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
if (allCoords.length > 0) {
|
|
699
|
+
const polyline = L.polyline(allCoords, {
|
|
700
|
+
color: routeSettings.color,
|
|
701
|
+
weight: routeSettings.weight,
|
|
702
|
+
opacity: routeSettings.opacity
|
|
703
|
+
}).addTo(map);
|
|
704
|
+
routePolylines.set(map, polyline);
|
|
645
705
|
}
|
|
706
|
+
|
|
707
|
+
// @type {TRouteParts}
|
|
708
|
+
const routeParts = {};
|
|
709
|
+
allParts.forEach((part, index) => {
|
|
710
|
+
if (index < orderedIds.length) {
|
|
711
|
+
const markerId = orderedIds[index];
|
|
712
|
+
routeParts[markerId] = {
|
|
713
|
+
duration: part.duration,
|
|
714
|
+
length: part.length,
|
|
715
|
+
};
|
|
716
|
+
}
|
|
717
|
+
});
|
|
718
|
+
|
|
719
|
+
const afterCallback = onAfterRouteCalculationMap.get(map);
|
|
720
|
+
if (afterCallback && window[afterCallback]) window[afterCallback](routeParts, totalLength, totalDuration);
|
|
646
721
|
}
|
|
647
722
|
|
|
648
723
|
function addDepotMarker(map, position, depotType) {
|
|
@@ -659,7 +734,7 @@ function addDepotMarker(map, position, depotType) {
|
|
|
659
734
|
iconAnchor: [img.width / 2, img.height]
|
|
660
735
|
});
|
|
661
736
|
|
|
662
|
-
L.marker(position, {
|
|
737
|
+
L.marker(position, {icon: icon}).addTo(map);
|
|
663
738
|
};
|
|
664
739
|
}
|
|
665
740
|
|
|
@@ -740,10 +815,31 @@ function setOrder(mapElement, markerId, orderNumber) {
|
|
|
740
815
|
updateMarkerOrderDisplay(mapElement, marker, orderNumber, true, color);
|
|
741
816
|
}
|
|
742
817
|
|
|
818
|
+
function onBeforeRouteCalculation(mapElement, callbackName) {
|
|
819
|
+
const map = mapInstances.get(mapElement);
|
|
820
|
+
if (!map) return;
|
|
821
|
+
onBeforeRouteCalculationMap.set(map, callbackName);
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
function onAfterRouteCalculation(mapElement, callbackName) {
|
|
825
|
+
const map = mapInstances.get(mapElement);
|
|
826
|
+
if (!map) return;
|
|
827
|
+
onAfterRouteCalculationMap.set(map, callbackName);
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
function recalculateRoute(mapElement) {
|
|
831
|
+
const map = mapInstances.get(mapElement);
|
|
832
|
+
if (!map) return;
|
|
833
|
+
calculateRoute(map);
|
|
834
|
+
}
|
|
835
|
+
|
|
743
836
|
export default {
|
|
744
837
|
run,
|
|
745
838
|
getSelectedMarkers,
|
|
746
839
|
clearSelection,
|
|
747
840
|
toggleMarker,
|
|
748
841
|
setOrder,
|
|
842
|
+
onBeforeRouteCalculation,
|
|
843
|
+
onAfterRouteCalculation,
|
|
844
|
+
recalculateRoute,
|
|
749
845
|
}
|