fix(gps): клик по точке открывает попап с названием (делегирование только по data-gps-action); спайдерфай кластеров в одной координате на max zoom
This commit is contained in:
@@ -84,7 +84,8 @@ export function OsmMap({
|
||||
iconCreateFunction: (cluster) =>
|
||||
L.divIcon({ html: gpsClusterHtml(cluster.getChildCount()), className: '', iconSize: [0, 0] }),
|
||||
zoomToBoundsOnClick: false,
|
||||
spiderfyOnMaxZoom: false,
|
||||
// Точки в одной координате («3») на max zoom раскрываются «паучком»
|
||||
spiderfyOnMaxZoom: true,
|
||||
showCoverageOnHover: false,
|
||||
}).addTo(map);
|
||||
clusterLayerRef.current = clusterLayer;
|
||||
@@ -113,9 +114,11 @@ export function OsmMap({
|
||||
// Делегированный клик по пункту списка кластера в popup
|
||||
// (контент popup рендерится внутри контейнера карты)
|
||||
map.getContainer().addEventListener('click', (ev) => {
|
||||
const el = (ev.target as HTMLElement | null)?.closest?.('[data-gps-marker-id]') as HTMLElement | null;
|
||||
const el = (ev.target as HTMLElement | null)?.closest?.('[data-gps-action]') as HTMLElement | null;
|
||||
if (!el) return;
|
||||
const marker = markersByIdRef.current.get(el.dataset.gpsMarkerId || '');
|
||||
const action = el.dataset.gpsAction || '';
|
||||
if (!action.startsWith('open:')) return;
|
||||
const marker = markersByIdRef.current.get(action.slice(5));
|
||||
if (marker?.onClick) {
|
||||
marker.onClick();
|
||||
map.closePopup();
|
||||
|
||||
@@ -170,9 +170,11 @@ export function Yandex21Map({
|
||||
const container = containerRef.current;
|
||||
if (!mapReady || !container) return;
|
||||
const handler = (ev: MouseEvent) => {
|
||||
const el = (ev.target as HTMLElement | null)?.closest?.('[data-gps-marker-id]') as HTMLElement | null;
|
||||
const el = (ev.target as HTMLElement | null)?.closest?.('[data-gps-action]') as HTMLElement | null;
|
||||
if (!el) return;
|
||||
const marker = markersByIdRef.current.get(el.dataset.gpsMarkerId || '');
|
||||
const action = el.dataset.gpsAction || '';
|
||||
if (!action.startsWith('open:')) return;
|
||||
const marker = markersByIdRef.current.get(action.slice(5));
|
||||
if (marker?.onClick) {
|
||||
marker.onClick();
|
||||
mapRef.current?.balloon.close();
|
||||
|
||||
@@ -94,9 +94,10 @@ export function gpsMarkerHtml(marker: GpsMapMarker): string {
|
||||
}
|
||||
}
|
||||
|
||||
// data-gps-marker-id: делегированный обработчик контейнера карты ловит клики
|
||||
// по любому маркеру (надёжнее нативных событий placemark/divIcon)
|
||||
return `<div data-gps-marker-id="${escapeHtml(String(marker.id))}" style="display:flex;flex-direction:column;align-items:center;width:${layout.width}px;user-select:none;cursor:pointer;${opacity}">${body}${label}</div>`;
|
||||
// data-* атрибута на корне НЕТ намеренно: делегированный обработчик ловит
|
||||
// только кнопки с data-gps-action (список кластера, «Открыть задачу» в попапе),
|
||||
// иначе клик по точке сразу вызывал onClick и глушил открытие попапа
|
||||
return `<div style="display:flex;flex-direction:column;align-items:center;width:${layout.width}px;user-select:none;cursor:pointer;${opacity}">${body}${label}</div>`;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -119,7 +120,7 @@ export function gpsClusterHtml(count: number | string): string {
|
||||
export function gpsClusterListHtml(markers: GpsMapMarker[]): string {
|
||||
const rows = markers
|
||||
.map(
|
||||
(m) => `<button type="button" data-gps-marker-id="${escapeHtml(String(m.id))}" style="display:flex;align-items:center;gap:6px;width:100%;padding:4px 6px;border:0;background:none;cursor:pointer;font-size:12px;text-align:left;border-radius:4px;">
|
||||
(m) => `<button type="button" data-gps-action="open:${escapeHtml(String(m.id))}" style="display:flex;align-items:center;gap:6px;width:100%;padding:4px 6px;border:0;background:none;cursor:pointer;font-size:12px;text-align:left;border-radius:4px;">
|
||||
<span style="width:10px;height:10px;border-radius:50%;background:${m.color || DEFAULT_COLOR};border:1px solid #fff;box-shadow:0 0 1px rgba(0,0,0,0.4);flex-shrink:0;"></span>
|
||||
<span style="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;">${escapeHtml(m.clusterLabel || m.label || 'Объект')}</span>
|
||||
</button>`
|
||||
|
||||
@@ -236,7 +236,7 @@ export function GpsMapTab({ onShowRoute }: { onShowRoute: (assetId: number) => v
|
||||
const st = shortTitle(t.title);
|
||||
// Попап по клику: название (две строки) + кнопка «Открыть задачу».
|
||||
// Работает и при выключенных подписях — название видно по клику.
|
||||
const popup = `<div style="max-width:220px;"><b>${esc(st.line1)}</b>${st.line2 ? `<div style="color:#52525b;font-size:11px;">${esc(st.line2)}</div>` : ''}<button type="button" data-gps-marker-id="task-${t.id}" style="margin-top:6px;font-size:11px;color:#2563eb;background:none;border:0;cursor:pointer;padding:0;">Открыть задачу</button></div>`;
|
||||
const popup = `<div style="max-width:220px;"><b>${esc(st.line1)}</b>${st.line2 ? `<div style="color:#52525b;font-size:11px;">${esc(st.line2)}</div>` : ''}<button type="button" data-gps-action="open:task-${t.id}" style="margin-top:6px;font-size:11px;color:#2563eb;background:none;border:0;cursor:pointer;padding:0;">Открыть задачу</button></div>`;
|
||||
markers.push({
|
||||
id: `task-${t.id}`,
|
||||
lat: geo.lat,
|
||||
|
||||
Reference in New Issue
Block a user