Files
WEBGISPOVERTYMAP/sig-bansos/PENGGUNA UMUM.html
T

236 lines
13 KiB
HTML

<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SIG Bansos - Pengguna Umum</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: 'Segoe UI', sans-serif; background: #f0f2f5; }
#map { height: 80vh; width: 100%; border-radius: 10px; box-shadow: 0 4px 6px rgba(0,0,0,0.1); }
.sidebar { background: white; border-radius: 10px; padding: 15px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); height: 80vh; overflow-y: auto; }
.stat-box { background: white; border-radius: 10px; padding: 15px; text-align: center; box-shadow: 0 2px 4px rgba(0,0,0,0.1); margin-bottom: 10px; }
.stat-box h3 { font-size: 24px; font-weight: 700; margin: 0; }
.stat-box p { margin: 0; font-size: 12px; color: #6c757d; }
.data-list { max-height: 400px; overflow-y: auto; }
.data-item { background: #f8f9fa; padding: 10px; margin-bottom: 6px; border-radius: 8px; cursor: pointer; border-left: 4px solid #0d6efd; }
.data-item:hover { background: #e9ecef; }
.data-item strong { display: block; font-size: 13px; }
.data-item small { color: #6c757d; font-size: 11px; display: block; }
.legend { background: white; padding: 10px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
.legend-item { display: flex; align-items: center; gap: 8px; margin-bottom: 5px; font-size: 12px; }
.legend-dot { width: 12px; height: 12px; border-radius: 50%; }
.leaflet-popup-content-wrapper { border-radius: 12px; padding: 0; overflow: hidden; }
.leaflet-popup-content { margin: 0 !important; width: 260px; }
.popup-header { padding: 10px; color: white; font-weight: 600; font-size: 14px; }
.popup-body { padding: 10px 12px; font-size: 12px; }
.popup-row { display: flex; justify-content: space-between; margin-bottom: 3px; }
.popup-label { color: #888; }
.popup-value { font-weight: 500; }
</style>
</head>
<body>
<div class="container-fluid p-3">
<div class="d-flex justify-content-between align-items-center mb-3">
<h4><i class="fas fa-map-marked-alt"></i> SIG Bantuan Sosial - Peta Persebaran</h4>
<span class="badge bg-info">Pengguna Umum</span>
</div>
<!-- Statistik -->
<div class="row mb-3">
<div class="col-md-3">
<div class="stat-box">
<h3 id="totalOrang" style="color:#17a2b8;">0</h3>
<p>Orang Berkebutuhan</p>
</div>
</div>
<div class="col-md-3">
<div class="stat-box">
<h3 id="totalIbadah" style="color:#28a745;">0</h3>
<p>Tempat Ibadah</p>
</div>
</div>
<div class="col-md-6">
<div class="legend">
<strong><i class="fas fa-list"></i> Legenda:</strong>
<div class="row mt-2">
<div class="col-6">
<div class="legend-item"><div class="legend-dot" style="background:#17a2b8;"></div> Orang Berkebutuhan</div>
<div class="legend-item"><div class="legend-dot" style="background:#28a745;"></div> Masjid</div>
<div class="legend-item"><div class="legend-dot" style="background:#dc3545;"></div> Gereja</div>
</div>
<div class="col-6">
<div class="legend-item"><div class="legend-dot" style="background:#ff6f00;"></div> Klenteng</div>
<div class="legend-item"><div class="legend-dot" style="background:#ff9800;"></div> Vihara</div>
<div class="legend-item"><div class="legend-dot" style="background:#9c27b0;"></div> Pura</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-8">
<div id="map"></div>
</div>
<div class="col-md-4">
<div class="sidebar">
<ul class="nav nav-tabs" id="listTab" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link active" data-bs-toggle="tab" data-bs-target="#tabOrang">👤 Orang Berkebutuhan</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#tabIbadah">🕌 Tempat Ibadah</button>
</li>
</ul>
<div class="tab-content mt-3">
<div class="tab-pane fade show active" id="tabOrang">
<input type="text" class="form-control form-control-sm mb-2" placeholder="Cari orang..." oninput="filterList('orang', this.value)">
<div id="orangList" class="data-list"></div>
</div>
<div class="tab-pane fade" id="tabIbadah">
<input type="text" class="form-control form-control-sm mb-2" placeholder="Cari tempat ibadah..." oninput="filterList('ibadah', this.value)">
<div id="ibadahList" class="data-list"></div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
const API_ORANG = '/sig-jalan/api_orang.php';
const API_IBADAH = '/sig-jalan/api_ibadah.php';
const warnaIbadah = { masjid: '#28a745', gereja: '#dc3545', klenteng: '#ff6f00', vihara: '#ff9800', pura: '#9c27b0' };
const ikonIbadah = { masjid: 'fa-mosque', gereja: 'fa-church', klenteng: 'fa-torii-gate', vihara: 'fa-om', pura: 'fa-gopuram' };
var map = L.map('map').setView([-0.026330, 109.342519], 13);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 19 }).addTo(map);
let orangData = [];
let ibadahData = [];
async function apiCall(url) {
const res = await fetch(url);
return await res.json();
}
async function loadAllData() {
// Load orang
const resOrang = await apiCall(API_ORANG+'?action=getAll');
if(resOrang.success) orangData = resOrang.data;
// Load ibadah
const jenisList = ['masjid','gereja','klenteng','vihara','pura'];
ibadahData = [];
for(const j of jenisList) {
const res = await apiCall(API_IBADAH+'?type='+j+'&action=getAll');
if(res.success) {
res.data.forEach(d => d._jenis = j);
ibadahData = ibadahData.concat(res.data);
}
}
updateStats();
renderMarkers();
renderLists();
}
function updateStats() {
document.getElementById('totalOrang').textContent = orangData.length;
document.getElementById('totalIbadah').textContent = ibadahData.length;
}
function renderMarkers() {
// Marker Orang
orangData.forEach(o => {
const icon = L.divIcon({
html: '<i class="fas fa-user" style="font-size:24px;color:#17a2b8;"></i>',
className: 'custom-marker', iconSize: [24,24], iconAnchor: [12,24], popupAnchor: [0,-24]
});
const m = L.marker([parseFloat(o.latitude), parseFloat(o.longitude)], {icon}).addTo(map);
m.bindPopup(`
<div>
<div class="popup-header" style="background:#17a2b8"><i class="fas fa-user"></i> ${o.nama}</div>
<div class="popup-body">
<div class="popup-row"><span class="popup-label">Alamat</span><span class="popup-value">${o.alamat||'-'}</span></div>
<div class="popup-row"><span class="popup-label">Kebutuhan</span><span class="popup-value">${o.jenis_kebutuhan||'-'}</span></div>
<div class="popup-row"><span class="popup-label">Keterangan</span><span class="popup-value">${o.keterangan||'-'}</span></div>
</div>
</div>
`);
});
// Marker Ibadah
ibadahData.forEach(d => {
const color = warnaIbadah[d._jenis];
const icon = L.divIcon({
html: '<i class="fas '+ikonIbadah[d._jenis]+'" style="font-size:24px;color:'+color+';"></i>',
className: 'custom-marker', iconSize: [24,24], iconAnchor: [12,24], popupAnchor: [0,-24]
});
const m = L.marker([parseFloat(d.latitude), parseFloat(d.longitude)], {icon}).addTo(map);
m.bindPopup(`
<div>
<div class="popup-header" style="background:${color}"><i class="fas ${ikonIbadah[d._jenis]}"></i> ${d.nama}</div>
<div class="popup-body">
<div class="popup-row"><span class="popup-label">Jenis</span><span class="popup-value">${d._jenis}</span></div>
<div class="popup-row"><span class="popup-label">Alamat</span><span class="popup-value">${d.alamat||'-'}</span></div>
<div class="popup-row"><span class="popup-label">Keterangan</span><span class="popup-value">${d.keterangan||'-'}</span></div>
</div>
</div>
`);
});
}
function renderLists() {
document.getElementById('orangList').innerHTML = orangData.map(o => `
<div class="data-item" onclick="zoomTo(${o.latitude},${o.longitude})">
<strong><i class="fas fa-user"></i> ${o.nama}</strong>
<small>${o.jenis_kebutuhan||'-'} | ${o.alamat||'-'}</small>
</div>
`).join('') || '<p class="text-muted text-center">Tidak ada data</p>';
document.getElementById('ibadahList').innerHTML = ibadahData.map(d => `
<div class="data-item" style="border-left-color:${warnaIbadah[d._jenis]}" onclick="zoomTo(${d.latitude},${d.longitude})">
<strong style="color:${warnaIbadah[d._jenis]}"><i class="fas ${ikonIbadah[d._jenis]}"></i> ${d.nama}</strong>
<small>${d._jenis} | ${d.alamat||'-'}</small>
</div>
`).join('') || '<p class="text-muted text-center">Tidak ada data</p>';
}
function filterList(type, keyword) {
const kw = keyword.toLowerCase();
const data = type === 'orang' ? orangData : ibadahData;
const filtered = data.filter(d => d.nama.toLowerCase().includes(kw) || (d.alamat||'').toLowerCase().includes(kw));
const container = type === 'orang' ? document.getElementById('orangList') : document.getElementById('ibadahList');
if(type === 'orang') {
container.innerHTML = filtered.map(o => `
<div class="data-item" onclick="zoomTo(${o.latitude},${o.longitude})">
<strong><i class="fas fa-user"></i> ${o.nama}</strong>
<small>${o.jenis_kebutuhan||'-'} | ${o.alamat||'-'}</small>
</div>
`).join('') || '<p class="text-muted text-center">Tidak ada data</p>';
} else {
container.innerHTML = filtered.map(d => `
<div class="data-item" style="border-left-color:${warnaIbadah[d._jenis]}" onclick="zoomTo(${d.latitude},${d.longitude})">
<strong style="color:${warnaIbadah[d._jenis]}"><i class="fas ${ikonIbadah[d._jenis]}"></i> ${d.nama}</strong>
<small>${d._jenis} | ${d.alamat||'-'}</small>
</div>
`).join('') || '<p class="text-muted text-center">Tidak ada data</p>';
}
}
function zoomTo(lat, lng) {
map.flyTo([parseFloat(lat), parseFloat(lng)], 17);
}
loadAllData();
</script>
</body>
</html>