Initial commit
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
CREATE TABLE lokasi (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
nama_spbu VARCHAR(100) NOT NULL,
|
||||
no_wa VARCHAR(50),
|
||||
status VARCHAR(50),
|
||||
latitude DOUBLE,
|
||||
longitude DOUBLE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE jalan (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
nama_jalan VARCHAR(100) NOT NULL,
|
||||
status VARCHAR(50),
|
||||
panjang DOUBLE,
|
||||
geom TEXT NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE kavling (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
pemilik VARCHAR(100) NOT NULL,
|
||||
status VARCHAR(50),
|
||||
luas DOUBLE,
|
||||
geom TEXT NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
include 'koneksi.php';
|
||||
|
||||
// =====================
|
||||
// SPBU (POINT)
|
||||
// =====================
|
||||
$spbu = [];
|
||||
$q1 = $conn->query("SELECT * FROM lokasi");
|
||||
while($row = $q1->fetch_assoc()){
|
||||
$spbu[] = $row;
|
||||
}
|
||||
|
||||
// =====================
|
||||
// JALAN (POLYLINE)
|
||||
// =====================
|
||||
$jalan = [];
|
||||
$q2 = $conn->query("SELECT * FROM jalan");
|
||||
while($row = $q2->fetch_assoc()){
|
||||
$jalan[] = $row;
|
||||
}
|
||||
|
||||
// =====================
|
||||
// KAVLING (POLYGON)
|
||||
// =====================
|
||||
$kavling = [];
|
||||
$q3 = $conn->query("SELECT * FROM kavling");
|
||||
while($row = $q3->fetch_assoc()){
|
||||
$kavling[] = $row;
|
||||
}
|
||||
|
||||
// gabungkan
|
||||
echo json_encode([
|
||||
"spbu" => $spbu,
|
||||
"jalan" => $jalan,
|
||||
"kavling" => $kavling
|
||||
]);
|
||||
?>
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
include 'koneksi.php';
|
||||
|
||||
$id = $_GET['id'];
|
||||
$type = $_GET['type'];
|
||||
|
||||
if($type == 'spbu'){
|
||||
$conn->query("DELETE FROM lokasi WHERE id=$id");
|
||||
}
|
||||
elseif($type == 'jalan'){
|
||||
$conn->query("DELETE FROM jalan WHERE id=$id");
|
||||
}
|
||||
elseif($type == 'kavling'){
|
||||
$conn->query("DELETE FROM kavling WHERE id=$id");
|
||||
}
|
||||
|
||||
echo "OK";
|
||||
?>
|
||||
+993
@@ -0,0 +1,993 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>WebGIS SPBU — Kota Pontianak</title>
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css"/>
|
||||
|
||||
<style>
|
||||
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
|
||||
html, body {
|
||||
height: 100%;
|
||||
font-family: 'Inter', -apple-system, 'Segoe UI', sans-serif;
|
||||
background-color: #f1f5f9;
|
||||
}
|
||||
|
||||
#map {
|
||||
margin-left: 300px;
|
||||
height: 100vh;
|
||||
width: calc(100% - 300px);
|
||||
}
|
||||
|
||||
/* =========================================
|
||||
SIDEBAR
|
||||
========================================= */
|
||||
#sidebar {
|
||||
position: absolute;
|
||||
left: 0; top: 0;
|
||||
width: 300px;
|
||||
height: 100%;
|
||||
background: linear-gradient(180deg, #0f172a 0%, #1e293b 100%);
|
||||
color: #f8fafc;
|
||||
z-index: 1000;
|
||||
padding: 0;
|
||||
overflow-y: auto;
|
||||
box-shadow: 4px 0 25px rgba(0,0,0,0.15);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
/* Scrollbar styling */
|
||||
#sidebar::-webkit-scrollbar { width: 4px; }
|
||||
#sidebar::-webkit-scrollbar-track { background: transparent; }
|
||||
#sidebar::-webkit-scrollbar-thumb { background: #334155; border-radius: 4px; }
|
||||
|
||||
#sidebar h2 {
|
||||
text-align: left;
|
||||
margin: 0;
|
||||
padding: 24px 20px 20px;
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
letter-spacing: -0.3px;
|
||||
background: linear-gradient(135deg, rgba(6,182,212,0.1) 0%, rgba(139,92,246,0.08) 100%);
|
||||
border-bottom: 1px solid rgba(255,255,255,0.06);
|
||||
}
|
||||
|
||||
.section {
|
||||
margin-top: 4px;
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
.section h3 {
|
||||
font-size: 10px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 1.5px;
|
||||
color: #64748b;
|
||||
margin-bottom: 8px;
|
||||
margin-top: 16px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.section h4 {
|
||||
font-size: 12px;
|
||||
color: #94a3b8;
|
||||
margin-bottom: 6px;
|
||||
margin-top: 14px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* Search input */
|
||||
#searchInput {
|
||||
width: calc(100% - 40px);
|
||||
margin: 16px 20px 4px;
|
||||
padding: 10px 12px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid #334155;
|
||||
background: rgba(15, 23, 42, 0.6);
|
||||
color: #f8fafc;
|
||||
font-family: inherit;
|
||||
font-size: 13px;
|
||||
outline: none;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
#searchInput::placeholder { color: #475569; }
|
||||
#searchInput:focus {
|
||||
border-color: #06b6d4;
|
||||
box-shadow: 0 0 0 3px rgba(6, 182, 212, 0.1);
|
||||
background: rgba(15, 23, 42, 0.8);
|
||||
}
|
||||
|
||||
/* List items */
|
||||
.list-item {
|
||||
background: rgba(51, 65, 85, 0.5);
|
||||
padding: 10px 12px;
|
||||
margin-bottom: 6px;
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
.list-item:hover {
|
||||
background: rgba(71, 85, 105, 0.6);
|
||||
transform: translateX(4px);
|
||||
border-color: rgba(6, 182, 212, 0.3);
|
||||
box-shadow: 0 2px 12px rgba(6, 182, 212, 0.06);
|
||||
}
|
||||
.list-item div[style*="font-weight"] { font-size: 13px; }
|
||||
.list-item small { font-size: 10px; color: #64748b !important; }
|
||||
|
||||
/* Sidebar buttons */
|
||||
#sidebar button {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
margin-top: 5px;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
background: linear-gradient(135deg, #0891b2, #06b6d4);
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
font-family: inherit;
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
transition: all 0.25s;
|
||||
box-shadow: 0 2px 8px rgba(6, 182, 212, 0.2);
|
||||
}
|
||||
#sidebar button:hover {
|
||||
background: linear-gradient(135deg, #0e7490, #0891b2);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 12px rgba(6, 182, 212, 0.3);
|
||||
}
|
||||
|
||||
/* =========================================
|
||||
POPUP FORM STYLING
|
||||
========================================= */
|
||||
.leaflet-popup-content {
|
||||
font-family: 'Inter', sans-serif !important;
|
||||
font-size: 13px;
|
||||
line-height: 1.5;
|
||||
min-width: 220px;
|
||||
}
|
||||
.leaflet-popup-content b {
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
color: #0f172a;
|
||||
}
|
||||
|
||||
input[type="text"], select {
|
||||
width: 100%;
|
||||
padding: 8px 10px;
|
||||
margin-bottom: 10px;
|
||||
margin-top: 4px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #e2e8f0;
|
||||
background: #f8fafc;
|
||||
font-family: inherit;
|
||||
font-size: 13px;
|
||||
color: #0f172a;
|
||||
outline: none;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
input[type="text"]:focus, select:focus {
|
||||
border-color: #06b6d4;
|
||||
box-shadow: 0 0 0 3px rgba(6, 182, 212, 0.1);
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
form button[type="submit"] {
|
||||
background: linear-gradient(135deg, #059669, #10b981);
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 10px 14px;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
width: 100%;
|
||||
font-family: inherit;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
transition: all 0.25s;
|
||||
box-shadow: 0 2px 8px rgba(16, 185, 129, 0.2);
|
||||
}
|
||||
form button[type="submit"]:hover {
|
||||
background: linear-gradient(135deg, #047857, #059669);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 12px rgba(16, 185, 129, 0.3);
|
||||
}
|
||||
|
||||
/* Popup edit/delete buttons */
|
||||
.leaflet-popup-content button {
|
||||
padding: 6px 14px;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
font-family: inherit;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
transition: all 0.2s;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.leaflet-editing-icon {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="sidebar">
|
||||
<h2>🌍 WebGIS</h2>
|
||||
|
||||
<input type="text" id="searchInput" placeholder="Cari layer..." onkeyup="filterList()">
|
||||
|
||||
<div class="section">
|
||||
<h3>📍 Layer</h3>
|
||||
<h4>⛽ SPBU 24 Jam</h4>
|
||||
<div id="list24"></div>
|
||||
|
||||
<h4>⛽ SPBU Tidak 24 Jam</h4>
|
||||
<div id="listTidak"></div>
|
||||
|
||||
<h4>🛣️ Jalan</h4>
|
||||
<div id="listJalan"></div>
|
||||
|
||||
<h4>🏡 Kavling</h4>
|
||||
<div id="listKavling"></div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h3>🎛 Tools</h3>
|
||||
<button onclick="map.zoomIn()">Zoom In</button>
|
||||
<button onclick="map.zoomOut()">Zoom Out</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="map"></div>
|
||||
|
||||
<script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
|
||||
<link rel="stylesheet" href="https://unpkg.com/leaflet-draw/dist/leaflet.draw.css"/>
|
||||
<script src="https://unpkg.com/leaflet-draw/dist/leaflet.draw.js"></script>
|
||||
<script src="https://unpkg.com/leaflet-geometryutil"></script>
|
||||
|
||||
<script>
|
||||
// =======================
|
||||
// FUNGSI SEARCH LAYER
|
||||
// =======================
|
||||
function filterList() {
|
||||
let input = document.getElementById('searchInput').value.toLowerCase();
|
||||
let items = document.querySelectorAll('.list-item');
|
||||
|
||||
items.forEach(item => {
|
||||
let text = item.innerText.toLowerCase();
|
||||
item.style.display = text.includes(input) ? "block" : "none";
|
||||
});
|
||||
}
|
||||
|
||||
// =======================
|
||||
// HAPUS DATA
|
||||
// =======================
|
||||
function hapusData(id){
|
||||
if(confirm("Yakin hapus data?")){
|
||||
fetch('hapus.php?id=' + id + '&type=spbu')
|
||||
.then(res => res.text())
|
||||
.then(res => {
|
||||
alert("Data dihapus!");
|
||||
location.reload();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// =======================
|
||||
// EDIT DATA
|
||||
// =======================
|
||||
function editData(id, nama, wa, status){
|
||||
let formEdit = `
|
||||
<form id="editForm">
|
||||
<input type="hidden" name="type" value="spbu">
|
||||
<input type="hidden" name="id" value="${id}">
|
||||
|
||||
Nama SPBU:
|
||||
<input type="text" name="nama_spbu" value="${nama}">
|
||||
|
||||
No WA:
|
||||
<input type="text" name="no_wa" value="${wa}">
|
||||
|
||||
Status:
|
||||
<select name="status">
|
||||
<option value="24jam" ${status === '24jam' ? 'selected' : ''}>24 Jam</option>
|
||||
<option value="tidak" ${status === 'tidak' ? 'selected' : ''}>Tidak</option>
|
||||
</select>
|
||||
|
||||
<button type="submit">Update</button>
|
||||
</form>
|
||||
`;
|
||||
|
||||
L.popup()
|
||||
.setLatLng(map.getCenter())
|
||||
.setContent(formEdit)
|
||||
.openOn(map);
|
||||
}
|
||||
|
||||
// =======================
|
||||
// SUBMIT EDIT
|
||||
// =======================
|
||||
document.addEventListener('submit', function(e){
|
||||
if(e.target && e.target.id === 'editForm'){
|
||||
e.preventDefault();
|
||||
|
||||
let formData = new FormData(e.target);
|
||||
|
||||
fetch('update.php', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then(res => res.text())
|
||||
.then(res => {
|
||||
if (res.trim() === 'OK') {
|
||||
alert("Data berhasil diupdate!");
|
||||
location.reload();
|
||||
} else {
|
||||
alert("Gagal mengupdate data: " + res);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
alert("Terjadi kesalahan jaringan: " + err.message);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// =======================
|
||||
// INIT MAP
|
||||
// =======================
|
||||
// Menambahkan zoomControl: false agar tombol +- bawaan yang tertimpa sidebar hilang
|
||||
const map = L.map('map', { zoomControl: false }).setView([-0.0557, 109.3491], 13);
|
||||
|
||||
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||
attribution: '© OpenStreetMap'
|
||||
}).addTo(map);
|
||||
|
||||
// AKTIFKAN DRAW TOOL
|
||||
var drawnItems = new L.FeatureGroup();
|
||||
map.addLayer(drawnItems);
|
||||
|
||||
var drawControl = new L.Control.Draw({
|
||||
position: 'topright', // POSISI DRAW TOOL DIUBAH KE KANAN ATAS
|
||||
draw: {
|
||||
polygon: true,
|
||||
polyline: true,
|
||||
marker: true,
|
||||
circle: false,
|
||||
rectangle: false
|
||||
},
|
||||
edit: {
|
||||
featureGroup: drawnItems,
|
||||
edit: true,
|
||||
remove: true
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// HITUNG PANJANG & LUAS OTOMATIS
|
||||
map.addControl(drawControl);
|
||||
|
||||
map.on(L.Draw.Event.CREATED, function (e) {
|
||||
|
||||
var layer = e.layer;
|
||||
var type = e.layerType;
|
||||
|
||||
// =====================
|
||||
// MARKER (SPBU)
|
||||
// =====================
|
||||
if(type === 'marker'){
|
||||
var spbuIcon = L.icon({
|
||||
iconUrl: 'https://maps.google.com/mapfiles/ms/icons/blue-dot.png',
|
||||
iconSize: [32, 32]
|
||||
});
|
||||
|
||||
layer.setIcon(spbuIcon);
|
||||
|
||||
let lat = layer.getLatLng().lat;
|
||||
let lng = layer.getLatLng().lng;
|
||||
|
||||
let form = `
|
||||
<form id="formData">
|
||||
<b>Tambah SPBU</b><br><br>
|
||||
|
||||
Nama SPBU:
|
||||
<input type="text" name="nama_spbu" required>
|
||||
|
||||
No WhatsApp:
|
||||
<input type="text" name="no_wa" required>
|
||||
|
||||
Status:
|
||||
<select name="status">
|
||||
<option value="24jam">Buka 24 Jam</option>
|
||||
<option value="tidak">Tidak</option>
|
||||
</select>
|
||||
|
||||
<input type="hidden" name="latitude" value="${lat}">
|
||||
<input type="hidden" name="longitude" value="${lng}">
|
||||
|
||||
<button type="submit">Simpan</button>
|
||||
</form>
|
||||
`;
|
||||
|
||||
layer.bindPopup(form).openPopup();
|
||||
}
|
||||
|
||||
// =====================
|
||||
// TAMBAH KE MAP
|
||||
// =====================
|
||||
drawnItems.addLayer(layer);
|
||||
|
||||
let geojson = layer.toGeoJSON();
|
||||
|
||||
// =====================
|
||||
// POLYLINE
|
||||
// =====================
|
||||
if(type === 'polyline'){
|
||||
|
||||
layer.setStyle({
|
||||
color: 'blue',
|
||||
weight: 4
|
||||
});
|
||||
|
||||
let latlngs = layer.getLatLngs();
|
||||
let panjang = 0;
|
||||
|
||||
for(let i=0; i<latlngs.length-1; i++){
|
||||
panjang += latlngs[i].distanceTo(latlngs[i+1]);
|
||||
}
|
||||
|
||||
layer.bindPopup(`
|
||||
<form id="formJalan">
|
||||
Nama Jalan:
|
||||
<input type="text" name="nama_jalan">
|
||||
|
||||
Status:
|
||||
<select name="status">
|
||||
<option value="nasional">Nasional</option>
|
||||
<option value="provinsi">Provinsi</option>
|
||||
<option value="kabupaten">Kabupaten</option>
|
||||
</select>
|
||||
|
||||
Panjang: ${panjang.toFixed(2)} meter
|
||||
|
||||
<input type="hidden" name="panjang" value="${panjang}">
|
||||
<input type="hidden" name="geom" value='${JSON.stringify(geojson)}'>
|
||||
|
||||
<button type="submit">Simpan</button>
|
||||
</form>
|
||||
`).openPopup();
|
||||
}
|
||||
|
||||
// =====================
|
||||
// POLYGON
|
||||
// =====================
|
||||
if(type === 'polygon'){
|
||||
|
||||
let latlngs = layer.getLatLngs()[0];
|
||||
let luas = L.GeometryUtil.geodesicArea(latlngs);
|
||||
|
||||
layer.myId = null; // sementara
|
||||
|
||||
drawnItems.addLayer(layer);
|
||||
|
||||
layer.bindPopup(`
|
||||
<form id="formKavling">
|
||||
Nama Pemilik:
|
||||
<input type="text" name="pemilik">
|
||||
|
||||
Status:
|
||||
<select name="status">
|
||||
<option value="SHM">SHM</option>
|
||||
<option value="HGB">HGB</option>
|
||||
<option value="HGU">HGU</option>
|
||||
<option value="HP">HP</option>
|
||||
</select>
|
||||
|
||||
Luas: ${luas.toFixed(2)} m²
|
||||
|
||||
<input type="hidden" name="luas" value="${luas}">
|
||||
<input type="hidden" name="geom" value='${JSON.stringify(geojson)}'>
|
||||
|
||||
<button type="submit">Simpan</button>
|
||||
</form>
|
||||
`).openPopup();
|
||||
}
|
||||
});
|
||||
|
||||
// WARNA OTOMATIS
|
||||
// Polyline
|
||||
|
||||
function getWarnaJalan(status){
|
||||
if(status === 'nasional') return 'blue';
|
||||
if(status === 'provinsi') return 'green';
|
||||
return 'red';
|
||||
}
|
||||
|
||||
// Polygon
|
||||
function getWarnaKavling(status){
|
||||
if(status === 'SHM') return 'green';
|
||||
if(status === 'HGB') return 'blue';
|
||||
if(status === 'HGU') return 'orange';
|
||||
return 'purple';
|
||||
}
|
||||
|
||||
// SIMPAN JALAN
|
||||
document.addEventListener('submit', function(e){
|
||||
if(e.target.id === 'formJalan'){
|
||||
e.preventDefault();
|
||||
|
||||
let formData = new FormData(e.target);
|
||||
|
||||
fetch('simpan_jalan.php', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then(res => res.text())
|
||||
.then(res => {
|
||||
if (res.trim() === 'OK') {
|
||||
alert("Jalan disimpan!");
|
||||
location.reload();
|
||||
} else {
|
||||
alert("Gagal menyimpan jalan: " + res);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
alert("Terjadi kesalahan jaringan: " + err.message);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// SIMPAN KAVLING
|
||||
document.addEventListener('submit', function(e){
|
||||
if(e.target.id === 'formKavling'){
|
||||
e.preventDefault();
|
||||
|
||||
let formData = new FormData(e.target);
|
||||
|
||||
fetch('simpan_kavling.php', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then(res => res.text())
|
||||
.then(res => {
|
||||
if (res.trim() === 'OK') {
|
||||
alert("Kavling disimpan!");
|
||||
location.reload();
|
||||
} else {
|
||||
alert("Gagal menyimpan kavling: " + res);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
alert("Terjadi kesalahan jaringan: " + err.message);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// =======================
|
||||
// ICON MARKER
|
||||
// =======================
|
||||
const greenIcon = new L.Icon({
|
||||
iconUrl: 'https://maps.google.com/mapfiles/ms/icons/green-dot.png',
|
||||
iconSize: [32, 32]
|
||||
});
|
||||
|
||||
const redIcon = new L.Icon({
|
||||
iconUrl: 'https://maps.google.com/mapfiles/ms/icons/red-dot.png',
|
||||
iconSize: [32, 32]
|
||||
});
|
||||
// =======================
|
||||
// LAYER GROUP SPBU
|
||||
// =======================
|
||||
var spbu24Jam = L.layerGroup();
|
||||
var spbuTidak24Jam = L.layerGroup();
|
||||
|
||||
// Tambahkan ke map default (opsional)
|
||||
spbu24Jam.addTo(map);
|
||||
spbuTidak24Jam.addTo(map);
|
||||
|
||||
fetch('get_all.php')
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
|
||||
// =====================
|
||||
// SPBU (POINT)
|
||||
// =====================
|
||||
if(data.spbu) { // Ditambahkan pengecekan agar tidak error jika data kosong
|
||||
data.spbu.forEach(item => {
|
||||
|
||||
let icon = item.status === '24jam' ? greenIcon : redIcon;
|
||||
|
||||
let marker = L.marker([item.latitude, item.longitude], {
|
||||
icon: icon,
|
||||
draggable: true
|
||||
});
|
||||
|
||||
marker.myId = item.id;
|
||||
// MASUKKAN KE GROUP SESUAI STATUS
|
||||
drawnItems.addLayer(marker);
|
||||
|
||||
// tetap simpan ke group hanya untuk kontrol layer
|
||||
if(item.status === '24jam'){
|
||||
spbu24Jam.addLayer(marker);
|
||||
} else {
|
||||
spbuTidak24Jam.addLayer(marker);
|
||||
}
|
||||
// tetap tambahkan ke drawnItems jika ingin bisa edit
|
||||
drawnItems.addLayer(marker);
|
||||
|
||||
marker.bindPopup(`
|
||||
<b>${item.nama_spbu}</b><br>
|
||||
WA: ${item.no_wa}<br>
|
||||
Status: ${item.status}<br><br>
|
||||
|
||||
<button onclick="editData(${item.id}, '${item.nama_spbu}', '${item.no_wa}', '${item.status}')">Edit</button>
|
||||
<button onclick="hapusData(${item.id})">Hapus</button>
|
||||
`);
|
||||
|
||||
marker.on('dragend', function(e){
|
||||
let posisi = e.target.getLatLng();
|
||||
|
||||
fetch('update_posisi.php', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
|
||||
body: `id=${item.id}&lat=${posisi.lat}&lng=${posisi.lng}`
|
||||
});
|
||||
});
|
||||
|
||||
tambahKeList(
|
||||
item.nama_spbu,
|
||||
[item.latitude, item.longitude],
|
||||
marker,
|
||||
item.status,
|
||||
'spbu'
|
||||
);
|
||||
});
|
||||
}
|
||||
// =======================
|
||||
// LAYER CONTROL
|
||||
// =======================
|
||||
var overlayMaps = {
|
||||
"SPBU 24 Jam": spbu24Jam,
|
||||
"SPBU Tidak 24 Jam": spbuTidak24Jam
|
||||
};
|
||||
|
||||
L.control.layers(null, overlayMaps, {
|
||||
collapsed: false
|
||||
}).addTo(map);
|
||||
// =====================
|
||||
// KAVLING (POLYGON)
|
||||
// =====================
|
||||
if(data.kavling) {
|
||||
data.kavling.forEach(item => {
|
||||
|
||||
try {
|
||||
let geojson = JSON.parse(item.geom);
|
||||
let warna = getWarnaKavling(item.status);
|
||||
|
||||
let layer = L.geoJSON(geojson, {
|
||||
style: {
|
||||
color: warna,
|
||||
fillOpacity: 0.5
|
||||
}
|
||||
});
|
||||
|
||||
layer.eachLayer(l => {
|
||||
l.myId = item.id;
|
||||
drawnItems.addLayer(l);
|
||||
|
||||
l.bindPopup(`
|
||||
<b>${item.pemilik || 'Tanpa Nama'}</b><br>
|
||||
Status: ${item.status}<br>
|
||||
Luas: ${parseFloat(item.luas).toFixed(2)} m²<br><br>
|
||||
|
||||
<button onclick="editKavling(${item.id}, '${item.pemilik || ''}', '${item.status}')">Edit</button>
|
||||
<button onclick="hapusKavling(${item.id})">Hapus</button>
|
||||
`);
|
||||
|
||||
tambahKeList(item.pemilik || 'Kavling', l.getBounds().getCenter(), l, null, 'kavling');
|
||||
});
|
||||
|
||||
} catch(e){
|
||||
console.log("Geom error kavling ID:", item.id);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
// =====================
|
||||
// JALAN (POLYLINE)
|
||||
// =====================
|
||||
if(data.jalan) {
|
||||
data.jalan.forEach(item => {
|
||||
|
||||
try {
|
||||
let geojson = JSON.parse(item.geom);
|
||||
let warna = getWarnaJalan(item.status);
|
||||
|
||||
let layer = L.geoJSON(geojson, {
|
||||
style: {
|
||||
color: warna,
|
||||
weight: 4
|
||||
}
|
||||
});
|
||||
|
||||
layer.eachLayer(l => {
|
||||
l.myId = item.id;
|
||||
drawnItems.addLayer(l);
|
||||
|
||||
l.bindPopup(`
|
||||
<b>${item.nama_jalan}</b><br>
|
||||
Status: ${item.status}<br>
|
||||
Panjang: ${parseFloat(item.panjang).toFixed(2)} meter<br><br>
|
||||
|
||||
<button onclick="editJalan(${item.id}, '${item.nama_jalan}', '${item.status}')">Edit</button>
|
||||
<button onclick="hapusJalan(${item.id})">Hapus</button>
|
||||
`);
|
||||
|
||||
tambahKeList(item.nama_jalan, l.getBounds().getCenter(), l, null, 'jalan');
|
||||
});
|
||||
|
||||
} catch(e){
|
||||
console.log("Geom error jalan ID:", item.id);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
// =======================
|
||||
// SUBMIT FORM
|
||||
// =======================
|
||||
document.addEventListener('submit', function(e){
|
||||
if(e.target && e.target.id === 'formData'){
|
||||
e.preventDefault();
|
||||
|
||||
let formData = new FormData(e.target);
|
||||
|
||||
fetch('simpan.php', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then(res => res.text())
|
||||
.then(res => {
|
||||
if (res.trim() === 'OK') {
|
||||
alert("Data berhasil disimpan!");
|
||||
location.reload();
|
||||
} else {
|
||||
alert("Gagal menyimpan data: " + res);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
alert("Terjadi kesalahan jaringan: " + err.message);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
map.on(L.Draw.Event.EDITED, function (e) {
|
||||
let layers = e.layers;
|
||||
|
||||
layers.eachLayer(function(layer){
|
||||
|
||||
// =====================
|
||||
// MARKER (SPBU)
|
||||
// =====================
|
||||
if(layer instanceof L.Marker){
|
||||
|
||||
let latlng = layer.getLatLng();
|
||||
|
||||
fetch('update_posisi.php', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
|
||||
body: `id=${layer.myId}&lat=${latlng.lat}&lng=${latlng.lng}`
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
// =====================
|
||||
// POLYLINE / POLYGON
|
||||
// =====================
|
||||
else {
|
||||
|
||||
let geojson = layer.toGeoJSON();
|
||||
let type = (layer instanceof L.Polygon) ? 'kavling' : 'jalan';
|
||||
|
||||
fetch('update_geom.php', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({
|
||||
id: layer.myId,
|
||||
geom: geojson,
|
||||
type: type
|
||||
})
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
function hapusJalan(id){
|
||||
if(confirm("Yakin hapus jalan?")){
|
||||
fetch('hapus.php?id=' + id + '&type=jalan')
|
||||
.then(res => res.text())
|
||||
.then(res => {
|
||||
alert("Jalan dihapus!");
|
||||
location.reload();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function hapusKavling(id){
|
||||
if(confirm("Yakin hapus kavling?")){
|
||||
fetch('hapus.php?id=' + id + '&type=kavling')
|
||||
.then(() => {
|
||||
alert("Kavling dihapus!");
|
||||
location.reload();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function editJalan(id, nama, status){
|
||||
|
||||
let form = `
|
||||
<form id="editJalanForm">
|
||||
<input type="hidden" name="type" value="jalan">
|
||||
<input type="hidden" name="id" value="${id}">
|
||||
|
||||
Nama Jalan:
|
||||
<input type="text" name="nama_jalan" value="${nama}" required>
|
||||
|
||||
Status:
|
||||
<select name="status">
|
||||
<option value="nasional" ${status==='nasional'?'selected':''}>Nasional</option>
|
||||
<option value="provinsi" ${status==='provinsi'?'selected':''}>Provinsi</option>
|
||||
<option value="kabupaten" ${status==='kabupaten'?'selected':''}>Kabupaten</option>
|
||||
</select>
|
||||
|
||||
<button type="submit">Update</button>
|
||||
</form>
|
||||
`;
|
||||
|
||||
L.popup()
|
||||
.setLatLng(map.getCenter())
|
||||
.setContent(form)
|
||||
.openOn(map);
|
||||
}
|
||||
|
||||
document.addEventListener('submit', function(e){
|
||||
|
||||
// EDIT JALAN
|
||||
if(e.target.id === 'editJalanForm'){
|
||||
e.preventDefault();
|
||||
|
||||
let formData = new FormData(e.target);
|
||||
|
||||
fetch('update.php', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then(res => res.text())
|
||||
.then(res => {
|
||||
if (res.trim() === 'OK') {
|
||||
alert("Jalan berhasil diupdate!");
|
||||
location.reload();
|
||||
} else {
|
||||
alert("Gagal mengupdate jalan: " + res);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
alert("Terjadi kesalahan jaringan: " + err.message);
|
||||
});
|
||||
}
|
||||
|
||||
// EDIT KAVLING
|
||||
if(e.target.id === 'editKavlingForm'){
|
||||
e.preventDefault();
|
||||
|
||||
let formData = new FormData(e.target);
|
||||
|
||||
fetch('update.php', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then(res => res.text())
|
||||
.then(res => {
|
||||
if (res.trim() === 'OK') {
|
||||
alert("Kavling berhasil diupdate!");
|
||||
location.reload();
|
||||
} else {
|
||||
alert("Gagal mengupdate kavling: " + res);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
alert("Terjadi kesalahan jaringan: " + err.message);
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
function editKavling(id, pemilik, status){
|
||||
let form = `
|
||||
<form id="editKavlingForm">
|
||||
<input type="hidden" name="type" value="kavling">
|
||||
<input type="hidden" name="id" value="${id}">
|
||||
|
||||
Nama Pemilik:
|
||||
<input type="text" name="pemilik" value="${pemilik}">
|
||||
|
||||
Status:
|
||||
<select name="status">
|
||||
<option value="SHM" ${status==='SHM'?'selected':''}>SHM</option>
|
||||
<option value="HGB" ${status==='HGB'?'selected':''}>HGB</option>
|
||||
<option value="HGU" ${status==='HGU'?'selected':''}>HGU</option>
|
||||
<option value="HP" ${status==='HP'?'selected':''}>HP</option>
|
||||
</select>
|
||||
|
||||
<button type="submit">Update</button>
|
||||
</form>
|
||||
`;
|
||||
L.popup().setLatLng(map.getCenter()).setContent(form).openOn(map);
|
||||
}
|
||||
|
||||
map.on(L.Draw.Event.DRAWSTART, function(){
|
||||
console.log("Mulai gambar");
|
||||
});
|
||||
|
||||
map.on(L.Draw.Event.DRAWSTOP, function(){
|
||||
console.log("Selesai gambar");
|
||||
});
|
||||
|
||||
function tambahKeList(nama, latlng, layer, status, type){
|
||||
|
||||
let div;
|
||||
let icon = "";
|
||||
|
||||
if (type === 'jalan') {
|
||||
div = document.getElementById('listJalan');
|
||||
icon = "🛣️";
|
||||
} else if (type === 'kavling') {
|
||||
div = document.getElementById('listKavling');
|
||||
icon = "🏡";
|
||||
} else {
|
||||
// PILIH CONTAINER BERDASARKAN STATUS
|
||||
if(status === '24jam'){
|
||||
div = document.getElementById('list24');
|
||||
} else {
|
||||
div = document.getElementById('listTidak');
|
||||
}
|
||||
icon = "⛽";
|
||||
}
|
||||
|
||||
let item = document.createElement('div');
|
||||
item.className = 'list-item';
|
||||
|
||||
item.innerHTML = `
|
||||
<div style="font-weight:bold">${icon} ${nama}</div>
|
||||
<small style="color:#cbd5f5;">Klik untuk fokus</small>
|
||||
`;
|
||||
|
||||
item.onclick = function(){
|
||||
map.setView(latlng, 16);
|
||||
|
||||
if(layer.getBounds){
|
||||
map.fitBounds(layer.getBounds());
|
||||
}
|
||||
|
||||
layer.openPopup();
|
||||
};
|
||||
|
||||
div.appendChild(item);
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
$conn = new mysqli("localhost", "root", "", "webgis1");
|
||||
|
||||
if ($conn->connect_error) {
|
||||
die("Koneksi gagal: " . $conn->connect_error);
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
include 'koneksi.php';
|
||||
|
||||
$nama = $_POST['nama_spbu'];
|
||||
$wa = $_POST['no_wa'];
|
||||
$status = $_POST['status'];
|
||||
$lat = $_POST['latitude'];
|
||||
$lng = $_POST['longitude'];
|
||||
|
||||
$stmt = $conn->prepare("INSERT INTO lokasi (nama_spbu, no_wa, status, latitude, longitude) VALUES (?, ?, ?, ?, ?)");
|
||||
$stmt->bind_param("sssdd", $nama, $wa, $status, $lat, $lng);
|
||||
|
||||
if($stmt->execute()){
|
||||
echo "OK";
|
||||
} else {
|
||||
echo "Gagal";
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
include 'koneksi.php';
|
||||
|
||||
// ambil data
|
||||
$nama = $_POST['nama_jalan'];
|
||||
$status = $_POST['status'];
|
||||
$panjang = $_POST['panjang'];
|
||||
$geom = $_POST['geom'];
|
||||
|
||||
// cek data kosong
|
||||
if(empty($nama) || empty($geom)){
|
||||
echo "Data tidak lengkap";
|
||||
exit;
|
||||
}
|
||||
|
||||
// prepare query
|
||||
$stmt = $conn->prepare("INSERT INTO jalan (nama_jalan, status, panjang, geom) VALUES (?, ?, ?, ?)");
|
||||
|
||||
if(!$stmt){
|
||||
echo "Prepare gagal: " . $conn->error;
|
||||
exit;
|
||||
}
|
||||
|
||||
// binding
|
||||
$stmt->bind_param("ssds", $nama, $status, $panjang, $geom);
|
||||
|
||||
// eksekusi
|
||||
if($stmt->execute()){
|
||||
echo "OK";
|
||||
} else {
|
||||
echo "Gagal: " . $stmt->error;
|
||||
}
|
||||
|
||||
$stmt->close();
|
||||
$conn->close();
|
||||
?>
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
include 'koneksi.php';
|
||||
|
||||
$pemilik = $_POST['pemilik'];
|
||||
$status = $_POST['status'];
|
||||
$luas = $_POST['luas'];
|
||||
$geom = $_POST['geom'];
|
||||
|
||||
if(empty($pemilik) || empty($geom)){
|
||||
echo "Data tidak lengkap";
|
||||
exit;
|
||||
}
|
||||
|
||||
$stmt = $conn->prepare("INSERT INTO kavling (pemilik, status, luas, geom) VALUES (?, ?, ?, ?)");
|
||||
|
||||
if(!$stmt){
|
||||
echo "Prepare gagal: " . $conn->error;
|
||||
exit;
|
||||
}
|
||||
|
||||
$stmt->bind_param("ssds", $pemilik, $status, $luas, $geom);
|
||||
|
||||
if($stmt->execute()){
|
||||
echo "OK";
|
||||
} else {
|
||||
echo "Gagal: " . $stmt->error;
|
||||
}
|
||||
|
||||
$stmt->close();
|
||||
$conn->close();
|
||||
?>
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
include 'koneksi.php';
|
||||
|
||||
$type = $_POST['type'];
|
||||
|
||||
// =====================
|
||||
// UPDATE SPBU
|
||||
// =====================
|
||||
if($type == 'spbu'){
|
||||
|
||||
$id = $_POST['id'];
|
||||
$nama = $_POST['nama_spbu'];
|
||||
$wa = $_POST['no_wa'];
|
||||
$status = $_POST['status'];
|
||||
|
||||
$stmt = $conn->prepare("UPDATE lokasi SET nama_spbu=?, no_wa=?, status=? WHERE id=?");
|
||||
$stmt->bind_param("sssi", $nama, $wa, $status, $id);
|
||||
$stmt->execute();
|
||||
}
|
||||
|
||||
// =====================
|
||||
// UPDATE JALAN
|
||||
// =====================
|
||||
elseif($type == 'jalan'){
|
||||
|
||||
$id = $_POST['id'];
|
||||
$nama = $_POST['nama_jalan'];
|
||||
$status = $_POST['status'];
|
||||
|
||||
$stmt = $conn->prepare("UPDATE jalan SET nama_jalan=?, status=? WHERE id=?");
|
||||
$stmt->bind_param("ssi", $nama, $status, $id);
|
||||
$stmt->execute();
|
||||
}
|
||||
|
||||
// =====================
|
||||
// UPDATE KAVLING
|
||||
// =====================
|
||||
elseif($type == 'kavling'){
|
||||
|
||||
$id = $_POST['id'];
|
||||
$pemilik = $_POST['pemilik'];
|
||||
$status = $_POST['status'];
|
||||
|
||||
$stmt = $conn->prepare("UPDATE kavling SET pemilik=?, status=? WHERE id=?");
|
||||
$stmt->bind_param("ssi", $pemilik, $status, $id);
|
||||
$stmt->execute();
|
||||
}
|
||||
|
||||
echo "OK";
|
||||
?>
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
include 'koneksi.php';
|
||||
|
||||
// ambil data JSON dari JS
|
||||
$data = json_decode(file_get_contents("php://input"), true);
|
||||
|
||||
$id = $data['id'];
|
||||
$geom = json_encode($data['geom']);
|
||||
$type = $data['type'];
|
||||
|
||||
if ($type == 'jalan') {
|
||||
$conn->query("UPDATE jalan SET geom='$geom' WHERE id=$id");
|
||||
} elseif ($type == 'kavling') {
|
||||
$conn->query("UPDATE kavling SET geom='$geom' WHERE id=$id");
|
||||
}
|
||||
|
||||
echo "OK";
|
||||
?>
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
include 'koneksi.php';
|
||||
|
||||
$id = $_POST['id'];
|
||||
$lat = $_POST['lat'];
|
||||
$lng = $_POST['lng'];
|
||||
|
||||
$stmt = $conn->prepare("UPDATE lokasi SET latitude=?, longitude=? WHERE id=?");
|
||||
$stmt->bind_param("ddi", $lat, $lng, $id);
|
||||
|
||||
$stmt->execute();
|
||||
|
||||
echo "OK";
|
||||
?>
|
||||
Reference in New Issue
Block a user