fix all bug
This commit is contained in:
@@ -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
@@ -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>
|
||||
|
||||
+108
-15
@@ -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,30 +36,96 @@ 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);
|
||||
const checkbox = document.getElementById('layer-spbu');
|
||||
if (checkbox && checkbox.checked) {
|
||||
mapLayers.spbu.addTo(appMap);
|
||||
}
|
||||
} catch (e) {
|
||||
window.showToast("Gagal meload data: "+e.message, 'error');
|
||||
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) => {
|
||||
const ext = props.buka_24_jam !== undefined ? `<p>Buka 24 Jam: <strong style="color:${props.buka_24_jam?'#10B981':'#EF4444'}">${props.buka_24_jam ? 'Ya' : 'Tidak'}</strong></p>` : '';
|
||||
layer.bindPopup(`
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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' ? `
|
||||
<div class="form-group">
|
||||
<label class="checkbox-group">
|
||||
<input type="checkbox" id="input-24jam">
|
||||
<span>Buka 24 Jam</span>
|
||||
</label>
|
||||
</div>
|
||||
` : '';
|
||||
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';
|
||||
|
||||
@@ -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
@@ -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
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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
@@ -65,6 +65,33 @@
|
||||
<p>Kumulatif P01 & 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
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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)')
|
||||
);
|
||||
|
||||
-- ============================================================
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -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'],
|
||||
],
|
||||
];
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -603,7 +603,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
</div>
|
||||
|
||||
<div class="left-footer">
|
||||
D1041231071 — Naufal Zaky Ramadhan © 2025
|
||||
D1041231071 — Naufal Zaky Ramadhan © 2026
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -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'; ?>
|
||||
|
||||
@@ -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'; ?>
|
||||
|
||||
@@ -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;
|
||||
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>`;
|
||||
document.getElementById('spbuPanelResult').innerHTML = html;
|
||||
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">${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();
|
||||
// Show marker
|
||||
if (state.layers.spbuRoute) state.map.removeLayer(state.layers.spbuRoute);
|
||||
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">Data geometri SPBU terdekat tidak valid.</div>`;
|
||||
}
|
||||
} else {
|
||||
document.getElementById('spbuPanelResult').innerHTML = `<div class="spbu-result">${j.message || 'Tidak ada SPBU'}</div>`;
|
||||
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>`;
|
||||
|
||||
@@ -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;
|
||||
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>`;
|
||||
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();
|
||||
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">${jarakVal} km</div>
|
||||
</div>`;
|
||||
if (state.layers.spbuRoute) state.map.removeLayer(state.layers.spbuRoute);
|
||||
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">Data geometri SPBU terdekat tidak valid.</div>`;
|
||||
}
|
||||
} else {
|
||||
document.getElementById('spbuPanelResult').innerHTML = `<div class="spbu-result">${j.message || 'Tidak ada SPBU'}</div>`;
|
||||
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>`;
|
||||
|
||||
Reference in New Issue
Block a user