fix(geoportal): Google satellite, ESC/right-click exit, no UAT fill, ANCPI bbox fix
Basemaps: added Google Satellite option ANCPI ortofoto: fixed bbox conversion (all 4 corners, not just SW/NE) Selection: ESC key and right-click exit selection mode, tooltips updated UAT layers: removed fill (only lines + labels), less visual clutter Proprietari vechi: greyed out (opacity-50) so current owners stand out Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -31,12 +31,19 @@ function tileToBbox(z: number, x: number, y: number): [number, number, number, n
|
||||
return [lonW, latS, lonE, latN];
|
||||
}
|
||||
|
||||
/** Reproject WGS84 bbox to EPSG:3844 */
|
||||
/** Reproject WGS84 bbox to EPSG:3844 using all 4 corners (handles projection curvature) */
|
||||
function bboxTo3844(bbox4326: [number, number, number, number]): [number, number, number, number] {
|
||||
const [w, s, e, n] = bbox4326;
|
||||
const sw = proj4("EPSG:4326", "EPSG:3844", [w, s]);
|
||||
const ne = proj4("EPSG:4326", "EPSG:3844", [e, n]);
|
||||
return [sw[0]!, sw[1]!, ne[0]!, ne[1]!];
|
||||
// Project all 4 corners to handle non-linear projection
|
||||
const corners = [
|
||||
proj4("EPSG:4326", "EPSG:3844", [w, s]),
|
||||
proj4("EPSG:4326", "EPSG:3844", [e, s]),
|
||||
proj4("EPSG:4326", "EPSG:3844", [w, n]),
|
||||
proj4("EPSG:4326", "EPSG:3844", [e, n]),
|
||||
];
|
||||
const xs = corners.map((c) => c[0]!);
|
||||
const ys = corners.map((c) => c[1]!);
|
||||
return [Math.min(...xs), Math.min(...ys), Math.max(...xs), Math.max(...ys)];
|
||||
}
|
||||
|
||||
// Simple in-memory cookie cache for eTerra session
|
||||
|
||||
@@ -8,7 +8,8 @@ import type { BasemapId } from "../types";
|
||||
const BASEMAPS: { id: BasemapId; label: string; icon: typeof Map }[] = [
|
||||
{ id: "liberty", label: "Harta", icon: Map },
|
||||
{ id: "dark", label: "Dark", icon: Moon },
|
||||
{ id: "satellite", label: "Satelit", icon: Satellite },
|
||||
{ id: "google", label: "Satelit", icon: Satellite },
|
||||
{ id: "satellite", label: "ESRI", icon: Satellite },
|
||||
{ id: "orto", label: "ANCPI", icon: TreePine },
|
||||
];
|
||||
|
||||
|
||||
@@ -133,7 +133,11 @@ export function FeatureInfoPanel({ feature, onClose }: FeatureInfoPanelProps) {
|
||||
<>
|
||||
<div className="border-t pt-1.5 mt-1.5" />
|
||||
<WrapRow label="Proprietari" value={e?.PROPRIETARI} />
|
||||
<WrapRow label="Proprietari vechi" value={e?.PROPRIETARI_VECHI} />
|
||||
{e?.PROPRIETARI_VECHI && e.PROPRIETARI_VECHI !== "-" && (
|
||||
<div className="opacity-50">
|
||||
<WrapRow label="Proprietari vechi" value={e.PROPRIETARI_VECHI} />
|
||||
</div>
|
||||
)}
|
||||
<Row label="Intravilan" value={e?.INTRAVILAN} />
|
||||
<Row label="Categorie" value={e?.CATEGORIE_FOLOSINTA} />
|
||||
<WrapRow label="Adresa" value={e?.ADRESA} />
|
||||
|
||||
@@ -80,6 +80,13 @@ const BASEMAPS: Record<BasemapId, BasemapDef> = {
|
||||
attribution: '© <a href="https://www.esri.com">Esri</a>, Maxar',
|
||||
tileSize: 256,
|
||||
},
|
||||
google: {
|
||||
type: "raster",
|
||||
tiles: ["https://mt0.google.com/vt/lyrs=s&x={x}&y={y}&z={z}"],
|
||||
attribution: '© Google',
|
||||
tileSize: 256,
|
||||
maxzoom: 20,
|
||||
},
|
||||
orto: {
|
||||
type: "raster",
|
||||
tiles: ["/api/eterra/tiles/orto?z={z}&x={x}&y={y}"],
|
||||
@@ -383,15 +390,11 @@ export const MapViewer = forwardRef<MapViewerHandle, MapViewerProps>(
|
||||
|
||||
// === UAT z5-8: coarse ===
|
||||
map.addSource(SOURCES.uatsZ5, { type: "vector", tiles: [`${m}/${SOURCES.uatsZ5}/{z}/{x}/{y}`], minzoom: 5, maxzoom: 8 });
|
||||
map.addLayer({ id: LAYER_IDS.uatsZ5Fill, type: "fill", source: SOURCES.uatsZ5, "source-layer": SOURCES.uatsZ5, minzoom: 5, maxzoom: 8,
|
||||
paint: { "fill-color": "#8b5cf6", "fill-opacity": 0.03 } });
|
||||
map.addLayer({ id: LAYER_IDS.uatsZ5Line, type: "line", source: SOURCES.uatsZ5, "source-layer": SOURCES.uatsZ5, minzoom: 5, maxzoom: 8,
|
||||
paint: { "line-color": "#7c3aed", "line-width": 0.6 } });
|
||||
|
||||
// === UAT z8-12: moderate ===
|
||||
map.addSource(SOURCES.uatsZ8, { type: "vector", tiles: [`${m}/${SOURCES.uatsZ8}/{z}/{x}/{y}`], minzoom: 8, maxzoom: 12 });
|
||||
map.addLayer({ id: LAYER_IDS.uatsZ8Fill, type: "fill", source: SOURCES.uatsZ8, "source-layer": SOURCES.uatsZ8, minzoom: 8, maxzoom: 12,
|
||||
paint: { "fill-color": "#8b5cf6", "fill-opacity": 0.05 } });
|
||||
map.addLayer({ id: LAYER_IDS.uatsZ8Line, type: "line", source: SOURCES.uatsZ8, "source-layer": SOURCES.uatsZ8, minzoom: 8, maxzoom: 12,
|
||||
paint: { "line-color": "#7c3aed", "line-width": 1 } });
|
||||
map.addLayer({ id: LAYER_IDS.uatsZ8Label, type: "symbol", source: SOURCES.uatsZ8, "source-layer": SOURCES.uatsZ8, minzoom: 9, maxzoom: 12,
|
||||
@@ -400,8 +403,6 @@ export const MapViewer = forwardRef<MapViewerHandle, MapViewerProps>(
|
||||
|
||||
// === UAT z12+: full detail (no simplification) ===
|
||||
map.addSource(SOURCES.uatsZ12, { type: "vector", tiles: [`${m}/${SOURCES.uatsZ12}/{z}/{x}/{y}`], minzoom: 12, maxzoom: 16 });
|
||||
map.addLayer({ id: LAYER_IDS.uatsZ12Fill, type: "fill", source: SOURCES.uatsZ12, "source-layer": SOURCES.uatsZ12, minzoom: 12,
|
||||
paint: { "fill-color": "#8b5cf6", "fill-opacity": 0.08 } });
|
||||
map.addLayer({ id: LAYER_IDS.uatsZ12Line, type: "line", source: SOURCES.uatsZ12, "source-layer": SOURCES.uatsZ12, minzoom: 12,
|
||||
paint: { "line-color": "#7c3aed", "line-width": 2 } });
|
||||
map.addLayer({ id: LAYER_IDS.uatsZ12Label, type: "symbol", source: SOURCES.uatsZ12, "source-layer": SOURCES.uatsZ12, minzoom: 12,
|
||||
@@ -473,7 +474,6 @@ export const MapViewer = forwardRef<MapViewerHandle, MapViewerProps>(
|
||||
/* ---- Click handler — NO popup, only callback ---- */
|
||||
const clickableLayers = [
|
||||
LAYER_IDS.terenuriFill, LAYER_IDS.cladiriFill,
|
||||
LAYER_IDS.uatsZ5Fill, LAYER_IDS.uatsZ8Fill, LAYER_IDS.uatsZ12Fill,
|
||||
];
|
||||
|
||||
map.on("click", (e) => {
|
||||
@@ -685,6 +685,25 @@ export const MapViewer = forwardRef<MapViewerHandle, MapViewerProps>(
|
||||
canvas.addEventListener("mousemove", onRectMouseMove);
|
||||
canvas.addEventListener("mouseup", onRectMouseUp);
|
||||
|
||||
/* ---- ESC key exits selection mode ---- */
|
||||
const onKeyDown = (e: KeyboardEvent) => {
|
||||
if (e.key === "Escape" && selectionTypeRef.current !== "off") {
|
||||
onFeatureClick?.(null as unknown as ClickedFeature);
|
||||
clearDrawState();
|
||||
// Notify parent to turn off selection
|
||||
onSelectionChange?.([]);
|
||||
}
|
||||
};
|
||||
document.addEventListener("keydown", onKeyDown);
|
||||
|
||||
/* ---- Right-click exits selection / cancels draw ---- */
|
||||
map.on("contextmenu", (e) => {
|
||||
if (selectionTypeRef.current !== "off") {
|
||||
e.preventDefault();
|
||||
clearDrawState();
|
||||
}
|
||||
});
|
||||
|
||||
/* ---- Cursor change ---- */
|
||||
for (const lid of clickableLayers) {
|
||||
map.on("mouseenter", lid, () => { map.getCanvas().style.cursor = "pointer"; });
|
||||
@@ -693,6 +712,7 @@ export const MapViewer = forwardRef<MapViewerHandle, MapViewerProps>(
|
||||
|
||||
/* ---- Cleanup ---- */
|
||||
return () => {
|
||||
document.removeEventListener("keydown", onKeyDown);
|
||||
canvas.removeEventListener("mousedown", onRectMouseDown);
|
||||
canvas.removeEventListener("mousemove", onRectMouseMove);
|
||||
canvas.removeEventListener("mouseup", onRectMouseUp);
|
||||
|
||||
@@ -29,9 +29,9 @@ const EXPORT_FORMATS: { id: ExportFormat; label: string }[] = [
|
||||
];
|
||||
|
||||
const MODE_BUTTONS: { mode: SelectionMode; icon: typeof MousePointerClick; label: string; tooltip: string }[] = [
|
||||
{ mode: "click", icon: MousePointerClick, label: "Click", tooltip: "Click pe parcele individuale pentru a le selecta/deselecta" },
|
||||
{ mode: "rect", icon: Square, label: "Dreptunghi", tooltip: "Trage un dreptunghi pe harta pentru a selecta toate parcelele din zona" },
|
||||
{ mode: "freehand", icon: PenTool, label: "Desen", tooltip: "Deseneaza o zona libera pe harta (click puncte, dublu-click pentru a inchide)" },
|
||||
{ mode: "click", icon: MousePointerClick, label: "Click", tooltip: "Click pe parcele individuale. ESC sau right-click pentru a iesi." },
|
||||
{ mode: "rect", icon: Square, label: "Dreptunghi", tooltip: "Trage un dreptunghi pe harta. ESC sau right-click pentru a anula." },
|
||||
{ mode: "freehand", icon: PenTool, label: "Desen", tooltip: "Click puncte pe harta, dublu-click inchide. ESC sau right-click anuleaza." },
|
||||
];
|
||||
|
||||
export function SelectionToolbar({
|
||||
|
||||
@@ -46,7 +46,7 @@ export type MapViewState = {
|
||||
/* Basemap */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
export type BasemapId = "liberty" | "dark" | "satellite" | "orto";
|
||||
export type BasemapId = "liberty" | "dark" | "satellite" | "google" | "orto";
|
||||
|
||||
export type BasemapDef = {
|
||||
id: BasemapId;
|
||||
|
||||
Reference in New Issue
Block a user