fix(gps): фильтр несогласованности скоростей против LBS-телепортов; fix: плейхед не закрывает balloon точек трека

This commit is contained in:
2026-08-28 10:33:45 +03:00
parent ac4f89d42e
commit 96e088c890
2 changed files with 54 additions and 9 deletions

View File

@@ -57,6 +57,7 @@ export function Yandex21Map({
const onReadyRef = useRef(onReady);
const onErrorRef = useRef(onError);
const onMapClickRef = useRef(onMapClick);
const placemarksRef = useRef(new Map<string, any>());
const markersByIdRef = useRef(new Map<string, GpsMapMarker>());
useEffect(() => {
onReadyRef.current = onReady;
@@ -189,7 +190,11 @@ export function Yandex21Map({
// (объектов немного — removeAll + добавить заново дёшево);
// колбэки кликов не входят в ключ — они читаются из ref в момент клика
const dataKey = JSON.stringify([
markers.map((m) => [m.id, m.lat, m.lng, m.color, m.kind, m.label, m.offline, !!m.onClick, m.zIndex, m.popup, m.noCluster, m.course]),
// Плейхед без координат: его перемещение не должно пересобирать коллекцию
// (иначе открытый balloon точки трека уничтожается ребилдом при seek)
markers.map((m) => m.id === 'playhead'
? [m.id, m.kind, m.color, m.zIndex]
: [m.id, m.lat, m.lng, m.color, m.kind, m.label, m.offline, !!m.onClick, m.zIndex, m.popup, m.noCluster, m.course]),
polygons.map((p) => [p.id, p.points, p.color, p.fillOpacity, p.strokeWidth]),
polylines.map((l) => [l.id, l.points, l.color, l.dashed]),
]);
@@ -199,6 +204,7 @@ export function Yandex21Map({
if (!mapReady || !collection || !clusterer) return;
collection.removeAll();
clusterer.removeAll();
placemarksRef.current.clear();
for (const p of polygons) {
if (p.points.length < 3) continue;
@@ -255,6 +261,7 @@ export function Yandex21Map({
// в обычную коллекцию (точки трека, старт/финиш, вершины геозон)
const clusterable = (m.kind === 'vehicle' || m.kind === 'person') && !m.noCluster;
const placemark = createPlacemark(m);
placemarksRef.current.set(String(m.id), placemark);
if (clusterable) {
clusterer.add(placemark);
} else {
@@ -264,6 +271,15 @@ export function Yandex21Map({
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [dataKey, mapReady]);
// Плейхед двигаем напрямую (без removeAll — иначе закрывается balloon)
const playhead = markers.find((m) => m.id === 'playhead');
useEffect(() => {
if (!mapReady || !playhead) return;
const pm = placemarksRef.current.get('playhead');
if (pm) pm.geometry?.setCoordinates([playhead.lat, playhead.lng]);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [playhead?.lat, playhead?.lng, mapReady]);
return (
<div className={className} style={{ position: 'relative' }}>
<div ref={containerRef} className="h-full w-full" />