/* ============================================================
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 = [
''
].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');
}
};