This commit is contained in:
Spynder 2025-05-05 01:19:59 +03:00
parent fb16891de3
commit 4b20c94b70
9 changed files with 110 additions and 80 deletions

View File

@ -3,7 +3,7 @@ export const PATH_WIDTH = 15;
export const STATION_RADIUS = 20;
export const STATION_OUTLINE_WIDTH = 10;
export const SIGHT_SIZE = 60;
export const SCALE_FACTOR = 40;
export const SCALE_FACTOR = 50;
export const BACKGROUND_COLOR = 0x111111;
export const PATH_COLOR = 0xff4d4d;

View File

@ -116,6 +116,11 @@ export function InfiniteCanvas({children} : Readonly<{children?: ReactNode}>) {
setScale(newScale);
};
useEffect(() => {
applicationRef?.current?.getApplication()?.render();
console.log(position, scale, rotation);
}, [position, scale, rotation]);
return (
<ErrorBoundary>

View File

@ -1,11 +1,9 @@
import { useCustom, useShow, useApiUrl } from "@refinedev/core";
import { useCustom, useApiUrl } from "@refinedev/core";
import { useParams } from "react-router";
import { createContext, ReactNode, useContext, useEffect, useMemo, useState } from "react";
import { RouteData, SightData, StationData, StationPatchData } from "./types";
import { axiosInstance } from "../../providers/data";
const MapDataContext = createContext<{
originalRouteData?: RouteData,
originalStationData?: StationData[],
@ -63,7 +61,7 @@ export function MapDataProvider({ children }: Readonly<{ children: ReactNode }>)
});
const { data: stationQuery, isLoading: isStationLoading } = useCustom({
url: `${apiUrl}/route/${routeId}/station`,
method: 'get',
method: 'get'
});
const { data: sightQuery, isLoading: isSightLoading } = useCustom({
url: `${apiUrl}/route/${routeId}/sight`,
@ -110,8 +108,7 @@ export function MapDataProvider({ children }: Readonly<{ children: ReactNode }>)
}
async function saveChanges() {
console.log("saveChanges", routeData);
const response = await axiosInstance.patch(`/route/${routeId}`, routeData);
await axiosInstance.patch(`/route/${routeId}`, routeData);
saveStationChanges();
}

View File

@ -2,7 +2,7 @@ import { Button, Stack, TextField, Typography } from "@mui/material";
import { useMapData } from "./MapDataContext";
import { useEffect, useState } from "react";
import { useTransform } from "./TransformContext";
import { localToCoordinates } from "./utils";
import { coordinatesToLocal, localToCoordinates } from "./utils";
export function RightSidebar() {
const { routeData, setScaleRange, saveChanges, originalRouteData, setMapRotation, setMapCenter } = useMapData();
@ -52,7 +52,8 @@ export function RightSidebar() {
}
function pan({x, y}: {x: number, y: number}) {
setTransform(x, y);
const coordinates = coordinatesToLocal(y,x);
setTransform(coordinates.x, coordinates.y);
}
if(!routeData) {

View File

@ -40,10 +40,6 @@ export function StationLabel({
const [startPosition, setStartPosition] = useState({ x: 0, y: 0 });
const [startMousePosition, setStartMousePosition] = useState({ x: 0, y: 0 });
useEffect(() => {
console.log(position);
}, [position]);
if(!station) {
console.error("station is null");
return null;
@ -64,8 +60,8 @@ export function StationLabel({
};
const handlePointerMove = (e: FederatedMouseEvent) => {
if (!isDragging) return;
const dx = (e.globalX - startMousePosition.x) / scale;
const dy = (e.globalY - startMousePosition.y) / scale;
const dx = (e.globalX - startMousePosition.x);
const dy = (e.globalY - startMousePosition.y);
const cos = Math.cos(rotation);
const sin = Math.sin(rotation);
const newPosition = {
@ -93,13 +89,17 @@ export function StationLabel({
onPointerUpOutside={handlePointerUp}
width={48}
height={48}
x={coordinates.x * UP_SCALE + position.x*scale}
y={coordinates.y * UP_SCALE + position.y*scale}
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',

View File

@ -1,4 +1,4 @@
import { createContext, ReactNode, RefObject, useContext, useEffect, useMemo, useRef, useState } from "react";
import { createContext, ReactNode, RefObject, useContext, useMemo, useRef, useState } from "react";
import {
ApplicationRef
} from '@pixi/react';

View File

@ -72,7 +72,7 @@ export function RouteMap() {
}, [originalRouteData]);
useEffect(() => {
if(!applicationRef?.current || isSetup) {
if(!applicationRef?.current?.getCanvas() || isSetup) {
return;
}
@ -111,7 +111,7 @@ export function RouteMap() {
);
setIsSetup(true);
}
}, [points, originalRouteData?.center_latitude, originalRouteData?.center_longitude, originalRouteData?.rotate, applicationRef?.current, isSetup]);
}, [points, originalRouteData?.center_latitude, originalRouteData?.center_longitude, originalRouteData?.rotate, applicationRef?.current?.getCanvas(), isSetup]);
if (!routeData || !stationData || !sightData) {
console.error("routeData, stationData or sightData is null");

View File

@ -1,10 +1,9 @@
// approximation
export function coordinatesToLocal(longitude: number, latitude: number) {
return {
x: latitude,
y: -longitude*2
}
//return {x: longitude, y: latitude}
}
export function localToCoordinates(x: number, y: number) {
@ -12,5 +11,4 @@ export function localToCoordinates(x: number, y: number) {
latitude: x,
longitude: -y/2
}
// return {latitude: x, longitude: y}
}

View File

@ -444,8 +444,8 @@ export const SightEdit = observer(() => {
onChange={(_, newValue) => setTabValue(newValue)}
aria-label="basic tabs example"
>
<Tab label="Левый виджет" {...a11yProps(1)} />
<Tab label="Правый виджет" {...a11yProps(2)} />
<Tab label="Левая статья" {...a11yProps(1)} />
<Tab label="Правая статья" {...a11yProps(2)} />
<Tab label="Основная информация" {...a11yProps(3)} />
</Tabs>
</Box>
@ -594,20 +594,6 @@ export const SightEdit = observer(() => {
name="coordinates"
/> */}
<TextField
{...register("address", {
required: "Это поле является обязательным",
})}
error={!!(errors as any)?.address}
helperText={(errors as any)?.address?.message}
margin="normal"
fullWidth
InputLabelProps={{ shrink: true }}
type="text"
label={"Адрес *"}
name="address"
/>
<Controller
control={control}
name="city_id"
@ -1153,7 +1139,7 @@ export const SightEdit = observer(() => {
display: "flex",
flexDirection: "column",
position: "fixed",
p: 2,
p: 0,
height: "max-content",
width: "30%",
@ -1172,7 +1158,6 @@ export const SightEdit = observer(() => {
display: "flex",
flexDirection: "column",
flexGrow: 1,
gap: 2,
}}
>
{!previewSelected && (
@ -1192,7 +1177,6 @@ export const SightEdit = observer(() => {
alt={mediaFile.filename}
style={{
maxWidth: "100%",
height: "300px",
objectFit: "contain",
borderRadius: 8,
}}
@ -1255,14 +1239,14 @@ export const SightEdit = observer(() => {
{
<Box
sx={{
mt: 2,
mb: 2,
mt: 0,
mb: 0,
flexGrow: 1,
display: "flex",
flexDirection: "column",
justifyContent: "space-between",
height: "250px",
overflowY: "scroll",
overflowY: "auto",
}}
>
{previewSelected &&
@ -1356,7 +1340,16 @@ export const SightEdit = observer(() => {
<Typography
variant="h4"
gutterBottom
sx={{ color: "text.primary" }}
px={2}
py={.5}
sx={{
color: "text.primary",
background:
"linear-gradient(180deg, hsla(0,0%,100%,.2), hsla(0,0%,100%,0)), hsla(29,15%,65%,.4)",
boxShadow: "inset 4px 4px 12px hsla(0,0%,100%,.12)",
}}
>
{selectedArticle.heading}
</Typography>
@ -1366,6 +1359,7 @@ export const SightEdit = observer(() => {
<Typography
variant="body1"
gutterBottom
px={2}
sx={{ color: "text.primary" }}
>
{selectedArticle.body}
@ -1374,47 +1368,50 @@ export const SightEdit = observer(() => {
</Box>
)}
<Box>
<Typography variant="h6" gutterBottom>
Привязанные статьи
</Typography>
<Box
sx={{
display: "grid",
gridTemplateColumns: "1fr 1fr",
borderRadius: 2,
display: "flex",
flexDirection: "row",
justifyContent: "center",
margin: "0 auto",
background:
"linear-gradient(180deg, hsla(0,0%,100%,.2), hsla(0,0%,100%,0)), hsla(29,15%,65%,.4)",
boxShadow: "inset 4px 4px 12px hsla(0,0%,100%,.12)",
gap: 1,
mt: 2,
}}
>
{linkedArticles.map((article, index) => (
<Box
key={article.id}
onClick={() => {
setSelectedArticleIndex(index);
setPreviewSelected(false);
}}
sx={{
cursor: "pointer",
bgcolor:
selectedArticleIndex === index
? "primary.main"
: "transparent",
color:
selectedArticleIndex === index
? "white"
: "inherit",
p: 1,
borderRadius: 1,
}}
>
<Typography variant="body1" gutterBottom>
{article.heading}
</Typography>
</Box>
))}
<Box
sx={{
display: "flex",
flexDirection: "row",
flexWrap: "wrap",
borderRadius: 2,
}}
>
{linkedArticles.map((article, index) => (
<Box
key={article.id}
onClick={() => {
setSelectedArticleIndex(index);
setPreviewSelected(false);
}}
sx={{
cursor: "pointer",
bgcolor: "transparent",
color: "inherit",
textDecoration:
selectedArticleIndex === index ?
"underline" : "none",
p: 1,
borderRadius: 1,
}}
>
<Typography variant="body1">
{article.heading}
</Typography>
</Box>
))}
</Box>
</Box>
</Box>
</Box>
@ -1446,6 +1443,21 @@ export const SightEdit = observer(() => {
sx={{ flex: 1, display: "flex", flexDirection: "column" }}
autoComplete="off"
>
<TextField
{...register("address", {
required: "Это поле является обязательным",
})}
error={!!(errors as any)?.address}
helperText={(errors as any)?.address?.message}
margin="normal"
fullWidth
InputLabelProps={{ shrink: true }}
type="text"
label={"Адрес *"}
name="address"
/>
<Controller
control={control}
name="thumbnail"
@ -1618,6 +1630,23 @@ export const SightEdit = observer(() => {
{thumbnailPreview && (
<Box>
<Typography
variant="body1"
sx={{ display: "flex", flexDirection: "column", mb: 2 }}
>
<Box component="span" sx={{ color: "text.secondary" }}>
Адрес:{" "}
</Box>
<Box
component="span"
sx={{
color: (theme) =>
theme.palette.mode === "dark" ? "grey.300" : "grey.800",
}}
>
{`${addressContent}`}
</Box>
</Typography>
<Typography
variant="body2"
gutterBottom