/* ============================================================ map.js – WebGIS Pemetaan Kemiskinan & Masjid (SRS v1.0) ============================================================ */ window.appState = { mode: "view", activeType: "kemiskinan", layers: {}, layerVisibility: { kemiskinan: true, masjid: true }, isHeatmap: false, isRouting: false, routingWaypoints: [] }; /* ── Utility: escape HTML ── */ window.escapeHtml = function (value) { return String(value ?? "") .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """) .replace(/'/g, "'"); }; /* ── Utility: SVG pin marker ── */ window.createPinIcon = function (bgColor, svgSymbol) { var svg = [ '', '', '', '', '', '', /* Pin body */ '', /* White inner circle */ '', /* Symbol */ svgSymbol, '' ].join(''); return L.divIcon({ className: 'custom-pin-icon', html: svg, iconSize: [32, 42], iconAnchor: [16, 42], popupAnchor: [0, -44] }); }; /* Kemiskinan – merah (tidak terjangkau) */ window.redIcon = window.createPinIcon('#dc2626', '👪' ); /* Kemiskinan – hijau (terjangkau) */ window.greenIcon = window.createPinIcon('#16a34a', '👪' ); /* Masjid – biru */ window.blueIcon = window.createPinIcon('#1d4ed8', '🕌' ); /* Fallback orange (tidak digunakan, tapi tetap didefinisikan) */ window.orangeIcon = window.createPinIcon('#f97316', '👪' ); /* ── Utility: POST form-encoded ── */ window.postForm = async function (url, payload) { var response = await fetch(url, { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded" }, body: new URLSearchParams(payload) }); var text = (await response.text()).trim(); if (!response.ok || text !== "success") { throw new Error(text || "Permintaan gagal."); } }; /* ── Navbar hint ── */ window.updateMapHint = function () { var hint = document.getElementById("mapHint"); if (!hint) { return; } if (appState.mode === "view") { hint.textContent = "Mode Lihat aktif — data keluarga prasejahtera & rumah ibadah ditampilkan. Klik kartu untuk navigasi peta."; return; } if (appState.activeType === "kemiskinan") { hint.textContent = "Mode Edit aktif — klik titik di peta untuk menambahkan data keluarga prasejahtera."; return; } hint.textContent = "Mode Edit aktif — klik titik di peta untuk menambahkan data rumah ibadah baru."; }; /* ── Toolbar state ── */ window.updateToolbarState = function () { var states = { modeViewBtn: appState.mode === "view", modeEditBtn: appState.mode === "edit", typeKemiskinanBtn: appState.activeType === "kemiskinan", typeMasjidBtn: appState.activeType === "masjid" }; Object.keys(states).forEach(function (id) { var btn = document.getElementById(id); if (!btn) { return; } btn.classList.toggle("active", states[id]); /* Mode buttons get a different active colour */ if (id === "modeEditBtn" && states[id]) { btn.classList.add("mode-active"); } else { btn.classList.remove("mode-active"); } }); var viewBtn = document.getElementById("luminaModeView"); var editBtn = document.getElementById("luminaModeEdit"); if (viewBtn && editBtn) { viewBtn.style.opacity = appState.mode === "view" ? "1" : "0.5"; viewBtn.style.boxShadow = appState.mode === "view" ? "0 4px 12px rgba(99,102,241,0.25)" : "none"; editBtn.style.opacity = appState.mode === "edit" ? "1" : "0.5"; editBtn.style.boxShadow = appState.mode === "edit" ? "0 4px 12px rgba(20,184,166,0.25)" : "none"; } }; window.setActiveMenu = function(element) { var items = document.querySelectorAll('.lumina-menu-item'); items.forEach(function(item) { item.classList.remove('active'); }); element.classList.add('active'); }; /* ── Layer visibility ── */ window.setLayerVisibility = function (key, isVisible) { appState.layerVisibility[key] = !!isVisible; var layer = appState.layers[key]; if (!layer || !window.map) { return; } if (isVisible) { if (!map.hasLayer(layer)) { map.addLayer(layer); } } else { if (map.hasLayer(layer)) { map.removeLayer(layer); } } }; /* ── Mode & type switches ── */ window.setMode = function (mode) { appState.mode = mode; window.updateToolbarState(); window.updateMapHint(); var mapEl = document.getElementById("map"); if (mapEl) { if (mode === "edit") { mapEl.classList.add("edit-mode"); } else { mapEl.classList.remove("edit-mode"); } } if (typeof window.loadAllData === "function") { window.loadAllData(); } }; window.setDataType = function (type) { appState.activeType = type; window.updateToolbarState(); window.updateMapHint(); if (typeof window.filterSidebar === 'function') { window.filterSidebar(type); } }; window.filterSidebar = function(type) { var secKem = document.getElementById('sec-kemiskinan'); var secMsj = document.getElementById('sec-masjid'); if (secKem) secKem.style.display = (type === 'semua' || type === 'kemiskinan') ? 'block' : 'none'; if (secMsj) secMsj.style.display = (type === 'semua' || type === 'masjid') ? 'block' : 'none'; var btnSemua = document.getElementById('filter-btn-semua'); var btnKem = document.getElementById('filter-btn-kemiskinan'); var btnMsj = document.getElementById('filter-btn-masjid'); if (btnSemua) btnSemua.classList.toggle('active', type === 'semua'); if (btnKem) btnKem.classList.toggle('active', type === 'kemiskinan'); if (btnMsj) btnMsj.classList.toggle('active', type === 'masjid'); var sidebarSub = document.getElementById('sidebar-sub'); if (sidebarSub) { if (type === 'semua') sidebarSub.textContent = 'Menampilkan semua data'; else if (type === 'kemiskinan') sidebarSub.textContent = 'Menampilkan list Data Keluarga'; else sidebarSub.textContent = 'Menampilkan list Rumah Ibadah'; } var sidebar = document.getElementById('sidebar'); if (sidebar && sidebar.style.display === 'none') { sidebar.style.display = 'flex'; var pes = document.getElementById('panel-pesan'); if (pes) pes.style.display = 'none'; var lap = document.getElementById('panel-laporan'); if (lap) lap.style.display = 'none'; } }; /* ── Format helpers ── */ window.formatMeters = function (value) { return Number(value).toLocaleString("id-ID", { maximumFractionDigits: 0 }) + " m"; }; window.isValidCoordinate = function (lat, lng) { return Number.isFinite(Number(lat)) && Number.isFinite(Number(lng)); }; window.isValidRadius = function (radius) { var r = Number(radius); return Number.isFinite(r) && r >= 100 && r <= 5000; }; /* ───────────────────────────────────────────── DOMContentLoaded – inisialisasi peta (KF-01) ───────────────────────────────────────────── */ document.addEventListener("DOMContentLoaded", function () { /* Inisialisasi peta terpusat di Pontianak */ window.map = L.map("map").setView([-0.0263, 109.3425], 13); // --- Base maps --- window.osmBase = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { attribution: '© OpenStreetMap contributors' }); window.darkBase = L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png', { attribution: '© OpenStreetMap contributors © CARTO' }); // Add default basemap window.osmBase.addTo(map); /* ── Layers ── */ appState.layers.kemiskinan = L.layerGroup().addTo(map); appState.layers.masjid = L.layerGroup().addTo(map); appState.layers.heatmap = L.layerGroup(); // Do not add yet /* Klik peta – hanya aktif di Mode Edit (KF-03, KF-07) */ map.on("click", function (event) { if (appState.mode !== "edit") { return; } var lat = event.latlng.lat; var lng = event.latlng.lng; if (appState.activeType === "kemiskinan") { if (typeof window.openKemiskinanModal === "function") { window.openKemiskinanModal(lat, lng); } return; } if (appState.activeType === "masjid") { if (typeof window.openMasjidModal === "function") { window.openMasjidModal(lat, lng); } } }); /* Init state awal */ window.setMode("view"); window.setDataType("kemiskinan"); setTimeout(function () { map.invalidateSize(); }, 300); /* Cek session login, lalu load data */ if (typeof window.checkAuthState === "function") { window.checkAuthState().then(function () { if (typeof window.loadAllData === "function") { window.loadAllData(); } }); } else if (typeof window.loadAllData === "function") { window.loadAllData(); } }); /* ── Heatmap & Routing Features ── */ window.toggleHeatmap = function(btnEl) { if(!window.appState) return; window.appState.isHeatmap = !window.appState.isHeatmap; btnEl.classList.toggle('active', window.appState.isHeatmap); if(window.appState.isHeatmap) { document.getElementById('desc-heatmap').style.display = 'block'; // Hide kemiskinan markers window.appState.layers.kemiskinan.eachLayer(function(l) { l.setOpacity(0); }); // Show heatmap if(!window.map.hasLayer(window.appState.layers.heatmap)) { window.appState.layers.heatmap.addTo(window.map); } // Switch to Dark mode for better visual window.map.removeLayer(window.osmBase); window.darkBase.addTo(window.map); } else { document.getElementById('desc-heatmap').style.display = 'none'; // Show kemiskinan markers window.appState.layers.kemiskinan.eachLayer(function(l) { l.setOpacity(1); }); // Hide heatmap if(window.map.hasLayer(window.appState.layers.heatmap)) { window.map.removeLayer(window.appState.layers.heatmap); } // Restore map base window.map.removeLayer(window.darkBase); window.osmBase.addTo(window.map); } }; window.toggleRoutingMode = function(btnEl) { if(!window.appState) return; window.appState.isRouting = true; window.appState.routingWaypoints = []; btnEl.classList.add('active'); document.getElementById('desc-routing').style.display = 'block'; // Show instruction panel document.getElementById('routing-instruction-panel').style.display = 'block'; document.getElementById('routing-instruction-text').innerHTML = 'Silakan klik Masjid atau Rumah Warga di peta sebagai titik awal rute.'; }; window.cancelRouting = function() { if(!window.appState) return; window.appState.isRouting = false; window.appState.routingWaypoints = []; document.getElementById('btn-toggle-routing').classList.remove('active'); document.getElementById('desc-routing').style.display = 'none'; document.getElementById('routing-instruction-panel').style.display = 'none'; // Remove routing control if exists if(window.routingControl) { window.map.removeControl(window.routingControl); window.routingControl = null; } }; window.handleRoutingClick = function(lat, lng, name) { window.appState.routingWaypoints.push(L.latLng(lat, lng)); var pts = window.appState.routingWaypoints; var inst = document.getElementById('routing-instruction-text'); if(pts.length === 1) { inst.innerHTML = '
Titik Awal: ' + window.escapeHtml(name) + '
' + '
Langkah 2: Pilih Tujuan
' + 'Klik rumah/masjid lain di peta sebagai tujuan akhir.'; } else if(pts.length === 2) { inst.innerHTML = '
Rute Berhasil Dibuat
' + 'Detail arah jalan (navigasi) muncul di layar sebelah kanan peta.'; // Remove existing control if(window.routingControl) { window.map.removeControl(window.routingControl); } window.routingControl = L.Routing.control({ waypoints: pts, routeWhileDragging: false, addWaypoints: false, show: true, lineOptions: { styles: [{color: '#2563eb', opacity: 0.8, weight: 6}] } }).addTo(window.map); window.appState.isRouting = false; // Turn off click interception after 2 points document.getElementById('btn-toggle-routing').classList.remove('active'); } };