All checks were successful
release-tag / release-image (push) Successful in 2m17s
Co-authored-by: itoshi <kkzemeow@gmail.com> Co-authored-by: Spynder <19329095+Spynder@users.noreply.github.com> Reviewed-on: #12 Co-authored-by: Alexander Lazarenko <kerblif@unprism.ru> Co-committed-by: Alexander Lazarenko <kerblif@unprism.ru>
177 lines
4.9 KiB
TypeScript
177 lines
4.9 KiB
TypeScript
import { useRef, useEffect, useState } from "react";
|
|
|
|
import { Application, ApplicationRef, extend } from "@pixi/react";
|
|
import {
|
|
Container,
|
|
Graphics,
|
|
Sprite,
|
|
Texture,
|
|
TilingSprite,
|
|
Text,
|
|
} from "pixi.js";
|
|
import { Stack } from "@mui/material";
|
|
import { MapDataProvider, useMapData } from "./MapDataContext";
|
|
import { TransformProvider, useTransform } from "./TransformContext";
|
|
import { InfiniteCanvas } from "./InfiniteCanvas";
|
|
import { Sight } from "./Sight";
|
|
import { UP_SCALE } from "./Constants";
|
|
import { Station } from "./Station";
|
|
import { TravelPath } from "./TravelPath";
|
|
import { LeftSidebar } from "./LeftSidebar";
|
|
import { RightSidebar } from "./RightSidebar";
|
|
import { Widgets } from "./Widgets";
|
|
import { coordinatesToLocal } from "./utils";
|
|
import { LanguageSwitch } from "@/components/LanguageSwitch";
|
|
import { languageStore } from "@stores";
|
|
import { observer } from "mobx-react-lite";
|
|
|
|
extend({
|
|
Container,
|
|
Graphics,
|
|
Sprite,
|
|
Texture,
|
|
TilingSprite,
|
|
Text,
|
|
});
|
|
|
|
export const RoutePreview = () => {
|
|
return (
|
|
<MapDataProvider>
|
|
<TransformProvider>
|
|
<Stack direction="row" height="100vh" width="100vw" overflow="hidden">
|
|
<div
|
|
style={{
|
|
position: "absolute",
|
|
top: 0,
|
|
left: "50%",
|
|
transform: "translateX(-50%)",
|
|
zIndex: 1000,
|
|
}}
|
|
>
|
|
<LanguageSwitch />
|
|
</div>
|
|
<LeftSidebar />
|
|
<Stack direction="row" flex={1} position="relative" height="100%">
|
|
<Widgets />
|
|
<RouteMap />
|
|
<RightSidebar />
|
|
</Stack>
|
|
</Stack>
|
|
</TransformProvider>
|
|
</MapDataProvider>
|
|
);
|
|
};
|
|
|
|
export const RouteMap = observer(() => {
|
|
const { language } = languageStore;
|
|
const { setPosition, screenToLocal, setTransform, screenCenter } =
|
|
useTransform();
|
|
const { routeData, stationData, sightData, originalRouteData } = useMapData();
|
|
console.log(stationData);
|
|
const [points, setPoints] = useState<{ x: number; y: number }[]>([]);
|
|
const [isSetup, setIsSetup] = useState(false);
|
|
|
|
const parentRef = useRef<HTMLDivElement>(null);
|
|
|
|
useEffect(() => {
|
|
if (originalRouteData) {
|
|
const path = originalRouteData?.path;
|
|
const points =
|
|
path?.map(([x, y]: [number, number]) => ({
|
|
x: x * UP_SCALE,
|
|
y: y * UP_SCALE,
|
|
})) ?? [];
|
|
setPoints(points);
|
|
}
|
|
}, [originalRouteData]);
|
|
|
|
useEffect(() => {
|
|
if (isSetup || !screenCenter) {
|
|
return;
|
|
}
|
|
|
|
if (
|
|
originalRouteData?.center_latitude ===
|
|
originalRouteData?.center_longitude &&
|
|
originalRouteData?.center_latitude === 0
|
|
) {
|
|
if (points.length > 0) {
|
|
let boundingBox = {
|
|
from: { x: Infinity, y: Infinity },
|
|
to: { x: -Infinity, y: -Infinity },
|
|
};
|
|
for (const point of points) {
|
|
boundingBox.from.x = Math.min(boundingBox.from.x, point.x);
|
|
boundingBox.from.y = Math.min(boundingBox.from.y, point.y);
|
|
boundingBox.to.x = Math.max(boundingBox.to.x, point.x);
|
|
boundingBox.to.y = Math.max(boundingBox.to.y, point.y);
|
|
}
|
|
const newCenter = {
|
|
x: -(boundingBox.from.x + boundingBox.to.x) / 2,
|
|
y: -(boundingBox.from.y + boundingBox.to.y) / 2,
|
|
};
|
|
setPosition(newCenter);
|
|
setIsSetup(true);
|
|
}
|
|
} else if (
|
|
originalRouteData?.center_latitude &&
|
|
originalRouteData?.center_longitude
|
|
) {
|
|
const coordinates = coordinatesToLocal(
|
|
originalRouteData?.center_latitude,
|
|
originalRouteData?.center_longitude
|
|
);
|
|
|
|
setTransform(
|
|
coordinates.x,
|
|
coordinates.y,
|
|
originalRouteData?.rotate,
|
|
originalRouteData?.scale_min
|
|
);
|
|
setIsSetup(true);
|
|
}
|
|
}, [
|
|
points,
|
|
originalRouteData?.center_latitude,
|
|
originalRouteData?.center_longitude,
|
|
originalRouteData?.rotate,
|
|
isSetup,
|
|
screenCenter,
|
|
]);
|
|
|
|
if (!routeData || !stationData || !sightData) {
|
|
console.error("routeData, stationData or sightData is null");
|
|
return <div>Loading...</div>;
|
|
}
|
|
|
|
return (
|
|
<div style={{ width: "100%", height: "100%" }} ref={parentRef}>
|
|
<Application resizeTo={parentRef} background="#fff">
|
|
<InfiniteCanvas>
|
|
<TravelPath points={points} />
|
|
{stationData[language].map((obj, index) => (
|
|
<Station
|
|
station={obj}
|
|
key={obj.id}
|
|
ruLabel={
|
|
language === "ru"
|
|
? stationData.en[index].name
|
|
: stationData.ru[index].name
|
|
}
|
|
/>
|
|
))}
|
|
|
|
<pixiGraphics
|
|
draw={(g) => {
|
|
g.clear();
|
|
const localCenter = screenToLocal(0, 0);
|
|
g.circle(localCenter.x, localCenter.y, 10);
|
|
g.fill("#fff");
|
|
}}
|
|
/>
|
|
</InfiniteCanvas>
|
|
</Application>
|
|
</div>
|
|
);
|
|
});
|