tambah fitur add tempat ibadah
This commit is contained in:
@@ -170,6 +170,19 @@
|
||||
z-index: 2000;
|
||||
}
|
||||
.toast.show { opacity: 1; transform: translateY(0); }
|
||||
.ibadah-legend { display: none; }
|
||||
.ibadah-legend.active { display: block; }
|
||||
.ibadah-map-marker {
|
||||
display: grid;
|
||||
place-items: center;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border-radius: 999px;
|
||||
color: white;
|
||||
border: 3px solid white;
|
||||
box-shadow: 0 10px 24px rgba(15, 23, 42, .28);
|
||||
font-size: 15px;
|
||||
}
|
||||
@media (max-width: 880px) {
|
||||
body { overflow: hidden; }
|
||||
.app { grid-template-columns: 1fr; }
|
||||
@@ -222,6 +235,7 @@
|
||||
<input id="searchInput" placeholder="Nama, alamat, atau wilayah" />
|
||||
</label>
|
||||
<label class="switch"><span>Heatmap persebaran</span><input id="heatToggle" type="checkbox" checked /></label>
|
||||
<label class="switch"><span>⛪ Tempat Ibadah</span><input id="ibadahToggle" type="checkbox" /></label>
|
||||
</section>
|
||||
|
||||
<section class="panel">
|
||||
@@ -234,6 +248,17 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel ibadah-legend" id="ibadahLegendPanel">
|
||||
<h2>Legenda Tempat Ibadah</h2>
|
||||
<div class="legend">
|
||||
<span><i class="dot" style="background:#7c3aed"></i>Gereja Katolik</span>
|
||||
<span><i class="dot" style="background:#2563eb"></i>GPIB</span>
|
||||
<span><i class="dot" style="background:#0891b2"></i>GKI</span>
|
||||
<span><i class="dot" style="background:#16a34a"></i>HKBP</span>
|
||||
<span><i class="dot" style="background:#ea580c"></i>Pentakosta</span>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel">
|
||||
<h2>Statistik Wilayah</h2>
|
||||
<div id="areaStats"></div>
|
||||
@@ -262,11 +287,12 @@
|
||||
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
|
||||
<script>
|
||||
const API = "/api/poverty";
|
||||
const state = { rows: [], dashboard: null, markers: new Map() };
|
||||
const state = { rows: [], dashboard: null, markers: new Map(), ibadah: [], ibadahLoaded: false };
|
||||
const map = L.map("map", { zoomControl: true }).setView([-0.0263, 109.3425], 12);
|
||||
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", { maxZoom: 19, attribution: "© OpenStreetMap" }).addTo(map);
|
||||
const markerLayer = L.layerGroup().addTo(map);
|
||||
const heatLayer = L.layerGroup().addTo(map);
|
||||
const ibadahLayer = L.layerGroup();
|
||||
|
||||
const el = (id) => document.getElementById(id);
|
||||
const esc = (value) => String(value ?? "").replace(/[&<>"']/g, (char) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }[char]));
|
||||
@@ -274,6 +300,13 @@
|
||||
const score = (value) => Number(value || 0).toFixed(3);
|
||||
const badgeClass = (kategori) => kategori === "Sangat Membutuhkan" ? "sangat" : kategori === "Membutuhkan" ? "butuh" : kategori === "Rentan" ? "rentan" : "mampu";
|
||||
const color = (kategori) => kategori === "Sangat Membutuhkan" ? "#dc2626" : kategori === "Membutuhkan" ? "#f97316" : kategori === "Rentan" ? "#facc15" : "#22c55e";
|
||||
const ibadahColors = {
|
||||
"Gereja Katolik": "#7c3aed",
|
||||
GPIB: "#2563eb",
|
||||
GKI: "#0891b2",
|
||||
HKBP: "#16a34a",
|
||||
Pentakosta: "#ea580c",
|
||||
};
|
||||
|
||||
function toast(message) {
|
||||
el("toast").textContent = message;
|
||||
@@ -350,6 +383,47 @@
|
||||
`;
|
||||
}
|
||||
|
||||
function ibadahIcon(jenis) {
|
||||
const markerColor = ibadahColors[jenis] || "#64748b";
|
||||
return L.divIcon({
|
||||
className: "",
|
||||
html: `<div class="ibadah-map-marker" style="background:${markerColor}">⛪</div>`,
|
||||
iconSize: [30, 30],
|
||||
iconAnchor: [15, 30],
|
||||
popupAnchor: [0, -28],
|
||||
});
|
||||
}
|
||||
|
||||
function ibadahPopupHtml(item) {
|
||||
const markerColor = ibadahColors[item.jenis] || "#64748b";
|
||||
return `
|
||||
<div class="popup">
|
||||
<h3>${esc(item.nama)}</h3>
|
||||
<span class="badge" style="background:${markerColor}22;color:${markerColor};border:1px solid ${markerColor}44">${esc(item.jenis)}</span>
|
||||
<p style="margin-top:10px">${esc(item.alamat)}<br>${esc(item.kelurahan)}</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
function renderIbadahMarkers() {
|
||||
ibadahLayer.clearLayers();
|
||||
state.ibadah.forEach((item) => {
|
||||
const latlng = [Number(item.lat), Number(item.lng)];
|
||||
if (!Number.isFinite(latlng[0]) || !Number.isFinite(latlng[1])) return;
|
||||
L.marker(latlng, { icon: ibadahIcon(item.jenis) })
|
||||
.bindPopup(ibadahPopupHtml(item))
|
||||
.addTo(ibadahLayer);
|
||||
});
|
||||
}
|
||||
|
||||
async function loadIbadahLayer(force = false) {
|
||||
if (state.ibadahLoaded && !force) return;
|
||||
const payload = await fetchJson("/ibadah");
|
||||
state.ibadah = payload.data || [];
|
||||
state.ibadahLoaded = true;
|
||||
renderIbadahMarkers();
|
||||
}
|
||||
|
||||
function renderMarkers() {
|
||||
markerLayer.clearLayers();
|
||||
heatLayer.clearLayers();
|
||||
@@ -408,6 +482,22 @@
|
||||
|
||||
let debounce;
|
||||
["categoryFilter", "heatToggle"].forEach((id) => el(id).addEventListener("change", () => loadData().catch((error) => toast(error.message))));
|
||||
el("ibadahToggle").addEventListener("change", async () => {
|
||||
try {
|
||||
if (el("ibadahToggle").checked) {
|
||||
await loadIbadahLayer(true);
|
||||
ibadahLayer.addTo(map);
|
||||
el("ibadahLegendPanel").classList.add("active");
|
||||
} else {
|
||||
map.removeLayer(ibadahLayer);
|
||||
el("ibadahLegendPanel").classList.remove("active");
|
||||
}
|
||||
} catch (error) {
|
||||
el("ibadahToggle").checked = false;
|
||||
el("ibadahLegendPanel").classList.remove("active");
|
||||
toast(error.message);
|
||||
}
|
||||
});
|
||||
el("searchInput").addEventListener("input", () => {
|
||||
clearTimeout(debounce);
|
||||
debounce = setTimeout(() => loadData().catch((error) => toast(error.message)), 260);
|
||||
|
||||
Reference in New Issue
Block a user