From 3ee9b92ce7471c0f33e02f71e87498f4b0d323eb Mon Sep 17 00:00:00 2001 From: Sosokker Date: Fri, 4 Apr 2025 15:25:35 +0700 Subject: [PATCH] ui: update map to receive initial value --- .../components/google-map-with-drawing.tsx | 158 +++++++++++++++--- 1 file changed, 133 insertions(+), 25 deletions(-) diff --git a/frontend/components/google-map-with-drawing.tsx b/frontend/components/google-map-with-drawing.tsx index 0cdd310..91bfcca 100644 --- a/frontend/components/google-map-with-drawing.tsx +++ b/frontend/components/google-map-with-drawing.tsx @@ -1,52 +1,160 @@ -// google-map-with-drawing.tsx -import React from "react"; -import { ControlPosition, Map, MapControl } from "@vis.gl/react-google-maps"; - +import React, { useEffect, useRef, useState } from "react"; +import { Map, useMap, useMapsLibrary, MapControl, ControlPosition } from "@vis.gl/react-google-maps"; import { UndoRedoControl } from "@/components/map-component/undo-redo-control"; -// Import ShapeData and useDrawingManager from the correct path -import { useDrawingManager, type ShapeData } from "@/components/map-component/use-drawing-manager"; // Adjust path if needed +import { useDrawingManager } from "@/components/map-component/use-drawing-manager"; +import { GeoFeatureData, GeoPosition } from "@/types"; -// Export the type so the form can use it -export { type ShapeData }; +export type ShapeData = GeoFeatureData; -// Define props for the component interface GoogleMapWithDrawingProps { - onShapeDrawn: (data: ShapeData) => void; // Callback prop - // Add any other props you might need, e.g., initialCenter, initialZoom - initialCenter?: { lat: number; lng: number }; + onShapeDrawn?: (data: GeoFeatureData) => void; + initialCenter?: GeoPosition; initialZoom?: number; + initialFeatures?: GeoFeatureData[] | null; + drawingMode?: google.maps.drawing.OverlayType | null; + editable?: boolean; + displayOnly?: boolean; + mapId?: string; } -// Rename DrawingExample to GoogleMapWithDrawing and accept props -const GoogleMapWithDrawing = ({ - onShapeDrawn, // Destructure the callback prop - initialCenter = { lat: 13.7563, lng: 100.5018 }, // Default center - initialZoom = 10, // Default zoom +const GoogleMapWithDrawingInternal = ({ + onShapeDrawn, + initialCenter = { lat: 13.7563, lng: 100.5018 }, + initialZoom = 10, + initialFeatures, + drawingMode = null, + editable = true, + displayOnly = false, }: GoogleMapWithDrawingProps) => { - // Pass the onShapeDrawn callback directly to the hook + const map = useMap(); + const geometryLib = useMapsLibrary("geometry"); + const [drawnOverlays, setDrawnOverlays] = useState< + (google.maps.Marker | google.maps.Polygon | google.maps.Polyline)[] + >([]); + const isMountedRef = useRef(false); + const drawingManager = useDrawingManager(onShapeDrawn); + useEffect(() => { + if (!map || !initialFeatures || initialFeatures.length === 0 || !geometryLib) return; + if (isMountedRef.current && !displayOnly) return; + + drawnOverlays.forEach((overlay) => overlay.setMap(null)); + const newOverlays: (google.maps.Marker | google.maps.Polygon | google.maps.Polyline)[] = []; + const bounds = new google.maps.LatLngBounds(); + + initialFeatures.forEach((feature) => { + if (!feature) return; + + let overlay: google.maps.Marker | google.maps.Polygon | google.maps.Polyline | null = null; + + try { + if (feature.type === "marker" && feature.position) { + const marker = new google.maps.Marker({ + position: feature.position, + map: map, + }); + bounds.extend(feature.position); + overlay = marker; + } else if (feature.type === "polygon" && feature.path && feature.path.length > 0) { + const polygon = new google.maps.Polygon({ + paths: feature.path, + map: map, + strokeColor: "#FF0000", + strokeOpacity: 0.8, + strokeWeight: 2, + fillColor: "#FF0000", + fillOpacity: 0.35, + }); + feature.path.forEach((pos) => bounds.extend(pos)); + overlay = polygon; + } else if (feature.type === "polyline" && feature.path && feature.path.length > 0) { + const polyline = new google.maps.Polyline({ + path: feature.path, + map: map, + strokeColor: "#0000FF", + strokeOpacity: 1.0, + strokeWeight: 3, + }); + feature.path.forEach((pos) => bounds.extend(pos)); + overlay = polyline; + } + + if (overlay) { + newOverlays.push(overlay); + } + } catch (e) { + console.error("Error creating map overlay:", e, "Feature:", feature); + } + }); + + setDrawnOverlays(newOverlays); + + if (newOverlays.length === 1 && initialFeatures[0]?.type === "marker") { + map.setCenter(initialFeatures[0].position); + map.setZoom(initialZoom + 4); + } else if (!bounds.isEmpty()) { + map.fitBounds(bounds); + } else { + map.setCenter(initialCenter); + map.setZoom(initialZoom); + } + isMountedRef.current = true; + + return () => { + newOverlays.forEach((overlay) => { + try { + overlay.setMap(null); + } catch (e) { + console.warn("Error removing overlay during cleanup:", e); + } + }); + setDrawnOverlays([]); + isMountedRef.current = false; + }; + }, [map, initialFeatures, geometryLib, displayOnly]); + + useEffect(() => { + if (drawingManager) { + drawingManager.setOptions({ + drawingControl: !displayOnly, + drawingMode: displayOnly ? null : drawingMode, + markerOptions: { + draggable: !displayOnly && editable, + }, + polygonOptions: { + editable: !displayOnly && editable, + draggable: !displayOnly && editable, + }, + polylineOptions: { + editable: !displayOnly && editable, + draggable: !displayOnly && editable, + }, + }); + } + }, [drawingManager, displayOnly, drawingMode, editable]); + return ( <> - {/* Use props for map defaults */} - {/* Render controls only if drawingManager is available */} - {drawingManager && ( + {!displayOnly && drawingManager && ( - {/* Pass drawingManager to UndoRedoControl */} - + {editable && } )} - {/* The drawing controls (marker, polygon etc.) are added by useDrawingManager */} ); }; +const GoogleMapWithDrawing = (props: GoogleMapWithDrawingProps) => { + return ; +}; + export default GoogleMapWithDrawing;