From 6535ae815f3a7f50dd2a0a96885e696ab53a0a5f Mon Sep 17 00:00:00 2001 From: tistopandita Date: Thu, 11 Jun 2026 23:54:47 +0700 Subject: [PATCH] update fitur peta pada tambah spbu --- frontend/admin.html | 260 +++++++++++++++++++++++++++++++++++--- frontend/poverty-map.html | 15 +-- 2 files changed, 247 insertions(+), 28 deletions(-) diff --git a/frontend/admin.html b/frontend/admin.html index b44e768..e09dde4 100644 --- a/frontend/admin.html +++ b/frontend/admin.html @@ -473,11 +473,85 @@ font-weight: 900; } + /* ── Map SPBU (pin klik) ── */ + .spbu-map-wrap { + grid-column: 1 / -1; + display: grid; + grid-template-columns: 1fr 1fr; + gap: 16px; + align-items: start; + } + .spbu-map-box { + border: 2px solid var(--border); + border-radius: 12px; + overflow: hidden; + height: 300px; + position: relative; + cursor: crosshair; + } + .spbu-map-box.has-pin { + border-color: var(--accent); + } + .spbu-coords-hint { + padding: 9px 12px; + background: #eff6ff; + border: 1px solid #bfdbfe; + border-radius: 10px; + font-size: 0.82rem; + color: #1e40af; + margin-bottom: 10px; + line-height: 1.5; + } + .spbu-coords-hint strong { + display: block; + margin-bottom: 3px; + } + .coords-pill { + display: flex; + align-items: center; + gap: 8px; + padding: 9px 12px; + background: #f8fafc; + border: 1px solid var(--border); + border-radius: 10px; + font-size: 0.82rem; + color: var(--muted); + font-family: monospace; + margin-top: 8px; + } + .coords-pill.filled { + color: var(--text); + border-color: var(--accent); + background: #eff6ff; + } + .coords-pill span { + flex: 1; + } + .coords-clear { + width: 22px; + height: 22px; + border: 0; + border-radius: 6px; + background: #e2e8f0; + cursor: pointer; + font-size: 0.85rem; + line-height: 1; + display: none; + } + .coords-pill.filled .coords-clear { + display: inline-flex; + align-items: center; + justify-content: center; + } + /* ── Responsive ── */ @media (max-width: 860px) { .map-input-wrap { grid-template-columns: 1fr; } + .spbu-map-wrap { + grid-template-columns: 1fr; + } } @media (max-width: 600px) { .form-grid { @@ -554,14 +628,75 @@ placeholder="Jl. ..., Kelurahan, Kecamatan" /> -
- - -
-
- - + + +
+
+
+ 📍 Tentukan lokasi SPBU di peta + Klik langsung di peta untuk menempatkan pin lokasi SPBU. + Klik di tempat lain untuk memindahkan pin. +
+
+
+ Belum ada pin. Klik di peta untuk menentukan + lokasi. + +
+
+ +
+
+ + +
+
+ + +
+

+ Koordinat diisi otomatis saat kamu klik peta. Tidak perlu + mengetik secara manual. +

+
+
@@ -939,7 +1074,7 @@ }); // ─── Tab switching ──────────────────────────────────────────────────────────── - let mapsInitialized = { jalan: false, bangunan: false }; + let mapsInitialized = { spbu: false, jalan: false, bangunan: false }; document.querySelectorAll(".tab-btn").forEach((btn) => { btn.addEventListener("click", () => { @@ -954,6 +1089,12 @@ document.getElementById(tabId).classList.add("active"); // Init peta saat tab dibuka pertama kali (Leaflet butuh container visible) + if (tabId === "tab-spbu" && !mapsInitialized.spbu) { + setTimeout(() => { + initSpbuMap(); + mapsInitialized.spbu = true; + }, 80); + } if (tabId === "tab-jalan" && !mapsInitialized.jalan) { setTimeout(() => { initJalanMap(); @@ -969,6 +1110,79 @@ }); }); + // ══════════════════════════════════════════════════════════════════════════════ + // ─── PETA SPBU (pin klik) ──────────────────────────────────────────────────── + // ══════════════════════════════════════════════════════════════════════════════ + let spbuMap, spbuPinMarker; + + function initSpbuMap() { + spbuMap = L.map("mapSpbu").setView(PONTIANAK_CENTER, 13); + L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", { + maxZoom: 19, + attribution: + '© OpenStreetMap', + }).addTo(spbuMap); + + spbuMap.on("click", (e) => { + const { lat, lng } = e.latlng; + setSpbuPin(lat, lng); + }); + } + + function setSpbuPin(lat, lng) { + const latR = parseFloat(lat.toFixed(6)); + const lngR = parseFloat(lng.toFixed(6)); + + // Hapus marker lama, pasang yang baru + if (spbuPinMarker) spbuMap.removeLayer(spbuPinMarker); + spbuPinMarker = L.marker([latR, lngR], { + icon: L.divIcon({ + className: "", + html: `
+ +
`, + iconSize: [36, 36], + iconAnchor: [18, 34], + }), + draggable: true, + }).addTo(spbuMap); + + // Drag marker juga update koordinat + spbuPinMarker.on("dragend", (ev) => { + const pos = ev.target.getLatLng(); + setSpbuPin(pos.lat, pos.lng); + }); + + // Update input fields & pill + spbuEl.fLat.value = latR; + spbuEl.fLng.value = lngR; + document.getElementById("coordsTextSpbu").textContent = + `Lat: ${latR} | Lng: ${lngR}`; + const pill = document.getElementById("coordsPillSpbu"); + pill.classList.add("filled"); + document.getElementById("mapSpbu").classList.add("has-pin"); + } + + function clearSpbuPin() { + if (spbuPinMarker) { + spbuMap.removeLayer(spbuPinMarker); + spbuPinMarker = null; + } + spbuEl.fLat.value = ""; + spbuEl.fLng.value = ""; + document.getElementById("coordsTextSpbu").textContent = + "Belum ada pin. Klik di peta untuk menentukan lokasi."; + document.getElementById("coordsPillSpbu").classList.remove("filled"); + document.getElementById("mapSpbu").classList.remove("has-pin"); + } + + document + .getElementById("clearPinSpbu") + .addEventListener("click", clearSpbuPin); + // ══════════════════════════════════════════════════════════════════════════════ // ─── TAB SPBU ──────────────────────────────────────────────────────────────── // ══════════════════════════════════════════════════════════════════════════════ @@ -1080,16 +1294,12 @@ } function resetSpbuForm() { spbuEl.editId.value = ""; - spbuEl.fKode.value = - spbuEl.fNama.value = - spbuEl.fAlamat.value = - spbuEl.fLat.value = - spbuEl.fLng.value = - ""; + spbuEl.fKode.value = spbuEl.fNama.value = spbuEl.fAlamat.value = ""; spbuEl.fJamBuka.value = "06:00"; spbuEl.fJamTutup.value = "22:00"; spbuEl.fOverride.value = "auto"; renderFuelChecks([]); + clearSpbuPin(); spbuEl.formTitle.textContent = "➕ Tambah SPBU Baru"; spbuEl.submitBtn.textContent = "💾 Simpan SPBU"; spbuEl.resetBtn.style.display = "none"; @@ -1101,8 +1311,6 @@ spbuEl.fKode.value = spbu.kode; spbuEl.fNama.value = spbu.nama; spbuEl.fAlamat.value = spbu.alamat; - spbuEl.fLat.value = spbu.lat; - spbuEl.fLng.value = spbu.lng; spbuEl.fJamBuka.value = spbu.jam_buka; spbuEl.fJamTutup.value = spbu.jam_tutup; spbuEl.fOverride.value = spbu.manual_override || "auto"; @@ -1111,6 +1319,21 @@ spbuEl.submitBtn.textContent = "💾 Update SPBU"; spbuEl.resetBtn.style.display = ""; window.scrollTo({ top: 0, behavior: "smooth" }); + + // Set pin di peta — inisialisasi peta dulu kalau belum + const doPin = () => { + setSpbuPin(spbu.lat, spbu.lng); + spbuMap.setView([spbu.lat, spbu.lng], 15); + }; + if (!mapsInitialized.spbu) { + setTimeout(() => { + initSpbuMap(); + mapsInitialized.spbu = true; + setTimeout(doPin, 200); + }, 80); + } else { + doPin(); + } } async function submitSpbu() { const id = spbuEl.editId.value; @@ -1171,6 +1394,11 @@ spbuEl.resetBtn.addEventListener("click", resetSpbuForm); renderFuelChecks([]); loadSpbu(); + // Tab SPBU aktif saat load — init petanya langsung + setTimeout(() => { + initSpbuMap(); + mapsInitialized.spbu = true; + }, 120); // ══════════════════════════════════════════════════════════════════════════════ // ─── TAB JALAN ─────────────────────────────────────────────────────────────── diff --git a/frontend/poverty-map.html b/frontend/poverty-map.html index 377d0b4..44a47a6 100644 --- a/frontend/poverty-map.html +++ b/frontend/poverty-map.html @@ -194,7 +194,7 @@
Gereja Peduli

WebGIS Poverty Mapping

-

Peta prioritas keluarga penerima bantuan berbasis SAW, terpusat, dan mendukung mode privasi.

+

Peta prioritas keluarga penerima bantuan berbasis SAW, terpusat, dan mudah dipantau.

@@ -209,12 +209,6 @@

Filter Peta

- -
@@ -296,11 +289,9 @@ } function params() { - const role = el("roleSelect").value; - const privacy = el("privacyToggle").checked ? "1" : "0"; const kategori = encodeURIComponent(el("categoryFilter").value); const search = encodeURIComponent(el("searchInput").value.trim()); - return `role=${role}&privacy=${privacy}&kategori=${kategori}&search=${search}`; + return `kategori=${kategori}&search=${search}`; } async function loadData() { @@ -416,7 +407,7 @@ } let debounce; - ["roleSelect", "categoryFilter", "privacyToggle", "heatToggle"].forEach((id) => el(id).addEventListener("change", () => loadData().catch((error) => toast(error.message)))); + ["categoryFilter", "heatToggle"].forEach((id) => el(id).addEventListener("change", () => loadData().catch((error) => toast(error.message)))); el("searchInput").addEventListener("input", () => { clearTimeout(debounce); debounce = setTimeout(() => loadData().catch((error) => toast(error.message)), 260);