+
+
+
+
+ {/* Base layers — only one mounted at a time (key forces tile swap). */}
+ {base === "sat" ? (
+
+ ) : (
+
+ )}
+
+ {/* ЗОУИТ охранные зоны — background fill (under markers). */}
+ {visible.has("zouit") && zouitCount > 0 && (
+
+ )}
+
+ {/* Competitors (ЖК) + pipeline (будущие проекты). */}
+ {(visible.has("competitors") || visible.has("pipeline")) && (
+
+ )}
+
+ {/* POI markers (Школы·Детсады / Парки·Метро). */}
+ {(["edu", "greenmetro"] as PoiBucket[]).flatMap((bucket) => {
+ if (!visible.has(bucket)) return [];
+ const style = POI_BUCKET_STYLES[bucket];
+ return poiByBucket[bucket].map((poi, idx) => (
+
+
+ {poi.name ?? style.label} · {formatMeters(poi.distance_m)}
+
+
+ ));
+ })}
+
+ {/* Connection points + polylines to the parcel centroid. */}
+ {visible.has("connections") && connectionPoints && (
+ <>
+ {connectionLines.map((line, idx) => (
+
+ ))}
+
+ >
+ )}
+
+ {/* Parcel polygon — cyan, on top of fills so it always reads. */}
+ {visible.has("parcel") && geom && (
)}
+
+ {/* Custom POI — topmost; add/edit/delete wired to useCustomPois. */}
+ {visible.has("custompoi") && customPoiList.length > 0 && (
+ setEditingPoi(poi)}
+ onDelete={(id) => deleteMutation.mutate(id)}
+ />
+ )}
+
+ {/* ── Legend / layer-toggle overlay ────────────────────────────────────── */}
+
+
+
+ {base === "sat" ? "Спутник · свежий снимок" : "Схема · тёмная карта"}
+
+
+
+
+
+
+
+
+
toggleLayer("parcel")}
+ />
+ toggleLayer("competitors")}
+ />
+ toggleLayer("pipeline")}
+ />
+ toggleLayer("edu")}
+ />
+ toggleLayer("greenmetro")}
+ />
+ {zouitCount > 0 && (
+ toggleLayer("zouit")}
+ />
+ )}
+ toggleLayer("connections")}
+ />
+ {/* Изохроны — реальный источник (ORS) пока вне /analyze: «скоро». */}
+
+
+ Изохроны доступности
+ скоро
+
+ toggleLayer("custompoi")}
+ />
+ {onOpenDrawer && (
+
+ )}
+
+
+ {cpCount > 0 && (
+ <>
+
+
Точки подключения ресурсов
+ {CP_ALL_CATEGORIES.filter((c) => cpNearest.has(c)).map((catKey) => {
+ const dist = cpNearest.get(catKey);
+ if (dist === undefined) return null;
+ const style = CP_CATEGORY_STYLES[catKey];
+ return (
+
+
+ {style.label}
+ {formatMeters(dist)}
+
+ );
+ })}
+ >
+ )}
+
+
+ {/* ── Map tools (add-POI · 3D) ─────────────────────────────────────────── */}
+
+
+ {onOpenDrawer && (
+
+ )}
+
+
+ {addMode && (
+
Кликните на карте для точки
+ )}
+
+ {/* Add / edit modals (reuse the analysis-map custom-POI flow). */}
+ {pendingCoords && (
+
{
+ addMutation.mutate(payload, {
+ onSuccess: () => setPendingCoords(null),
+ });
+ }}
+ onCancel={() => setPendingCoords(null)}
+ />
+ )}
+ {editingPoi && (
+ {
+ updateMutation.mutate(
+ { id: editingPoi.id, data: updateData },
+ { onSuccess: () => setEditingPoi(null) },
+ );
+ }}
+ onCancel={() => setEditingPoi(null)}
+ />
+ )}
);
}
+
+// ── Legend row (toggle button) ─────────────────────────────────────────────────
+
+function LegendRow({
+ color,
+ label,
+ count,
+ on,
+ onToggle,
+}: {
+ color: string;
+ label: string;
+ count: number;
+ on: boolean;
+ onToggle: () => void;
+}) {
+ return (
+