차량 위치 이동 애니메이션 개선
This commit is contained in:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user