93 lines
2.4 KiB
TypeScript
93 lines
2.4 KiB
TypeScript
import { Graphics } from "pixi.js";
|
|
import { useCallback } from "react";
|
|
import { PATH_COLOR, PATH_WIDTH, UNPASSED_STATION_COLOR } from "./Constants";
|
|
|
|
interface TravelPathProps {
|
|
points: { x: number; y: number }[];
|
|
busCoordinates?: { x: number; y: number };
|
|
}
|
|
|
|
const PASSED_PATH_COLOR = PATH_COLOR;
|
|
const UNPASSED_PATH_COLOR = UNPASSED_STATION_COLOR;
|
|
|
|
export function TravelPath({
|
|
points,
|
|
busCoordinates,
|
|
}: Readonly<TravelPathProps>) {
|
|
const draw = useCallback(
|
|
(g: Graphics) => {
|
|
g.clear();
|
|
|
|
if (points.length < 2) {
|
|
return;
|
|
}
|
|
|
|
g.moveTo(points[0].x, points[0].y);
|
|
for (let i = 1; i < points.length; i++) {
|
|
g.lineTo(points[i].x, points[i].y);
|
|
}
|
|
g.stroke({
|
|
color: UNPASSED_PATH_COLOR,
|
|
width: PATH_WIDTH,
|
|
});
|
|
|
|
if (!busCoordinates) {
|
|
return;
|
|
}
|
|
|
|
let minDistance = Infinity;
|
|
let closestSegmentIndex = -1;
|
|
let busSegmentStartPoint: { x: number; y: number } | null = null;
|
|
|
|
for (let i = 0; i < points.length - 1; i++) {
|
|
const p1 = points[i];
|
|
const p2 = points[i + 1];
|
|
|
|
const lineLengthSq = (p2.x - p1.x) ** 2 + (p2.y - p1.y) ** 2;
|
|
if (lineLengthSq === 0) continue;
|
|
|
|
const t =
|
|
((busCoordinates.x - p1.x) * (p2.x - p1.x) +
|
|
(busCoordinates.y - p1.y) * (p2.y - p1.y)) /
|
|
lineLengthSq;
|
|
const projectionT = Math.max(0, Math.min(1, t));
|
|
|
|
const projectedX = p1.x + projectionT * (p2.x - p1.x);
|
|
const projectedY = p1.y + projectionT * (p2.y - p1.y);
|
|
|
|
const dist = Math.sqrt(
|
|
(busCoordinates.x - projectedX) ** 2 +
|
|
(busCoordinates.y - projectedY) ** 2
|
|
);
|
|
|
|
if (dist < minDistance) {
|
|
minDistance = dist;
|
|
closestSegmentIndex = i;
|
|
busSegmentStartPoint = { x: projectedX, y: projectedY };
|
|
}
|
|
}
|
|
|
|
if (closestSegmentIndex !== -1 && busSegmentStartPoint) {
|
|
g.moveTo(points[0].x, points[0].y);
|
|
for (let i = 1; i <= closestSegmentIndex; i++) {
|
|
g.lineTo(points[i].x, points[i].y);
|
|
}
|
|
g.lineTo(busSegmentStartPoint.x, busSegmentStartPoint.y);
|
|
|
|
g.stroke({
|
|
color: PASSED_PATH_COLOR,
|
|
width: PATH_WIDTH,
|
|
});
|
|
}
|
|
},
|
|
[points, busCoordinates]
|
|
);
|
|
|
|
if (points.length === 0) {
|
|
console.error("points is empty");
|
|
return null;
|
|
}
|
|
|
|
return <pixiGraphics draw={draw} />;
|
|
}
|