This commit is contained in:
2026-03-23 01:21:44 +03:00
parent b6a9cecba6
commit 442160ba38
16 changed files with 973 additions and 174 deletions

View File

@@ -36,12 +36,13 @@ const MapDataContext = createContext<{
setMapCenter: (x: number, y: number) => void;
setStationOffset: (stationId: number, x: number, y: number) => void;
setStationAlign: (stationId: number, align: number) => void;
setStationIconSize: (stationId: number, size: number) => void;
setSightCoordinates: (
sightId: number,
latitude: number,
longitude: number
) => void;
setIconSize: (size: number) => void;
setSightIconSize: (sightId: number, size: number) => void;
setFontSize: (size: number) => void;
saveChanges: () => void;
}>({
@@ -62,8 +63,9 @@ const MapDataContext = createContext<{
setMapCenter: () => {},
setStationOffset: () => {},
setStationAlign: () => {},
setStationIconSize: () => {},
setSightCoordinates: () => {},
setIconSize: () => {},
setSightIconSize: () => {},
setFontSize: () => {},
saveChanges: () => {},
});
@@ -145,16 +147,16 @@ export const MapDataProvider = observer(
}, [routeId]);
useEffect(() => {
if (originalRouteData)
if (originalRouteData) {
setRouteData({ ...originalRouteData, ...routeChanges });
if (originalSightData) setSightData(originalSightData);
}, [
originalRouteData,
originalSightData,
routeChanges,
stationChanges,
sightChanges,
]);
}
}, [originalRouteData, routeChanges]);
useEffect(() => {
if (originalSightData) {
setSightData(originalSightData);
}
}, [originalSightData]);
function setScaleRange(min: number, max: number) {
setRouteChanges((prev) => {
@@ -168,16 +170,6 @@ export const MapDataProvider = observer(
});
}
function setIconSize(size: number) {
const clamped = Math.max(1, Math.min(300, size));
setRouteChanges((prev) => {
if (prev.icon_size === clamped) {
return prev;
}
return { ...prev, icon_size: clamped };
});
}
function setFontSize(size: number) {
const clamped = Math.max(1, Math.min(300, size));
setRouteChanges((prev) => {
@@ -241,6 +233,11 @@ export const MapDataProvider = observer(
...s,
offset_x: station.offset_x,
offset_y: station.offset_y,
align: station.align,
icon_size:
typeof station.icon_size === "number"
? station.icon_size
: s.icon_size,
}
: s
);
@@ -262,6 +259,10 @@ export const MapDataProvider = observer(
...s,
latitude: sight.latitude,
longitude: sight.longitude,
icon_size:
typeof sight.icon_size === "number"
? sight.icon_size
: s.icon_size,
}
: s
)
@@ -306,6 +307,7 @@ export const MapDataProvider = observer(
offset_x: x,
offset_y: y,
align: originalStation?.align ?? 1,
icon_size: originalStation?.icon_size,
transfers: originalStation?.transfers ?? {
bus: "",
metro_blue: "",
@@ -367,6 +369,7 @@ export const MapDataProvider = observer(
align: align,
offset_x: originalStation?.offset_x ?? 0,
offset_y: originalStation?.offset_y ?? 0,
icon_size: originalStation?.icon_size,
transfers: originalStation?.transfers ?? {
bus: "",
metro_blue: "",
@@ -397,6 +400,70 @@ export const MapDataProvider = observer(
});
}
function setStationIconSize(stationId: number, size: number) {
const clamped = Math.max(1, Math.min(300, Math.round(size)));
const currentStation = stationData.ru?.find(
(station) => station.id === stationId
);
if (currentStation?.icon_size === clamped) {
return;
}
setStationChanges((prev) => {
const existingIndex = prev.findIndex(
(station) => station.station_id === stationId
);
if (existingIndex !== -1) {
const next = [...prev];
next[existingIndex] = {
...next[existingIndex],
icon_size: clamped,
};
return next;
}
const originalStation = originalStationData?.find(
(s) => s.id === stationId
);
return [
...prev,
{
station_id: stationId,
offset_x: currentStation?.offset_x ?? originalStation?.offset_x ?? 0,
offset_y: currentStation?.offset_y ?? originalStation?.offset_y ?? 0,
align: currentStation?.align ?? originalStation?.align ?? 1,
icon_size: clamped,
transfers: currentStation?.transfers ??
originalStation?.transfers ?? {
bus: "",
metro_blue: "",
metro_green: "",
metro_orange: "",
metro_purple: "",
metro_red: "",
train: "",
tram: "",
trolleybus: "",
},
},
];
});
setStationData((prev) => {
const updated = { ...prev };
Object.keys(updated).forEach((lang) => {
updated[lang] = updated[lang].map((station) =>
station.id === stationId
? { ...station, icon_size: clamped }
: station
);
});
return updated;
});
}
function setSightCoordinates(
sightId: number,
latitude: number,
@@ -435,6 +502,7 @@ export const MapDataProvider = observer(
sight_id: sightId,
latitude,
longitude,
icon_size: foundSight.icon_size,
},
];
}
@@ -443,6 +511,49 @@ export const MapDataProvider = observer(
});
}
function setSightIconSize(sightId: number, size: number) {
const clamped = Math.max(1, Math.min(300, Math.round(size)));
setSightData((prev) =>
prev
? prev.map((sight) =>
sight.id === sightId ? { ...sight, icon_size: clamped } : sight
)
: prev
);
setSightChanges((prev) => {
const existingIndex = prev.findIndex(
(sight) => sight.sight_id === sightId
);
if (existingIndex !== -1) {
const next = [...prev];
next[existingIndex] = {
...next[existingIndex],
icon_size: clamped,
};
return next;
}
const foundSight =
sightData?.find((sight) => sight.id === sightId) ??
originalSightData?.find((sight) => sight.id === sightId);
if (!foundSight) {
return prev;
}
return [
...prev,
{
sight_id: sightId,
latitude: foundSight.latitude,
longitude: foundSight.longitude,
icon_size: clamped,
},
];
});
}
useEffect(() => {}, [sightChanges]);
const value = useMemo(
@@ -464,8 +575,9 @@ export const MapDataProvider = observer(
saveChanges,
setStationOffset,
setStationAlign,
setStationIconSize,
setSightCoordinates,
setIconSize,
setSightIconSize,
setFontSize,
}),
[
@@ -479,7 +591,8 @@ export const MapDataProvider = observer(
isStationLoading,
isSightLoading,
selectedSight,
setIconSize,
setStationIconSize,
setSightIconSize,
setFontSize,
]
);

View File

@@ -21,7 +21,6 @@ export function RightSidebar() {
originalRouteData,
setMapRotation,
setMapCenter,
setIconSize: updateIconSize,
setFontSize: updateFontSize,
} = useMapData();
const { rotation, rotateToAngle, scale, setScaleAtCenter } = useTransform();
@@ -34,7 +33,6 @@ export function RightSidebar() {
});
const [rotationDegrees, setRotationDegrees] = useState<number>(0);
const [isUserEditing, setIsUserEditing] = useState<boolean>(false);
const [iconSize, setIconSize] = useState<number>(100);
const [fontSize, setFontSize] = useState<number>(100);
const [isSaving, setIsSaving] = useState<boolean>(false);
@@ -53,7 +51,6 @@ export function RightSidebar() {
x: originalRouteData.center_latitude ?? 0,
y: originalRouteData.center_longitude ?? 0,
});
setIconSize(originalRouteData.icon_size ?? 100);
setFontSize(originalRouteData.font_size ?? 100);
}
}, [originalRouteData]);
@@ -97,15 +94,6 @@ export function RightSidebar() {
rotateToAngle((degrees * Math.PI) / 180);
}
const handleIconSizeChange = (value: number) => {
if (!Number.isFinite(value)) {
return;
}
const clamped = Math.max(1, Math.min(300, Math.round(value)));
setIconSize(clamped);
updateIconSize(clamped);
};
const handleFontSizeChange = (value: number) => {
if (!Number.isFinite(value)) {
return;
@@ -115,11 +103,6 @@ export function RightSidebar() {
updateFontSize(clamped);
};
useEffect(() => {
const next = routeData?.icon_size ?? originalRouteData?.icon_size ?? 100;
setIconSize((prev) => (Math.abs(prev - next) > 0.5 ? next : prev));
}, [routeData?.icon_size, originalRouteData?.icon_size]);
useEffect(() => {
const next = routeData?.font_size ?? originalRouteData?.font_size ?? 100;
setFontSize((prev) => (Math.abs(prev - next) > 0.5 ? next : prev));
@@ -307,33 +290,6 @@ export function RightSidebar() {
}}
/>
<TextField
type="number"
label="Размер иконок (%)"
variant="filled"
value={iconSize}
onChange={(e) => {
const value = Number(e.target.value);
if (!isNaN(value)) {
handleIconSizeChange(value);
}
}}
style={{ backgroundColor: "#222", borderRadius: 4 }}
sx={{
"& .MuiInputLabel-root": {
color: "#fff",
},
"& .MuiInputBase-input": {
color: "#fff",
},
}}
inputProps={{
min: 1,
max: 300,
step: 1,
}}
/>
<TextField
type="number"
label="Размер шрифта (%)"

View File

@@ -3,7 +3,7 @@ export interface RouteData {
carrier_id: number;
center_latitude: number;
center_longitude: number;
icon_size: number;
icon_size?: number;
font_size: number;
governor_appeal: number;
id: number;
@@ -34,6 +34,7 @@ export interface StationData {
city_id?: number;
description: string;
icon?: string;
icon_size?: number;
id: number;
latitude: number;
longitude: number;
@@ -51,25 +52,33 @@ export interface StationPatchData {
offset_y: number;
align: number;
transfers: StationTransferData;
icon_size?: number;
}
export interface SightPatchData {
sight_id: number;
latitude: number;
longitude: number;
icon_size?: number;
}
export interface SightData {
address: string;
alt_icon?: string | null; // uuid
city: string;
city_id: number;
id: number;
is_default_icon?: boolean;
icon?: string | null; // uuid
icon_size?: number;
latitude: number;
left_article: number;
longitude: number;
name: string;
offset_x?: number;
offset_y?: number;
preview_media: number;
thumbnail: string; // uuid
thumbnail?: string | null; // uuid
watermark_lu: string; // uuid
watermark_rd: string; // uuid
}