feat: update map anchor for station and desciprtion search
This commit is contained in:
@@ -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<Transform | null>(null);
|
||||
const lastTransformRef = useRef<Transform | null>(null);
|
||||
const [transformState, setTransformState] = useState<Transform | null>(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",
|
||||
|
||||
@@ -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 = <
|
||||
<TextField
|
||||
{...params}
|
||||
label="Выберите остановку"
|
||||
placeholder="Введите название или описание остановки..."
|
||||
fullWidth
|
||||
/>
|
||||
)}
|
||||
@@ -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={
|
||||
<div className="flex justify-between items-center w-full gap-10">
|
||||
<p>{String(item.name)}</p>
|
||||
<p className="text-xs text-gray-500 max-w-[300px] truncate text-ellipsis">
|
||||
{String(item.description)}
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
sx={{
|
||||
margin: 0,
|
||||
"& .MuiFormControlLabel-label": {
|
||||
fontSize: "0.9rem",
|
||||
width: "100%",
|
||||
},
|
||||
}}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user