update fitur peta pada tambah spbu
This commit is contained in:
+244
-16
@@ -473,11 +473,85 @@
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
/* ── Map SPBU (pin klik) ── */
|
||||
.spbu-map-wrap {
|
||||
grid-column: 1 / -1;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 16px;
|
||||
align-items: start;
|
||||
}
|
||||
.spbu-map-box {
|
||||
border: 2px solid var(--border);
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
height: 300px;
|
||||
position: relative;
|
||||
cursor: crosshair;
|
||||
}
|
||||
.spbu-map-box.has-pin {
|
||||
border-color: var(--accent);
|
||||
}
|
||||
.spbu-coords-hint {
|
||||
padding: 9px 12px;
|
||||
background: #eff6ff;
|
||||
border: 1px solid #bfdbfe;
|
||||
border-radius: 10px;
|
||||
font-size: 0.82rem;
|
||||
color: #1e40af;
|
||||
margin-bottom: 10px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.spbu-coords-hint strong {
|
||||
display: block;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
.coords-pill {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 9px 12px;
|
||||
background: #f8fafc;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 10px;
|
||||
font-size: 0.82rem;
|
||||
color: var(--muted);
|
||||
font-family: monospace;
|
||||
margin-top: 8px;
|
||||
}
|
||||
.coords-pill.filled {
|
||||
color: var(--text);
|
||||
border-color: var(--accent);
|
||||
background: #eff6ff;
|
||||
}
|
||||
.coords-pill span {
|
||||
flex: 1;
|
||||
}
|
||||
.coords-clear {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
border: 0;
|
||||
border-radius: 6px;
|
||||
background: #e2e8f0;
|
||||
cursor: pointer;
|
||||
font-size: 0.85rem;
|
||||
line-height: 1;
|
||||
display: none;
|
||||
}
|
||||
.coords-pill.filled .coords-clear {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* ── Responsive ── */
|
||||
@media (max-width: 860px) {
|
||||
.map-input-wrap {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.spbu-map-wrap {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
@media (max-width: 600px) {
|
||||
.form-grid {
|
||||
@@ -554,14 +628,75 @@
|
||||
placeholder="Jl. ..., Kelurahan, Kecamatan"
|
||||
/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="fLat">Latitude *</label>
|
||||
<input id="fLat" type="text" placeholder="Contoh: -0.0350" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="fLng">Longitude *</label>
|
||||
<input id="fLng" type="text" placeholder="Contoh: 109.3400" />
|
||||
|
||||
<!-- Peta pin SPBU -->
|
||||
<div class="spbu-map-wrap">
|
||||
<div>
|
||||
<div class="spbu-coords-hint">
|
||||
<strong>📍 Tentukan lokasi SPBU di peta</strong>
|
||||
Klik langsung di peta untuk menempatkan pin lokasi SPBU.
|
||||
Klik di tempat lain untuk memindahkan pin.
|
||||
</div>
|
||||
<div id="mapSpbu" class="spbu-map-box"></div>
|
||||
<div class="coords-pill" id="coordsPillSpbu">
|
||||
<span id="coordsTextSpbu"
|
||||
>Belum ada pin. Klik di peta untuk menentukan
|
||||
lokasi.</span
|
||||
>
|
||||
<button
|
||||
class="coords-clear"
|
||||
id="clearPinSpbu"
|
||||
title="Hapus pin"
|
||||
type="button"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Input lat/lng tetap ada tapi read-only dan tersembunyi untuk keperluan submit -->
|
||||
<div style="display: flex; flex-direction: column; gap: 10px">
|
||||
<div class="form-group">
|
||||
<label>Latitude (otomatis dari peta)</label>
|
||||
<input
|
||||
id="fLat"
|
||||
type="text"
|
||||
placeholder="Klik peta untuk mengisi"
|
||||
readonly
|
||||
style="
|
||||
background: #f1f5f9;
|
||||
cursor: not-allowed;
|
||||
color: var(--muted);
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Longitude (otomatis dari peta)</label>
|
||||
<input
|
||||
id="fLng"
|
||||
type="text"
|
||||
placeholder="Klik peta untuk mengisi"
|
||||
readonly
|
||||
style="
|
||||
background: #f1f5f9;
|
||||
cursor: not-allowed;
|
||||
color: var(--muted);
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
<p
|
||||
style="
|
||||
margin: 4px 0 0;
|
||||
font-size: 0.78rem;
|
||||
color: var(--muted);
|
||||
line-height: 1.5;
|
||||
"
|
||||
>
|
||||
Koordinat diisi otomatis saat kamu klik peta. Tidak perlu
|
||||
mengetik secara manual.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="fJamBuka">Jam Buka *</label>
|
||||
<input id="fJamBuka" type="time" value="06:00" />
|
||||
@@ -939,7 +1074,7 @@
|
||||
});
|
||||
|
||||
// ─── Tab switching ────────────────────────────────────────────────────────────
|
||||
let mapsInitialized = { jalan: false, bangunan: false };
|
||||
let mapsInitialized = { spbu: false, jalan: false, bangunan: false };
|
||||
|
||||
document.querySelectorAll(".tab-btn").forEach((btn) => {
|
||||
btn.addEventListener("click", () => {
|
||||
@@ -954,6 +1089,12 @@
|
||||
document.getElementById(tabId).classList.add("active");
|
||||
|
||||
// Init peta saat tab dibuka pertama kali (Leaflet butuh container visible)
|
||||
if (tabId === "tab-spbu" && !mapsInitialized.spbu) {
|
||||
setTimeout(() => {
|
||||
initSpbuMap();
|
||||
mapsInitialized.spbu = true;
|
||||
}, 80);
|
||||
}
|
||||
if (tabId === "tab-jalan" && !mapsInitialized.jalan) {
|
||||
setTimeout(() => {
|
||||
initJalanMap();
|
||||
@@ -969,6 +1110,79 @@
|
||||
});
|
||||
});
|
||||
|
||||
// ══════════════════════════════════════════════════════════════════════════════
|
||||
// ─── PETA SPBU (pin klik) ────────────────────────────────────────────────────
|
||||
// ══════════════════════════════════════════════════════════════════════════════
|
||||
let spbuMap, spbuPinMarker;
|
||||
|
||||
function initSpbuMap() {
|
||||
spbuMap = L.map("mapSpbu").setView(PONTIANAK_CENTER, 13);
|
||||
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
|
||||
maxZoom: 19,
|
||||
attribution:
|
||||
'© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>',
|
||||
}).addTo(spbuMap);
|
||||
|
||||
spbuMap.on("click", (e) => {
|
||||
const { lat, lng } = e.latlng;
|
||||
setSpbuPin(lat, lng);
|
||||
});
|
||||
}
|
||||
|
||||
function setSpbuPin(lat, lng) {
|
||||
const latR = parseFloat(lat.toFixed(6));
|
||||
const lngR = parseFloat(lng.toFixed(6));
|
||||
|
||||
// Hapus marker lama, pasang yang baru
|
||||
if (spbuPinMarker) spbuMap.removeLayer(spbuPinMarker);
|
||||
spbuPinMarker = L.marker([latR, lngR], {
|
||||
icon: L.divIcon({
|
||||
className: "",
|
||||
html: `<div style="
|
||||
width:36px;height:36px;display:grid;place-items:center;
|
||||
background:#dc2626;border:3px solid white;border-radius:50% 50% 50% 10%;
|
||||
transform:rotate(-45deg);box-shadow:0 6px 18px rgba(0,0,0,.3);">
|
||||
<span style="transform:rotate(45deg);font-size:18px">⛽</span>
|
||||
</div>`,
|
||||
iconSize: [36, 36],
|
||||
iconAnchor: [18, 34],
|
||||
}),
|
||||
draggable: true,
|
||||
}).addTo(spbuMap);
|
||||
|
||||
// Drag marker juga update koordinat
|
||||
spbuPinMarker.on("dragend", (ev) => {
|
||||
const pos = ev.target.getLatLng();
|
||||
setSpbuPin(pos.lat, pos.lng);
|
||||
});
|
||||
|
||||
// Update input fields & pill
|
||||
spbuEl.fLat.value = latR;
|
||||
spbuEl.fLng.value = lngR;
|
||||
document.getElementById("coordsTextSpbu").textContent =
|
||||
`Lat: ${latR} | Lng: ${lngR}`;
|
||||
const pill = document.getElementById("coordsPillSpbu");
|
||||
pill.classList.add("filled");
|
||||
document.getElementById("mapSpbu").classList.add("has-pin");
|
||||
}
|
||||
|
||||
function clearSpbuPin() {
|
||||
if (spbuPinMarker) {
|
||||
spbuMap.removeLayer(spbuPinMarker);
|
||||
spbuPinMarker = null;
|
||||
}
|
||||
spbuEl.fLat.value = "";
|
||||
spbuEl.fLng.value = "";
|
||||
document.getElementById("coordsTextSpbu").textContent =
|
||||
"Belum ada pin. Klik di peta untuk menentukan lokasi.";
|
||||
document.getElementById("coordsPillSpbu").classList.remove("filled");
|
||||
document.getElementById("mapSpbu").classList.remove("has-pin");
|
||||
}
|
||||
|
||||
document
|
||||
.getElementById("clearPinSpbu")
|
||||
.addEventListener("click", clearSpbuPin);
|
||||
|
||||
// ══════════════════════════════════════════════════════════════════════════════
|
||||
// ─── TAB SPBU ────────────────────────────────────────────────────────────────
|
||||
// ══════════════════════════════════════════════════════════════════════════════
|
||||
@@ -1080,16 +1294,12 @@
|
||||
}
|
||||
function resetSpbuForm() {
|
||||
spbuEl.editId.value = "";
|
||||
spbuEl.fKode.value =
|
||||
spbuEl.fNama.value =
|
||||
spbuEl.fAlamat.value =
|
||||
spbuEl.fLat.value =
|
||||
spbuEl.fLng.value =
|
||||
"";
|
||||
spbuEl.fKode.value = spbuEl.fNama.value = spbuEl.fAlamat.value = "";
|
||||
spbuEl.fJamBuka.value = "06:00";
|
||||
spbuEl.fJamTutup.value = "22:00";
|
||||
spbuEl.fOverride.value = "auto";
|
||||
renderFuelChecks([]);
|
||||
clearSpbuPin();
|
||||
spbuEl.formTitle.textContent = "➕ Tambah SPBU Baru";
|
||||
spbuEl.submitBtn.textContent = "💾 Simpan SPBU";
|
||||
spbuEl.resetBtn.style.display = "none";
|
||||
@@ -1101,8 +1311,6 @@
|
||||
spbuEl.fKode.value = spbu.kode;
|
||||
spbuEl.fNama.value = spbu.nama;
|
||||
spbuEl.fAlamat.value = spbu.alamat;
|
||||
spbuEl.fLat.value = spbu.lat;
|
||||
spbuEl.fLng.value = spbu.lng;
|
||||
spbuEl.fJamBuka.value = spbu.jam_buka;
|
||||
spbuEl.fJamTutup.value = spbu.jam_tutup;
|
||||
spbuEl.fOverride.value = spbu.manual_override || "auto";
|
||||
@@ -1111,6 +1319,21 @@
|
||||
spbuEl.submitBtn.textContent = "💾 Update SPBU";
|
||||
spbuEl.resetBtn.style.display = "";
|
||||
window.scrollTo({ top: 0, behavior: "smooth" });
|
||||
|
||||
// Set pin di peta — inisialisasi peta dulu kalau belum
|
||||
const doPin = () => {
|
||||
setSpbuPin(spbu.lat, spbu.lng);
|
||||
spbuMap.setView([spbu.lat, spbu.lng], 15);
|
||||
};
|
||||
if (!mapsInitialized.spbu) {
|
||||
setTimeout(() => {
|
||||
initSpbuMap();
|
||||
mapsInitialized.spbu = true;
|
||||
setTimeout(doPin, 200);
|
||||
}, 80);
|
||||
} else {
|
||||
doPin();
|
||||
}
|
||||
}
|
||||
async function submitSpbu() {
|
||||
const id = spbuEl.editId.value;
|
||||
@@ -1171,6 +1394,11 @@
|
||||
spbuEl.resetBtn.addEventListener("click", resetSpbuForm);
|
||||
renderFuelChecks([]);
|
||||
loadSpbu();
|
||||
// Tab SPBU aktif saat load — init petanya langsung
|
||||
setTimeout(() => {
|
||||
initSpbuMap();
|
||||
mapsInitialized.spbu = true;
|
||||
}, 120);
|
||||
|
||||
// ══════════════════════════════════════════════════════════════════════════════
|
||||
// ─── TAB JALAN ───────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -194,7 +194,7 @@
|
||||
<div class="brand">
|
||||
<small>Gereja Peduli</small>
|
||||
<h1>WebGIS Poverty Mapping</h1>
|
||||
<p>Peta prioritas keluarga penerima bantuan berbasis SAW, terpusat, dan mendukung mode privasi.</p>
|
||||
<p>Peta prioritas keluarga penerima bantuan berbasis SAW, terpusat, dan mudah dipantau.</p>
|
||||
</div>
|
||||
|
||||
<section class="panel">
|
||||
@@ -209,12 +209,6 @@
|
||||
|
||||
<section class="panel">
|
||||
<h2>Filter Peta</h2>
|
||||
<label class="field">Role Akses
|
||||
<select id="roleSelect">
|
||||
<option value="admin">Admin - semua data</option>
|
||||
<option value="pengurus">Pengurus - data sensitif disembunyikan</option>
|
||||
</select>
|
||||
</label>
|
||||
<label class="field">Kategori
|
||||
<select id="categoryFilter">
|
||||
<option value="">Semua Kategori</option>
|
||||
@@ -227,7 +221,6 @@
|
||||
<label class="field">Pencarian Keluarga
|
||||
<input id="searchInput" placeholder="Nama, alamat, atau wilayah" />
|
||||
</label>
|
||||
<label class="switch"><span>Mode Privasi</span><input id="privacyToggle" type="checkbox" /></label>
|
||||
<label class="switch"><span>Heatmap persebaran</span><input id="heatToggle" type="checkbox" checked /></label>
|
||||
</section>
|
||||
|
||||
@@ -296,11 +289,9 @@
|
||||
}
|
||||
|
||||
function params() {
|
||||
const role = el("roleSelect").value;
|
||||
const privacy = el("privacyToggle").checked ? "1" : "0";
|
||||
const kategori = encodeURIComponent(el("categoryFilter").value);
|
||||
const search = encodeURIComponent(el("searchInput").value.trim());
|
||||
return `role=${role}&privacy=${privacy}&kategori=${kategori}&search=${search}`;
|
||||
return `kategori=${kategori}&search=${search}`;
|
||||
}
|
||||
|
||||
async function loadData() {
|
||||
@@ -416,7 +407,7 @@
|
||||
}
|
||||
|
||||
let debounce;
|
||||
["roleSelect", "categoryFilter", "privacyToggle", "heatToggle"].forEach((id) => el(id).addEventListener("change", () => loadData().catch((error) => toast(error.message))));
|
||||
["categoryFilter", "heatToggle"].forEach((id) => el(id).addEventListener("change", () => loadData().catch((error) => toast(error.message))));
|
||||
el("searchInput").addEventListener("input", () => {
|
||||
clearTimeout(debounce);
|
||||
debounce = setTimeout(() => loadData().catch((error) => toast(error.message)), 260);
|
||||
|
||||
Reference in New Issue
Block a user