|
|
|
|
@@ -5,6 +5,7 @@ const state = {
|
|
|
|
|
infoOverlay: null,
|
|
|
|
|
routeOverlay: null,
|
|
|
|
|
routeDestinationOverlay: null,
|
|
|
|
|
markerAnimationMs: 900,
|
|
|
|
|
drivers: new Map(),
|
|
|
|
|
locations: new Map(),
|
|
|
|
|
selectedDriverId: "",
|
|
|
|
|
@@ -652,7 +653,8 @@ function updateMarker(location) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function updateKakaoMarker(location) {
|
|
|
|
|
const position = new kakao.maps.LatLng(location.latitude, location.longitude);
|
|
|
|
|
const targetPosition = createPosition(location.latitude, location.longitude);
|
|
|
|
|
const kakaoPosition = new kakao.maps.LatLng(targetPosition.latitude, targetPosition.longitude);
|
|
|
|
|
const status = getLocationStatus(location);
|
|
|
|
|
const markerElement = createTruckMarkerElement(location, status);
|
|
|
|
|
|
|
|
|
|
@@ -662,23 +664,25 @@ function updateKakaoMarker(location) {
|
|
|
|
|
marker = {
|
|
|
|
|
provider: "kakao",
|
|
|
|
|
overlay: new kakao.maps.CustomOverlay({
|
|
|
|
|
position,
|
|
|
|
|
position: kakaoPosition,
|
|
|
|
|
content: markerElement,
|
|
|
|
|
yAnchor: 1
|
|
|
|
|
})
|
|
|
|
|
}),
|
|
|
|
|
currentPosition: targetPosition
|
|
|
|
|
};
|
|
|
|
|
marker.overlay.setMap(state.map);
|
|
|
|
|
state.markers.set(location.driverId, marker);
|
|
|
|
|
} else {
|
|
|
|
|
marker.overlay.setPosition(position);
|
|
|
|
|
marker.overlay.setContent(markerElement);
|
|
|
|
|
animateMarkerPosition(marker, targetPosition);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function updateLeafletMarker(location) {
|
|
|
|
|
const status = getLocationStatus(location);
|
|
|
|
|
const vehicleType = getVehicleType(location);
|
|
|
|
|
const position = [location.latitude, location.longitude];
|
|
|
|
|
const targetPosition = createPosition(location.latitude, location.longitude);
|
|
|
|
|
const leafletPosition = [targetPosition.latitude, targetPosition.longitude];
|
|
|
|
|
const icon = L.divIcon({
|
|
|
|
|
className: `leaflet-truck-marker truck-marker ${status.key} ${vehicleType.className}`,
|
|
|
|
|
html: createTruckMarkerHtml(location, vehicleType),
|
|
|
|
|
@@ -692,16 +696,17 @@ function updateLeafletMarker(location) {
|
|
|
|
|
if (!marker) {
|
|
|
|
|
marker = {
|
|
|
|
|
provider: "leaflet",
|
|
|
|
|
marker: L.marker(position, { icon, title: location.vehicleNo || location.driverId })
|
|
|
|
|
marker: L.marker(leafletPosition, { icon, title: location.vehicleNo || location.driverId }),
|
|
|
|
|
currentPosition: targetPosition
|
|
|
|
|
};
|
|
|
|
|
marker.marker.on("click", () => focusLocation(location));
|
|
|
|
|
marker.marker.addTo(state.map);
|
|
|
|
|
state.markers.set(location.driverId, marker);
|
|
|
|
|
} else {
|
|
|
|
|
marker.marker.setLatLng(position);
|
|
|
|
|
marker.marker.setIcon(icon);
|
|
|
|
|
marker.marker.off("click");
|
|
|
|
|
marker.marker.on("click", () => focusLocation(location));
|
|
|
|
|
animateMarkerPosition(marker, targetPosition);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -728,7 +733,85 @@ function createTruckMarkerHtml(location, vehicleType = getVehicleType(location))
|
|
|
|
|
`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function animateMarkerPosition(marker, targetPosition) {
|
|
|
|
|
const fromPosition = marker.currentPosition || getMarkerPosition(marker) || targetPosition;
|
|
|
|
|
|
|
|
|
|
if (calculateDistanceKm(fromPosition, targetPosition) < 0.01) {
|
|
|
|
|
setMarkerPosition(marker, targetPosition);
|
|
|
|
|
marker.currentPosition = targetPosition;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cancelMarkerAnimation(marker);
|
|
|
|
|
|
|
|
|
|
const startedAt = window.performance.now();
|
|
|
|
|
const duration = state.markerAnimationMs;
|
|
|
|
|
|
|
|
|
|
const tick = (timestamp) => {
|
|
|
|
|
const progress = Math.min(1, (timestamp - startedAt) / duration);
|
|
|
|
|
const easedProgress = easeInOutCubic(progress);
|
|
|
|
|
const nextPosition = {
|
|
|
|
|
latitude: interpolateNumber(fromPosition.latitude, targetPosition.latitude, easedProgress),
|
|
|
|
|
longitude: interpolateNumber(fromPosition.longitude, targetPosition.longitude, easedProgress)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
setMarkerPosition(marker, nextPosition);
|
|
|
|
|
marker.currentPosition = nextPosition;
|
|
|
|
|
|
|
|
|
|
if (progress < 1) {
|
|
|
|
|
marker.animationFrame = window.requestAnimationFrame(tick);
|
|
|
|
|
} else {
|
|
|
|
|
marker.animationFrame = null;
|
|
|
|
|
marker.currentPosition = targetPosition;
|
|
|
|
|
setMarkerPosition(marker, targetPosition);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
marker.animationFrame = window.requestAnimationFrame(tick);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function cancelMarkerAnimation(marker) {
|
|
|
|
|
if (!marker?.animationFrame) return;
|
|
|
|
|
window.cancelAnimationFrame(marker.animationFrame);
|
|
|
|
|
marker.animationFrame = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getMarkerPosition(marker) {
|
|
|
|
|
if (marker.provider === "leaflet" && marker.marker?.getLatLng) {
|
|
|
|
|
const position = marker.marker.getLatLng();
|
|
|
|
|
return createPosition(position.lat, position.lng);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return marker.currentPosition || null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function setMarkerPosition(marker, position) {
|
|
|
|
|
if (marker.provider === "kakao") {
|
|
|
|
|
marker.overlay.setPosition(new kakao.maps.LatLng(position.latitude, position.longitude));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (marker.provider === "leaflet") {
|
|
|
|
|
marker.marker.setLatLng([position.latitude, position.longitude]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function createPosition(latitude, longitude) {
|
|
|
|
|
return {
|
|
|
|
|
latitude: Number(latitude),
|
|
|
|
|
longitude: Number(longitude)
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function easeInOutCubic(value) {
|
|
|
|
|
return value < 0.5
|
|
|
|
|
? 4 * value * value * value
|
|
|
|
|
: 1 - ((-2 * value + 2) ** 3) / 2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function removeMarker(marker) {
|
|
|
|
|
cancelMarkerAnimation(marker);
|
|
|
|
|
|
|
|
|
|
if (marker.provider === "kakao") {
|
|
|
|
|
marker.overlay.setMap(null);
|
|
|
|
|
return;
|
|
|
|
|
|