Keep flight map route endpoints visible

This commit is contained in:
2026-04-30 17:48:15 +03:00
parent a29cdb8018
commit 297a3f659a
2 changed files with 60 additions and 3 deletions
@@ -507,6 +507,50 @@ describe("MapCanvas — polylines (C.3)", () => {
expect(createdPolylines.length).toBe(afterInitialRender);
});
it("keeps drawn route endpoints visible even when their zoom tier is hidden", () => {
render(
<MapCanvas
markers={[
cm("A", "ru", { highlighted: true }),
cm("B", "ru", { zoomLevel: 6 }),
]}
polylines={[pl("line", ["A", "B"])]}
tileUrl="t"
/>,
);
const map = createdMaps[0]!;
map.setZoom(3);
map.fireZoomend();
const endpoint = createdMarkers.find((m) => m.options.title === "B")!;
const owningLayer = createdLayerGroups.find((l) => l._markers.includes(endpoint));
expect(owningLayer).toBeDefined();
const addedToMap =
map.addLayer.mock.calls.map((c) => c[0]).includes(owningLayer!) ||
owningLayer!.addTo.mock.calls.length > 0;
expect(addedToMap).toBe(true);
});
it("force-opens drawn route endpoint tooltips at zoom <= 3", () => {
render(
<MapCanvas
markers={[
cm("A", "ru", { highlighted: true }),
cm("B", "ru", { zoomLevel: 6 }),
]}
polylines={[pl("line", ["A", "B"])]}
tileUrl="t"
/>,
);
const map = createdMaps[0]!;
map.setZoom(3);
map.fireZoomend();
const endpoint = createdMarkers.find((m) => m.options.title === "B")!;
expect(endpoint.openTooltip).toHaveBeenCalled();
});
it("silently skips polylines with unknown city codes", () => {
render(
<MapCanvas
@@ -183,6 +183,7 @@ export const MapCanvas: FC<MapCanvasProps> = ({
const markerIndexRef = useRef<Map<string, L.Marker>>(new Map());
const highlightedIdsRef = useRef<Set<string>>(new Set());
const intermediateIdsRef = useRef<Set<string>>(new Set());
const routeEndpointIdsRef = useRef<Set<string>>(new Set());
// Track latest toggles so the zoomend handler sees current values
const domesticRef = useRef(domestic);
@@ -247,8 +248,13 @@ export const MapCanvas: FC<MapCanvasProps> = ({
}
});
// Pass 2: force-open intermediate route tooltips (Angular parity).
for (const id of intermediateIdsRef.current) {
// Pass 2: force-open visible route labels. Intermediate cities and
// currently drawn endpoints must stay readable even when LOD hides labels.
const forcedTooltipIds = new Set([
...intermediateIdsRef.current,
...routeEndpointIdsRef.current,
]);
for (const id of forcedTooltipIds) {
const m = markerIndexRef.current.get(id);
if (m) m.openTooltip();
}
@@ -351,6 +357,7 @@ export const MapCanvas: FC<MapCanvasProps> = ({
markerIndexRef.current = new Map();
highlightedIdsRef.current = new Set();
intermediateIdsRef.current = new Set();
routeEndpointIdsRef.current = new Set();
};
}, []);
@@ -371,10 +378,14 @@ export const MapCanvas: FC<MapCanvasProps> = ({
}
markerIndexRef.current = new Map();
highlightedIdsRef.current = new Set();
routeEndpointIdsRef.current = new Set(
polylines.flatMap((pl) => pl.cityIds),
);
for (const m of markers) {
const isCategorized =
m.zoomLevel !== undefined && m.countryType !== undefined;
const isRouteEndpoint = routeEndpointIdsRef.current.has(m.id);
const iconStyle: MarkerStyle = m.highlighted ? "orange" : m.style;
const marker = L.marker([m.lat, m.lng], {
@@ -399,6 +410,8 @@ export const MapCanvas: FC<MapCanvasProps> = ({
if (m.highlighted) {
highlightedIdsRef.current.add(m.id);
marker.addTo(highlightLayer);
} else if (isRouteEndpoint) {
marker.addTo(highlightLayer);
} else if (isCategorized) {
const countryIdx = m.countryType === "ru" ? 0 : 1;
const rawTier = m.zoomLevel ?? 6;
@@ -413,7 +426,7 @@ export const MapCanvas: FC<MapCanvasProps> = ({
syncVisibility();
syncTooltips();
}, [markers]);
}, [markers, polylines]);
useEffect(() => {
syncMarkers();