Files
TUGAS-SIG/01/index.html
T

277 lines
14 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>WebGIS Pro - Layer Control SPBU</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
<link rel="stylesheet" href="https://unpkg.com/@geoman-io/leaflet-geoman-free@latest/dist/leaflet-geoman.css" />
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script src="https://unpkg.com/@geoman-io/leaflet-geoman-free@latest/dist/leaflet-geoman.min.js"></script>
<script src="https://unpkg.com/@turf/turf@6/turf.min.js"></script>
<style>
html, body, #map { height: 100%; margin: 0; padding: 0; font-family: 'Segoe UI', sans-serif; }
.form-container { width: 220px; padding: 10px; }
.btn-simpan { background: #28a745; color: white; border: none; padding: 8px; width: 100%; cursor: pointer; border-radius: 4px; font-weight: bold; margin-top: 10px; }
.btn-update { background: #ffc107; color: black; border: none; padding: 8px; width: 100%; cursor: pointer; border-radius: 4px; font-weight: bold; margin-top: 10px; }
select, input { width: 100%; margin-bottom: 8px; padding: 5px; box-sizing: border-box; }
.ikon-edit-atribut { display: flex; align-items: center; justify-content: center; }
.ikon-edit-atribut::after { content: '📝'; font-size: 16px; }
</style>
</head>
<body>
<div id="map"></div>
<script>
const map = L.map('map').setView([-0.0541467, 109.3491684], 14);
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
const layer_spbu_24 = L.layerGroup();
const layer_spbu_non_24 = L.layerGroup();
L.control.layers(null, {
"SPBU Buka 24 Jam": layer_spbu_24,
"SPBU Tidak Buka 24 Jam": layer_spbu_non_24
}).addTo(map);
map.pm.addControls({
position: 'topleft', drawMarker: true, drawPolyline: true, drawPolygon: true, removalMode: true, editMode: true, dragMode: true
});
map.pm.setGlobalOptions({ allowSelfIntersection: false });
let is_edit_atribut_mode = false;
map.pm.Toolbar.createCustomControl({
name: 'EditAtributData',
block: 'custom',
title: 'Edit Nama & Status',
className: 'ikon-edit-atribut',
toggle: true,
onClick: () => {
is_edit_atribut_mode = !is_edit_atribut_mode;
}
});
function gaya_jalan(status) {
if (status === 'Nasional') return { color: 'red', weight: 6 };
if (status === 'Provinsi') return { color: 'blue', weight: 4 };
return { color: 'green', weight: 2 };
}
let sedang_memproses = false;
// Menangani penggambaran objek
map.on('pm:create', function(e) {
if (sedang_memproses) { map.removeLayer(e.layer); return; }
sedang_memproses = true;
setTimeout(() => { sedang_memproses = false; }, 500);
const layer = e.layer;
const shape = e.shape;
let popup_content = "";
if (shape === 'Line') {
const geojson_mentah = layer.toGeoJSON();
const geo_data = JSON.stringify(geojson_mentah.geometry).replace(/"/g, '&quot;');
const panjang_meter = turf.length(geojson_mentah, {units: 'kilometers'}) * 1000;
popup_content = `<div class="form-container"><h4>Tambah Jalan Baru</h4>
<input type="text" id="nama_jln" placeholder="Nama Jalan">
<select id="stat_jln"><option value="Nasional">Nasional</option><option value="Provinsi">Provinsi</option><option value="Kabupaten">Kabupaten</option></select>
<p>Panjang: <b>${panjang_meter.toFixed(2)} m</b></p>
<button class="btn-simpan" onclick="simpan_baru('jalan', ${panjang_meter}, '${geo_data}')">Simpan Baru</button></div>`;
}
else if (shape === 'Polygon') {
const geojson_mentah = layer.toGeoJSON();
const geo_data = JSON.stringify(geojson_mentah.geometry).replace(/"/g, '&quot;');
const luas_meter_p = turf.area(geojson_mentah);
popup_content = `<div class="form-container"><h4>Tambah Persil Baru</h4>
<input type="text" id="no_psl" placeholder="Nomor Persil">
<select id="stat_psl"><option value="SHM">SHM</option><option value="HGB">HGB</option><option value="HGU">HGU</option><option value="HP">HP</option></select>
<p>Luas: <b>${luas_meter_p.toFixed(2)} m²</b></p>
<button class="btn-simpan" onclick="simpan_baru('persil', ${luas_meter_p}, '${geo_data}')">Simpan Baru</button></div>`;
layer.setStyle({fillColor: 'yellow', fillOpacity: 0.5, color: 'black'});
}
else if (shape === 'Marker') {
/* * Menarik titik presisi lintang dan bujur langsung dari objek Leaflet.
* Ini diperlukan karena tabel spbu_locations meminta kolom lat dan lng terpisah, bukan geojson.
*/
const titik_kordinat = layer.getLatLng();
popup_content = `<div class="form-container"><h4>Tambah SPBU Baru</h4>
<input type="text" id="nama_spbu" placeholder="Nama SPBU">
<input type="text" id="hp_spbu" placeholder="No. HP">
<select id="stat_spbu">
<option value="24 Jam">Buka 24 Jam</option>
<option value="Tidak 24 Jam">Tidak Buka 24 Jam</option>
</select>
<button class="btn-simpan" onclick="simpan_baru('spbu', 0, null, ${titik_kordinat.lat}, ${titik_kordinat.lng})">Simpan Baru</button></div>`;
}
layer.bindPopup(popup_content);
setTimeout(() => { layer.openPopup(); }, 100);
});
// Menghapus data terpilih
map.on('pm:remove', function(e) {
const layer = e.layer;
if (layer.db_id && layer.db_type) {
if(confirm('Yakin ingin menghapus data ini dari Database permanen?')) {
fetch('hapus_feature.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ id: layer.db_id, type: layer.db_type })
}).then(r => r.json()).then(res => {
if(res.status !== 'success') { alert('Gagal Hapus: ' + res.message); location.reload(); }
});
} else {
location.reload();
}
}
});
// Mengirim payload ke server PHP
window.simpan_baru = function(type, hitungan, geo, lat = null, lng = null) {
let payload = { type: type };
if (type === 'jalan') {
payload.nama = document.getElementById('nama_jln').value;
payload.status = document.getElementById('stat_jln').value;
payload.besaran = hitungan;
payload.geojson = geo;
} else if (type === 'persil') {
payload.nama = document.getElementById('no_psl').value;
payload.status = document.getElementById('stat_psl').value;
payload.besaran = hitungan;
payload.geojson = geo;
} else if (type === 'spbu') {
payload.nama = document.getElementById('nama_spbu').value;
payload.jam24 = document.getElementById('stat_spbu').value;
payload.hp = document.getElementById('hp_spbu').value;
payload.lat = lat;
payload.lng = lng;
}
fetch('simpan_feature.php', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) })
.then(r => r.json()).then(res => {
if(res.status === 'success') {
alert('Berhasil Disimpan!');
location.reload();
} else {
alert('Gagal: ' + res.message);
console.error(res);
}
});
};
// Memperbarui atribut yang ada
window.update_data = function(type, id) {
let payload = {
type: type,
id: id,
nama: document.getElementById('edit_nama').value,
status: document.getElementById('edit_status').value
};
fetch('edit_feature.php', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) })
.then(r => r.json()).then(res => {
if(res.status === 'success') { alert('Berhasil Diupdate!'); location.reload(); } else alert('Gagal Update: ' + res.message);
});
};
// Merender data dari database
function muat_data_feature() {
fetch('tampil_feature.php').then(response => response.json()).then(res => {
if (res.status === "success") {
// Jalan
res.jalan.forEach(j => {
const geojson_obj = JSON.parse(j.geojson);
L.geoJSON(geojson_obj, {
style: gaya_jalan(j.status_jalan),
onEachFeature: function(feature, layer) {
layer.db_id = j.id; layer.db_type = 'jalan';
layer.on('click', function(e) {
let html_konten = is_edit_atribut_mode ?
`<div class="form-container"><h4>Edit Atribut Jalan</h4>
<input type="text" id="edit_nama" value="${j.nama_jalan}">
<select id="edit_status">
<option value="Nasional" ${j.status_jalan=='Nasional'?'selected':''}>Nasional</option>
<option value="Provinsi" ${j.status_jalan=='Provinsi'?'selected':''}>Provinsi</option>
<option value="Kabupaten" ${j.status_jalan=='Kabupaten'?'selected':''}>Kabupaten</option>
</select>
<button class="btn-update" onclick="update_data('jalan', ${j.id})">Simpan Perubahan</button></div>` :
`<b>Jalan: ${j.nama_jalan}</b><br>Status: ${j.status_jalan}<br>Panjang: ${j.panjang_m} m`;
L.popup().setLatLng(e.latlng).setContent(html_konten).openOn(map);
});
}
}).addTo(map);
});
// Persil
res.persil.forEach(p => {
const geojson_obj = JSON.parse(p.geojson);
L.geoJSON(geojson_obj, {
style: { color: 'orange', weight: 2, fillOpacity: 0.4 },
onEachFeature: function(feature, layer) {
layer.db_id = p.id; layer.db_type = 'persil';
layer.on('click', function(e) {
let html_konten = is_edit_atribut_mode ?
`<div class="form-container"><h4>Edit Atribut Persil</h4>
<input type="text" id="edit_nama" value="${p.nomor_persil}">
<select id="edit_status">
<option value="SHM" ${p.status_milik=='SHM'?'selected':''}>SHM</option>
<option value="HGB" ${p.status_milik=='HGB'?'selected':''}>HGB</option>
<option value="HGU" ${p.status_milik=='HGU'?'selected':''}>HGU</option>
<option value="HP" ${p.status_milik=='HP'?'selected':''}>HP</option>
</select>
<button class="btn-update" onclick="update_data('persil', ${p.id})">Simpan Perubahan</button></div>` :
`<b>Nomor Persil: ${p.nomor_persil}</b><br>Status: ${p.status_milik}<br>Luas: ${p.luas_m2} m²`;
L.popup().setLatLng(e.latlng).setContent(html_konten).openOn(map);
});
}
}).addTo(map);
});
// SPBU
res.spbu.forEach(s => {
const spbu_marker = L.marker([parseFloat(s.lat), parseFloat(s.lng)]);
spbu_marker.db_id = s.id;
spbu_marker.db_type = 'spbu';
spbu_marker.on('click', function(e) {
let html_konten = is_edit_atribut_mode ?
`<div class="form-container"><h4>Edit Atribut SPBU</h4>
<input type="text" id="edit_nama" value="${s.nama_spbu}">
<select id="edit_status">
<option value="24 Jam" ${s.is_24jam=='24 Jam'?'selected':''}>Buka 24 Jam</option>
<option value="Tidak 24 Jam" ${s.is_24jam=='Tidak 24 Jam'?'selected':''}>Tidak Buka 24 Jam</option>
</select>
<button class="btn-update" onclick="update_data('spbu', ${s.id})">Simpan Perubahan</button></div>` :
`<b>SPBU: ${s.nama_spbu}</b><br>Status: ${s.is_24jam}<br>No. HP: ${s.no_hp}`;
L.popup().setLatLng(e.latlng).setContent(html_konten).openOn(map);
});
if (s.is_24jam === '24 Jam') {
spbu_marker.addTo(layer_spbu_24);
} else {
spbu_marker.addTo(layer_spbu_non_24);
}
});
layer_spbu_24.addTo(map);
layer_spbu_non_24.addTo(map);
}
else {
// TAMBAHKAN DUA BARIS INI: Menampilkan peringatan jika database gagal ditarik
alert("Gagal memuat data peta: " + res.message);
console.error("Kesalahan Sistem:", res.message);
}
});
}
muat_data_feature();
</script>
</body>
</html>