menambahkan fitur heatmap dan memperbarui ui layer control

This commit is contained in:
powji17
2026-06-12 11:39:27 +07:00
parent 34cdf384c8
commit 94ca490bf2
3 changed files with 191 additions and 15 deletions
+56 -7
View File
@@ -282,13 +282,53 @@ html, body {
top: 0; bottom: 0; left: 0; right: 0;
}
/* ===== LAYER CONTROL ===== */
.leaflet-control-layers {
border-radius: 10px !important;
border: none !important;
box-shadow: 0 2px 12px rgba(0,0,0,0.12) !important;
font-family: 'Segoe UI', Arial, sans-serif !important;
font-size: 13px !important;
/* ===== LAYER CONTROL DI SIDEBAR ===== */
.layer-control {
display: flex;
flex-direction: column;
gap: 6px;
padding: 4px 2px;
}
.layer-item {
display: flex;
align-items: center;
gap: 8px;
font-size: 13px;
color: #444;
cursor: pointer;
padding: 4px 2px;
border-radius: 6px;
transition: background 0.15s;
}
.layer-item:hover {
background: #f0f4f8;
}
.layer-item input[type="checkbox"] {
width: 15px;
height: 15px;
cursor: pointer;
accent-color: #1B2A4A;
flex-shrink: 0;
}
.layer-dot {
width: 12px;
height: 12px;
border-radius: 50%;
display: inline-block;
flex-shrink: 0;
}
.layer-radius-icon {
width: 16px;
height: 10px;
border: 2px dashed #8e44ad;
border-radius: 50%;
display: inline-block;
flex-shrink: 0;
}
.map-legend {
@@ -327,4 +367,13 @@ html, body {
border-radius: 50%;
display: inline-block;
flex-shrink: 0;
}
.layer-heatmap-icon {
width: 16px;
height: 12px;
border-radius: 4px;
background: linear-gradient(to right, #3498db, #f1c40f, #e67e22, #e74c3c);
display: inline-block;
flex-shrink: 0;
}
+72 -8
View File
@@ -11,14 +11,21 @@ const layerTidakTercakup = L.layerGroup().addTo(map);
const layerIbadah = L.layerGroup().addTo(map);
const layerRadius = L.layerGroup().addTo(map);
// 2. DAFTARKAN LAYER-LAYER TERSEBUT KE DALAM CONTROL PANEL
const overlays = {
"<span style='color:#27ae60'>⌂</span> Prasejahtera Tercakup": layerTercakup,
"<span style='color:#e74c3c'>⌂</span> Prasejahtera Tidak Tercakup": layerTidakTercakup,
"<i class='fa-solid fa-place-of-worship' style='color:purple'></i> Rumah Ibadah": layerIbadah,
"○ Radius Jangkauan": layerRadius,
};
L.control.layers(null, overlays, { collapsed: false }).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');
@@ -38,6 +45,14 @@ legend.onAdd = function() {
<div class="legend-item"><span class="legend-dot" style="background:#e74c3c;"></span> Klenteng</div>
<hr style="margin:6px 0; border-color:#eee;">
<div class="legend-item"><span class="legend-radius"></span> Radius Jangkauan</div>
<div class="legend-item">
<span style="
width:40px; height:10px;
background: linear-gradient(to right, #3498db, #f1c40f, #e67e22, #e74c3c);
border-radius:4px; display:inline-block; flex-shrink:0;
"></span>
Heatmap Kemiskinan
</div>
`;
return div;
};
@@ -372,6 +387,12 @@ function loadDB() {
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();
});
@@ -391,6 +412,8 @@ function refreshPeta() {
// 3. Panggil ulang data terbaru dari database
loadDB();
if (heatmapAktif) buatHeatmap();
}
// --- EVENT KLIK PETA ---
@@ -864,4 +887,45 @@ function simpanEditIbadah(id) {
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);
}
+63
View File
@@ -56,6 +56,37 @@ $role = $isLoggedIn ? $_SESSION['role'] : 'viewer';
</a>
<?php endif; ?>
<div class="sidebar-divider"></div>
<span class="sidebar-label">Visualisasi</span>
<div class="layer-control">
<label class="layer-item">
<input type="checkbox" checked onchange="toggleLayer('tercakup', this)">
<span class="layer-dot" style="background:#27ae60;"></span>
Prasejahtera Tercakup
</label>
<label class="layer-item">
<input type="checkbox" checked onchange="toggleLayer('tidakTercakup', this)">
<span class="layer-dot" style="background:#e74c3c;"></span>
Prasejahtera Tidak Tercakup
</label>
<label class="layer-item">
<input type="checkbox" checked onchange="toggleLayer('ibadah', this)">
<span class="layer-dot" style="background:#9b59b6;"></span>
Rumah Ibadah
</label>
<label class="layer-item">
<input type="checkbox" checked onchange="toggleLayer('radius', this)">
<span class="layer-radius-icon"></span>
Radius Jangkauan
</label>
<label class="layer-item" style="cursor:pointer;">
<input type="checkbox" id="checkbox-heatmap" checked onchange="toggleHeatmap()">
<span class="layer-heatmap-icon"></span>
Heatmap Kemiskinan
</label>
</div>
<div class="sidebar-divider"></div>
<a href="logout.php" class="btn-logout">
<i class="fa-solid fa-right-from-bracket"></i> Logout
@@ -70,6 +101,37 @@ $role = $isLoggedIn ? $_SESSION['role'] : 'viewer';
<i class="fa-solid fa-right-to-bracket"></i> Login
</a>
<div class="sidebar-divider"></div>
<span class="sidebar-label">Visualisasi</span>
<div class="layer-control">
<label class="layer-item">
<input type="checkbox" checked onchange="toggleLayer('tercakup', this)">
<span class="layer-dot" style="background:#27ae60;"></span>
Prasejahtera Tercakup
</label>
<label class="layer-item">
<input type="checkbox" checked onchange="toggleLayer('tidakTercakup', this)">
<span class="layer-dot" style="background:#e74c3c;"></span>
Prasejahtera Tidak Tercakup
</label>
<label class="layer-item">
<input type="checkbox" checked onchange="toggleLayer('ibadah', this)">
<span class="layer-dot" style="background:#9b59b6;"></span>
Rumah Ibadah
</label>
<label class="layer-item">
<input type="checkbox" checked onchange="toggleLayer('radius', this)">
<span class="layer-radius-icon"></span>
Radius Jangkauan
</label>
<label class="layer-item" style="cursor:pointer;">
<input type="checkbox" id="checkbox-heatmap" checked onchange="toggleHeatmap()">
<span class="layer-heatmap-icon"></span>
Heatmap Kemiskinan
</label>
</div>
<?php endif; ?>
</div>
@@ -88,6 +150,7 @@ $role = $isLoggedIn ? $_SESSION['role'] : 'viewer';
const ROLE = '<?= $role ?>';
</script>
<script src="https://unpkg.com/leaflet.heat@0.2.0/dist/leaflet-heat.js"></script>
<script src="assets/js/script.js"></script>
</body>
</html>