// --- INISIALISASI PETA (Koordinat Pontianak) ---
const map = L.map('map').setView([-0.055348, 109.349512], 13);
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 19, attribution: '© OpenStreetMap' }).addTo(map);
const popup = L.popup();
const daftarMarker = {}, daftarPolyline = {}, daftarPolygon = {};
// 1. BUAT KERTAS TRANSPARAN (LAYER GROUPS)
const layerTercakup = L.layerGroup().addTo(map);
const layerTidakTercakup = L.layerGroup().addTo(map);
const layerIbadah = L.layerGroup().addTo(map);
const layerRadius = L.layerGroup().addTo(map);
function toggleLayer(namaLayer, checkbox) {
const layers = {
'tercakup': layerTercakup,
'tidakTercakup': layerTidakTercakup,
'ibadah': layerIbadah,
'radius': layerRadius,
};
if (checkbox.checked) {
layers[namaLayer].addTo(map);
} else {
map.removeLayer(layers[namaLayer]);
}
}
let legend = L.control({ position: 'topright' });
legend.onAdd = function() {
let div = L.DomUtil.create('div', 'map-legend');
div.innerHTML = `
Legenda
Prasejahtera Tercakup
Prasejahtera Tidak Tercakup
Masjid
Gereja
Vihara
Pura
Klenteng
Radius Jangkauan
Heatmap Kemiskinan
`;
return div;
};
legend.addTo(map);
let currentMode = 'none';
let tempLatLngs = [], tempPolyline = null;
let tempPolygonLatLngs = [], tempPolygon = null;
let targetEditJalanId = null; // Menyimpan ID jalan yang sedang diedit
let targetEditKavlingId = null; // Menyimpan ID kavling yang sedang diedit
// Konfigurasi SweetAlert2 (Toast Pojok Kanan Atas)
const Toast = Swal.mixin({
toast: true, position: 'top-end', showConfirmButton: false, timer: 3000, timerProgressBar: true
});
// Definisi Ikon Kustom
const ikonHijau = new L.Icon({ iconUrl: 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-green.png', shadowUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/images/marker-shadow.png', iconSize: [25, 41], iconAnchor: [12, 41], popupAnchor: [1, -34], shadowSize: [41, 41] });
const ikonMerah = new L.Icon({ iconUrl: 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-red.png', shadowUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/images/marker-shadow.png', iconSize: [25, 41], iconAnchor: [12, 41], popupAnchor: [1, -34], shadowSize: [41, 41] });
// ikon rumah prasejahtera
const ikonPrasejahtera = L.divIcon({
html: `
`,
iconSize: [32, 32],
iconAnchor: [16, 32],
popupAnchor: [0, -34],
className: ''
});
const ikonPrasejahteraTercakup = L.divIcon({
html: `
`,
iconSize: [32, 32], iconAnchor: [16, 32], popupAnchor: [0, -34], className: ''
});
function buatIkonIbadah(jenis) {
const config = {
'Masjid': { icon: 'fa-mosque', color: '#1abc9c' },
'Gereja': { icon: 'fa-church', color: '#3498db' },
'Vihara': { icon: 'fa-torii-gate', color: '#e67e22' },
'Pura': { icon: 'fa-om', color: '#9b59b6' },
'Klenteng': { icon: 'fa-yin-yang', color: '#e74c3c' },
};
const c = config[jenis] || { icon: 'fa-place-of-worship', color: '#7f8c8d' };
return L.divIcon({
html: `
`,
iconSize: [32, 32], iconAnchor: [16, 32], popupAnchor: [0, -34], className: ''
});
}
// Simpan data ibadah dan prasejahtera dalam memori untuk kalkulasi
const dataPrasejahtera = {}; // { id: {lat, lng, marker} }
const dataIbadah = {}; // { id: {lat, lng, radius_m, lingkaran} }
function perbaruiWarnaPrasejahtera() {
for (let pid in dataPrasejahtera) {
let p = dataPrasejahtera[pid];
let tercakup = false;
for (let iid in dataIbadah) {
let ib = dataIbadah[iid];
let jarak = map.distance([p.lat, p.lng], [ib.lat, ib.lng]);
if (jarak <= ib.radius_m) { tercakup = true; break; }
}
// Ganti ikon sesuai status
let ikonBaru = tercakup ? ikonPrasejahteraTercakup : ikonPrasejahtera;
p.marker.setIcon(ikonBaru);
layerTercakup.removeLayer(p.marker);
layerTidakTercakup.removeLayer(p.marker);
if (tercakup) {
p.marker.addTo(layerTercakup);
} else {
p.marker.addTo(layerTidakTercakup);
}
}
updateRingkasan();
}
// --- MANAJEMEN MODE UI ---
function ubahMode(mode) {
if (ROLE === 'viewer') return;
console.log('Mode diklik:', mode, '| Mode saat ini:', currentMode); // ← tambah ini
if (currentMode === mode) {
// Jika mode yang diklik sama dengan yang aktif, matikan semua
currentMode = 'none'; // Mode netral
map.pm.disableGlobalEditMode();
if (targetEditJalanId) batalkanEditJalan();
if (targetEditKavlingId) batalkanEditKavling();
// Matikan semua highlight tombol aktif
document.querySelectorAll('.mode-btn').forEach(btn => btn.classList.remove('active'));
// Sembunyikan semua panel sidebar
document.getElementById('polyline-actions').style.display = 'none';
document.getElementById('polygon-actions').style.display = 'none';
document.getElementById('edit-jalan-actions').style.display = 'none';
document.getElementById('edit-kavling-actions').style.display = 'none';
map.closePopup();
batalPolyline();
batalPolygon();
return; // Hentikan eksekusi, tidak perlu lanjut ke bawah
}
currentMode = mode;
// Matikan mode edit Geoman global jika sedang aktif
map.pm.disableGlobalEditMode();
// Reset state edit
if (targetEditJalanId) batalkanEditJalan();
if (targetEditKavlingId) batalkanEditKavling();
// Atur tampilan tombol aktif
document.querySelectorAll('.mode-btn').forEach(btn => btn.classList.remove('active'));
document.querySelector(`.mode-btn[data-mode="${mode}"]`).classList.add('active');
// Munculkan menu yang sesuai di sidebar
document.getElementById('polyline-actions').style.display = (mode === 'polyline') ? 'block' : 'none';
document.getElementById('polygon-actions').style.display = (mode === 'polygon') ? 'block' : 'none';
document.getElementById('edit-jalan-actions').style.display = (mode === 'edit_jalan') ? 'block' : 'none';
document.getElementById('edit-kavling-actions').style.display = (mode === 'edit_kavling') ? 'block' : 'none';
map.closePopup();
if (mode !== 'polyline') batalPolyline();
if (mode !== 'polygon') batalPolygon();
}
// --- LOAD DATA DARI DATABASE ---
function loadIbadah() {
fetch('api/rumahibadah/load_ibadah.php').then(res => res.json()).then(data => {
data.forEach(ib => {
let marker = L.marker([ib.lat, ib.lng], {
icon: buatIkonIbadah(ib.jenis),
draggable: ROLE === 'admin' || ROLE === 'operator'
})
.addTo(layerIbadah);
// Lingkaran radius
let lingkaran = L.circle([ib.lat, ib.lng], {
radius: ib.radius_m, color: '#8e44ad',
fillColor: '#8e44ad', fillOpacity: 0.1, weight: 1, dashArray: '5,5'
}).addTo(layerRadius);
const totalPrasejahtera = Object.keys(dataPrasejahtera).length;
const persen = totalPrasejahtera > 0
? Math.round((ib.jumlah_tercakup / totalPrasejahtera) * 100)
: 0;
marker.bindPopup(`
${ib.nama_ibadah}
Jenis: ${ib.jenis}
Jangkauan Bantuan: ${ib.radius_m} m
${ib.jumlah_tercakup}
rumah tercakup dari ${totalPrasejahtera} total
${persen}% dari total prasejahtera
${ROLE === 'admin' || ROLE === 'operator' ? `
` : ''}
${ROLE === 'admin' ? `
` : ''}
`);
marker.on('dragend', function(e) {
let pos = e.target.getLatLng();
lingkaran.setLatLng(pos);
dataIbadah[ib.id] = { lat: pos.lat, lng: pos.lng, radius_m: ib.radius_m, lingkaran };
updateLokasiIbadah(ib.id, pos.lat, pos.lng);
perbaruiWarnaPrasejahtera();
});
dataIbadah[ib.id] = { lat: ib.lat, lng: ib.lng, radius_m: ib.radius_m, lingkaran };
daftarMarker['ib_' + ib.id] = marker;
});
// Setelah semua ibadah dimuat, perbarui warna prasejahtera
perbaruiWarnaPrasejahtera();
});
}
function formatRupiah(angka) {
return new Intl.NumberFormat('id-ID', { style: 'currency', currency: 'IDR' }).format(angka);
}
function loadDB() {
fetch('api/prasejahtera/load_prasejahtera.php').then(res => res.json()).then(data => {
data.forEach(rumah => {
// PERBAIKAN: Gunakan 'rumah.', bukan 'data.'
let penghasilanTeks = formatRupiah(rumah.penghasilan);
let statusOrtuTeks = `Status Ortu: ${rumah.status_ortu}
`;
if (rumah.status_ortu === 'Bekerja') {
statusOrtuTeks += `Penghasilan: ${formatRupiah(rumah.penghasilan)}
`;
} else if (rumah.status_ortu === 'Pensiun') {
statusOrtuTeks += `Uang Pensiun: ${rumah.ada_pensiun === 'Ya' ? formatRupiah(rumah.nominal_pensiun) : 'Tidak Ada'}
`;
} else if (rumah.status_ortu === 'Meninggal') {
statusOrtuTeks += `Uang Terusan: ${rumah.ada_terusan === 'Ya' ? formatRupiah(rumah.nominal_terusan) : 'Tidak Ada'}
`;
}
let isiPopup = `
${rumah.nama_kepala_keluarga}
Anak: ${rumah.jumlah_anak} orang (Umur: ${rumah.umur_anak || '-'})
${statusOrtuTeks}
Keterangan: ${rumah.keterangan || '-'}
${ROLE === 'admin' || ROLE === 'operator' ? `
` : ''}
${ROLE === 'admin' ? `
` : ''}
`;
let marker = L.marker([rumah.lat, rumah.lng], {
icon: ikonPrasejahtera,
draggable: ROLE === 'admin' || ROLE === 'operator'
});
marker.bindPopup(isiPopup);
marker.on('dragend', function(e) {
let pos = e.target.getLatLng();
dataPrasejahtera[rumah.id].lat = pos.lat;
dataPrasejahtera[rumah.id].lng = pos.lng;
updateLokasiPrasejahtera(rumah.id, pos.lat, pos.lng);
perbaruiWarnaPrasejahtera();
});
dataPrasejahtera[rumah.id] = { lat: rumah.lat, lng: rumah.lng, marker };
daftarMarker['p_' + rumah.id] = marker;
marker.bindPopup(isiPopup);
marker.on('dragend', function(e) {
let pos = e.target.getLatLng();
dataPrasejahtera[rumah.id].lat = pos.lat;
dataPrasejahtera[rumah.id].lng = pos.lng;
updateLokasiPrasejahtera(rumah.id, pos.lat, pos.lng);
perbaruiWarnaPrasejahtera();
});
dataPrasejahtera[rumah.id] = { lat: rumah.lat, lng: rumah.lng, marker };
daftarMarker['p_' + rumah.id] = marker;
});
// Perbarui heatmap setelah data prasejahtera termuat
if (document.getElementById('checkbox-heatmap')?.checked) {
buatHeatmap();
heatmapAktif = true;
}
// Muat ibadah SETELAH prasejahtera selesai
loadIbadah();
});
}
loadDB();
// --- FUNGSI UNTUK ME-REFRESH PETA SECARA OTOMATIS (SOFT REFRESH) ---
function refreshPeta() {
layerTercakup.clearLayers();
layerTidakTercakup.clearLayers();
layerIbadah.clearLayers();
layerRadius.clearLayers();
// 2. Bersihkan memori agar ID tidak menumpuk/ganda
for (let id in dataIbadah) delete dataIbadah[id];
for (let id in dataPrasejahtera) delete dataPrasejahtera[id];
// 3. Panggil ulang data terbaru dari database
loadDB();
if (heatmapAktif) buatHeatmap();
}
// --- EVENT KLIK PETA ---
function onMapClick(e) {
if (ROLE === 'viewer') return;
if (currentMode === 'point') {
let formHtml = `
SPBU Baru
`;
popup.setLatLng(e.latlng).setContent(formHtml).openOn(map);
} else if (currentMode === 'polyline') {
tempLatLngs.push(e.latlng);
if (!tempPolyline) tempPolyline = L.polyline(tempLatLngs, {color: '#3498db', weight: 4}).addTo(map);
else tempPolyline.setLatLngs(tempLatLngs);
} else if (currentMode === 'polygon') {
tempPolygonLatLngs.push(e.latlng);
if (!tempPolygon) tempPolygon = L.polygon(tempPolygonLatLngs, {color: '#2ecc71', fillColor: '#2ecc71', fillOpacity: 0.4}).addTo(map);
else tempPolygon.setLatLngs(tempPolygonLatLngs);
} else if (currentMode === 'prasejahtera') {
let formHtml = `
`;
popup.setLatLng(e.latlng).setContent(formHtml).openOn(map);
} else if (currentMode === 'ibadah') {
let formHtml = `
Rumah Ibadah
`;
popup.setLatLng(e.latlng).setContent(formHtml).openOn(map);
}
}
map.on('click', onMapClick);
function simpanPrasejahtera(lat, lng) {
// 1. Validasi Manual
let nama_kk = document.getElementById('nama_kk').value.trim();
if (!nama_kk || nama_kk === "") {
Toast.fire({ icon: 'warning', title: 'Nama Kepala Keluarga wajib diisi!' });
return; // Hentikan proses eksekusi jika kosong
}
// 2. Susun Data
let dataKirim = {
lat: lat, lng: lng,
nama_kk: nama_kk,
penghasilan: parseInt(document.getElementById('penghasilan').value) || 0,
jumlah_anak: parseInt(document.getElementById('jumlah_anak').value) || 0,
umur_anak: document.getElementById('umur_anak').value,
status_ortu: document.getElementById('status_ortu').value,
ada_pensiun: document.getElementById('ada_pensiun').value,
nominal_pensiun: parseInt(document.getElementById('nominal_pensiun').value) || 0,
ada_terusan: document.getElementById('ada_terusan').value,
nominal_terusan: parseInt(document.getElementById('nominal_terusan').value) || 0,
keterangan: document.getElementById('keterangan').value
};
// 3. Kirim ke Database
fetch('api/prasejahtera/simpan_prasejahtera.php', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(dataKirim)
})
.then(res => res.json())
.then(data => {
if (data.status === 'success') {
Toast.fire({ icon: 'success', title: 'Data Berhasil Disimpan!' });
map.closePopup();
refreshPeta(); // Sinkronisasi seketika
} else {
Toast.fire({ icon: 'error', title: 'Gagal Menyimpan: ' + (data.message || 'Error Database') });
}
})
.catch(error => {
console.error("Terjadi masalah:", error);
Toast.fire({ icon: 'error', title: 'Koneksi ke Server Gagal!' });
});
}
function hapusPrasejahtera(id) {
Swal.fire({ title: 'Hapus data ini?', icon: 'warning', showCancelButton: true,
confirmButtonColor: '#d33', cancelButtonColor: '#3085d6',
confirmButtonText: 'Ya, Hapus!', cancelButtonText: 'Batal'
}).then(result => {
if (result.isConfirmed) {
fetch('api/prasejahtera/hapus_prasejahtera.php', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ id: id }) })
.then(res => res.json()).then(data => {
if (data.status === 'success') {
Toast.fire({ icon: 'success', title: 'Data Dihapus!' });
// Cukup panggil fungsi ini, Leaflet akan menyapu bersih peta
// dan memanggil ulang data terbaru dari database secara otomatis!
refreshPeta();
} else Toast.fire({ icon: 'error', title: 'Gagal Menghapus!' });
});
}
});
}
function updateLokasiPrasejahtera(id, lat, lng) {
fetch('api/prasejahtera/update_prasejahtera.php', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ id, lat, lng }) })
.then(res => res.json()).then(data => { if (data.status === 'success') Toast.fire({ icon: 'info', title: 'Posisi Diperbarui' }); });
}
function simpanIbadah(event, lat, lng) {
event.preventDefault();
let dataKirim = {
lat, lng,
nama_ibadah: document.getElementById('nama_ibadah').value,
jenis: document.getElementById('jenis_ibadah').value,
radius_m: parseInt(document.getElementById('radius_ibadah').value)
};
fetch('api/rumahibadah/simpan_ibadah.php', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(dataKirim) })
.then(res => res.json()).then(data => {
if (data.status === 'success') {
Toast.fire({ icon: 'success', title: 'Rumah Ibadah Disimpan!' });
map.closePopup();
refreshPeta();
} else Toast.fire({ icon: 'error', title: 'Gagal Menyimpan!' });
});
}
function hapusIbadah(id) {
Swal.fire({ title: 'Hapus Rumah Ibadah?', icon: 'warning', showCancelButton: true,
confirmButtonColor: '#d33', cancelButtonColor: '#3085d6',
confirmButtonText: 'Ya, Hapus!', cancelButtonText: 'Batal'
}).then(result => {
if (result.isConfirmed) {
fetch('api/rumahibadah/hapus_ibadah.php', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ id }) })
.then(res => res.json()).then(data => {
if (data.status === 'success') {
Toast.fire({ icon: 'success', title: 'Data Dihapus!' });
// Gunakan refreshPeta agar sinkron dengan database 100%
refreshPeta();
} else Toast.fire({ icon: 'error', title: 'Gagal Menghapus!' });
});
}
});
}
function updateLokasiIbadah(id, lat, lng) {
fetch('api/rumahibadah/update_ibadah.php', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ id, lat, lng }) })
.then(res => res.json()).then(data => { if (data.status === 'success') Toast.fire({ icon: 'info', title: 'Posisi Diperbarui' }); });
}
// --- FUNGSI TOGGLE FORM PRASEJAHTERA ---
function toggleStatusOrtu() {
let status = document.getElementById('status_ortu').value;
// Atur visibilitas grup
document.getElementById('grup_bekerja').style.display = (status === 'Bekerja') ? 'block' : 'none';
document.getElementById('grup_pensiun').style.display = (status === 'Pensiun') ? 'block' : 'none';
document.getElementById('grup_meninggal').style.display = (status === 'Meninggal') ? 'block' : 'none';
// Reset nilai yang tersembunyi agar tidak ikut tersimpan salah
if(status !== 'Bekerja') document.getElementById('penghasilan').value = 0;
if(status !== 'Pensiun') { document.getElementById('ada_pensiun').value = 'Tidak'; togglePensiun(); }
if(status !== 'Meninggal') { document.getElementById('ada_terusan').value = 'Tidak'; toggleTerusan(); }
}
function togglePensiun() {
let ada = document.getElementById('ada_pensiun').value;
document.getElementById('grup_nominal_pensiun').style.display = (ada === 'Ya') ? 'block' : 'none';
if(ada === 'Tidak') document.getElementById('nominal_pensiun').value = 0;
}
function toggleTerusan() {
let ada = document.getElementById('ada_terusan').value;
document.getElementById('grup_nominal_terusan').style.display = (ada === 'Ya') ? 'block' : 'none';
if(ada === 'Tidak') document.getElementById('nominal_terusan').value = 0;
}
// --- EDIT PRASEJAHTERA ---
function editPrasejahtera(id) {
fetch(`api/prasejahtera/get_prasejahtera.php?id=${id}`)
.then(res => res.json())
.then(d => {
let formHtml = `
`;
// Ganti konten popup yang sudah terbuka dengan form edit
daftarMarker['p_' + id].getPopup().setContent(formHtml);
})
.catch(() => Toast.fire({ icon: 'error', title: 'Gagal memuat data!' }));
}
function toggleEditStatusOrtu() {
let status = document.getElementById('edit_status_ortu').value;
document.getElementById('edit_grup_bekerja').style.display = status === 'Bekerja' ? 'block' : 'none';
document.getElementById('edit_grup_pensiun').style.display = status === 'Pensiun' ? 'block' : 'none';
document.getElementById('edit_grup_meninggal').style.display = status === 'Meninggal' ? 'block' : 'none';
if (status !== 'Bekerja') document.getElementById('edit_penghasilan').value = 0;
if (status !== 'Pensiun') { document.getElementById('edit_ada_pensiun').value = 'Tidak'; toggleEditPensiun(); }
if (status !== 'Meninggal') { document.getElementById('edit_ada_terusan').value = 'Tidak'; toggleEditTerusan(); }
}
function toggleEditPensiun() {
let ada = document.getElementById('edit_ada_pensiun').value;
document.getElementById('edit_grup_nominal_pensiun').style.display = ada === 'Ya' ? 'block' : 'none';
if (ada === 'Tidak') document.getElementById('edit_nominal_pensiun').value = 0;
}
function toggleEditTerusan() {
let ada = document.getElementById('edit_ada_terusan').value;
document.getElementById('edit_grup_nominal_terusan').style.display = ada === 'Ya' ? 'block' : 'none';
if (ada === 'Tidak') document.getElementById('edit_nominal_terusan').value = 0;
}
function simpanEditPrasejahtera(id) {
let nama_kk = document.getElementById('edit_nama_kk').value.trim();
if (!nama_kk) {
Toast.fire({ icon: 'warning', title: 'Nama Kepala Keluarga wajib diisi!' });
return;
}
let dataKirim = {
id: id,
nama_kk: nama_kk,
jumlah_anak: parseInt(document.getElementById('edit_jumlah_anak').value) || 0,
umur_anak: document.getElementById('edit_umur_anak').value,
status_ortu: document.getElementById('edit_status_ortu').value,
penghasilan: parseInt(document.getElementById('edit_penghasilan').value) || 0,
ada_pensiun: document.getElementById('edit_ada_pensiun').value,
nominal_pensiun: parseInt(document.getElementById('edit_nominal_pensiun').value) || 0,
ada_terusan: document.getElementById('edit_ada_terusan').value,
nominal_terusan: parseInt(document.getElementById('edit_nominal_terusan').value) || 0,
keterangan: document.getElementById('edit_keterangan').value
};
fetch('api/prasejahtera/update_prasejahtera.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(dataKirim)
})
.then(res => res.json())
.then(data => {
if (data.status === 'success') {
Toast.fire({ icon: 'success', title: 'Data Berhasil Diperbarui!' });
map.closePopup();
refreshPeta();
} else {
Toast.fire({ icon: 'error', title: 'Gagal: ' + (data.message || 'Error') });
}
});
}
// --- EDIT IBADAH ---
function editIbadah(id) {
fetch(`api/rumahibadah/get_ibadah.php?id=${id}`)
.then(res => res.json())
.then(d => {
let jenisOptions = ['Masjid', 'Gereja', 'Vihara', 'Pura', 'Klenteng'].map(j =>
``
).join('');
let formHtml = `
Edit Rumah Ibadah
`;
daftarMarker['ib_' + id].getPopup().setContent(formHtml);
})
.catch(() => Toast.fire({ icon: 'error', title: 'Gagal memuat data!' }));
}
function simpanEditIbadah(id) {
let nama = document.getElementById('edit_nama_ibadah').value.trim();
if (!nama) {
Toast.fire({ icon: 'warning', title: 'Nama Rumah Ibadah wajib diisi!' });
return;
}
let dataKirim = {
id: id,
nama_ibadah: nama,
jenis: document.getElementById('edit_jenis_ibadah').value,
radius_m: parseInt(document.getElementById('edit_radius_ibadah').value)
};
fetch('api/rumahibadah/update_ibadah.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(dataKirim)
})
.then(res => res.json())
.then(data => {
if (data.status === 'success') {
Toast.fire({ icon: 'success', title: 'Rumah Ibadah Diperbarui!' });
map.closePopup();
refreshPeta();
} else {
Toast.fire({ icon: 'error', title: 'Gagal: ' + (data.message || 'Error') });
}
});
}
// --- HEATMAP ---
let heatmapLayer = null;
let heatmapAktif = false;
function toggleHeatmap() {
let checkbox = document.getElementById('checkbox-heatmap');
if (checkbox.checked) {
buatHeatmap();
heatmapAktif = true;
} else {
if (heatmapLayer) map.removeLayer(heatmapLayer);
heatmapAktif = false;
}
}
function buatHeatmap() {
// Ambil koordinat dari dataPrasejahtera yang sudah ada di memori
let points = [];
for (let id in dataPrasejahtera) {
let p = dataPrasejahtera[id];
points.push([p.lat, p.lng, 1]); // [lat, lng, intensity]
}
// Hapus layer lama kalau ada
if (heatmapLayer) map.removeLayer(heatmapLayer);
heatmapLayer = L.heatLayer(points, {
radius: 35, // ukuran area panas per titik
blur: 25, // tingkat kehalusan gradasi
maxZoom: 17, // zoom maksimal sebelum intensitas penuh
max: 1.0,
gradient: {
0.2: '#3498db', // biru = kepadatan rendah
0.5: '#f1c40f', // kuning = kepadatan sedang
0.8: '#e67e22', // oranye = kepadatan tinggi
1.0: '#e74c3c' // merah = kepadatan sangat tinggi
}
}).addTo(map);
}
function updateRingkasan() {
let totalPrasejahtera = Object.keys(dataPrasejahtera).length;
let totalIbadah = Object.keys(dataIbadah).length;
let totalTercakup = layerTercakup.getLayers().length;
let totalTidak = layerTidakTercakup.getLayers().length;
let persen = totalPrasejahtera > 0
? Math.round((totalTercakup / totalPrasejahtera) * 100) : 0;
document.getElementById('stat-total').textContent = totalPrasejahtera;
document.getElementById('stat-tercakup').textContent = totalTercakup;
document.getElementById('stat-tidak').textContent = totalTidak;
document.getElementById('stat-persen').textContent = persen + '%';
document.getElementById('stat-ibadah').textContent = totalIbadah;
// Update progress bar
document.getElementById('stat-progress').style.width = persen + '%';
// Warna progress bar berdasarkan persentase
let warna = persen >= 70 ? '#27ae60' : persen >= 40 ? '#f39c12' : '#e74c3c';
document.getElementById('stat-progress').style.background = warna;
}