// ==========================================
// 1. INISIALISASI PETA & LAYER
// ==========================================
// 1. Definisikan Pilihan Basemap (Tile Layers)
var osm = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
});
var googleSatellite = L.tileLayer('http://{s}.google.com/vt/lyrs=s&x={x}&y={y}&z={z}', {
maxZoom: 20,
subdomains: ['mt0', 'mt1', 'mt2', 'mt3'],
attribution: 'Map data © Google'
});
var darkMap = L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png', {
attribution: '© OpenStreetMap contributors © CARTO'
});
// 2. Inisialisasi Peta
// Pastikan id 'map' sesuai dengan id div pada file index.php Anda
var map = L.map('map', {
center: [-0.0227, 109.3340], // Titik tengah peta (Pontianak)
zoom: 13,
layers: [osm], // Basemap default yang langsung aktif saat web dibuka
zoomControl: false
});
// 3. Gabungkan Basemap ke dalam satu Grup Objek
var baseMaps = {
"Peta Standar (OSM)": osm,
"Satelit (Google)": googleSatellite,
"Mode Gelap (Dark)": darkMap
};
// Zoom control di kanan bawah (lebih bersih)
L.control.zoom({ position: 'bottomright' }).addTo(map);
// Tambahkan Tombol Kontrol Layer ke Bawah Kanan Peta
L.control.layers(baseMaps, null, { position: 'bottomright' }).addTo(map);
// Custom pane initialization removed
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
}).addTo(map);
// Layer Group untuk masing-masing data
var drawnItems = new L.FeatureGroup().addTo(map);
//var batasKotaLayer = L.layerGroup().addTo(map);
//var sungaiLayer = L.layerGroup().addTo(map);
var rumahIbadahLayer = L.layerGroup().addTo(map);
var radiusLayer = L.layerGroup().addTo(map);
var pendudukMiskinLayer = L.layerGroup().addTo(map);
var pendudukMiskinCluster = L.markerClusterGroup({
showCoverageOnHover: false,
zoomToBoundsOnClick: true,
maxClusterRadius: 50
}).addTo(map);
// Inisialisasi Heatmap kosong (akan diisi datanya saat load data)
var povertyHeatLayer = L.heatLayer([], { radius: 22, blur: 18, maxZoom: 17 }).addTo(map);
// Inisialisasi Layers Control (di kanan atas)
var overlayMaps = {
"🕌 Rumah Ibadah": rumahIbadahLayer,
"🔥 Kepadatan Kemiskinan (Heatmap)": povertyHeatLayer,
"👥 Semua Penduduk Miskin": pendudukMiskinCluster,
"👥 Penduduk Terdekat (Analisis)": pendudukMiskinLayer
};
L.control.layers(null, overlayMaps, { collapsed: true, position: 'bottomleft' }).addTo(map);
// ==========================================
// ICON DEFINITIONS
// ==========================================
// Unused marker icons removed
// Icon Rumah Ibadah Kustom — bangunan rumah ibadah bergaya universal
var rumahIbadahIcon = L.divIcon({
className: '',
html: `
`,
iconSize: [38, 38],
iconAnchor: [19, 38],
popupAnchor: [0, -38]
});
var databasePendudukMiskin = [];
function loadRumahIbadah() {
rumahIbadahLayer.clearLayers();
databasePencarian = []; // Reset database pencarian untuk mencegah duplikat
fetch('load.php?jenis=rumah_ibadah')
.then(res => res.json())
.then(dataRumahIbadah => {
fetch('load.php?jenis=penduduk_miskin')
.then(res => res.json())
.then(dataPendudukMiskin => {
databasePendudukMiskin = dataPendudukMiskin;
// Mengisi koordinat data kemiskinan ke dalam Heatmap
var heatPoints = dataPendudukMiskin.map(p => [
parseFloat(p.lat || p.latitude),
parseFloat(p.lng || p.longitude),
1.0
]);
povertyHeatLayer.setLatLngs(heatPoints);
// Marker Clustering untuk semua penduduk miskin
pendudukMiskinCluster.clearLayers();
dataPendudukMiskin.forEach(penduduk => {
var latPenduduk = parseFloat(penduduk.lat || penduduk.latitude);
var lngPenduduk = parseFloat(penduduk.lng || penduduk.longitude);
var statusBantuan = penduduk.bantuan || 'Belum Menerima';
var poorFamilyIcon = L.divIcon({
className: '',
html: ``,
iconSize: [14, 14],
iconAnchor: [7, 7],
popupAnchor: [0, -7]
});
var actionButtons = '';
if (IS_ADMIN) {
actionButtons = `
`;
}
var htmlIsi = `
`;
var marker = L.marker([latPenduduk, lngPenduduk], { icon: poorFamilyIcon })
.bindPopup(htmlIsi);
pendudukMiskinCluster.addLayer(marker);
var namaKK = penduduk.nama_kk || 'Tanpa Nama';
databasePencarian.push({
namaLower: namaKK.toLowerCase(),
namaAsli: namaKK,
kategori: 'Penduduk Miskin',
bantuan: statusBantuan,
ikon: '👥',
tipe: 'titik',
layer: marker
});
});
dataRumahIbadah.forEach(ibadah => {
var latIbadah = ibadah.lat || ibadah.latitude;
var lngIbadah = ibadah.lng || ibadah.longitude;
var radiusMeter = 500;
var ibadahId = ibadah.id;
var actionButtons = '';
if (IS_ADMIN) {
actionButtons = `
`;
}
// HTML untuk Popup Rumah Ibadah dengan range slider untuk mengatur radius analisis
var htmlIbadah = `
`;
var ibadahMarker = L.marker([latIbadah, lngIbadah], { icon: rumahIbadahIcon })
.bindPopup(htmlIbadah)
.addTo(rumahIbadahLayer);
databasePencarian.push({
namaLower: ibadah.nama.toLowerCase(),
namaAsli: ibadah.nama,
kategori: 'Rumah Ibadah',
ikon: '🕌',
tipe: 'titik',
layer: ibadahMarker
});
// Saat popup dibuka, jalankan fungsi updatePopupRadius
ibadahMarker.on('popupopen', function (e) {
map.flyTo(e.target.getLatLng(), 16, { animate: true });
setTimeout(function () {
updatePopupRadius(ibadahId, latIbadah, lngIbadah);
}, 50);
});
});
});
})
.catch(e => console.log('Belum ada data Rumah Ibadah', e));
}
// Fungsi untuk memperbarui lingkaran radius dan penduduk miskin terdekat secara interaktif
function updatePopupRadius(ibadahId, lat, lng) {
var slider = document.getElementById('radius-slider-' + ibadahId);
var label = document.getElementById('radius-val-' + ibadahId);
if (!slider || !label) return;
var newRadius = parseInt(slider.value);
label.textContent = newRadius + ' meter';
var centerPoint = L.latLng(lat, lng);
radiusLayer.clearLayers();
pendudukMiskinLayer.clearLayers();
// Gambar lingkaran radius baru
var areaRadius = L.circle(centerPoint, {
color: '#2563eb',
fillColor: '#3b82f6',
fillOpacity: 0.1,
radius: newRadius,
interactive: true
}).addTo(radiusLayer);
areaRadius.on('click', function (evt) { L.DomEvent.stopPropagation(evt); });
var totalKK = 0;
var sudahBantuan = 0;
var belumBantuan = 0;
var familiesInRadius = [];
// Saring dan tampilkan penduduk miskin yang berada dalam radius baru
databasePendudukMiskin.forEach(penduduk => {
var latPenduduk = penduduk.lat || penduduk.latitude;
var lngPenduduk = penduduk.lng || penduduk.longitude;
var pendudukLatLng = L.latLng(latPenduduk, lngPenduduk);
var jarak = centerPoint.distanceTo(pendudukLatLng);
if (jarak <= newRadius) {
totalKK++;
var statusBantuan = penduduk.bantuan || 'Belum Menerima';
if (statusBantuan === 'Sudah Menerima') {
sudahBantuan++;
} else {
belumBantuan++;
}
familiesInRadius.push(penduduk);
var warnaDot = statusBantuan === 'Sudah Menerima' ? '#10b981' : '#ef4444';
var redDot = L.circleMarker(pendudukLatLng, {
radius: 7,
color: '#ffffff',
fillColor: warnaDot,
fillOpacity: 1,
weight: 1.5
}).addTo(pendudukMiskinLayer);
redDot.on('click', function (e) {
L.DomEvent.stopPropagation(e);
var pendudukId = penduduk.id;
var namaKeluarga = penduduk.nama_kk ? penduduk.nama_kk : "Tanpa Nama";
var alamatLengkap = penduduk.alamat ? penduduk.alamat : "Alamat belum diinput manual";
var latAngka = parseFloat(latPenduduk);
var lngAngka = parseFloat(lngPenduduk);
var actionButtons = '';
if (IS_ADMIN) {
actionButtons = `
`;
}
// Typo fix: penduid -> pendudukId
actionButtons = actionButtons.replace('\'${penduid}\'', `'${pendudukId}'`);
var htmlIsi = `
`;
redDot.bindPopup(htmlIsi).openPopup();
});
}
});
// Cari nama rumah ibadah dari databasePencarian
var ibadahObj = databasePencarian.find(item => item.layer && item.layer._popup && item.layer._popup.getContent().includes('popup-ibadah-' + ibadahId));
var ibadahName = ibadahObj ? ibadahObj.namaAsli : "Rumah Ibadah";
showDashboard(ibadahName, totalKK, sudahBantuan, belumBantuan, familiesInRadius);
}
map.on('click', function () {
if (sidebarPickMode) return; // Ditangani oleh listener sidebar
radiusLayer.clearLayers();
pendudukMiskinLayer.clearLayers();
closeDashboard();
});
loadRumahIbadah();
// ==========================================
// 7. HAPUS DATA
// ==========================================
function deleteData(tabel, id) {
if (confirm('Apakah Anda yakin ingin menghapus data ini?')) {
var formData = new FormData();
formData.append('id', id);
formData.append('tabel', tabel);
fetch('delete_data.php', { method: 'POST', body: formData })
.then(r => r.text()).then(res => {
alert(res);
map.closePopup();
loadRumahIbadah();
});
}
}
// ==========================================
// 8. EDIT DATA
// ==========================================
function formEditRumahIbadah(id, nama, lat, lng) {
setTimeout(function () {
document.getElementById(`popup-ibadah-${id}`).innerHTML = `
`;
}, 50);
}
function formEditPenduduk(id, nama, alamat, statusBantuan, lat, lng) {
setTimeout(function () {
document.getElementById(`popup-penduduk-${id}`).innerHTML = `
`;
}, 50);
}
// ==========================================
// 9. UPDATE DATA
// ==========================================
function updateData(e, tabel, id) {
e.preventDefault();
var formData = new FormData();
formData.append('tabel', tabel);
formData.append('id', id);
if (tabel === 'rumah_ibadah') {
formData.append('nama', document.getElementById('edit_nama_ibadah').value);
formData.append('latitude', document.getElementById('edit_lat_ibadah').value);
formData.append('longitude', document.getElementById('edit_lng_ibadah').value);
} else if (tabel === 'penduduk_miskin') {
formData.append('nama', document.getElementById('edit_nama_penduduk').value);
formData.append('alamat', document.getElementById('edit_alamat_penduduk').value);
formData.append('bantuan', document.getElementById('edit_status_bantuan').value);
formData.append('latitude', document.getElementById('edit_lat_penduduk').value);
formData.append('longitude', document.getElementById('edit_lng_penduduk').value);
}
fetch('update_data.php', { method: 'POST', body: formData })
.then(r => r.text()).then(res => {
alert(res);
map.closePopup();
if (tabel === 'rumah_ibadah' || tabel === 'penduduk_miskin') {
loadRumahIbadah();
}
});
}
// ==========================================
// 10. LEGENDA PETA
// ==========================================
var legend = L.control({ position: 'bottomleft' });
legend.onAdd = function (map) {
var div = L.DomUtil.create('div', 'info legend');
div.innerHTML = `
Legenda Peta
Sosial & Keagamaan
Penduduk Miskin (Sudah Menerima)
Penduduk Miskin (Belum Menerima)
`;
return div;
};
legend.addTo(map);
// ==========================================
// 11. SISTEM PENCARIAN
// ==========================================
var databasePencarian = [];
var ikonKategori = {
'Rumah Ibadah': '🕌',
'Penduduk Miskin': '👥'
};
var warnaBadge = {
'Rumah Ibadah': 'badge-Rumah-Ibadah'
};
function jalankanPencarian() {
var kataKunci = document.getElementById('search-input').value.toLowerCase();
var kategori = document.getElementById('search-category').value;
var wadahHasil = document.getElementById('search-results');
wadahHasil.innerHTML = '';
if (kataKunci.length < 2) {
wadahHasil.style.display = 'none';
return;
}
var hasil = databasePencarian.filter(function (item) {
var cocokNama = item.namaLower.includes(kataKunci);
var cocokKategori = (kategori === 'Semua') || (item.kategori === kategori);
return cocokNama && cocokKategori;
});
if (hasil.length > 0) {
wadahHasil.style.display = 'block';
wadahHasil.innerHTML = ``;
hasil.forEach(function (item) {
var badgeClass = warnaBadge[item.kategori] || 'badge-default';
var kategoriText = item.kategori;
var ikon = item.ikon || '📍';
var bgColors = {
'Rumah Ibadah': 'rgba(59,130,246,0.12)',
'Penduduk Miskin': item.bantuan === 'Sudah Menerima' ? 'rgba(16,185,129,0.12)' : 'rgba(239,68,68,0.12)'
};
if (item.kategori === 'Penduduk Miskin') {
if (item.bantuan === 'Sudah Menerima') {
badgeClass = 'badge-penduduk-sudah';
kategoriText = 'Sudah Menerima';
} else {
badgeClass = 'badge-penduduk-belum';
kategoriText = 'Belum Menerima';
}
}
var subText = 'Klik untuk zoom ke lokasi';
if (item.kategori === 'Penduduk Miskin') {
subText = 'Penduduk Miskin • ' + subText;
}
var div = document.createElement('div');
div.className = 'result-item';
div.innerHTML = `
${ikon}
${item.namaAsli}
${subText}
${kategoriText}`;
div.onclick = function () {
if (item.tipe === 'titik') {
if (item.kategori === 'Penduduk Miskin') {
// For markers in markerClusterGroup, use zoomToShowLayer to expand clusters
pendudukMiskinCluster.zoomToShowLayer(item.layer, function () {
item.layer.openPopup();
});
} else {
map.flyTo(item.layer.getLatLng(), 17, { animate: true, duration: 1.5 });
item.layer.openPopup();
}
} else {
map.fitBounds(item.layer.getBounds());
}
wadahHasil.style.display = 'none';
document.getElementById('search-input').value = item.namaAsli;
toggleClearBtn();
};
wadahHasil.appendChild(div);
});
} else {
wadahHasil.style.display = 'block';
wadahHasil.innerHTML = `
🔍
Data tidak ditemukan
Coba kata kunci lain
`;
}
}
function toggleClearBtn() {
var input = document.getElementById('search-input');
var clearBtn = document.getElementById('search-clear');
clearBtn.style.display = input.value.length > 0 ? 'flex' : 'none';
}
function clearSearch() {
document.getElementById('search-input').value = '';
document.getElementById('search-results').style.display = 'none';
document.getElementById('search-clear').style.display = 'none';
}
// Tutup hasil saat klik di luar
document.addEventListener('click', function (e) {
var wrapper = document.querySelector('.search-wrapper');
if (!wrapper.contains(e.target)) {
document.getElementById('search-results').style.display = 'none';
}
});
// Shortcut Cmd/Ctrl + K
document.addEventListener('keydown', function (e) {
if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
e.preventDefault();
document.getElementById('search-input').focus();
}
if (e.key === 'Escape') {
clearSearch();
document.getElementById('search-input').blur();
}
});
// ==========================================
// 12. LOGIKA SIDEBAR INPUT TERPUSAT
// ==========================================
var sidebarPickMode = null; // 'ibadah' | 'penduduk'
var sidebarTempLat = 0, sidebarTempLng = 0;
// Buka/Tutup Sidebar
document.getElementById('sidebar-toggle').addEventListener('click', function () {
var sidebar = document.getElementById('input-sidebar');
sidebar.classList.toggle('open');
this.classList.toggle('open');
});
document.getElementById('sidebar-close').addEventListener('click', function () {
document.getElementById('input-sidebar').classList.remove('open');
document.getElementById('sidebar-toggle').classList.remove('open');
});
// Ganti Tab
function switchSidebarTab(tabName) {
document.querySelectorAll('.stab').forEach(function (t) { t.classList.remove('active'); });
document.querySelectorAll('.stab-content').forEach(function (c) { c.classList.remove('active'); });
document.querySelector('.stab[data-tab="' + tabName + '"]').classList.add('active');
document.getElementById('tab-' + tabName).classList.add('active');
// batalkan mode pick/draw jika ganti tab
deactivatePickMode();
}
// Aktifkan mode pilih titik di peta
function activatePickMode(jenis) {
sidebarPickMode = jenis;
document.getElementById('pick-overlay').classList.add('active');
var teks = { ibadah: 'Klik di peta untuk posisi Rumah Ibadah', penduduk: 'Klik di peta untuk posisi Penduduk Miskin' };
document.getElementById('pick-overlay-text').textContent = teks[jenis] || 'Klik lokasi di peta...';
var btnMap = { ibadah: 'btn-pick-ibadah', penduduk: 'btn-pick-penduduk' };
if (btnMap[jenis]) document.getElementById(btnMap[jenis]).classList.add('active-pick');
map.getContainer().style.cursor = 'crosshair';
}
// Batalkan semua mode
function deactivatePickMode() {
sidebarPickMode = null;
document.getElementById('pick-overlay').classList.remove('active');
document.querySelectorAll('.btn-pick-location').forEach(function (b) { b.classList.remove('active-pick'); });
map.getContainer().style.cursor = '';
}
// Tangkap klik peta untuk mode pick titik
map.on('click', function (e) {
if (!sidebarPickMode) return;
var lat = e.latlng.lat.toFixed(6);
var lng = e.latlng.lng.toFixed(6);
sidebarTempLat = e.latlng.lat;
sidebarTempLng = e.latlng.lng;
radiusLayer.clearLayers();
pendudukMiskinLayer.clearLayers();
if (sidebarPickMode === 'ibadah') {
var el = document.getElementById('coords-ibadah-val');
el.textContent = lat + ', ' + lng;
el.classList.add('has-coords');
} else if (sidebarPickMode === 'penduduk') {
var el = document.getElementById('coords-penduduk-val');
el.textContent = lat + ', ' + lng;
el.classList.add('has-coords');
var alamatInput = document.getElementById('sb_alamat_penduduk');
alamatInput.value = "Sedang mencari alamat..."; // Indikator loading
// Memanggil API Nominatim OpenStreetMap
fetch(`https://nominatim.openstreetmap.org/reverse?format=json&lat=${lat}&lon=${lng}`)
.then(response => response.json())
.then(data => {
if (data && data.display_name) {
// Isi textarea alamat dengan hasil dari Nominatim
alamatInput.value = data.display_name;
} else {
alamatInput.value = "Alamat tidak ditemukan, silakan isi manual.";
}
})
.catch(error => {
console.error("Error Reverse Geocoding:", error);
alamatInput.value = "";
});
}
deactivatePickMode();
});
// ===== FUNGSI SIMPAN DARI SIDEBAR =====
function saveRumahIbadahSidebar() {
var coords = document.getElementById('coords-ibadah-val').textContent;
if (coords === 'Belum dipilih') { alert('Pilih lokasi di peta terlebih dahulu!'); return; }
var nama = document.getElementById('sb_nama_ibadah').value.trim();
if (!nama) { alert('Nama rumah ibadah wajib diisi!'); return; }
var formData = new FormData();
formData.append('nama', nama);
formData.append('latitude', sidebarTempLat);
formData.append('longitude', sidebarTempLng);
fetch('save_rumah_ibadah.php', { method: 'POST', body: formData })
.then(r => r.text()).then(res => {
alert(res);
document.getElementById('sb_nama_ibadah').value = '';
document.getElementById('coords-ibadah-val').textContent = 'Belum dipilih';
document.getElementById('coords-ibadah-val').classList.remove('has-coords');
sidebarTempLat = 0; sidebarTempLng = 0;
loadRumahIbadah();
}).catch(e => console.error(e));
}
function savePendudukSidebar() {
var coords = document.getElementById('coords-penduduk-val').textContent;
if (coords === 'Belum dipilih') { alert('Pilih lokasi di peta terlebih dahulu!'); return; }
var nama = document.getElementById('sb_nama_penduduk').value.trim();
var alamat = document.getElementById('sb_alamat_penduduk').value.trim();
var statusBantuan = document.getElementById('sb_status_bantuan').value;
if (!nama) { alert('Nama kepala keluarga wajib diisi!'); return; }
if (!alamat) { alert('Alamat wajib diisi!'); return; }
var formData = new FormData();
formData.append('nama', nama);
formData.append('alamat', alamat);
formData.append('bantuan', statusBantuan);
formData.append('latitude', sidebarTempLat);
formData.append('longitude', sidebarTempLng);
fetch('save_penduduk_miskin.php', { method: 'POST', body: formData })
.then(r => r.text()).then(res => {
alert(res);
document.getElementById('sb_nama_penduduk').value = '';
document.getElementById('sb_alamat_penduduk').value = '';
document.getElementById('sb_status_bantuan').value = 'Belum Menerima';
document.getElementById('coords-penduduk-val').textContent = 'Belum dipilih';
document.getElementById('coords-penduduk-val').classList.remove('has-coords');
sidebarTempLat = 0; sidebarTempLng = 0;
loadRumahIbadah();
}).catch(e => console.error(e));
}
// ==========================================
// 14. LOGIKA CUSTOM DROPDOWN
// ==========================================
document.addEventListener('DOMContentLoaded', function () {
var wrap = document.getElementById('custom-select-wrap');
var trigger = document.getElementById('custom-select-trigger');
var options = document.getElementById('custom-select-options');
var hiddenInput = document.getElementById('search-category');
var optionItems = document.querySelectorAll('.custom-option');
// Buka/Tutup dropdown saat kotak di-klik
wrap.addEventListener('click', function (e) {
e.stopPropagation();
options.classList.toggle('show');
});
// Saat salah satu pilihan (seperti SPBU atau Jalan) diklik
optionItems.forEach(function (item) {
item.addEventListener('click', function (e) {
e.stopPropagation();
// Hapus status aktif dari yang lain, pasang ke yang di-klik
optionItems.forEach(opt => opt.classList.remove('selected'));
this.classList.add('selected');
// Ganti teks yang tampil dan simpan nilainya ke input tersembunyi
trigger.textContent = this.textContent;
hiddenInput.value = this.getAttribute('data-value');
// Tutup dropdown
options.classList.remove('show');
// Otomatis jalankan fungsi pencarian (kode aslimu)
jalankanPencarian();
});
});
// Tutup dropdown otomatis jika klik area manapun di luar peta/header
document.addEventListener('click', function () {
options.classList.remove('show');
});
});
// ==========================================
// 15. DYNAMIC STATS DASHBOARD SIDEBAR (CHART.JS)
// ==========================================
var myPovertyChart = null;
function showDashboard(ibadahName, totalKK, sudahBantuan, belumBantuan, familiesInRadius) {
document.getElementById('dashboard-target-name').textContent = ibadahName;
document.getElementById('stat-total-kk').textContent = totalKK;
document.getElementById('stat-sudah-bantuan').textContent = sudahBantuan;
document.getElementById('stat-belum-bantuan').textContent = belumBantuan;
// Tampilkan sidebar kanan
document.getElementById('dashboard-sidebar').classList.add('open');
// Buat daftar KK miskin dalam radius
var listContainer = document.getElementById('dashboard-families-list');
listContainer.innerHTML = '';
if (familiesInRadius.length === 0) {
listContainer.innerHTML = 'Tidak ada KK Miskin dalam radius ini
';
} else {
familiesInRadius.forEach(f => {
var item = document.createElement('div');
item.className = 'family-item';
var statusClass = f.bantuan === 'Sudah Menerima' ? 'badge-success' : 'badge-danger';
var statusText = f.bantuan === 'Sudah Menerima' ? 'Sudah' : 'Belum';
item.innerHTML = `
${f.nama_kk}
${f.alamat || 'Alamat tidak diisi'}
${statusText}
`;
// Klik untuk zoom/fly ke marker
item.onclick = function () {
var lat = parseFloat(f.lat || f.latitude);
var lng = parseFloat(f.lng || f.longitude);
map.flyTo([lat, lng], 18, { animate: true });
};
listContainer.appendChild(item);
});
}
// Gambar Chart.js
var ctx = document.getElementById('povertyChart').getContext('2d');
if (myPovertyChart) {
myPovertyChart.destroy();
}
var chartLabels = ['Sudah Menerima', 'Belum Menerima'];
var chartData = [sudahBantuan, belumBantuan];
var bgColors = ['#10b981', '#ef4444'];
if (totalKK === 0) {
chartLabels = ['Tidak Ada Data'];
chartData = [1];
bgColors = ['#475569'];
}
myPovertyChart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: chartLabels,
datasets: [{
data: chartData,
backgroundColor: bgColors,
borderWidth: 0
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
position: 'bottom',
labels: {
color: '#cbd5e1',
font: {
family: 'Plus Jakarta Sans',
size: 10
},
boxWidth: 12
}
}
},
cutout: '65%'
}
});
}
function closeDashboard() {
document.getElementById('dashboard-sidebar').classList.remove('open');
}
// ==========================================
// 16. SISTEM MONITORING KONEKSI DINAMIS
// ==========================================
function updateConnectionStatus() {
var statusEl = document.getElementById('connection-status');
if (!statusEl) return;
if (navigator.onLine) {
statusEl.classList.remove('offline');
statusEl.classList.add('online');
statusEl.setAttribute('title', 'Koneksi Stabil');
} else {
statusEl.classList.remove('online');
statusEl.classList.add('offline');
statusEl.setAttribute('title', 'Koneksi Terputus - Peta mungkin tidak dimuat sempurna');
}
}
// Event listeners untuk mendeteksi perubahan status koneksi
window.addEventListener('online', updateConnectionStatus);
window.addEventListener('offline', updateConnectionStatus);
// Jalankan saat pertama kali dimuat
document.addEventListener('DOMContentLoaded', updateConnectionStatus);
updateConnectionStatus();
// ==========================================
// 17. MODAL TENTANG APLIKASI
// ==========================================
var aboutBtn = document.getElementById('about-btn');
var aboutModal = document.getElementById('about-modal');
var aboutCloseBtn = document.getElementById('about-close-btn');
var aboutOkBtn = document.getElementById('about-ok-btn');
if (aboutBtn && aboutModal) {
aboutBtn.addEventListener('click', function (e) {
e.preventDefault();
aboutModal.classList.add('active');
});
var closeModal = function () {
aboutModal.classList.remove('active');
};
if (aboutCloseBtn) aboutCloseBtn.addEventListener('click', closeModal);
if (aboutOkBtn) aboutOkBtn.addEventListener('click', closeModal);
// Tutup modal jika klik area luar modal-content
aboutModal.addEventListener('click', function (e) {
if (e.target === aboutModal) {
closeModal();
}
});
}