128 lines
5.8 KiB
JavaScript
128 lines
5.8 KiB
JavaScript
/* =========================================================
|
||
skpl-layers.js — Layer SKPL reusable untuk peta login.
|
||
Choropleth kelurahan (KF-06) + Heatmap (KF-08) + legenda +
|
||
layer switcher overlay (KF-09) + pencarian wilayah (KF-11).
|
||
|
||
Pakai: panggil attachSkplLayers(map) setelah map dibuat.
|
||
Butuh leaflet.heat sudah dimuat di halaman.
|
||
========================================================= */
|
||
(function () {
|
||
function injectStyle() {
|
||
if (document.getElementById('skpl-layer-style')) return;
|
||
const css = `
|
||
.skpl-legend{background:#fff;padding:10px 12px;border-radius:10px;box-shadow:0 2px 10px rgba(0,0,0,.15);font-size:.76rem;line-height:1.6}
|
||
.skpl-legend h4{font-size:.78rem;margin:0 0 6px}
|
||
.skpl-legend i{display:inline-block;width:13px;height:13px;border-radius:3px;margin-right:6px;vertical-align:middle}
|
||
.skpl-search{background:#fff;border-radius:10px;box-shadow:0 2px 10px rgba(0,0,0,.15);padding:6px;width:220px}
|
||
.skpl-search input{width:100%;border:1px solid #E5E7EB;border-radius:7px;padding:7px 9px;font-size:.83rem;outline:none}
|
||
.skpl-search input:focus{border-color:#2563EB}
|
||
.skpl-results .item{padding:7px 9px;font-size:.82rem;cursor:pointer;border-radius:6px}
|
||
.skpl-results .item:hover{background:#EFF6FF;color:#1D4ED8}`;
|
||
const s = document.createElement('style');
|
||
s.id = 'skpl-layer-style';
|
||
s.textContent = css;
|
||
document.head.appendChild(s);
|
||
}
|
||
|
||
function colorFor(p) {
|
||
return p >= 10 ? '#EF4444' : p >= 5 ? '#FB923C' : p >= 2 ? '#FBBF24' : p > 0 ? '#A3E635' : '#2ECC71';
|
||
}
|
||
|
||
window.attachSkplLayers = async function (map) {
|
||
if (!map || typeof L === 'undefined') return;
|
||
injectStyle();
|
||
const API = (typeof APP_BASE !== 'undefined' ? APP_BASE : '') + '/api';
|
||
let features = [];
|
||
|
||
// Choropleth
|
||
let choro = null;
|
||
try {
|
||
const j = await (await fetch(`${API}/wilayah.php`)).json();
|
||
const data = j.status === 'success' ? j.data : { type: 'FeatureCollection', features: [] };
|
||
features = data.features || [];
|
||
choro = L.geoJSON(data, {
|
||
style: f => ({
|
||
fillColor: colorFor(f.properties.persentase_miskin || 0),
|
||
fillOpacity: 0.5, color: '#374151', weight: 1.5,
|
||
}),
|
||
onEachFeature: (f, layer) => {
|
||
const p = f.properties;
|
||
layer.bindPopup(`<div style="font-weight:700;margin-bottom:6px;">${p.nama}</div>
|
||
<div style="font-size:.85rem;line-height:1.6;">
|
||
Penduduk: <strong>${p.jumlah_penduduk}</strong><br>
|
||
Warga miskin: <strong>${p.jumlah_miskin}</strong><br>
|
||
Persentase: <strong>${p.persentase_miskin}%</strong></div>`);
|
||
layer.bindTooltip(p.nama, { sticky: true });
|
||
},
|
||
});
|
||
} catch (e) { /* abaikan */ }
|
||
|
||
// Heatmap
|
||
let heat = null;
|
||
try {
|
||
const j = await (await fetch(`${API}/heatmap.php`)).json();
|
||
const pts = j.status === 'success' ? j.data : [];
|
||
if (L.heatLayer) {
|
||
heat = L.heatLayer(pts, {
|
||
radius: 30, blur: 22, maxZoom: 17,
|
||
gradient: { 0.2: '#3B82F6', 0.5: '#FBBF24', 0.9: '#EF4444' },
|
||
});
|
||
}
|
||
} catch (e) { /* abaikan */ }
|
||
|
||
// Layer switcher overlay
|
||
const overlays = {};
|
||
if (choro) overlays['🗺️ Choropleth Kelurahan'] = choro;
|
||
if (heat) overlays['🔥 Heatmap Kepadatan'] = heat;
|
||
if (Object.keys(overlays).length) {
|
||
L.control.layers(null, overlays, { collapsed: true, position: 'topright' }).addTo(map);
|
||
}
|
||
|
||
// Legenda
|
||
const legend = L.control({ position: 'bottomleft' });
|
||
legend.onAdd = function () {
|
||
const div = L.DomUtil.create('div', 'skpl-legend');
|
||
const g = [
|
||
['#2ECC71', 'Tidak ada kasus'], ['#A3E635', '< 2%'],
|
||
['#FBBF24', '2 – 5%'], ['#FB923C', '5 – 10%'], ['#EF4444', '> 10% (prioritas)'],
|
||
];
|
||
div.innerHTML = '<h4>Tingkat Kemiskinan</h4>' +
|
||
g.map(x => `<div><i style="background:${x[0]}"></i>${x[1]}</div>`).join('');
|
||
return div;
|
||
};
|
||
legend.addTo(map);
|
||
|
||
// Pencarian wilayah (KF-11)
|
||
const search = L.control({ position: 'topright' });
|
||
search.onAdd = function () {
|
||
const div = L.DomUtil.create('div', 'skpl-search');
|
||
div.innerHTML = `<input type="text" placeholder="🔍 Cari kelurahan...">
|
||
<div class="skpl-results"></div>`;
|
||
L.DomEvent.disableClickPropagation(div);
|
||
return div;
|
||
};
|
||
search.addTo(map);
|
||
const root = document.querySelector('.skpl-search');
|
||
if (root) {
|
||
const input = root.querySelector('input');
|
||
const res = root.querySelector('.skpl-results');
|
||
input.addEventListener('input', function () {
|
||
const q = this.value.toLowerCase().trim();
|
||
res.innerHTML = '';
|
||
if (!q) return;
|
||
features.filter(f => f.properties.nama.toLowerCase().includes(q)).slice(0, 6).forEach(f => {
|
||
const it = document.createElement('div');
|
||
it.className = 'item';
|
||
it.textContent = f.properties.nama;
|
||
it.onclick = () => {
|
||
map.fitBounds(L.geoJSON(f).getBounds(), { padding: [60, 60] });
|
||
res.innerHTML = '';
|
||
input.value = f.properties.nama;
|
||
};
|
||
res.appendChild(it);
|
||
});
|
||
});
|
||
}
|
||
};
|
||
})();
|