ui: update map to receive initial value

This commit is contained in:
Sosokker 2025-04-04 15:25:35 +07:00
parent df38e1c9f2
commit 3ee9b92ce7

View File

@ -1,52 +1,160 @@
// google-map-with-drawing.tsx import React, { useEffect, useRef, useState } from "react";
import React from "react"; import { Map, useMap, useMapsLibrary, MapControl, ControlPosition } from "@vis.gl/react-google-maps";
import { ControlPosition, Map, MapControl } from "@vis.gl/react-google-maps";
import { UndoRedoControl } from "@/components/map-component/undo-redo-control"; import { UndoRedoControl } from "@/components/map-component/undo-redo-control";
// Import ShapeData and useDrawingManager from the correct path import { useDrawingManager } from "@/components/map-component/use-drawing-manager";
import { useDrawingManager, type ShapeData } from "@/components/map-component/use-drawing-manager"; // Adjust path if needed import { GeoFeatureData, GeoPosition } from "@/types";
// Export the type so the form can use it export type ShapeData = GeoFeatureData;
export { type ShapeData };
// Define props for the component
interface GoogleMapWithDrawingProps { interface GoogleMapWithDrawingProps {
onShapeDrawn: (data: ShapeData) => void; // Callback prop onShapeDrawn?: (data: GeoFeatureData) => void;
// Add any other props you might need, e.g., initialCenter, initialZoom initialCenter?: GeoPosition;
initialCenter?: { lat: number; lng: number };
initialZoom?: number; 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 GoogleMapWithDrawingInternal = ({
const GoogleMapWithDrawing = ({ onShapeDrawn,
onShapeDrawn, // Destructure the callback prop initialCenter = { lat: 13.7563, lng: 100.5018 },
initialCenter = { lat: 13.7563, lng: 100.5018 }, // Default center initialZoom = 10,
initialZoom = 10, // Default zoom initialFeatures,
drawingMode = null,
editable = true,
displayOnly = false,
}: GoogleMapWithDrawingProps) => { }: 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); 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 ( return (
<> <>
{/* Use props for map defaults */}
<Map <Map
defaultZoom={initialZoom} defaultZoom={initialZoom}
defaultCenter={initialCenter} defaultCenter={initialCenter}
gestureHandling={"greedy"} gestureHandling={"greedy"}
disableDefaultUI={true} disableDefaultUI={true}
mapId={"YOUR_MAP_ID"} // Recommended: Add a Map ID mapId={"YOUR_MAP_ID"}
/> />
{/* Render controls only if drawingManager is available */} {!displayOnly && drawingManager && (
{drawingManager && (
<MapControl position={ControlPosition.TOP_LEFT}> <MapControl position={ControlPosition.TOP_LEFT}>
{/* Pass drawingManager to UndoRedoControl */} {editable && <UndoRedoControl drawingManager={drawingManager} />}
<UndoRedoControl drawingManager={drawingManager} />
</MapControl> </MapControl>
)} )}
{/* The drawing controls (marker, polygon etc.) are added by useDrawingManager */}
</> </>
); );
}; };
const GoogleMapWithDrawing = (props: GoogleMapWithDrawingProps) => {
return <GoogleMapWithDrawingInternal {...props} />;
};
export default GoogleMapWithDrawing; export default GoogleMapWithDrawing;