"use client"; import { useAtom } from "jotai"; import { MapPinIcon, SlashIcon, Scale3DIcon } from "lucide-react"; import { useState, useEffect, useRef } from "react"; import { mapAtom } from "../../../state/map"; import L, { DrawMap } from "leaflet"; import "leaflet-draw"; import "leaflet-draw/dist/leaflet.draw.css"; import * as turf from "@turf/turf"; export default function DrawingTools() { const [map] = useAtom(mapAtom); const [activeTab, setActiveTab] = useState< "location" | "edit" | "expand" | null >(null); // Refs untuk menyimpan instance drawing tools dan layer group const drawnItemsRef = useRef(null); const drawingToolsRef = useRef<{ marker: L.Draw.Marker | null; polyline: L.Draw.Polyline | null; polygon: L.Draw.Polygon | null; }>({ marker: null, polyline: null, polygon: null, }); // Inisialisasi layer group dan events useEffect(() => { if (!map) return; // Buat FeatureGroup untuk items yang digambar const drawnItems = new L.FeatureGroup(); map.addLayer(drawnItems); drawnItemsRef.current = drawnItems; // Inisialisasi drawing tools drawingToolsRef.current = { marker: new L.Draw.Marker(map as DrawMap, { icon: new L.Icon.Default(), }), polyline: new L.Draw.Polyline(map as DrawMap, { shapeOptions: { color: "#3388ff", weight: 4, opacity: 0.7, }, }), polygon: new L.Draw.Polygon(map as DrawMap, { shapeOptions: { color: "#f03", fillColor: "#f03", fillOpacity: 0.3, weight: 3, }, showArea: true, }), }; // Menangani event ketika objek selesai digambar // eslint-disable-next-line @typescript-eslint/no-explicit-any map.on(L.Draw.Event.CREATED, function (e: any) { const layer = e.layer; // Tambahkan layer ke drawnItems drawnItems.addLayer(layer); // Tambahkan popup informasi berdasarkan tipe layer if (layer instanceof L.Marker) { addMarkerPopup(layer); } else if (layer instanceof L.Polyline && !(layer instanceof L.Polygon)) { addPolylinePopup(layer); } else if (layer instanceof L.Polygon) { addPolygonPopup(layer); } }); // Cleanup event listeners ketika component unmount return () => { if (map) { map.off(L.Draw.Event.CREATED); if (drawnItems) { map.removeLayer(drawnItems); } } }; // eslint-disable-next-line react-hooks/exhaustive-deps }, [map]); // Function to add a popup to a marker const addMarkerPopup = (marker: L.Marker) => { const latlng = marker.getLatLng(); marker.bindPopup(` `); }; // Function to add a popup to a polyline const addPolylinePopup = (polyline: L.Polyline) => { const latlngs = polyline.getLatLngs() as L.LatLng[]; const distance = calculateDistance(latlngs); polyline.bindPopup(` `); }; // Function to add a popup to a polygon const addPolygonPopup = (polygon: L.Polygon) => { const latlngs = polygon.getLatLngs()[0] as L.LatLng[]; const area = calculateArea(latlngs); polygon.bindPopup(` `); }; // Hitung jarak polyline dalam meter dengan Turf const calculateDistance = (latlngs: L.LatLng[]): number => { if (latlngs.length < 2) return 0; const coords = latlngs.map((p) => [p.lng, p.lat]); const line = turf.lineString(coords); return turf.length(line, { units: "kilometers" }) * 1000; // dalam meter }; // Hitung luas polygon dalam meter persegi dengan Turf const calculateArea = (latlngs: L.LatLng[]): number => { if (latlngs.length < 3) return 0; const coords = latlngs.map((p) => [p.lng, p.lat]); // Tutup polygon jika belum tertutup if ( coords[0][0] !== coords[coords.length - 1][0] || coords[0][1] !== coords[coords.length - 1][1] ) { coords.push(coords[0]); } const polygon = turf.polygon([coords]); return turf.area(polygon); // m² }; // Utility function to format distances const formatDistance = (distance: number): string => { if (distance >= 1000) { // Convert to kilometers, format with commas, and ensure two decimal places return `${new Intl.NumberFormat("id-ID").format( parseFloat((distance / 1000).toFixed(2)) )} km`; } // Format in meters with commas and ensure two decimal places return `${new Intl.NumberFormat("id-ID").format( parseFloat(distance.toFixed(2)) )} meter`; }; // Utility function to format areas const formatArea = (area: number): string => { if (area >= 1000000) { // Convert to square kilometers, format with commas, and ensure two decimal places return `${new Intl.NumberFormat("id-ID").format( parseFloat((area / 1000000).toFixed(2)) )} km²`; } // Format in square meters with commas and ensure two decimal places return `${new Intl.NumberFormat("id-ID").format( parseFloat(area.toFixed(2)) )} m²`; }; // Handler untuk tab click const handleTabClick = (tab: "location" | "edit" | "expand") => { // Disable all drawing tools first if (drawingToolsRef.current) { drawingToolsRef.current.marker?.disable(); drawingToolsRef.current.polyline?.disable(); drawingToolsRef.current.polygon?.disable(); } // Toggle active tab setActiveTab((prevTab) => { if (prevTab === tab) { return null; } return tab; }); // If tab is deactivated, don't enable any drawing tool if (activeTab === tab) { return; } // Enable the selected drawing tool if (drawingToolsRef.current) { switch (tab) { case "location": drawingToolsRef.current.marker?.enable(); break; case "edit": drawingToolsRef.current.polyline?.enable(); break; case "expand": drawingToolsRef.current.polygon?.enable(); break; } } }; // Reset semua item yang digambar const handleReset = () => { setActiveTab(null); // Hapus semua layer if (drawnItemsRef.current) { drawnItemsRef.current.clearLayers(); } }; return (
); }