414 lines
20 KiB
PHP
414 lines
20 KiB
PHP
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<title>WebGIS SPBU, Jalan & Parsil Pontianak</title>
|
|
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.css"/>
|
|
|
|
<style>
|
|
#map { height: 100vh; width: 100%; }
|
|
body { margin: 0; font-family: 'Segoe UI', sans-serif; }
|
|
|
|
/* Popup Modern Design */
|
|
.leaflet-popup-content-wrapper { border-radius: 15px; padding: 0; overflow: hidden; box-shadow: 0 4px 15px rgba(0,0,0,0.2); }
|
|
.leaflet-popup-content { width: 280px !important; margin: 0 !important; }
|
|
.popup-header { background: #f8f9fa; padding: 12px 15px; border-bottom: 1px solid #eee; }
|
|
.popup-header b { font-size: 16px; color: #2c3e50; display: block; }
|
|
.popup-body { padding: 12px 15px; font-size: 13px; color: #555; }
|
|
.info-row { display: flex; justify-content: space-between; margin-bottom: 8px; }
|
|
|
|
/* Badges */
|
|
.badge { padding: 4px 10px; border-radius: 20px; font-size: 10px; font-weight: bold; text-transform: uppercase; }
|
|
.badge-ya { background: #e8f5e9; color: #2e7d32; border: 1px solid #a5d6a7; }
|
|
.badge-tidak { background: #ffebee; color: #c62828; border: 1px solid #ef9a9a; }
|
|
|
|
.popup-footer { display: flex; gap: 8px; padding: 0 15px 15px 15px; }
|
|
.btn-action { flex: 1; border: none; padding: 8px; border-radius: 8px; font-size: 12px; font-weight: 600; cursor: pointer; transition: 0.2s; }
|
|
.btn-edit { background: #e3f2fd; color: #1976d2; }
|
|
.btn-hapus { background: #ffebee; color: #c62828; }
|
|
.form-input { width: 100%; padding: 8px; margin-bottom: 8px; border: 1px solid #ddd; border-radius: 6px; box-sizing: border-box; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<div id="map"></div>
|
|
|
|
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.js"></script>
|
|
<script src="https://cdn.jsdelivr.net/npm/@turf/turf@6/turf.min.js"></script>
|
|
|
|
<script>
|
|
var tempGeoJSON = "";
|
|
var tempValue = 0;
|
|
|
|
var map = L.map('map').setView([-0.0263, 109.3425], 13);
|
|
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
|
|
|
|
// Icons
|
|
var greenIcon = new L.Icon({ iconUrl: 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-green.png', shadowUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/images/marker-shadow.png', iconSize: [25, 41], iconAnchor: [12, 41], popupAnchor: [1, -34], shadowSize: [41, 41] });
|
|
var redIcon = new L.Icon({ iconUrl: 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-red.png', shadowUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/images/marker-shadow.png', iconSize: [25, 41], iconAnchor: [12, 41], popupAnchor: [1, -34], shadowSize: [41, 41] });
|
|
|
|
// Fitur Draw (Menggambar)
|
|
var drawnItems = new L.FeatureGroup();
|
|
map.addLayer(drawnItems);
|
|
var drawControl = new L.Control.Draw({
|
|
draw: { polyline: true, polygon: true, circle: false, marker: true, rectangle: false, circlemarker: false },
|
|
edit: { featureGroup: drawnItems }
|
|
});
|
|
map.addControl(drawControl);
|
|
|
|
// 1. LOAD SEMUA DATA (Point, Line, Polygon)
|
|
// 1. LOAD SEMUA DATA (Point, Line, Polygon)
|
|
function loadMarkers() {
|
|
fetch('ambil.php')
|
|
.then(res => res.json())
|
|
.then(data => {
|
|
// Tampilkan SPBU (Point)
|
|
data.spbu.forEach(spbu => {
|
|
let is24 = (spbu.status_24jam === 'Ya');
|
|
let marker = L.marker([spbu.latitude, spbu.longitude], {
|
|
icon: is24 ? greenIcon : redIcon,
|
|
draggable: true
|
|
}).addTo(map);
|
|
|
|
marker.on('dragend', function(e) {
|
|
updatePosisi(spbu.id, marker.getLatLng().lat, marker.getLatLng().lng);
|
|
});
|
|
|
|
marker.bindPopup(`
|
|
<div class="popup-header"><b>⛽ ${spbu.nama_spbu}</b></div>
|
|
<div class="popup-body">
|
|
<div class="info-row"><span>📞 WhatsApp</span> <strong>${spbu.no_telp || '-'}</strong></div>
|
|
<div class="info-row"><span>🕒 Status</span> <span class="badge ${is24 ? 'badge-ya' : 'badge-tidak'}">${is24 ? 'Buka 24 Jam' : 'Tutup Malam'}</span></div>
|
|
<button class="btn-action btn-edit" onclick='tampilFormEditSPBU(${JSON.stringify(spbu)})'>Edit</button>
|
|
<button class="btn-action btn-hapus" onclick="hapusData(${spbu.id}, 'spbu')">Hapus</button>
|
|
</div>
|
|
`);
|
|
});
|
|
|
|
// Tampilkan Jalan (Line)
|
|
data.jalan.forEach(j => {
|
|
let warna = j.status_jalan == 'Nasional' ? 'red' : (j.status_jalan == 'Provinsi' ? 'blue' : 'green');
|
|
L.geoJSON(JSON.parse(j.geojson), { style: {color: warna, weight: 5} })
|
|
// Pastikan j.panjang_m sesuai dengan kolom di database
|
|
.bindPopup(`
|
|
<div class="popup-header"><b>🛣️ Jalan: ${j.nama_jalan}</b></div>
|
|
<div class="popup-body">
|
|
<div class="info-row"><span>📌 Status</span> <strong>${j.status_jalan}</strong></div>
|
|
<div class="info-row"><span>📏 Panjang</span> <strong>${j.panjang_m} m</strong></div>
|
|
<div class="popup-footer" style="padding: 10px 0 0 0;">
|
|
<button class="btn-action btn-edit" onclick='tampilFormEditJalan(${JSON.stringify(j).replace(/'/g, "\\'")})'>✏️ Edit</button>
|
|
<button class="btn-action btn-hapus" onclick="hapusData(${j.id}, 'data_jalan')">🗑️ Hapus</button>
|
|
</div>
|
|
</div>
|
|
`)
|
|
.addTo(map);
|
|
});
|
|
|
|
// Tampilkan Parsil (Polygon)
|
|
data.parsil.forEach(p => {
|
|
L.geoJSON(JSON.parse(p.geojson), { style: {fillColor: 'orange', color: 'black', weight: 1} })
|
|
// Pastikan p.luas_m2 sesuai dengan kolom di database
|
|
.bindPopup(`
|
|
<div class="popup-header"><b>🌿 Pemilik: ${p.pemilik}</b></div>
|
|
<div class="popup-body">
|
|
<div class="info-row"><span>📜 Status</span> <strong>${p.status_milik}</strong></div>
|
|
<div class="info-row"><span>📐 Luas</span> <strong>${p.luas_m2} m²</strong></div>
|
|
<div class="popup-footer" style="padding: 10px 0 0 0;">
|
|
<button class="btn-action btn-edit" onclick='tampilFormEditParsil(${JSON.stringify(p).replace(/'/g, "\\'")})'>✏️ Edit</button>
|
|
<button class="btn-action btn-hapus" onclick="hapusData(${p.id}, 'data_parsil')">🗑️ Hapus</button>
|
|
</div>
|
|
</div>
|
|
`)
|
|
.addTo(map);
|
|
});
|
|
});
|
|
}
|
|
function tampilFormEditSPBU(data) {
|
|
// Membuat konten HTML formulir edit dengan data lama yang sudah terisi
|
|
let formEdit = `
|
|
<div class="popup-body">
|
|
<b>✏️ Edit Data SPBU</b><br>
|
|
<input type="hidden" id="edit_id" value="${data.id}">
|
|
|
|
<label style="font-size:11px; color:#777;">Nama SPBU:</label>
|
|
<input type="text" id="edit_nama" class="form-input" value="${data.nama_spbu}" placeholder="Nama SPBU">
|
|
|
|
<label style="font-size:11px; color:#777;">No. WhatsApp:</label>
|
|
<input type="text" id="edit_telp" class="form-input" value="${data.no_telp}" placeholder="No Telp">
|
|
|
|
<label style="font-size:11px; color:#777;">Status 24 Jam:</label>
|
|
<select id="edit_status" class="form-input">
|
|
<option value="Ya" ${data.status_24jam == 'Ya' ? 'selected' : ''}>Buka 24 Jam</option>
|
|
<option value="Tidak" ${data.status_24jam == 'Tidak' ? 'selected' : ''}>Tutup Malam</option>
|
|
</select>
|
|
|
|
<div style="display:flex; gap:5px;">
|
|
<button class="btn-action btn-edit" onclick="prosesUpdateSPBU(${data.latitude}, ${data.longitude})">💾 Simpan Perubahan</button>
|
|
<button class="btn-action" style="background:#eee; color:#333;" onclick="map.closePopup()">Batal</button>
|
|
</div>
|
|
</div>`;
|
|
|
|
// Membuka popup baru di lokasi SPBU tersebut dengan konten formulir edit
|
|
L.popup()
|
|
.setLatLng([data.latitude, data.longitude])
|
|
.setContent(formEdit)
|
|
.openOn(map);
|
|
}
|
|
|
|
/**
|
|
* 2. Fungsi Edit Data
|
|
*/
|
|
function tampilFormEditJalan(data) {
|
|
let formEdit = `
|
|
<div class="popup-header"><b>✏️ Edit Jalan</b></div>
|
|
<div class="popup-body">
|
|
<input type="hidden" id="edit_j_id" value="${data.id}">
|
|
<label style="font-size:11px; color:#777;">Nama Jalan:</label>
|
|
<input type="text" id="edit_j_nama" class="form-input" value="${data.nama_jalan}">
|
|
<label style="font-size:11px; color:#777;">Status Jalan:</label>
|
|
<select id="edit_j_status" class="form-input">
|
|
<option value="Nasional" ${data.status_jalan == 'Nasional' ? 'selected' : ''}>Nasional</option>
|
|
<option value="Provinsi" ${data.status_jalan == 'Provinsi' ? 'selected' : ''}>Provinsi</option>
|
|
<option value="Kabupaten" ${data.status_jalan == 'Kabupaten' ? 'selected' : ''}>Kabupaten</option>
|
|
</select>
|
|
<div style="display:flex; gap:5px;">
|
|
<button class="btn-action btn-edit" onclick="prosesUpdateJalan()">💾 Simpan Perubahan</button>
|
|
<button class="btn-action" style="background:#eee; color:#333;" onclick="map.closePopup()">Batal</button>
|
|
</div>
|
|
</div>`;
|
|
|
|
// Untuk jalan, popup kita taruh di koordinat pertama feature geojson
|
|
let geometry = JSON.parse(data.geojson).geometry;
|
|
let latlng = [geometry.coordinates[0][1], geometry.coordinates[0][0]];
|
|
if(geometry.type === "MultiLineString") latlng = [geometry.coordinates[0][0][1], geometry.coordinates[0][0][0]];
|
|
|
|
L.popup().setLatLng(latlng).setContent(formEdit).openOn(map);
|
|
}
|
|
|
|
function prosesUpdateJalan() {
|
|
let fd = new FormData();
|
|
fd.append('type', 'jalan');
|
|
fd.append('id', document.getElementById('edit_j_id').value);
|
|
fd.append('nama_jalan', document.getElementById('edit_j_nama').value);
|
|
fd.append('status_jalan', document.getElementById('edit_j_status').value);
|
|
|
|
fetch('ambil.php', { method: 'POST', body: fd })
|
|
.then(res => res.text())
|
|
.then(txt => { alert(txt); location.reload(); });
|
|
}
|
|
|
|
function tampilFormEditParsil(data) {
|
|
let formEdit = `
|
|
<div class="popup-header"><b>✏️ Edit Parsil</b></div>
|
|
<div class="popup-body">
|
|
<input type="hidden" id="edit_p_id" value="${data.id}">
|
|
<label style="font-size:11px; color:#777;">Nama Pemilik:</label>
|
|
<input type="text" id="edit_p_pemilik" class="form-input" value="${data.pemilik}">
|
|
<label style="font-size:11px; color:#777;">Status Kepemilikan:</label>
|
|
<select id="edit_p_status" class="form-input">
|
|
<option value="SHM" ${data.status_milik == 'SHM' ? 'selected' : ''}>SHM</option>
|
|
<option value="HGB" ${data.status_milik == 'HGB' ? 'selected' : ''}>HGB</option>
|
|
</select>
|
|
<div style="display:flex; gap:5px;">
|
|
<button class="btn-action btn-edit" onclick="prosesUpdateParsil()">💾 Simpan Perubahan</button>
|
|
<button class="btn-action" style="background:#eee; color:#333;" onclick="map.closePopup()">Batal</button>
|
|
</div>
|
|
</div>`;
|
|
|
|
// Untuk parsil, popup ditaruh di koordinat pertama polygon
|
|
let geometry = JSON.parse(data.geojson).geometry;
|
|
let coords = geometry.coordinates[0][0];
|
|
if(geometry.type === "MultiPolygon") coords = geometry.coordinates[0][0][0];
|
|
let latlng = [coords[1], coords[0]];
|
|
|
|
L.popup().setLatLng(latlng).setContent(formEdit).openOn(map);
|
|
}
|
|
|
|
function prosesUpdateParsil() {
|
|
let fd = new FormData();
|
|
fd.append('type', 'parsil');
|
|
fd.append('id', document.getElementById('edit_p_id').value);
|
|
fd.append('pemilik', document.getElementById('edit_p_pemilik').value);
|
|
fd.append('status_milik', document.getElementById('edit_p_status').value);
|
|
|
|
fetch('ambil.php', { method: 'POST', body: fd })
|
|
.then(res => res.text())
|
|
.then(txt => { alert(txt); location.reload(); });
|
|
}
|
|
|
|
function prosesUpdateSPBU(lat, lng) {
|
|
const id = document.getElementById('edit_id').value;
|
|
const nama = document.getElementById('edit_nama').value;
|
|
const telp = document.getElementById('edit_telp').value;
|
|
const status = document.getElementById('edit_status').value;
|
|
|
|
let fd = new FormData();
|
|
fd.append('id', id);
|
|
fd.append('nama_spbu', nama);
|
|
fd.append('no_telp', telp);
|
|
fd.append('status_24jam', status);
|
|
fd.append('latitude', lat);
|
|
fd.append('longitude', lng);
|
|
|
|
fetch('ambil.php', { method: 'POST', body: fd })
|
|
.then(res => res.text())
|
|
.then(txt => {
|
|
if (txt.toLowerCase().includes("berhasil")) {
|
|
alert("✅ Perubahan disimpan!");
|
|
location.reload();
|
|
} else {
|
|
alert("Respon: " + txt);
|
|
location.reload();
|
|
}
|
|
});
|
|
}
|
|
// Fungsi Hapus Tambahan (Agar fitur di ambil.php terpakai)
|
|
function hapusData(id, tabel) {
|
|
if(confirm("Apakah Anda yakin ingin menghapus data ini?")) {
|
|
let fd = new FormData();
|
|
fd.append('hapus_id', id);
|
|
fd.append('tabel', tabel);
|
|
|
|
fetch('ambil.php', { method: 'POST', body: fd })
|
|
.then(res => res.text())
|
|
.then(txt => {
|
|
if (txt.includes("Berhasil")) {
|
|
alert("🗑️ Data telah terhapus!");
|
|
location.reload(); // Hanya reload jika benar-benar berhasil
|
|
} else {
|
|
alert("Gagal: " + txt);
|
|
}
|
|
})
|
|
.catch(err => console.error("Error:", err));
|
|
}
|
|
}
|
|
loadMarkers();
|
|
|
|
// 2. EVENT SAAT SELESAI MENGGAMBAR
|
|
map.on(L.Draw.Event.CREATED, function (event) {
|
|
var layer = event.layer;
|
|
var type = event.layerType;
|
|
drawnItems.addLayer(layer);
|
|
|
|
// Simpan GeoJSON ke variabel global agar tidak perlu dikirim lewat parameter onclick
|
|
tempGeoJSON = JSON.stringify(layer.toGeoJSON());
|
|
|
|
if (type === 'marker') {
|
|
tampilFormSPBU(layer.getLatLng().lat, layer.getLatLng().lng, layer);
|
|
} else if (type === 'polyline') {
|
|
tempValue = turf.length(layer.toGeoJSON(), {units: 'meters'}).toFixed(2);
|
|
tampilFormJalan(layer);
|
|
} else if (type === 'polygon') {
|
|
tempValue = turf.area(layer.toGeoJSON()).toFixed(2);
|
|
tampilFormParsil(layer);
|
|
}
|
|
});
|
|
|
|
// --- FORM POPUP ---
|
|
function tampilFormSPBU(lat, lng, layer) {
|
|
let form = `<div class="popup-header"><b>⛽ Tambah SPBU</b></div>
|
|
<div class="popup-body">
|
|
<label style="font-size:12px; color:#555; margin-bottom:4px; display:block;">Nama SPBU</label>
|
|
<input type="text" id="nama" class="form-input" placeholder="Contoh: SPBU Pertamina">
|
|
<label style="font-size:12px; color:#555; margin-bottom:4px; display:block;">No. WhatsApp</label>
|
|
<input type="text" id="telp" class="form-input" placeholder="Contoh: 08123456789">
|
|
<label style="font-size:12px; color:#555; margin-bottom:4px; display:block;">Status 24 Jam</label>
|
|
<select id="status" class="form-input"><option value="Ya">Buka 24 Jam</option><option value="Tidak">Tutup Malam</option></select>
|
|
<div class="popup-footer" style="padding: 10px 0 0 0;">
|
|
<button class="btn-action btn-edit" onclick="simpanData(${lat}, ${lng})">💾 Simpan Lokasi</button>
|
|
</div>
|
|
</div>`;
|
|
layer.bindPopup(form).openPopup();
|
|
}
|
|
|
|
function tampilFormJalan(layer) {
|
|
let form = `<div class="popup-header"><b>🛣️ Tambah Jalan</b></div>
|
|
<div class="popup-body">
|
|
<div class="info-row"><span>Panjang</span><strong>${tempValue} m</strong></div>
|
|
<label style="font-size:12px; color:#555; margin-bottom:4px; display:block;">Nama Jalan</label>
|
|
<input type="text" id="nama_j" class="form-input" placeholder="Contoh: Jl. Gajah Mada">
|
|
<label style="font-size:12px; color:#555; margin-bottom:4px; display:block;">Status Jalan</label>
|
|
<select id="status_j" class="form-input">
|
|
<option value="Nasional">Nasional</option>
|
|
<option value="Provinsi">Provinsi</option>
|
|
<option value="Kabupaten">Kabupaten</option>
|
|
</select>
|
|
<div class="popup-footer" style="padding: 10px 0 0 0;">
|
|
<button class="btn-action btn-edit" onclick="simpanJalan()">💾 Simpan Jalan</button>
|
|
</div>
|
|
</div>`;
|
|
layer.bindPopup(form).openPopup();
|
|
}
|
|
|
|
function tampilFormParsil(layer) {
|
|
let form = `<div class="popup-header"><b>🌿 Tambah Parsil</b></div>
|
|
<div class="popup-body">
|
|
<div class="info-row"><span>Luas</span><strong>${tempValue} m²</strong></div>
|
|
<label style="font-size:12px; color:#555; margin-bottom:4px; display:block;">Nama Pemilik</label>
|
|
<input type="text" id="pemilik" class="form-input" placeholder="Contoh: Budi Santoso">
|
|
<label style="font-size:12px; color:#555; margin-bottom:4px; display:block;">Status Kepemilikan</label>
|
|
<select id="status_p" class="form-input">
|
|
<option value="SHM">SHM</option>
|
|
<option value="HGB">HGB</option>
|
|
</select>
|
|
<div class="popup-footer" style="padding: 10px 0 0 0;">
|
|
<button class="btn-action btn-edit" onclick="simpanParsil()">💾 Simpan Parsil</button>
|
|
</div>
|
|
</div>`;
|
|
layer.bindPopup(form).openPopup();
|
|
}
|
|
|
|
// --- FUNGSI SIMPAN (AJAX) ---
|
|
function simpanData(lat, lng) {
|
|
let fd = new FormData();
|
|
fd.append('nama_spbu', document.getElementById('nama').value);
|
|
fd.append('no_telp', document.getElementById('telp').value);
|
|
fd.append('status_24jam', document.getElementById('status').value);
|
|
fd.append('latitude', lat); fd.append('longitude', lng);
|
|
fetch('ambil.php', { method: 'POST', body: fd }).then(() => location.reload());
|
|
}
|
|
|
|
function simpanJalan() {
|
|
const fd = new FormData();
|
|
fd.append('type', 'jalan');
|
|
fd.append('nama_jalan', document.getElementById('nama_j').value);
|
|
fd.append('status_jalan', document.getElementById('status_j').value);
|
|
fd.append('panjang_m', tempValue);
|
|
fd.append('geojson', tempGeoJSON); // Ambil dari variabel global
|
|
|
|
fetch('ambil.php', { method: 'POST', body: fd })
|
|
.then(res => res.text())
|
|
.then(txt => {
|
|
alert(txt);
|
|
location.reload();
|
|
});
|
|
}
|
|
|
|
function simpanParsil() {
|
|
let fd = new FormData();
|
|
fd.append('type', 'parsil');
|
|
fd.append('pemilik', document.getElementById('pemilik').value);
|
|
fd.append('status_milik', document.getElementById('status_p').value);
|
|
fd.append('luas_m2', tempValue);
|
|
fd.append('geojson', tempGeoJSON); // Ambil dari variabel global
|
|
|
|
fetch('ambil.php', { method: 'POST', body: fd })
|
|
.then(res => res.text())
|
|
.then(txt => {
|
|
alert(txt);
|
|
location.reload();
|
|
});
|
|
}
|
|
|
|
function updatePosisi(id, lat, lng) {
|
|
let fd = new FormData();
|
|
fd.append('action', 'update_posisi'); // Tambahkan flag action
|
|
fd.append('id', id);
|
|
fd.append('lat', lat);
|
|
fd.append('lng', lng);
|
|
fetch('ambil.php', { method: 'POST', body: fd });
|
|
}
|
|
</script>
|
|
</body>
|
|
</html> |