From c5c5f835bcf6b6eb8d7f7670f8dc8e3a0c053009 Mon Sep 17 00:00:00 2001 From: itoshi Date: Thu, 27 Nov 2025 20:17:23 +0300 Subject: [PATCH] feat: update map `anchor for station` and `desciprtion search` --- .../WebGLRouteMapPrototype.tsx | 24 +++++++++++-- src/pages/Sight/LinkedStations.tsx | 35 ++++++++++++------- 2 files changed, 45 insertions(+), 14 deletions(-) diff --git a/src/pages/Route/route-preview/webgl-prototype/WebGLRouteMapPrototype.tsx b/src/pages/Route/route-preview/webgl-prototype/WebGLRouteMapPrototype.tsx index b9b2c32..9a1193e 100644 --- a/src/pages/Route/route-preview/webgl-prototype/WebGLRouteMapPrototype.tsx +++ b/src/pages/Route/route-preview/webgl-prototype/WebGLRouteMapPrototype.tsx @@ -364,8 +364,20 @@ const computeViewTransform = ( return { scale, translation }; }; +const getAnchorFromOffset = ( + offsetX: number, + offsetY: number +): { x: number; y: number } => { + const length = Math.hypot(offsetX, offsetY); + + const nx = offsetX / length; + const ny = offsetY / length; + + return { x: (1 - nx) / 2, y: (1 - ny) / 2 }; +}; + const backgroundColor = toColor(BACKGROUND_COLOR); -// Override route & station color to ED1C24 + const pathColor = toColor(0xed1c24); export const WebGLRouteMapPrototype = observer(() => { @@ -395,6 +407,7 @@ export const WebGLRouteMapPrototype = observer(() => { const transformRef = useRef(null); const lastTransformRef = useRef(null); const [transformState, setTransformState] = useState(null); + const clampTransformScale = useCallback((transform: Transform): Transform => { const { min, max } = scaleLimitsRef.current; const clampedScale = clamp(transform.scale, min, max); @@ -1904,6 +1917,11 @@ export const WebGLRouteMapPrototype = observer(() => { const labelY = (rotatedY + offsetY) * camera.scale + camera.translation.y; + const anchor = getAnchorFromOffset(offsetX, offsetY); + const transformCss = `translate(${-anchor.x * 100}%, ${ + -anchor.y * 100 + }%)`; + const dpr = Math.max(1, window.devicePixelRatio || 1); const cssX = labelX / dpr; const cssY = labelY / dpr; @@ -1919,8 +1937,10 @@ export const WebGLRouteMapPrototype = observer(() => { const fontSizePercent = routeData?.font_size ?? originalRouteData?.font_size ?? 100; const fontScale = fontSizePercent / 100; + const primaryFontSize = 16 * fontScale; const secondaryFontSize = 13 * fontScale; + const secondaryMarginTop = 5 * fontScale; const backendAlign = station.align; @@ -1972,7 +1992,7 @@ export const WebGLRouteMapPrototype = observer(() => { position: "absolute", left: cssX, top: cssY, - transform: "translate(0, -50%)", + transform: transformCss, color: "#fff", fontFamily: "Roboto, sans-serif", textAlign: "left", diff --git a/src/pages/Sight/LinkedStations.tsx b/src/pages/Sight/LinkedStations.tsx index 7a2f80a..76a3690 100644 --- a/src/pages/Sight/LinkedStations.tsx +++ b/src/pages/Sight/LinkedStations.tsx @@ -135,7 +135,10 @@ const LinkedStationsContentsInner = < const filteredAvailableItems = availableItems.filter((item) => { if (!searchQuery.trim()) return true; - return String(item.name).toLowerCase().includes(searchQuery.toLowerCase()); + const query = searchQuery.toLowerCase(); + const name = String(item.name || "").toLowerCase(); + const description = String(item.description || "").toLowerCase(); + return name.includes(query) || description.includes(query); }); useEffect(() => { @@ -483,6 +486,7 @@ const LinkedStationsContentsInner = < )} @@ -490,16 +494,15 @@ const LinkedStationsContentsInner = < option.id === value?.id } filterOptions={(options, { inputValue }) => { - const searchWords = inputValue - .toLowerCase() - .split(" ") - .filter(Boolean); + if (!inputValue.trim()) return options; + const query = inputValue.toLowerCase(); return options.filter((option) => { - const optionWords = String(option.name) - .toLowerCase() - .split(" "); - return searchWords.every((searchWord) => - optionWords.some((word) => word.startsWith(searchWord)) + const name = String(option.name || "").toLowerCase(); + const description = String( + option.description || "" + ).toLowerCase(); + return ( + name.includes(query) || description.includes(query) ); }); }} @@ -534,7 +537,7 @@ const LinkedStationsContentsInner = < label="Поиск остановок" value={searchQuery} onChange={(e) => setSearchQuery(e.target.value)} - placeholder="Введите название остановки..." + placeholder="Введите название или описание остановки..." size="small" /> @@ -550,11 +553,19 @@ const LinkedStationsContentsInner = < size="small" /> } - label={String(item.name)} + label={ +
+

{String(item.name)}

+

+ {String(item.description)} +

+
+ } sx={{ margin: 0, "& .MuiFormControlLabel-label": { fontSize: "0.9rem", + width: "100%", }, }} />