"use client"; import { MapContainer, TileLayer, CircleMarker, Tooltip, Polyline } from "react-leaflet"; import "leaflet/dist/leaflet.css"; import type { Kabupaten, SurplusDeficitRow, Match } from "../lib/api"; const CENTER: [number, number] = [-7.7, 112.5]; // Jawa Timur centroid-ish const ZOOM = 8; type Props = { kabupaten: Kabupaten[]; surplusDeficit: SurplusDeficitRow[]; matches: Match[]; onSelectKab: (kabId: string) => void; selectedKabId: string | null; }; // Radius proportional to sqrt(volume) so visual area ~ volume. function bubbleRadius(tons: number): number { if (tons <= 0) return 4; return Math.max(6, Math.min(28, Math.sqrt(tons) * 1.8)); } export default function MapView({ kabupaten, surplusDeficit, matches, onSelectKab, selectedKabId, }: Props) { const rowByKab = new Map(); for (const r of surplusDeficit) rowByKab.set(r.kab_id, r); return ( {/* Flow lines for top matches */} {matches.slice(0, 10).map((m, idx) => ( ))} {/* Kabupaten bubbles */} {kabupaten.map((k) => { const row = rowByKab.get(k.id); const role = row?.role; const tons = row?.volume_tons ?? 0; const color = role === "surplus" ? "#16a34a" : role === "deficit" ? "#dc2626" : "#94a3b8"; const radius = row ? bubbleRadius(tons) : 4; const isSelected = selectedKabId === k.id; return ( onSelectKab(k.id) }} >
{k.nama}
Kategori Wilayah: {k.tier.replace("TIER_", "").replace("_HIGH", " Tinggi").replace("_MEDIUM", " Sedang")}
IPM: {k.ipm.toFixed(1)}
Jumlah Penduduk: {k.population.toLocaleString("id-ID")} jiwa
{row && (
{role === "surplus" ? "Stok Berlebih (Surplus)" : "Kekurangan Stok (Defisit)"}: {tons.toFixed(0)} ton
)}
); })}
); }