Project UAS WEBGIS SIG Talitha

This commit is contained in:
TalithaSyakirah
2026-06-09 15:29:53 +07:00
commit 7b48733283
16 changed files with 7482 additions and 0 deletions
+567
View File
@@ -0,0 +1,567 @@
<?php
session_start();
require_once __DIR__ . '/../env.php';
$host = env('DB_HOST', '127.0.0.1');
$user = env('DB_USER', 'root');
$pass = env('DB_PASS', '');
$db = env('DB_NAME', 'sig');
$port = (int) env('DB_PORT', 3306);
$conn = new mysqli($host, $user, $pass, $db, $port);
if ($conn->connect_error) {
die("Koneksi database gagal.");
}
$conn->set_charset("utf8mb4");
if (isset($_GET['action'])) {
header('Content-Type: application/json; charset=utf-8');
$action = $_GET['action'];
if ($action == 'get_spbu') {
$data = [];
$result = $conn->query("SELECT * FROM spbu ORDER BY id DESC");
while ($row = $result->fetch_assoc()) {
$data[] = $row;
}
echo json_encode($data);
exit;
}
if ($action == 'add_spbu') {
$nama_spbu = $_POST['nama_spbu'] ?? '';
$no_telepon = $_POST['no_telepon'] ?? '';
$buka_24_jam = isset($_POST['buka_24_jam']) ? (int) $_POST['buka_24_jam'] : 0;
$latitude = $_POST['latitude'] ?? '';
$longitude = $_POST['longitude'] ?? '';
if ($nama_spbu == '' || $no_telepon == '' || $latitude == '' || $longitude == '') {
echo json_encode(['status' => false, 'message' => 'Data belum lengkap']);
exit;
}
$stmt = $conn->prepare("INSERT INTO spbu (nama_spbu, no_telepon, buka_24_jam, latitude, longitude) VALUES (?, ?, ?, ?, ?)");
$stmt->bind_param("ssidd", $nama_spbu, $no_telepon, $buka_24_jam, $latitude, $longitude);
if ($stmt->execute()) {
echo json_encode(['status' => true, 'message' => 'Data SPBU berhasil ditambahkan']);
} else {
echo json_encode(['status' => false, 'message' => 'Gagal menambahkan data']);
}
exit;
}
if ($action == 'update_spbu') {
$id = (int) ($_POST['id'] ?? 0);
$nama_spbu = $_POST['nama_spbu'] ?? '';
$no_telepon = $_POST['no_telepon'] ?? '';
$buka_24_jam = isset($_POST['buka_24_jam']) ? (int) $_POST['buka_24_jam'] : 0;
$latitude = $_POST['latitude'] ?? '';
$longitude = $_POST['longitude'] ?? '';
$stmt = $conn->prepare("UPDATE spbu SET nama_spbu=?, no_telepon=?, buka_24_jam=?, latitude=?, longitude=? WHERE id=?");
$stmt->bind_param("ssiddi", $nama_spbu, $no_telepon, $buka_24_jam, $latitude, $longitude, $id);
if ($stmt->execute()) {
echo json_encode(['status' => true, 'message' => 'Data SPBU berhasil diupdate']);
} else {
echo json_encode(['status' => false, 'message' => 'Gagal update data']);
}
exit;
}
if ($action == 'delete_spbu') {
$id = (int) ($_POST['id'] ?? 0);
$stmt = $conn->prepare("DELETE FROM spbu WHERE id=?");
$stmt->bind_param("i", $id);
if ($stmt->execute()) {
echo json_encode(['status' => true, 'message' => 'Data SPBU berhasil dihapus']);
} else {
echo json_encode(['status' => false, 'message' => 'Gagal hapus data']);
}
exit;
}
if ($action == 'update_position') {
$id = (int) ($_POST['id'] ?? 0);
$latitude = $_POST['latitude'] ?? '';
$longitude = $_POST['longitude'] ?? '';
$stmt = $conn->prepare("UPDATE spbu SET latitude=?, longitude=? WHERE id=?");
$stmt->bind_param("ddi", $latitude, $longitude, $id);
if ($stmt->execute()) {
echo json_encode(['status' => true, 'message' => 'Posisi berhasil diupdate']);
} else {
echo json_encode(['status' => false, 'message' => 'Gagal update posisi']);
}
exit;
}
if ($action == 'get_shapes') {
$data = [];
$result = $conn->query("SELECT * FROM map_shapes ORDER BY id DESC");
while ($row = $result->fetch_assoc()) {
$data[] = $row;
}
echo json_encode($data);
exit;
}
if ($action == 'save_shape') {
$shape_type = $_POST['shape_type'] ?? '';
$coordinates = $_POST['coordinates'] ?? '';
if ($shape_type == '' || $coordinates == '') {
echo json_encode(['status' => false, 'message' => 'Data shape tidak lengkap']);
exit;
}
$stmt = $conn->prepare("INSERT INTO map_shapes (shape_type, coordinates) VALUES (?, ?)");
$stmt->bind_param("ss", $shape_type, $coordinates);
if ($stmt->execute()) {
echo json_encode(['status' => true, 'message' => 'Shape berhasil disimpan']);
} else {
echo json_encode(['status' => false, 'message' => 'Gagal menyimpan shape']);
}
exit;
}
if ($action == 'update_shape') {
$id = (int) ($_POST['id'] ?? 0);
$shape_type = $_POST['shape_type'] ?? '';
$coordinates = $_POST['coordinates'] ?? '';
if ($id <= 0 || $shape_type == '' || $coordinates == '') {
echo json_encode(['status' => false, 'message' => 'Data update shape tidak lengkap']);
exit;
}
$stmt = $conn->prepare("UPDATE map_shapes SET shape_type=?, coordinates=? WHERE id=?");
$stmt->bind_param("ssi", $shape_type, $coordinates, $id);
if ($stmt->execute()) {
echo json_encode(['status' => true, 'message' => 'Shape berhasil diupdate']);
} else {
echo json_encode(['status' => false, 'message' => 'Gagal update shape']);
}
exit;
}
if ($action == 'delete_shape') {
$id = (int) ($_POST['id'] ?? 0);
$stmt = $conn->prepare("DELETE FROM map_shapes WHERE id=?");
$stmt->bind_param("i", $id);
if ($stmt->execute()) {
echo json_encode(['status' => true, 'message' => 'Shape berhasil dihapus']);
} else {
echo json_encode(['status' => false, 'message' => 'Gagal hapus shape']);
}
exit;
}
echo json_encode(['status' => false, 'message' => 'Action tidak dikenal']);
exit;
}
?>
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<title>SPBU Pontianak - Leaflet CRUD</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />
<link rel="stylesheet" href="https://unpkg.com/leaflet-draw/dist/leaflet.draw.css" />
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id="map"></div>
<div id="formPanel" class="form-panel hidden">
<h3 id="formTitle">Tambah SPBU</h3>
<input type="hidden" id="spbu_id">
<input type="text" id="nama_spbu" placeholder="Nama SPBU">
<input type="text" id="no_telepon" placeholder="No Telepon">
<label>
<input type="checkbox" id="buka_24_jam"> Buka 24 Jam
</label>
<input type="text" id="latitude" placeholder="Latitude" readonly>
<input type="text" id="longitude" placeholder="Longitude" readonly>
<div class="btn-group">
<button id="btnSimpan">Simpan</button>
<button id="btnUpdate" class="hidden">Update</button>
<button id="btnBatal" class="btn-secondary">Batal</button>
</div>
</div>
<script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
<script src="https://unpkg.com/leaflet-draw/dist/leaflet.draw.js"></script>
<script>
const map = L.map('map').setView([-0.0263, 109.3425], 13);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 20,
attribution: '&copy; OpenStreetMap'
}).addTo(map);
const formPanel = document.getElementById('formPanel');
const formTitle = document.getElementById('formTitle');
const spbuId = document.getElementById('spbu_id');
const namaSpbu = document.getElementById('nama_spbu');
const noTelepon = document.getElementById('no_telepon');
const buka24Jam = document.getElementById('buka_24_jam');
const latitude = document.getElementById('latitude');
const longitude = document.getElementById('longitude');
const btnSimpan = document.getElementById('btnSimpan');
const btnUpdate = document.getElementById('btnUpdate');
const btnBatal = document.getElementById('btnBatal');
let tempMarker = null;
let markers = {};
const drawnItems = new L.FeatureGroup();
map.addLayer(drawnItems);
function createCustomIcon(is24Jam) {
let iconUrl = is24Jam == 1
? 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-green.png'
: 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-red.png';
return L.icon({
iconUrl: iconUrl,
shadowUrl: 'https://unpkg.com/leaflet@1.9.4/dist/images/marker-shadow.png',
iconSize: [25, 41],
iconAnchor: [12, 41],
popupAnchor: [1, -34],
shadowSize: [41, 41]
});
}
function showAddForm(lat, lng) {
formPanel.classList.remove('hidden');
formTitle.textContent = 'Tambah SPBU';
spbuId.value = '';
namaSpbu.value = '';
noTelepon.value = '';
buka24Jam.checked = false;
latitude.value = lat;
longitude.value = lng;
btnSimpan.classList.remove('hidden');
btnUpdate.classList.add('hidden');
}
function showEditForm(data) {
formPanel.classList.remove('hidden');
formTitle.textContent = 'Edit SPBU';
spbuId.value = data.id;
namaSpbu.value = data.nama_spbu;
noTelepon.value = data.no_telepon;
buka24Jam.checked = parseInt(data.buka_24_jam) === 1;
latitude.value = data.latitude;
longitude.value = data.longitude;
btnSimpan.classList.add('hidden');
btnUpdate.classList.remove('hidden');
}
function hideForm() {
formPanel.classList.add('hidden');
spbuId.value = '';
namaSpbu.value = '';
noTelepon.value = '';
buka24Jam.checked = false;
latitude.value = '';
longitude.value = '';
if (tempMarker) {
map.removeLayer(tempMarker);
tempMarker = null;
}
}
function loadSPBU() {
fetch('index.php?action=get_spbu')
.then(res => res.json())
.then(data => {
Object.values(markers).forEach(marker => map.removeLayer(marker));
markers = {};
data.forEach(item => {
const marker = L.marker([item.latitude, item.longitude], {
draggable: true,
icon: createCustomIcon(item.buka_24_jam)
}).addTo(map);
marker.bindPopup(`
<b>${item.nama_spbu}</b><br>
Telp: ${item.no_telepon}<br>
${parseInt(item.buka_24_jam) === 1 ? 'Buka 24 Jam' : 'Tidak 24 Jam'}<br>
Lat: ${item.latitude}<br>
Lng: ${item.longitude}<br><br>
<button onclick='editSPBU(${JSON.stringify(item)})'>Edit</button>
<button onclick='hapusSPBU(${item.id})'>Hapus</button>
`);
marker.on('dragend', function (e) {
const pos = e.target.getLatLng();
const formData = new URLSearchParams();
formData.append('id', item.id);
formData.append('latitude', pos.lat);
formData.append('longitude', pos.lng);
fetch('index.php?action=update_position', {
method: 'POST',
body: formData
})
.then(res => res.json())
.then(result => {
console.log(result.message);
loadSPBU();
});
});
markers[item.id] = marker;
});
});
}
window.editSPBU = function (data) {
showEditForm(data);
};
window.hapusSPBU = function (id) {
if (!confirm('Yakin ingin menghapus data SPBU ini?')) return;
const formData = new URLSearchParams();
formData.append('id', id);
fetch('index.php?action=delete_spbu', {
method: 'POST',
body: formData
})
.then(res => res.json())
.then(result => {
alert(result.message);
loadSPBU();
hideForm();
});
};
map.on('click', function (e) {
if (tempMarker) {
map.removeLayer(tempMarker);
}
tempMarker = L.marker(e.latlng).addTo(map);
showAddForm(e.latlng.lat, e.latlng.lng);
});
btnSimpan.addEventListener('click', function () {
const formData = new URLSearchParams();
formData.append('nama_spbu', namaSpbu.value);
formData.append('no_telepon', noTelepon.value);
formData.append('buka_24_jam', buka24Jam.checked ? 1 : 0);
formData.append('latitude', latitude.value);
formData.append('longitude', longitude.value);
fetch('index.php?action=add_spbu', {
method: 'POST',
body: formData
})
.then(res => res.json())
.then(result => {
alert(result.message);
if (result.status) {
loadSPBU();
hideForm();
}
});
});
btnUpdate.addEventListener('click', function () {
const formData = new URLSearchParams();
formData.append('id', spbuId.value);
formData.append('nama_spbu', namaSpbu.value);
formData.append('no_telepon', noTelepon.value);
formData.append('buka_24_jam', buka24Jam.checked ? 1 : 0);
formData.append('latitude', latitude.value);
formData.append('longitude', longitude.value);
fetch('index.php?action=update_spbu', {
method: 'POST',
body: formData
})
.then(res => res.json())
.then(result => {
alert(result.message);
if (result.status) {
loadSPBU();
hideForm();
}
});
});
btnBatal.addEventListener('click', function () {
hideForm();
});
const drawControl = new L.Control.Draw({
edit: {
featureGroup: drawnItems,
remove: true
},
draw: {
polyline: {
shapeOptions: {
color: 'black',
weight: 4
}
},
polygon: {
shapeOptions: {
color: 'green',
fillColor: 'green',
fillOpacity: 0.3
}
},
rectangle: false,
circle: false,
circlemarker: false,
marker: false
}
});
map.addControl(drawControl);
function loadShapes() {
drawnItems.clearLayers();
fetch('index.php?action=get_shapes')
.then(res => res.json())
.then(data => {
data.forEach(shape => {
let coords = JSON.parse(shape.coordinates);
let layer = null;
if (shape.shape_type === 'polyline') {
layer = L.polyline(coords, {
color: 'black',
weight: 4
});
} else if (shape.shape_type === 'polygon') {
layer = L.polygon(coords, {
color: 'green',
fillColor: 'green',
fillOpacity: 0.3
});
}
if (layer) {
layer._dbId = shape.id;
layer._shapeType = shape.shape_type;
drawnItems.addLayer(layer);
}
});
});
}
map.on(L.Draw.Event.CREATED, function (event) {
const layer = event.layer;
const type = event.layerType;
drawnItems.addLayer(layer);
let coordinates = [];
if (type === 'polyline') {
coordinates = layer.getLatLngs().map(latlng => [latlng.lat, latlng.lng]);
} else if (type === 'polygon') {
coordinates = layer.getLatLngs()[0].map(latlng => [latlng.lat, latlng.lng]);
}
const formData = new URLSearchParams();
formData.append('shape_type', type);
formData.append('coordinates', JSON.stringify(coordinates));
fetch('index.php?action=save_shape', {
method: 'POST',
body: formData
})
.then(res => res.json())
.then(result => {
console.log(result.message);
loadShapes();
});
});
map.on(L.Draw.Event.EDITED, function (event) {
event.layers.eachLayer(function (layer) {
if (!layer._dbId) return;
let coordinates = [];
let shapeType = '';
if (layer instanceof L.Polyline && !(layer instanceof L.Polygon)) {
shapeType = 'polyline';
coordinates = layer.getLatLngs().map(latlng => [latlng.lat, latlng.lng]);
} else if (layer instanceof L.Polygon) {
shapeType = 'polygon';
coordinates = layer.getLatLngs()[0].map(latlng => [latlng.lat, latlng.lng]);
}
const formData = new URLSearchParams();
formData.append('id', layer._dbId);
formData.append('shape_type', shapeType);
formData.append('coordinates', JSON.stringify(coordinates));
fetch('index.php?action=update_shape', {
method: 'POST',
body: formData
})
.then(res => res.json())
.then(result => {
console.log(result.message);
});
});
});
map.on(L.Draw.Event.DELETED, function (event) {
event.layers.eachLayer(function (layer) {
if (layer._dbId) {
const formData = new URLSearchParams();
formData.append('id', layer._dbId);
fetch('index.php?action=delete_shape', {
method: 'POST',
body: formData
})
.then(res => res.json())
.then(result => {
console.log(result.message);
});
}
});
});
loadSPBU();
loadShapes();
</script>
</body>
</html>
+111
View File
@@ -0,0 +1,111 @@
html, body {
margin: 0;
padding: 0;
height: 100%;
font-family: Arial, sans-serif;
}
#map {
width: 100%;
height: 100vh;
}
.form-panel {
position: fixed;
top: 20px;
right: 20px;
width: 320px;
background: #fff;
padding: 16px;
border-radius: 12px;
box-shadow: 0 4px 18px rgba(0,0,0,0.2);
z-index: 9999;
}
.form-panel h3 {
margin: 0 0 12px;
font-size: 20px;
}
.form-panel input[type="text"] {
width: 100%;
padding: 10px;
margin-bottom: 10px;
box-sizing: border-box;
border: 1px solid #ccc;
border-radius: 8px;
outline: none;
}
.form-panel input[type="text"]:focus {
border-color: #007bff;
}
.form-panel label {
display: block;
margin-bottom: 10px;
font-size: 14px;
}
.btn-group {
display: flex;
gap: 8px;
flex-wrap: wrap;
}
button {
padding: 10px 14px;
border: none;
border-radius: 8px;
cursor: pointer;
background: #007bff;
color: #fff;
font-size: 14px;
}
button:hover {
opacity: 0.9;
}
.btn-secondary {
background: #6c757d;
}
.hidden {
display: none;
}
.leaflet-popup-content button {
margin-top: 6px;
margin-right: 5px;
padding: 6px 10px;
font-size: 12px;
}
.custom-div-icon {
background: transparent;
border: none;
}
@media (max-width: 768px) {
.form-panel {
top: auto;
right: 10px;
left: 10px;
bottom: 10px;
width: auto;
padding: 14px;
}
.form-panel h3 {
font-size: 18px;
}
.form-panel input[type="text"] {
font-size: 14px;
}
button {
flex: 1;
}
}