fix all bug

This commit is contained in:
naukyy
2026-06-13 02:10:51 +07:00
parent d9cff90874
commit d18baa80e0
19 changed files with 818 additions and 149 deletions
+36
View File
@@ -299,6 +299,42 @@ body::before {
}
.leaflet-control-zoom a:hover { background: var(--primary-deep) !important; color: white !important; }
/* Custom Leaflet Layer Control style to match theme */
.leaflet-control-layers {
background: var(--bg-glass) !important;
backdrop-filter: blur(24px) !important;
-webkit-backdrop-filter: blur(24px) !important;
border: 1px solid var(--border-glass) !important;
border-radius: 14px !important;
box-shadow: var(--shadow) !important;
color: var(--text-main) !important;
font-family: var(--font) !important;
padding: 10px 14px !important;
transition: var(--transition);
}
.leaflet-control-layers-expanded {
min-width: 140px;
}
.leaflet-control-layers label {
margin-bottom: 6px !important;
font-size: 0.85rem !important;
cursor: pointer !important;
display: flex !important;
align-items: center !important;
gap: 8px !important;
color: var(--text-main) !important;
font-weight: 500;
}
.leaflet-control-layers label:last-child {
margin-bottom: 0 !important;
}
.leaflet-control-layers input[type="checkbox"] {
cursor: pointer !important;
width: 15px !important;
height: 15px !important;
accent-color: var(--primary-deep) !important;
}
.leaflet-popup-content-wrapper {
background: var(--bg-glass) !important;
backdrop-filter: blur(16px) !important;
+52 -1
View File
@@ -10,6 +10,38 @@
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css">
<link rel="stylesheet" href="css/main.css">
<script>
// Global error interceptor to assist in visual debugging
window.onerror = function(message, source, lineno, colno, error) {
const errorMsg = `JS Error: ${message} (at ${source ? source.split('/').pop() : 'unknown'}:${lineno}:${colno})`;
console.error(errorMsg, error);
const showInterval = setInterval(() => {
const toastContainer = document.getElementById('toast-container');
if (toastContainer) {
clearInterval(showInterval);
const t = document.createElement('div');
t.className = 'toast error';
t.innerHTML = errorMsg;
toastContainer.appendChild(t);
}
}, 100);
return false;
};
window.onunhandledrejection = function(event) {
const errorMsg = `Promise Error: ${event.reason?.message || event.reason}`;
console.error(errorMsg, event.reason);
const showInterval = setInterval(() => {
const toastContainer = document.getElementById('toast-container');
if (toastContainer) {
clearInterval(showInterval);
const t = document.createElement('div');
t.className = 'toast error';
t.innerHTML = errorMsg;
toastContainer.appendChild(t);
}
}, 100);
};
</script>
</head>
<body>
@@ -38,6 +70,25 @@
<p>Sistem Informasi Geografis — CRUD spasial titik, garis, dan area.</p>
</div>
<!-- Layer Peta (Centang) -->
<div class="menu-group">
<div class="menu-title">Layer Peta</div>
<div class="form-panel" style="gap: 10px;">
<label class="checkbox-group">
<input type="checkbox" id="layer-spbu" checked>
<span>Stasiun SPBU</span>
</label>
<label class="checkbox-group">
<input type="checkbox" id="layer-jalan" checked>
<span>Jalur Jalan</span>
</label>
<label class="checkbox-group">
<input type="checkbox" id="layer-kavling" checked>
<span>Kavling Tanah</span>
</label>
</div>
</div>
<!-- Spatial tools -->
<div class="menu-group">
<div class="menu-title">Alat Spasial</div>
@@ -85,7 +136,7 @@
icon.className = t === 'dark' ? 'fas fa-sun' : 'fas fa-moon';
}
</script>
<script type="module" src="js/app.js"></script>
<script type="module" src="js/app.js?v=20260613-9"></script>
</body>
</html>
+109 -16
View File
@@ -6,6 +6,13 @@ import { spbuService, jalanService, kavlingService } from './services/api.servic
let appMap;
let drawControl;
// Global layer object tracker
const mapLayers = {
spbu: null,
jalan: null,
kavling: null
};
// Custom SVG Icons Generator
export const createIcon = (svgPath, color) => {
return L.divIcon({
@@ -29,28 +36,94 @@ window.showToast = (msg, type='success') => {
setTimeout(() => { t.style.transform='translateX(100%)'; t.style.opacity=0; setTimeout(()=>t.remove(),300); }, 3000);
};
document.addEventListener('DOMContentLoaded', async () => {
appMap = initMap('map');
drawControl = setupDrawControls(appMap, handleGeometryCreated);
await loadAllData();
});
const setupCheckboxListeners = () => {
const layerConfigs = [
{ id: 'layer-spbu', key: 'spbu' },
{ id: 'layer-jalan', key: 'jalan' },
{ id: 'layer-kavling', key: 'kavling' }
];
const loadAllData = async () => {
layerConfigs.forEach(({ id, key }) => {
const checkbox = document.getElementById(id);
if (checkbox) {
checkbox.addEventListener('change', (e) => {
const layer = mapLayers[key];
if (layer) {
if (e.target.checked) {
if (!appMap.hasLayer(layer)) {
appMap.addLayer(layer);
}
} else {
if (appMap.hasLayer(layer)) {
appMap.removeLayer(layer);
}
}
}
});
}
});
};
const loadSPBUData = async () => {
try {
const spbu = await spbuService.getAll();
L.geoJSON(spbu, {
mapLayers.spbu = L.geoJSON(spbu, {
pointToLayer: (f, latlng) => L.marker(latlng, { icon: iconSPBU(f.properties.buka_24_jam) }),
onEachFeature: (f, l) => bindPopup(l, 'spbu', f.properties)
}).addTo(appMap);
});
const jalan = await jalanService.getAll();
L.geoJSON(jalan, { style: { color: '#F59E0B', weight: 4 }, onEachFeature: (f, l) => bindPopup(l, 'jalan', f.properties) }).addTo(appMap);
const kavling = await kavlingService.getAll();
L.geoJSON(kavling, { style: { color: '#3B82F6', weight: 2, fillColor: '#3B82F6', fillOpacity: 0.3 }, onEachFeature: (f, l) => bindPopup(l, 'kavling', f.properties) }).addTo(appMap);
} catch (e) {
window.showToast("Gagal meload data: "+e.message, 'error');
const checkbox = document.getElementById('layer-spbu');
if (checkbox && checkbox.checked) {
mapLayers.spbu.addTo(appMap);
}
} catch (e) {
console.error("Gagal meload data SPBU:", e);
window.showToast("Gagal meload data SPBU: " + e.message, 'error');
}
};
const loadJalanData = async () => {
try {
const jalan = await jalanService.getAll();
mapLayers.jalan = L.geoJSON(jalan, {
style: { color: '#F59E0B', weight: 4 },
onEachFeature: (f, l) => bindPopup(l, 'jalan', f.properties)
});
const checkbox = document.getElementById('layer-jalan');
if (checkbox && checkbox.checked) {
mapLayers.jalan.addTo(appMap);
}
} catch (e) {
console.error("Gagal meload data Jalan:", e);
window.showToast("Gagal meload data Jalan: " + e.message, 'error');
}
};
const loadKavlingData = async () => {
try {
const kavling = await kavlingService.getAll();
mapLayers.kavling = L.geoJSON(kavling, {
style: { color: '#3B82F6', weight: 2, fillColor: '#3B82F6', fillOpacity: 0.3 },
onEachFeature: (f, l) => bindPopup(l, 'kavling', f.properties)
});
const checkbox = document.getElementById('layer-kavling');
if (checkbox && checkbox.checked) {
mapLayers.kavling.addTo(appMap);
}
} catch (e) {
console.error("Gagal meload data Kavling:", e);
window.showToast("Gagal meload data Kavling: " + e.message, 'error');
}
};
const loadAllData = async () => {
await Promise.allSettled([
loadSPBUData(),
loadJalanData(),
loadKavlingData()
]);
};
const bindPopup = (layer, type, props) => {
@@ -82,7 +155,14 @@ const handleGeometryCreated = (type, geometry, layer) => {
try {
if(type==='spbu') await spbuService.create(payload);
if(type==='jalan') await jalanService.create(payload);
if(type==='kavling') await kavlingService.create(payload);
if(type==='kavling') {
const kavlingPayload = {
nama_pemilik: payload.nama,
luas: payload.luas || 0,
geometry: payload.geometry
};
await kavlingService.create(kavlingPayload);
}
window.showToast('Berhasil disimpan');
setTimeout(()=>location.reload(), 800);
} catch(e) { window.showToast('Gagal simpan', 'error'); }
@@ -90,3 +170,16 @@ const handleGeometryCreated = (type, geometry, layer) => {
appMap.removeLayer(tempLayer);
});
};
const init = async () => {
appMap = initMap('map');
setupCheckboxListeners();
drawControl = setupDrawControls(appMap, handleGeometryCreated);
await loadAllData();
};
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
+12 -2
View File
@@ -2,14 +2,23 @@ export const renderForm = (type, geometry, onSubmit, onCancel) => {
const container = document.getElementById('form-container');
container.style.display = 'flex';
const extraFields = type === 'spbu' ? `
let extraFields = '';
if (type === 'spbu') {
extraFields = `
<div class="form-group">
<label class="checkbox-group">
<input type="checkbox" id="input-24jam">
<span>Buka 24 Jam</span>
</label>
</div>
` : '';
`;
} else if (type === 'kavling') {
extraFields = `
<div class="form-group">
<input type="number" id="input-luas" class="form-control" placeholder="Luas (m²)" required min="1">
</div>
`;
}
container.innerHTML = `
<div class="form-panel">
@@ -36,6 +45,7 @@ export const renderForm = (type, geometry, onSubmit, onCancel) => {
deskripsi: document.getElementById('input-deskripsi').value,
};
if (type === 'spbu') payload.buka_24_jam = document.getElementById('input-24jam').checked;
if (type === 'kavling') payload.luas = document.getElementById('input-luas').value;
onSubmit(payload);
container.style.display = 'none';
+36
View File
@@ -299,6 +299,42 @@ body::before {
}
.leaflet-control-zoom a:hover { background: var(--primary-deep) !important; color: white !important; }
/* Custom Leaflet Layer Control style to match theme */
.leaflet-control-layers {
background: var(--bg-glass) !important;
backdrop-filter: blur(24px) !important;
-webkit-backdrop-filter: blur(24px) !important;
border: 1px solid var(--border-glass) !important;
border-radius: 14px !important;
box-shadow: var(--shadow) !important;
color: var(--text-main) !important;
font-family: var(--font) !important;
padding: 10px 14px !important;
transition: var(--transition);
}
.leaflet-control-layers-expanded {
min-width: 140px;
}
.leaflet-control-layers label {
margin-bottom: 6px !important;
font-size: 0.85rem !important;
cursor: pointer !important;
display: flex !important;
align-items: center !important;
gap: 8px !important;
color: var(--text-main) !important;
font-weight: 500;
}
.leaflet-control-layers label:last-child {
margin-bottom: 0 !important;
}
.leaflet-control-layers input[type="checkbox"] {
cursor: pointer !important;
width: 15px !important;
height: 15px !important;
accent-color: var(--primary-deep) !important;
}
.leaflet-popup-content-wrapper {
background: var(--bg-glass) !important;
backdrop-filter: blur(16px) !important;
+28 -1
View File
@@ -58,6 +58,33 @@
<p>Kumulatif P01 + Analisis radius jarak Haversine.</p>
</div>
<!-- Layer Peta (Centang) -->
<div class="menu-group">
<div class="menu-title">Layer Peta</div>
<div class="form-panel" style="gap: 10px;">
<label class="checkbox-group">
<input type="checkbox" id="layer-spbu" checked>
<span>Stasiun SPBU</span>
</label>
<label class="checkbox-group">
<input type="checkbox" id="layer-jalan" checked>
<span>Jalur Jalan</span>
</label>
<label class="checkbox-group">
<input type="checkbox" id="layer-kavling" checked>
<span>Kavling Tanah</span>
</label>
<label class="checkbox-group">
<input type="checkbox" id="layer-rumah" checked>
<span>Rumah Ibadah</span>
</label>
<label class="checkbox-group">
<input type="checkbox" id="layer-warga" checked>
<span>Warga Miskin</span>
</label>
</div>
</div>
<!-- Entitas Dasar (P01) -->
<div class="menu-group">
<div class="menu-title">Entitas Dasar (P01)</div>
@@ -121,7 +148,7 @@
icon.className = t === 'dark' ? 'fas fa-sun' : 'fas fa-moon';
}
</script>
<script type="module" src="js/app.js"></script>
<script type="module" src="js/app.js?v=20260613-9"></script>
</body>
</html>
+52 -17
View File
@@ -29,17 +29,6 @@ window.showToast = (msg, type='success') => {
setTimeout(() => { t.style.transform='translateX(100%)'; t.style.opacity=0; setTimeout(()=>t.remove(),300); }, 3000);
};
document.addEventListener('DOMContentLoaded', async () => {
appMap = initMap('map');
// Bind extra draw events for 02
document.getElementById('btn-draw-rumah')?.addEventListener('click', () => { window.currentDrawType='rumah_ibadah'; new L.Draw.Marker(appMap).enable(); });
document.getElementById('btn-draw-warga')?.addEventListener('click', () => { window.currentDrawType='warga_miskin'; new L.Draw.Marker(appMap).enable(); });
drawControl = setupDrawControls(appMap, handleGeometryCreated);
await loadAllData();
});
const loadAllData = async () => {
try {
const [spbu, jalan, kavling, rumah, warga] = await Promise.all([
@@ -47,11 +36,33 @@ const loadAllData = async () => {
rumahIbadahService.getAll(), wargaMiskinService.getAll()
]);
L.geoJSON(spbu, { pointToLayer: (f, ll) => L.marker(ll, { icon: iconSPBU(f.properties.buka_24_jam) }), onEachFeature: (f, l) => bindPopup(l, 'spbu', f.properties) }).addTo(appMap);
L.geoJSON(jalan, { style: { color: '#F59E0B', weight: 4 }, onEachFeature: (f, l) => bindPopup(l, 'jalan', f.properties) }).addTo(appMap);
L.geoJSON(kavling, { style: { color: '#3B82F6', weight: 2, fillColor: '#3B82F6', fillOpacity: 0.3 }, onEachFeature: (f, l) => bindPopup(l, 'kavling', f.properties) }).addTo(appMap);
L.geoJSON(rumah, { pointToLayer: (f, ll) => L.marker(ll, { icon: iconRumah }), onEachFeature: (f, l) => bindPopup(l, 'rumah_ibadah', f.properties, f) }).addTo(appMap);
L.geoJSON(warga, { pointToLayer: (f, ll) => L.marker(ll, { icon: iconWarga }), onEachFeature: (f, l) => bindPopup(l, 'warga_miskin', f.properties) }).addTo(appMap);
const spbuLayer = L.geoJSON(spbu, { pointToLayer: (f, ll) => L.marker(ll, { icon: iconSPBU(f.properties.buka_24_jam) }), onEachFeature: (f, l) => bindPopup(l, 'spbu', f.properties) }).addTo(appMap);
const jalanLayer = L.geoJSON(jalan, { style: { color: '#F59E0B', weight: 4 }, onEachFeature: (f, l) => bindPopup(l, 'jalan', f.properties) }).addTo(appMap);
const kavlingLayer = L.geoJSON(kavling, { style: { color: '#3B82F6', weight: 2, fillColor: '#3B82F6', fillOpacity: 0.3 }, onEachFeature: (f, l) => bindPopup(l, 'kavling', f.properties) }).addTo(appMap);
const rumahLayer = L.geoJSON(rumah, { pointToLayer: (f, ll) => L.marker(ll, { icon: iconRumah }), onEachFeature: (f, l) => bindPopup(l, 'rumah_ibadah', f.properties, f) }).addTo(appMap);
const wargaLayer = L.geoJSON(warga, { pointToLayer: (f, ll) => L.marker(ll, { icon: iconWarga }), onEachFeature: (f, l) => bindPopup(l, 'warga_miskin', f.properties) }).addTo(appMap);
// Bind checkbox events
document.getElementById('layer-spbu').addEventListener('change', (e) => {
if (e.target.checked) appMap.addLayer(spbuLayer);
else appMap.removeLayer(spbuLayer);
});
document.getElementById('layer-jalan').addEventListener('change', (e) => {
if (e.target.checked) appMap.addLayer(jalanLayer);
else appMap.removeLayer(jalanLayer);
});
document.getElementById('layer-kavling').addEventListener('change', (e) => {
if (e.target.checked) appMap.addLayer(kavlingLayer);
else appMap.removeLayer(kavlingLayer);
});
document.getElementById('layer-rumah').addEventListener('change', (e) => {
if (e.target.checked) appMap.addLayer(rumahLayer);
else appMap.removeLayer(rumahLayer);
});
document.getElementById('layer-warga').addEventListener('change', (e) => {
if (e.target.checked) appMap.addLayer(wargaLayer);
else appMap.removeLayer(wargaLayer);
});
} catch (e) {
window.showToast("Gagal meload data: "+e.message, 'error');
}
@@ -115,10 +126,34 @@ const handleGeometryCreated = (type, geometry, layer) => {
try {
if(type==='spbu') await spbuService.create(payload);
if(type==='jalan') await jalanService.create(payload);
if(type==='kavling') await kavlingService.create(payload);
if(type==='kavling') {
const kavlingPayload = {
nama_pemilik: payload.nama,
luas: payload.luas || 0,
geometry: payload.geometry
};
await kavlingService.create(kavlingPayload);
}
if(type==='rumah_ibadah') await rumahIbadahService.create(payload);
if(type==='warga_miskin') await wargaMiskinService.create(payload);
window.showToast('Tersimpan'); setTimeout(()=>location.reload(), 800);
} catch(e) { window.showToast('Gagal simpan', 'error'); }
}, () => appMap.removeLayer(tempLayer));
};
const init = async () => {
appMap = initMap('map');
// Bind extra draw events for 02
document.getElementById('btn-draw-rumah')?.addEventListener('click', () => { window.currentDrawType='rumah_ibadah'; new L.Draw.Marker(appMap).enable(); });
document.getElementById('btn-draw-warga')?.addEventListener('click', () => { window.currentDrawType='warga_miskin'; new L.Draw.Marker(appMap).enable(); });
drawControl = setupDrawControls(appMap, handleGeometryCreated);
await loadAllData();
};
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
+36
View File
@@ -299,6 +299,42 @@ body::before {
}
.leaflet-control-zoom a:hover { background: var(--primary-deep) !important; color: white !important; }
/* Custom Leaflet Layer Control style to match theme */
.leaflet-control-layers {
background: var(--bg-glass) !important;
backdrop-filter: blur(24px) !important;
-webkit-backdrop-filter: blur(24px) !important;
border: 1px solid var(--border-glass) !important;
border-radius: 14px !important;
box-shadow: var(--shadow) !important;
color: var(--text-main) !important;
font-family: var(--font) !important;
padding: 10px 14px !important;
transition: var(--transition);
}
.leaflet-control-layers-expanded {
min-width: 140px;
}
.leaflet-control-layers label {
margin-bottom: 6px !important;
font-size: 0.85rem !important;
cursor: pointer !important;
display: flex !important;
align-items: center !important;
gap: 8px !important;
color: var(--text-main) !important;
font-weight: 500;
}
.leaflet-control-layers label:last-child {
margin-bottom: 0 !important;
}
.leaflet-control-layers input[type="checkbox"] {
cursor: pointer !important;
width: 15px !important;
height: 15px !important;
accent-color: var(--primary-deep) !important;
}
.leaflet-popup-content-wrapper {
background: var(--bg-glass) !important;
backdrop-filter: blur(16px) !important;
+28 -1
View File
@@ -65,6 +65,33 @@
<p>Kumulatif P01 &amp; P02 + Choropleth Map (Point-in-Polygon).</p>
</div>
<!-- Layer Peta (Centang) -->
<div class="menu-group">
<div class="menu-title">Layer Peta</div>
<div class="form-panel" style="gap: 10px;">
<label class="checkbox-group">
<input type="checkbox" id="layer-spbu" checked>
<span>Stasiun SPBU</span>
</label>
<label class="checkbox-group">
<input type="checkbox" id="layer-jalan" checked>
<span>Jalur Jalan</span>
</label>
<label class="checkbox-group">
<input type="checkbox" id="layer-rumah" checked>
<span>Rumah Ibadah</span>
</label>
<label class="checkbox-group">
<input type="checkbox" id="layer-warga" checked>
<span>Warga Miskin</span>
</label>
<label class="checkbox-group">
<input type="checkbox" id="layer-choro" checked>
<span>Choropleth Kepadatan</span>
</label>
</div>
</div>
<!-- Draw Tools -->
<div class="menu-group">
<div class="menu-title">Draw Tools</div>
@@ -132,7 +159,7 @@
icon.className = t === 'dark' ? 'fas fa-sun' : 'fas fa-moon';
}
</script>
<script type="module" src="js/app.js"></script>
<script type="module" src="js/app.js?v=20260613-9"></script>
</body>
</html>
+49 -14
View File
@@ -30,14 +30,6 @@ window.showToast = (msg, type='success') => {
setTimeout(() => { t.style.opacity=0; setTimeout(()=>t.remove(),300); }, 3000);
};
document.addEventListener('DOMContentLoaded', async () => {
appMap = initMap('map');
document.getElementById('btn-draw-rumah')?.addEventListener('click', () => { window.currentDrawType='rumah_ibadah'; new L.Draw.Marker(appMap).enable(); });
document.getElementById('btn-draw-warga')?.addEventListener('click', () => { window.currentDrawType='warga_miskin'; new L.Draw.Marker(appMap).enable(); });
drawControl = setupDrawControls(appMap, handleGeometryCreated);
await loadAllData();
});
const loadAllData = async () => {
try {
const [spbu, jalan, choro, rumah, warga] = await Promise.all([
@@ -45,13 +37,13 @@ const loadAllData = async () => {
rumahIbadahService.getAll(), wargaMiskinService.getAll()
]);
L.geoJSON(spbu, { pointToLayer: (f, ll) => L.marker(ll, { icon: iconSPBU(f.properties.buka_24_jam) }), onEachFeature: (f, l) => bindPopup(l, 'spbu', f.properties) }).addTo(appMap);
L.geoJSON(jalan, { style: { color: '#F59E0B', weight: 4 }, onEachFeature: (f, l) => bindPopup(l, 'jalan', f.properties) }).addTo(appMap);
L.geoJSON(rumah, { pointToLayer: (f, ll) => L.marker(ll, { icon: iconRumah }), onEachFeature: (f, l) => bindPopup(l, 'rumah_ibadah', f.properties) }).addTo(appMap);
L.geoJSON(warga, { pointToLayer: (f, ll) => L.marker(ll, { icon: iconWarga }), onEachFeature: (f, l) => bindPopup(l, 'warga_miskin', f.properties) }).addTo(appMap);
const spbuLayer = L.geoJSON(spbu, { pointToLayer: (f, ll) => L.marker(ll, { icon: iconSPBU(f.properties.buka_24_jam) }), onEachFeature: (f, l) => bindPopup(l, 'spbu', f.properties) }).addTo(appMap);
const jalanLayer = L.geoJSON(jalan, { style: { color: '#F59E0B', weight: 4 }, onEachFeature: (f, l) => bindPopup(l, 'jalan', f.properties) }).addTo(appMap);
const rumahLayer = L.geoJSON(rumah, { pointToLayer: (f, ll) => L.marker(ll, { icon: iconRumah }), onEachFeature: (f, l) => bindPopup(l, 'rumah_ibadah', f.properties) }).addTo(appMap);
const wargaLayer = L.geoJSON(warga, { pointToLayer: (f, ll) => L.marker(ll, { icon: iconWarga }), onEachFeature: (f, l) => bindPopup(l, 'warga_miskin', f.properties) }).addTo(appMap);
let merahCount = 0;
L.geoJSON(choro, {
const choroLayer = L.geoJSON(choro, {
style: (f) => {
const count = f.properties.jumlah_warga_miskin;
let c = '#10B981'; // Hijau (0)
@@ -62,6 +54,28 @@ const loadAllData = async () => {
onEachFeature: (f, l) => bindPopup(l, 'kavling', f.properties)
}).addTo(appMap);
// Bind checkbox events
document.getElementById('layer-spbu').addEventListener('change', (e) => {
if (e.target.checked) appMap.addLayer(spbuLayer);
else appMap.removeLayer(spbuLayer);
});
document.getElementById('layer-jalan').addEventListener('change', (e) => {
if (e.target.checked) appMap.addLayer(jalanLayer);
else appMap.removeLayer(jalanLayer);
});
document.getElementById('layer-rumah').addEventListener('change', (e) => {
if (e.target.checked) appMap.addLayer(rumahLayer);
else appMap.removeLayer(rumahLayer);
});
document.getElementById('layer-warga').addEventListener('change', (e) => {
if (e.target.checked) appMap.addLayer(wargaLayer);
else appMap.removeLayer(wargaLayer);
});
document.getElementById('layer-choro').addEventListener('change', (e) => {
if (e.target.checked) appMap.addLayer(choroLayer);
else appMap.removeLayer(choroLayer);
});
document.getElementById('stat-total-warga').innerText = warga.features.length;
document.getElementById('stat-kavling-merah').innerText = merahCount;
@@ -101,10 +115,31 @@ const handleGeometryCreated = (type, geometry, layer) => {
try {
if(type==='spbu') await spbuService.create(payload);
if(type==='jalan') await jalanService.create(payload);
if(type==='kavling') await kavlingService.create(payload);
if(type==='kavling') {
const kavlingPayload = {
nama_pemilik: payload.nama,
luas: payload.luas || 0,
geometry: payload.geometry
};
await kavlingService.create(kavlingPayload);
}
if(type==='rumah_ibadah') await rumahIbadahService.create(payload);
if(type==='warga_miskin') await wargaMiskinService.create(payload);
window.showToast('Tersimpan'); setTimeout(()=>location.reload(), 800);
} catch(e) { window.showToast('Gagal simpan', 'error'); }
}, () => appMap.removeLayer(tempLayer));
};
const init = async () => {
appMap = initMap('map');
document.getElementById('btn-draw-rumah')?.addEventListener('click', () => { window.currentDrawType='rumah_ibadah'; new L.Draw.Marker(appMap).enable(); });
document.getElementById('btn-draw-warga')?.addEventListener('click', () => { window.currentDrawType='warga_miskin'; new L.Draw.Marker(appMap).enable(); });
drawControl = setupDrawControls(appMap, handleGeometryCreated);
await loadAllData();
};
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
+159 -26
View File
@@ -21,28 +21,112 @@ SET FOREIGN_KEY_CHECKS = 1;
-- ============================================================
INSERT INTO spbu (nama, deskripsi, buka_24_jam, geom) VALUES
(
'SPBU Bundaran Digulis Untan',
'SPBU terdekat dari kampus',
'SPBU COCO 61.781.01 Ahmad Yani',
'Jl. Jend. Ahmad Yani No.3, Pontianak (Dekat Bundaran Digulis Untan)',
1,
ST_GeomFromText('POINT(109.3440 -0.0565)')
ST_GeomFromText('POINT(109.344381 -0.056461)')
),
(
'SPBU Ahmad Yani',
'Dekat Mega Mall (24 Jam)',
'SPBU 64.781.11 Imam Bonjol',
'Jl. Imam Bonjol No.30, Pontianak Tenggara',
1,
ST_GeomFromText('POINT(109.3360 -0.0450)')
ST_GeomFromText('POINT(109.349692 -0.038148)')
),
(
'SPBU Imam Bonjol',
'SPBU pinggir kota',
0,
ST_GeomFromText('POINT(109.3410 -0.0380)')
'SPBU 64.781.06 Kota Baru',
'Jl. Prof. Dr. M. Yamin, Kota Baru, Pontianak Selatan',
1,
ST_GeomFromText('POINT(109.317589 -0.054378)')
),
(
'SPBU Kota Baru',
'Jl. Sultan Abdurrahman',
'SPBU 64.781.01 Adi Sucipto',
'Jl. Adi Sucipto, Pontianak Tenggara',
0,
ST_GeomFromText('POINT(109.3245 -0.0487)')
ST_GeomFromText('POINT(109.362241 -0.061730)')
),
(
'SPBU 64.781.03 KH. Ahmad Dahlan',
'Jl. KH. Ahmad Dahlan No.12, Pontianak Kota',
0,
ST_GeomFromText('POINT(109.333830 -0.033621)')
),
(
'SPBU 64.781.05 Tanjung Pura',
'Jl. Tanjung Pura, Pontianak Selatan',
1,
ST_GeomFromText('POINT(109.336184 -0.026788)')
),
(
'SPBU 64.781.12 Gusti Hamzah',
'Jl. Gusti Hamzah (Pancasila), Pontianak Kota',
0,
ST_GeomFromText('POINT(109.319760 -0.029415)')
),
(
'SPBU 64.781.14 Husein Hamzah',
'Jl. Husein Hamzah (Pal 3), Pontianak Barat',
0,
ST_GeomFromText('POINT(109.294121 -0.027963)')
),
(
'SPBU 64.781.15 RE Martadinata',
'Jl. RE Martadinata, Pontianak Barat',
0,
ST_GeomFromText('POINT(109.314227 -0.016335)')
),
(
'SPBU 63.781.02 28 Oktober',
'Jl. 28 Oktober, Pontianak Utara',
0,
ST_GeomFromText('POINT(109.366405 0.007621)')
),
(
'SPBU 64.782.01 Khatulistiwa',
'Jl. Khatulistiwa, Pontianak Utara',
1,
ST_GeomFromText('POINT(109.325983 0.035415)')
),
(
'SPBU OSO MT. Haryono',
'Jl. Letjen MT Haryono, Pontianak Selatan',
0,
ST_GeomFromText('POINT(109.3367485 -0.0448924)')
),
(
'SPBU 64.781.18 Danau Sentarum',
'Jl. Danau Sentarum, Pontianak Kota',
0,
ST_GeomFromText('POINT(109.311283 -0.046342)')
),
(
'SPBU 64.781.19 Serdam',
'Jl. Sungai Raya Dalam, Pontianak Tenggara',
0,
ST_GeomFromText('POINT(109.358241 -0.076389)')
),
(
'SPBU 64.781.02 Hasanuddin',
'Jl. Hasanuddin, Pontianak Barat',
0,
ST_GeomFromText('POINT(109.321873 -0.024502)')
),
(
'SPBU 64.781.21 Dr. Wahidin',
'Jl. Dr. Wahidin S., Pontianak Kota',
0,
ST_GeomFromText('POINT(109.308210 -0.034502)')
),
(
'SPBU 64.781.17 Komyos Sudarso',
'Jl. Komodor Yos Sudarso, Pontianak Barat',
0,
ST_GeomFromText('POINT(109.299100 -0.019500)')
),
(
'SPBU 64.781.19 HOS Cokroaminoto',
'Jl. HOS Cokroaminoto, Pontianak Kota',
1,
ST_GeomFromText('POINT(109.337500 -0.031500)')
);
-- ============================================================
@@ -53,25 +137,49 @@ INSERT INTO rumah_ibadah (nama, agama, radius_bantuan_meter, geom) VALUES
'Masjid Raya Mujahidin',
'Islam',
1000,
ST_GeomFromText('POINT(109.3356 -0.0454)')
ST_GeomFromText('POINT(109.3377 -0.0414)')
),
(
'Gereja Katedral St. Yosef',
'Masjid Jami Sultan Syarif Abdurrahman',
'Islam',
1000,
ST_GeomFromText('POINT(109.3522 -0.0229)')
),
(
'Gereja Katedral Santo Yosef',
'Katolik',
1000,
ST_GeomFromText('POINT(109.3368 -0.0298)')
ST_GeomFromText('POINT(109.3384 -0.0274)')
),
(
'Gereja Kristen Immanuel (GPIB)',
'Kristen',
1000,
ST_GeomFromText('POINT(109.3375 -0.0292)')
),
(
'Gereja GKKB Pontianak',
'Kristen',
1000,
ST_GeomFromText('POINT(109.3386 -0.0336)')
),
(
'Vihara Bodhisatva Karaniya Metta',
'Buddha',
1000,
ST_GeomFromText('POINT(109.3468 -0.0233)')
ST_GeomFromText('POINT(109.3432 -0.0215)')
),
(
'Masjid Jami Keraton Kadriyah',
'Islam',
'Maha Vihara Maitreya',
'Buddha',
1000,
ST_GeomFromText('POINT(109.3523 -0.0229)')
ST_GeomFromText('POINT(109.3649 -0.0732)')
),
(
'Pura Giripati Mulawarman',
'Hindu',
1000,
ST_GeomFromText('POINT(109.3802 -0.0663)')
);
-- ============================================================
@@ -79,19 +187,44 @@ INSERT INTO rumah_ibadah (nama, agama, radius_bantuan_meter, geom) VALUES
-- ============================================================
INSERT INTO jalan (nama, jenis_jalan, geom) VALUES
(
'Jalan Ahmad Yani',
'Jalan Jenderal Ahmad Yani',
'Arteri Primer',
ST_GeomFromText('LINESTRING(109.3448 -0.0583, 109.3360 -0.0450, 109.3310 -0.0320)')
ST_GeomFromText('LINESTRING(109.3621 -0.0768, 109.3444 -0.0565, 109.3360 -0.0450, 109.3330 -0.0330)')
),
(
'Jalan Gajah Mada',
'Kolektor',
ST_GeomFromText('LINESTRING(109.3310 -0.0320, 109.3410 -0.0290, 109.3460 -0.0250)')
'Arteri Primer',
ST_GeomFromText('LINESTRING(109.3310 -0.0320, 109.3380 -0.0290, 109.3450 -0.0250)')
),
(
'Jalan Tanjung Pura',
'Arteri Primer',
ST_GeomFromText('LINESTRING(109.3300 -0.0300, 109.3360 -0.0260, 109.3480 -0.0240, 109.3550 -0.0270)')
),
(
'Jalan Imam Bonjol',
'Lokal',
ST_GeomFromText('LINESTRING(109.3360 -0.0450, 109.3420 -0.0400, 109.3500 -0.0350)')
'Arteri Primer',
ST_GeomFromText('LINESTRING(109.3360 -0.0450, 109.3420 -0.0400, 109.3500 -0.0350, 109.3590 -0.0400)')
),
(
'Jalan Adi Sucipto',
'Arteri Primer',
ST_GeomFromText('LINESTRING(109.3590 -0.0400, 109.3650 -0.0600, 109.3750 -0.0700)')
),
(
'Jalan Khatulistiwa',
'Arteri Primer',
ST_GeomFromText('LINESTRING(109.3450 0.0050, 109.3350 0.0150, 109.3250 0.0350, 109.3150 0.0550)')
),
(
'Jalan Komodor Yos Sudarso',
'Arteri Primer',
ST_GeomFromText('LINESTRING(109.3250 -0.0280, 109.3150 -0.0240, 109.3000 -0.0180, 109.2850 -0.0150)')
),
(
'Jalan Prof. M. Yamin',
'Arteri Primer',
ST_GeomFromText('LINESTRING(109.3245 -0.0487, 109.3170 -0.0540, 109.3050 -0.0620)')
);
-- ============================================================
+159 -26
View File
@@ -61,28 +61,112 @@ CREATE TABLE spbu (
INSERT INTO spbu (nama, deskripsi, buka_24_jam, geom) VALUES
(
'SPBU Bundaran Digulis Untan',
'SPBU terdekat dari kampus',
'SPBU COCO 61.781.01 Ahmad Yani',
'Jl. Jend. Ahmad Yani No.3, Pontianak (Dekat Bundaran Digulis Untan)',
1,
ST_GeomFromText('POINT(109.3440 -0.0565)')
ST_GeomFromText('POINT(109.344381 -0.056461)')
),
(
'SPBU Ahmad Yani',
'Dekat Mega Mall (24 Jam)',
'SPBU 64.781.11 Imam Bonjol',
'Jl. Imam Bonjol No.30, Pontianak Tenggara',
1,
ST_GeomFromText('POINT(109.3360 -0.0450)')
ST_GeomFromText('POINT(109.349692 -0.038148)')
),
(
'SPBU Imam Bonjol',
'SPBU pinggir kota',
0,
ST_GeomFromText('POINT(109.3410 -0.0380)')
'SPBU 64.781.06 Kota Baru',
'Jl. Prof. Dr. M. Yamin, Kota Baru, Pontianak Selatan',
1,
ST_GeomFromText('POINT(109.317589 -0.054378)')
),
(
'SPBU Kota Baru',
'Jl. Sultan Abdurrahman',
'SPBU 64.781.01 Adi Sucipto',
'Jl. Adi Sucipto, Pontianak Tenggara',
0,
ST_GeomFromText('POINT(109.3245 -0.0487)')
ST_GeomFromText('POINT(109.362241 -0.061730)')
),
(
'SPBU 64.781.03 KH. Ahmad Dahlan',
'Jl. KH. Ahmad Dahlan No.12, Pontianak Kota',
0,
ST_GeomFromText('POINT(109.333830 -0.033621)')
),
(
'SPBU 64.781.05 Tanjung Pura',
'Jl. Tanjung Pura, Pontianak Selatan',
1,
ST_GeomFromText('POINT(109.336184 -0.026788)')
),
(
'SPBU 64.781.12 Gusti Hamzah',
'Jl. Gusti Hamzah (Pancasila), Pontianak Kota',
0,
ST_GeomFromText('POINT(109.319760 -0.029415)')
),
(
'SPBU 64.781.14 Husein Hamzah',
'Jl. Husein Hamzah (Pal 3), Pontianak Barat',
0,
ST_GeomFromText('POINT(109.294121 -0.027963)')
),
(
'SPBU 64.781.15 RE Martadinata',
'Jl. RE Martadinata, Pontianak Barat',
0,
ST_GeomFromText('POINT(109.314227 -0.016335)')
),
(
'SPBU 63.781.02 28 Oktober',
'Jl. 28 Oktober, Pontianak Utara',
0,
ST_GeomFromText('POINT(109.366405 0.007621)')
),
(
'SPBU 64.782.01 Khatulistiwa',
'Jl. Khatulistiwa, Pontianak Utara',
1,
ST_GeomFromText('POINT(109.325983 0.035415)')
),
(
'SPBU OSO MT. Haryono',
'Jl. Letjen MT Haryono, Pontianak Selatan',
0,
ST_GeomFromText('POINT(109.3367485 -0.0448924)')
),
(
'SPBU 64.781.18 Danau Sentarum',
'Jl. Danau Sentarum, Pontianak Kota',
0,
ST_GeomFromText('POINT(109.311283 -0.046342)')
),
(
'SPBU 64.781.19 Serdam',
'Jl. Sungai Raya Dalam, Pontianak Tenggara',
0,
ST_GeomFromText('POINT(109.358241 -0.076389)')
),
(
'SPBU 64.781.02 Hasanuddin',
'Jl. Hasanuddin, Pontianak Barat',
0,
ST_GeomFromText('POINT(109.321873 -0.024502)')
),
(
'SPBU 64.781.21 Dr. Wahidin',
'Jl. Dr. Wahidin S., Pontianak Kota',
0,
ST_GeomFromText('POINT(109.308210 -0.034502)')
),
(
'SPBU 64.781.17 Komyos Sudarso',
'Jl. Komodor Yos Sudarso, Pontianak Barat',
0,
ST_GeomFromText('POINT(109.299100 -0.019500)')
),
(
'SPBU 64.781.19 HOS Cokroaminoto',
'Jl. HOS Cokroaminoto, Pontianak Kota',
1,
ST_GeomFromText('POINT(109.337500 -0.031500)')
);
CREATE TABLE rumah_ibadah (
@@ -100,25 +184,49 @@ INSERT INTO rumah_ibadah (nama, agama, radius_bantuan_meter, geom) VALUES
'Masjid Raya Mujahidin',
'Islam',
1000,
ST_GeomFromText('POINT(109.3356 -0.0454)')
ST_GeomFromText('POINT(109.3377 -0.0414)')
),
(
'Gereja Katedral St. Yosef',
'Masjid Jami Sultan Syarif Abdurrahman',
'Islam',
1000,
ST_GeomFromText('POINT(109.3522 -0.0229)')
),
(
'Gereja Katedral Santo Yosef',
'Katolik',
1000,
ST_GeomFromText('POINT(109.3368 -0.0298)')
ST_GeomFromText('POINT(109.3384 -0.0274)')
),
(
'Gereja Kristen Immanuel (GPIB)',
'Kristen',
1000,
ST_GeomFromText('POINT(109.3375 -0.0292)')
),
(
'Gereja GKKB Pontianak',
'Kristen',
1000,
ST_GeomFromText('POINT(109.3386 -0.0336)')
),
(
'Vihara Bodhisatva Karaniya Metta',
'Buddha',
1000,
ST_GeomFromText('POINT(109.3468 -0.0233)')
ST_GeomFromText('POINT(109.3432 -0.0215)')
),
(
'Masjid Jami Keraton Kadriyah',
'Islam',
'Maha Vihara Maitreya',
'Buddha',
1000,
ST_GeomFromText('POINT(109.3523 -0.0229)')
ST_GeomFromText('POINT(109.3649 -0.0732)')
),
(
'Pura Giripati Mulawarman',
'Hindu',
1000,
ST_GeomFromText('POINT(109.3802 -0.0663)')
);
CREATE TABLE jalan (
@@ -132,19 +240,44 @@ CREATE TABLE jalan (
INSERT INTO jalan (nama, jenis_jalan, geom) VALUES
(
'Jalan Ahmad Yani',
'Jalan Jenderal Ahmad Yani',
'Arteri Primer',
ST_GeomFromText('LINESTRING(109.3448 -0.0583, 109.3360 -0.0450, 109.3310 -0.0320)')
ST_GeomFromText('LINESTRING(109.3621 -0.0768, 109.3444 -0.0565, 109.3360 -0.0450, 109.3330 -0.0330)')
),
(
'Jalan Gajah Mada',
'Kolektor',
ST_GeomFromText('LINESTRING(109.3310 -0.0320, 109.3410 -0.0290, 109.3460 -0.0250)')
'Arteri Primer',
ST_GeomFromText('LINESTRING(109.3310 -0.0320, 109.3380 -0.0290, 109.3450 -0.0250)')
),
(
'Jalan Tanjung Pura',
'Arteri Primer',
ST_GeomFromText('LINESTRING(109.3300 -0.0300, 109.3360 -0.0260, 109.3480 -0.0240, 109.3550 -0.0270)')
),
(
'Jalan Imam Bonjol',
'Lokal',
ST_GeomFromText('LINESTRING(109.3360 -0.0450, 109.3420 -0.0400, 109.3500 -0.0350)')
'Arteri Primer',
ST_GeomFromText('LINESTRING(109.3360 -0.0450, 109.3420 -0.0400, 109.3500 -0.0350, 109.3590 -0.0400)')
),
(
'Jalan Adi Sucipto',
'Arteri Primer',
ST_GeomFromText('LINESTRING(109.3590 -0.0400, 109.3650 -0.0600, 109.3750 -0.0700)')
),
(
'Jalan Khatulistiwa',
'Arteri Primer',
ST_GeomFromText('LINESTRING(109.3450 0.0050, 109.3350 0.0150, 109.3250 0.0350, 109.3150 0.0550)')
),
(
'Jalan Komodor Yos Sudarso',
'Arteri Primer',
ST_GeomFromText('LINESTRING(109.3250 -0.0280, 109.3150 -0.0240, 109.3000 -0.0180, 109.2850 -0.0150)')
),
(
'Jalan Prof. M. Yamin',
'Arteri Primer',
ST_GeomFromText('LINESTRING(109.3245 -0.0487, 109.3170 -0.0540, 109.3050 -0.0620)')
);
CREATE TABLE kavling (
+1
View File
@@ -52,6 +52,7 @@ try {
'deskripsi' => $row['deskripsi'],
'buka_24_jam' => (bool) $row['buka_24_jam'],
'jarak_meter' => round($row['jarak_meter'], 2),
'jarak_km' => round($row['jarak_meter'] / 1000, 2),
'created_at' => $row['created_at'],
],
];
+8 -4
View File
@@ -27,14 +27,18 @@ if ($method !== 'GET') {
}
try {
date_default_timezone_set('Asia/Jakarta');
$stmt = $pdo->query(
"SELECT
COUNT(*) AS total,
SUM(buka_24_jam = 1) AS buka_24_jam,
SUM(buka_24_jam = 0) AS tidak_24_jam
COUNT(*) AS total_spbu,
COALESCE(SUM(buka_24_jam = 1), 0) AS spbu_buka,
COALESCE(SUM(buka_24_jam = 0), 0) AS spbu_tutup
FROM spbu"
);
$summary = $stmt->fetch();
$summary = $stmt->fetch(PDO::FETCH_ASSOC);
if ($summary) {
$summary['server_time'] = date('Y-m-d H:i:s');
}
sendSuccess($summary, 'Status SPBU berhasil diambil');
} catch (PDOException $e) {
sendError('Gagal mengambil status SPBU: ' . $e->getMessage(), 500);
+1 -1
View File
@@ -603,7 +603,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
</div>
<div class="left-footer">
D1041231071 — Naufal Zaky Ramadhan &copy; 2025
D1041231071 — Naufal Zaky Ramadhan &copy; 2026
</div>
</div>
+4 -4
View File
@@ -30,7 +30,7 @@ require_once __DIR__ . '/partials/header.php';
<div class="layer-section-title">Infrastruktur</div>
<label class="layer-item">
<input type="checkbox" id="ly-spbu" checked>
<input type="checkbox" id="ly-spbu">
<span class="layer-color layer-point" style="--layer-color:#F59E0B"><i class="fas fa-gas-pump"></i></span>
<span class="layer-text">
<span class="layer-name">SPBU</span>
@@ -39,7 +39,7 @@ require_once __DIR__ . '/partials/header.php';
</label>
<label class="layer-item">
<input type="checkbox" id="ly-jalan" checked>
<input type="checkbox" id="ly-jalan">
<span class="layer-color layer-line" style="--layer-color:#3B82F6"></span>
<span class="layer-text">
<span class="layer-name">Jalan</span>
@@ -48,7 +48,7 @@ require_once __DIR__ . '/partials/header.php';
</label>
<label class="layer-item">
<input type="checkbox" id="ly-kavling" checked>
<input type="checkbox" id="ly-kavling">
<span class="layer-color layer-area" style="--layer-color:#7C3AED"></span>
<span class="layer-text">
<span class="layer-name">Kavling / Parsil</span>
@@ -168,6 +168,6 @@ require_once __DIR__ . '/partials/header.php';
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script src="https://unpkg.com/leaflet-draw@1.0.4/dist/leaflet.draw.js"></script>
<script src="<?= app_url('public_assets/js/peta-admin.js') ?>?v=20260612-fix"></script>
<script src="<?= app_url('public_assets/js/peta-admin.js') ?>?v=<?= time() ?>"></script>
<?php $extraScript = ''; ?>
<?php require_once __DIR__ . '/partials/footer.php'; ?>
+4 -4
View File
@@ -33,7 +33,7 @@ require_once __DIR__ . '/partials/header.php';
<div class="layer-section-title">Infrastruktur</div>
<label class="layer-item">
<input type="checkbox" id="ly-spbu" checked>
<input type="checkbox" id="ly-spbu">
<span class="layer-color layer-point" style="--layer-color:#F59E0B"><i class="fas fa-gas-pump"></i></span>
<span class="layer-text">
<span class="layer-name">SPBU</span>
@@ -42,7 +42,7 @@ require_once __DIR__ . '/partials/header.php';
</label>
<label class="layer-item">
<input type="checkbox" id="ly-jalan" checked>
<input type="checkbox" id="ly-jalan">
<span class="layer-color layer-line" style="--layer-color:#3B82F6"></span>
<span class="layer-text">
<span class="layer-name">Jalan</span>
@@ -51,7 +51,7 @@ require_once __DIR__ . '/partials/header.php';
</label>
<label class="layer-item">
<input type="checkbox" id="ly-kavling" checked>
<input type="checkbox" id="ly-kavling">
<span class="layer-color layer-area" style="--layer-color:#7C3AED"></span>
<span class="layer-text">
<span class="layer-name">Kavling / Parsil</span>
@@ -156,6 +156,6 @@ require_once __DIR__ . '/partials/header.php';
</div>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script src="<?= app_url('public_assets/js/peta-user.js') ?>?v=20260612-fix"></script>
<script src="<?= app_url('public_assets/js/peta-user.js') ?>?v=<?= time() ?>"></script>
<?php $extraScript = ''; ?>
<?php require_once __DIR__ . '/partials/footer.php'; ?>
+13 -7
View File
@@ -469,22 +469,28 @@ async function findNearestSpbu() {
try {
const r = await fetch(`${API}/spbu_terdekat.php?lat=${center.lat}&lng=${center.lng}`);
const j = await r.json();
if (j.status === 'success' && j.data) {
const p = j.data.properties;
const coords = j.data.geometry.coordinates;
if (j.status === 'success' && j.data && j.data.features && j.data.features.length > 0) {
const feature = j.data.features[0];
if (feature && feature.geometry && feature.geometry.coordinates) {
const p = feature.properties;
const coords = feature.geometry.coordinates;
const jarakVal = p.jarak_km !== undefined ? p.jarak_km : (p.jarak_meter / 1000).toFixed(2);
const html = `<div class="spbu-result">
<div class="spbu-result-name">⛽ ${p.nama}</div>
<div class="spbu-result-meta">${p.buka_24_jam ? '🟢 24 Jam' : '🟡 Terbatas'}</div>
<div class="spbu-result-distance">${p.jarak_km} km</div>
<div class="spbu-result-distance">${jarakVal} km</div>
</div>`;
document.getElementById('spbuPanelResult').innerHTML = html;
// Show marker
if (state.layers.spbuRoute) state.map.removeLayer(state.layers.spbuRoute);
state.layers.spbuRoute = L.marker([coords[1], coords[0]], { icon: ICONS.spbu }).addTo(state.map)
.bindPopup(`<b>${p.nama}</b><br>${p.jarak_km} km dari pusat peta`).openPopup();
state.layers.spbuRoute = L.marker([coords[1], coords[0]], { icon: p.buka_24_jam ? ICONS.spbu24 : ICONS.spbu }).addTo(state.map)
.bindPopup(`<b>${p.nama}</b><br>${jarakVal} km dari pusat peta`).openPopup();
} else {
document.getElementById('spbuPanelResult').innerHTML = `<div class="spbu-result">${j.message || 'Tidak ada SPBU'}</div>`;
document.getElementById('spbuPanelResult').innerHTML = `<div class="spbu-result">Data geometri SPBU terdekat tidak valid.</div>`;
}
} else {
document.getElementById('spbuPanelResult').innerHTML = `<div class="spbu-result">${j.message || 'Tidak ada SPBU dalam jangkauan'}</div>`;
}
} catch (e) {
document.getElementById('spbuPanelResult').innerHTML = `<div class="spbu-result">Error: ${e.message}</div>`;
+13 -7
View File
@@ -335,19 +335,25 @@ async function findNearestSpbu() {
try {
const r = await fetch(`${API}/spbu_terdekat.php?lat=${center.lat}&lng=${center.lng}`);
const j = await r.json();
if (j.status === 'success' && j.data) {
const p = j.data.properties;
const coords = j.data.geometry.coordinates;
if (j.status === 'success' && j.data && j.data.features && j.data.features.length > 0) {
const feature = j.data.features[0];
if (feature && feature.geometry && feature.geometry.coordinates) {
const p = feature.properties;
const coords = feature.geometry.coordinates;
const jarakVal = p.jarak_km !== undefined ? p.jarak_km : (p.jarak_meter / 1000).toFixed(2);
document.getElementById('spbuPanelResult').innerHTML = `<div class="spbu-result">
<div class="spbu-result-name">⛽ ${p.nama}</div>
<div class="spbu-result-meta">${p.buka_24_jam ? '🟢 24 Jam' : '🟡 Terbatas'}</div>
<div class="spbu-result-distance">${p.jarak_km} km</div>
<div class="spbu-result-distance">${jarakVal} km</div>
</div>`;
if (state.layers.spbuRoute) state.map.removeLayer(state.layers.spbuRoute);
state.layers.spbuRoute = L.marker([coords[1], coords[0]], { icon: ICONS.spbu }).addTo(state.map)
.bindPopup(`<b>${p.nama}</b><br>${p.jarak_km} km dari pusat peta`).openPopup();
state.layers.spbuRoute = L.marker([coords[1], coords[0]], { icon: p.buka_24_jam ? ICONS.spbu24 : ICONS.spbu }).addTo(state.map)
.bindPopup(`<b>${p.nama}</b><br>${jarakVal} km dari pusat peta`).openPopup();
} else {
document.getElementById('spbuPanelResult').innerHTML = `<div class="spbu-result">${j.message || 'Tidak ada SPBU'}</div>`;
document.getElementById('spbuPanelResult').innerHTML = `<div class="spbu-result">Data geometri SPBU terdekat tidak valid.</div>`;
}
} else {
document.getElementById('spbuPanelResult').innerHTML = `<div class="spbu-result">${j.message || 'Tidak ada SPBU dalam jangkauan'}</div>`;
}
} catch (e) {
document.getElementById('spbuPanelResult').innerHTML = `<div class="spbu-result">Error: ${e.message}</div>`;