110 lines
2.9 KiB
TypeScript
110 lines
2.9 KiB
TypeScript
import { FederatedMouseEvent, Graphics } from "pixi.js";
|
|
import { BACKGROUND_COLOR, PATH_COLOR, STATION_RADIUS, STATION_OUTLINE_WIDTH, UP_SCALE } from "./Constants";
|
|
import { useTransform } from "./TransformContext";
|
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|
import { StationData } from "./types";
|
|
import { useMapData } from "./MapDataContext";
|
|
import { coordinatesToLocal } from "./utils";
|
|
|
|
interface StationProps {
|
|
station: StationData;
|
|
}
|
|
|
|
export function Station({
|
|
station
|
|
}: Readonly<StationProps>) {
|
|
const draw = useCallback((g: Graphics) => {
|
|
g.clear();
|
|
const coordinates = coordinatesToLocal(station.latitude, station.longitude);
|
|
g.circle(coordinates.x * UP_SCALE, coordinates.y * UP_SCALE, STATION_RADIUS);
|
|
g.fill({color: PATH_COLOR});
|
|
g.stroke({color: BACKGROUND_COLOR, width: STATION_OUTLINE_WIDTH});
|
|
}, []);
|
|
|
|
return (
|
|
<pixiContainer>
|
|
<pixiGraphics draw={draw}/>
|
|
<StationLabel station={station}/>
|
|
</pixiContainer>
|
|
);
|
|
}
|
|
|
|
export function StationLabel({
|
|
station
|
|
}: Readonly<StationProps>) {
|
|
const { rotation, scale } = useTransform();
|
|
const { setStationOffset } = useMapData();
|
|
|
|
const [position, setPosition] = useState({ x: station.offset_x, y: station.offset_y });
|
|
const [isDragging, setIsDragging] = useState(false);
|
|
const [startPosition, setStartPosition] = useState({ x: 0, y: 0 });
|
|
const [startMousePosition, setStartMousePosition] = useState({ x: 0, y: 0 });
|
|
|
|
if(!station) {
|
|
console.error("station is null");
|
|
return null;
|
|
}
|
|
|
|
const handlePointerDown = (e: FederatedMouseEvent) => {
|
|
setIsDragging(true);
|
|
setStartPosition({
|
|
x: position.x,
|
|
y: position.y
|
|
});
|
|
setStartMousePosition({
|
|
x: e.globalX,
|
|
y: e.globalY
|
|
});
|
|
|
|
e.stopPropagation();
|
|
};
|
|
const handlePointerMove = (e: FederatedMouseEvent) => {
|
|
if (!isDragging) return;
|
|
const dx = (e.globalX - startMousePosition.x);
|
|
const dy = (e.globalY - startMousePosition.y);
|
|
const newPosition = {
|
|
x: startPosition.x + dx,
|
|
y: startPosition.y + dy
|
|
};
|
|
setPosition(newPosition);
|
|
setStationOffset(station.id, newPosition.x, newPosition.y);
|
|
e.stopPropagation();
|
|
};
|
|
|
|
const handlePointerUp = (e: FederatedMouseEvent) => {
|
|
setIsDragging(false);
|
|
e.stopPropagation();
|
|
};
|
|
const coordinates = coordinatesToLocal(station.latitude, station.longitude);
|
|
|
|
return (
|
|
<pixiContainer
|
|
eventMode='static'
|
|
interactive
|
|
onPointerDown={handlePointerDown}
|
|
onGlobalPointerMove={handlePointerMove}
|
|
onPointerUp={handlePointerUp}
|
|
onPointerUpOutside={handlePointerUp}
|
|
width={48}
|
|
height={48}
|
|
x={coordinates.x * UP_SCALE}
|
|
y={coordinates.y * UP_SCALE}
|
|
rotation={-rotation}
|
|
>
|
|
<pixiText
|
|
anchor={{x: 0.5, y: 0.5}}
|
|
text={station.name}
|
|
position={{
|
|
x: position.x/scale,
|
|
y: position.y/scale
|
|
}}
|
|
style={{
|
|
fontSize: 48,
|
|
fontWeight: 'bold',
|
|
fill: "#ffffff"
|
|
}}
|
|
/>
|
|
</pixiContainer>
|
|
);
|
|
}
|