This commit is contained in:
2026-06-10 18:07:01 +07:00
parent c4295c5395
commit 5257946cfa
69 changed files with 10741 additions and 0 deletions
+8
View File
@@ -0,0 +1,8 @@
FROM php:8.2-apache
RUN docker-php-ext-install mysqli pdo pdo_mysql \
&& a2enmod rewrite
COPY . /var/www/html/
RUN chown -R www-data:www-data /var/www/html
+54
View File
@@ -0,0 +1,54 @@
-- ============================================================
-- DATABASE PROYEK 02 — Jalanan, Parsil, Jalan Rusak
-- Import ini ke phpMyAdmin (dari server, bukan dari database)
-- ============================================================
SET FOREIGN_KEY_CHECKS = 0;
-- Database data_jalan: tabel jalan & parsil
CREATE DATABASE IF NOT EXISTS data_jalan
CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE data_jalan;
DROP TABLE IF EXISTS parsil;
DROP TABLE IF EXISTS jalan;
CREATE TABLE jalan (
id INT AUTO_INCREMENT PRIMARY KEY,
nama VARCHAR(150) NOT NULL,
status ENUM('baik','sedang','rusak_ringan','rusak_berat') DEFAULT 'baik',
panjang DECIMAL(10,2) DEFAULT 0,
geometry LONGTEXT COMMENT 'GeoJSON LineString',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE parsil (
id INT AUTO_INCREMENT PRIMARY KEY,
pemilik VARCHAR(150) NOT NULL,
status ENUM('milik_sendiri','sewa','hibah','sengketa') DEFAULT 'milik_sendiri',
luas DECIMAL(12,2) DEFAULT 0,
geometry LONGTEXT COMMENT 'GeoJSON Polygon',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- Database webgis: tabel jalan_rusak
CREATE DATABASE IF NOT EXISTS webgis
CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE webgis;
DROP TABLE IF EXISTS jalan_rusak;
CREATE TABLE jalan_rusak (
id INT AUTO_INCREMENT PRIMARY KEY,
keterangan TEXT,
tingkat ENUM('ringan','sedang','berat') DEFAULT 'sedang',
geometry LONGTEXT COMMENT 'GeoJSON geometry',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
SET FOREIGN_KEY_CHECKS = 1;
-- ============================================================
-- SELESAI — 2 database, 3 tabel siap dipakai
-- ============================================================
+12
View File
@@ -0,0 +1,12 @@
<?php
$host = getenv('DB_HOST');
$user = getenv('DB_USER');
$pass = getenv('DB_PASSWORD');
$db = getenv('DB_NAME');
$conn = mysqli_connect($host, $user, $pass, $db);
if (!$conn) {
die("Koneksi database gagal: " . mysqli_connect_error());
}
?>
+8
View File
@@ -0,0 +1,8 @@
<?php
include 'db.php';
$id = (int)($_GET['id'] ?? 0);
if ($conn->query("DELETE FROM jalan WHERE id=$id")) {
echo json_encode(['success' => true]);
} else {
echo json_encode(['success' => false, 'error' => $conn->error]);
}
+8
View File
@@ -0,0 +1,8 @@
<?php
include 'db.php';
$id = (int)($_GET['id'] ?? 0);
if ($conn->query("DELETE FROM parsil WHERE id=$id")) {
echo json_encode(['success' => true]);
} else {
echo json_encode(['success' => false, 'error' => $conn->error]);
}
+8
View File
@@ -0,0 +1,8 @@
<?php
include 'koneksi.php';
$id = (int)($_GET['id'] ?? 0);
if ($conn->query("DELETE FROM jalan_rusak WHERE id=$id")) {
echo json_encode(['success' => true]);
} else {
echo json_encode(['success' => false, 'error' => $conn->error]);
}
+11
View File
@@ -0,0 +1,11 @@
<?php
include 'db.php';
header('Content-Type: application/json');
$result = $conn->query("SELECT * FROM jalan");
$data = [];
while ($row = $result->fetch_assoc()) {
$row['geometry'] = json_decode($row['geometry']);
$data[] = $row;
}
echo json_encode($data);
+11
View File
@@ -0,0 +1,11 @@
<?php
include 'db.php';
header('Content-Type: application/json');
$result = $conn->query("SELECT * FROM parsil");
$data = [];
while ($row = $result->fetch_assoc()) {
$row['geometry'] = json_decode($row['geometry']);
$data[] = $row;
}
echo json_encode($data);
+11
View File
@@ -0,0 +1,11 @@
<?php
include 'koneksi.php';
header('Content-Type: application/json');
$q = $conn->query("SELECT * FROM jalan_rusak");
$data = [];
while ($d = $q->fetch_assoc()) {
$d['geometry'] = json_decode($d['geometry']);
$data[] = $d;
}
echo json_encode($data);
+341
View File
@@ -0,0 +1,341 @@
<!DOCTYPE html>
<html>
<head>
<title>WEB GIS FINAL</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css"/>
<link rel="stylesheet" href="https://unpkg.com/leaflet-draw/dist/leaflet.draw.css"/>
<script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
<script src="https://unpkg.com/leaflet-draw/dist/leaflet.draw.js"></script>
<script src="https://unpkg.com/leaflet-geometryutil"></script>
<style>
#map { height: 100vh; }
#searchBox{
position:absolute;
top:10px;
left:260px;
z-index:999;
padding:8px;
width:250px;
}
.modal {
display:none;
position:fixed;
z-index:999;
left:0;top:0;
width:100%;height:100%;
background:rgba(0,0,0,0.5);
}
.modal-content{
background:white;
padding:20px;
width:300px;
margin:120px auto;
border-radius:10px;
text-align:center;
}
</style>
</head>
<body>
<input type="text" id="searchBox" placeholder="Cari semua data...">
<div id="map"></div>
<div id="formModal" class="modal">
<div class="modal-content">
<h3 id="formTitle"></h3>
<input type="text" id="input1"><br>
<select id="input2"></select><br>
<button onclick="submitForm()">Simpan</button>
<button onclick="closeForm()">Batal</button>
</div>
</div>
<script>
// ================= MAP =================
var map = L.map('map').setView([-0.05,109.34],13);
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
var drawnItems = new L.FeatureGroup();
map.addLayer(drawnItems);
let semuaLayer = [];
let currentLayer = null;
let currentType = null;
// ================= WARNA =================
function warnaJalan(s){
return s=="Nasional"?"red":s=="Provinsi"?"blue":"green";
}
function warnaParsil(s){
return s=="SHM"?"yellow":
s=="HGB"?"orange":
s=="HGU"?"brown":
"purple";
}
// ================= FORMAT =================
function formatMeter(m){ return m.toFixed(2)+" m"; }
function formatMeter2(m){ return m.toFixed(2)+" m²"; }
// ================= FORM =================
function openForm(type, layer){
currentLayer = layer;
currentType = type;
document.getElementById("formModal").style.display="block";
let select = document.getElementById("input2");
select.innerHTML="";
if(type=="jalan"){
formTitle.innerText="Input Jalan";
input1.placeholder="Nama Jalan";
["Nasional","Provinsi","Kabupaten"].forEach(v=>{
let o=document.createElement("option");
o.value=v;o.text=v;
select.appendChild(o);
});
}
else if(type=="parsil"){
formTitle.innerText="Input Parsil";
input1.placeholder="Nama Pemilik";
["SHM","HGB","HGU","HP"].forEach(v=>{
let o=document.createElement("option");
o.value=v;o.text=v;
select.appendChild(o);
});
}
else if(type=="rusak"){
formTitle.innerText="Jalan Rusak";
input1.placeholder="Keterangan";
["Ringan","Sedang","Berat"].forEach(v=>{
let o=document.createElement("option");
o.value=v;o.text=v;
select.appendChild(o);
});
}
}
function closeForm(){
document.getElementById("formModal").style.display="none";
input1.value = "";
currentLayer = null;
currentType = null;
// Re-enable draw control
map.addControl(drawControl);
}
function submitForm(){
let v1 = input1.value.trim();
let v2 = input2.value;
if(!v1){
alert("Mohon isi nama/keterangan terlebih dahulu!");
return;
}
if(!currentLayer || !currentType){
alert("Tidak ada layer yang dipilih!");
closeForm();
return;
}
// Simpan referensi layer sebelum closeForm me-reset currentLayer
let layer = currentLayer;
let type = currentType;
closeForm();
if(type=="jalan") prosesJalan(layer, v1, v2);
else if(type=="parsil") prosesParsil(layer, v1, v2);
else if(type=="rusak") prosesRusak(layer, v1, v2);
}
// ================= DRAW =================
var drawControl = new L.Control.Draw({
edit:{ featureGroup: drawnItems },
draw:{
polyline:true,
polygon:true,
rectangle:false,
circle:false,
marker:true
}
});
map.addControl(drawControl);
map.on('draw:created', function(e){
var layer = e.layer;
drawnItems.addLayer(layer);
// Disable draw sementara sampai form disubmit
map.removeControl(drawControl);
if(e.layerType=="polyline") openForm("jalan",layer);
if(e.layerType=="polygon") openForm("parsil",layer);
if(e.layerType=="marker") openForm("rusak",layer);
});
// ================= JALAN =================
function prosesJalan(layer,nama,status){
let latlngs = layer.getLatLngs();
let panjang=0;
for(let i=0;i<latlngs.length-1;i++){
panjang += latlngs[i].distanceTo(latlngs[i+1]);
}
layer.setStyle({color:warnaJalan(status)});
fetch('save_jalan.php',{
method:'POST',
headers:{'Content-Type':'application/json'},
body:JSON.stringify({nama,status,panjang,geometry:layer.toGeoJSON().geometry})
})
.then(r=>r.json())
.then(res=> { if(res.success) layer.id=res.id; else console.error('save_jalan error:',res.error); });
layer.bindPopup(`<b>Jalan</b><br>${nama}<br>Panjang: ${formatMeter(panjang)}`);
semuaLayer.push({layer:layer,nama:nama});
}
// ================= PARSIL =================
function prosesParsil(layer,pemilik,status){
let luas = L.GeometryUtil.geodesicArea(layer.getLatLngs()[0]);
layer.setStyle({color:warnaParsil(status)});
fetch('save_parsil.php',{
method:'POST',
headers:{'Content-Type':'application/json'},
body:JSON.stringify({pemilik,status,luas,geometry:layer.toGeoJSON().geometry})
})
.then(r=>r.json())
.then(res=> { if(res.success) layer.id=res.id; else console.error('save_parsil error:',res.error); });
layer.bindPopup(`<b>Parsil</b><br>${pemilik}<br>Luas: ${formatMeter2(luas)}`);
semuaLayer.push({layer:layer,nama:pemilik});
}
// ================= RUSAK =================
function prosesRusak(layer,keterangan,tingkat){
let icon = L.icon({
iconUrl: tingkat=="Ringan"?
"https://maps.google.com/mapfiles/ms/icons/green-dot.png":
tingkat=="Sedang"?
"https://maps.google.com/mapfiles/ms/icons/yellow-dot.png":
"https://maps.google.com/mapfiles/ms/icons/red-dot.png",
iconSize:[25,41],
iconAnchor:[12,41]
});
layer.setIcon(icon);
fetch('save_rusak.php',{
method:'POST',
headers:{'Content-Type':'application/json'},
body:JSON.stringify({keterangan,tingkat,geometry:layer.toGeoJSON().geometry})
})
.then(r=>r.json())
.then(res=> { if(res.success) layer.id=res.id; else console.error('save_rusak error:',res.error); });
layer.bindPopup(`<b>Rusak</b><br>${keterangan}<br><b>Tingkat:</b> ${tingkat}`);
semuaLayer.push({layer:layer,nama:keterangan});
}
// ================= LOAD =================
fetch('get_jalan.php').then(r=>r.json()).then(data=>{
data.forEach(j=>{
let geo=j.geometry;
let layer=L.geoJSON(geo,{style:{color:warnaJalan(j.status)}}).addTo(map);
layer.eachLayer(l=>{
l.bindPopup(`<b>Jalan</b><br>${j.nama}<br>Panjang: ${formatMeter(j.panjang)}`);
semuaLayer.push({layer:l,nama:j.nama});
});
});
});
fetch('get_parsil.php').then(r=>r.json()).then(data=>{
data.forEach(p=>{
let geo=p.geometry;
let layer=L.geoJSON(geo,{style:{color:warnaParsil(p.status)}}).addTo(map);
layer.eachLayer(l=>{
l.bindPopup(`<b>Parsil</b><br>${p.pemilik}<br>Luas: ${formatMeter2(p.luas)}`);
semuaLayer.push({layer:l,nama:p.pemilik});
});
});
});
fetch('get_rusak.php').then(r=>r.json()).then(data=>{
data.forEach(r=>{
let geo=r.geometry;
let icon = L.icon({
iconUrl: r.tingkat=="Ringan"?
"https://maps.google.com/mapfiles/ms/icons/green-dot.png":
r.tingkat=="Sedang"?
"https://maps.google.com/mapfiles/ms/icons/yellow-dot.png":
"https://maps.google.com/mapfiles/ms/icons/red-dot.png",
iconSize:[25,41],
iconAnchor:[12,41]
});
let layer=L.geoJSON(geo,{
pointToLayer:(f,latlng)=>L.marker(latlng,{icon:icon})
}).addTo(map);
layer.eachLayer(l=>{
l.bindPopup(`<b>Rusak</b><br>${r.keterangan}<br><b>Tingkat:</b> ${r.tingkat}`);
semuaLayer.push({layer:l,nama:r.keterangan});
});
});
});
// ================= SEARCH =================
document.getElementById("searchBox").addEventListener("keyup",function(){
let key=this.value.toLowerCase();
semuaLayer.forEach(o=>{
let cocok=o.nama.toLowerCase().includes(key);
if(o.layer.setStyle){
o.layer.setStyle({
opacity:cocok?1:0.1,
fillOpacity:cocok?0.7:0.1
});
}
if(o.layer.setOpacity){
o.layer.setOpacity(cocok?1:0.2);
}
if(cocok){
try{ map.fitBounds(o.layer.getBounds()); }catch(e){}
}
});
});
</script>
</body>
</html>
+12
View File
@@ -0,0 +1,12 @@
<?php
$host = getenv('DB_HOST');
$user = getenv('DB_USER');
$pass = getenv('DB_PASSWORD');
$db = getenv('DB_NAME');
$conn = mysqli_connect($host, $user, $pass, $db);
if (!$conn) {
die("Koneksi database gagal: " . mysqli_connect_error());
}
?>
+23
View File
@@ -0,0 +1,23 @@
<?php
include 'db.php';
$data = json_decode(file_get_contents("php://input"), true);
if (!$data) {
echo json_encode(['success' => false, 'error' => 'Data tidak valid']);
exit;
}
$nama = $conn->real_escape_string($data['nama'] ?? '');
$status = $conn->real_escape_string($data['status'] ?? 'baik');
$panjang = floatval($data['panjang'] ?? 0);
$geometry = $conn->real_escape_string(json_encode($data['geometry']));
$sql = "INSERT INTO jalan (nama, status, panjang, geometry)
VALUES ('$nama', '$status', '$panjang', '$geometry')";
if ($conn->query($sql)) {
echo json_encode(['success' => true, 'id' => $conn->insert_id]);
} else {
echo json_encode(['success' => false, 'error' => $conn->error]);
}
+23
View File
@@ -0,0 +1,23 @@
<?php
include 'db.php';
$data = json_decode(file_get_contents("php://input"), true);
if (!$data) {
echo json_encode(['success' => false, 'error' => 'Data tidak valid']);
exit;
}
$pemilik = $conn->real_escape_string($data['pemilik'] ?? '');
$status = $conn->real_escape_string($data['status'] ?? 'milik_sendiri');
$luas = floatval($data['luas'] ?? 0);
$geometry = $conn->real_escape_string(json_encode($data['geometry']));
$sql = "INSERT INTO parsil (pemilik, status, luas, geometry)
VALUES ('$pemilik', '$status', '$luas', '$geometry')";
if ($conn->query($sql)) {
echo json_encode(['success' => true, 'id' => $conn->insert_id]);
} else {
echo json_encode(['success' => false, 'error' => $conn->error]);
}
+22
View File
@@ -0,0 +1,22 @@
<?php
include 'koneksi.php';
$data = json_decode(file_get_contents("php://input"));
if (!$data) {
echo json_encode(['success' => false, 'error' => 'Data tidak valid']);
exit;
}
$keterangan = $conn->real_escape_string($data->keterangan ?? '');
$tingkat = $conn->real_escape_string($data->tingkat ?? 'sedang');
$geometry = $conn->real_escape_string(json_encode($data->geometry));
$sql = "INSERT INTO jalan_rusak (keterangan, tingkat, geometry)
VALUES ('$keterangan', '$tingkat', '$geometry')";
if ($conn->query($sql)) {
echo json_encode(['success' => true, 'id' => $conn->insert_id]);
} else {
echo json_encode(['success' => false, 'error' => $conn->error]);
}
+13
View File
@@ -0,0 +1,13 @@
<?php
include 'db.php';
$data = json_decode(file_get_contents("php://input"), true);
$id = (int)($data['id'] ?? 0);
$panjang = floatval($data['panjang'] ?? 0);
$geometry = $conn->real_escape_string(json_encode($data['geometry']));
if ($conn->query("UPDATE jalan SET panjang='$panjang', geometry='$geometry' WHERE id=$id")) {
echo json_encode(['success' => true]);
} else {
echo json_encode(['success' => false, 'error' => $conn->error]);
}
+13
View File
@@ -0,0 +1,13 @@
<?php
include 'db.php';
$data = json_decode(file_get_contents("php://input"), true);
$id = (int)($data['id'] ?? 0);
$luas = floatval($data['luas'] ?? 0);
$geometry = $conn->real_escape_string(json_encode($data['geometry']));
if ($conn->query("UPDATE parsil SET luas='$luas', geometry='$geometry' WHERE id=$id")) {
echo json_encode(['success' => true]);
} else {
echo json_encode(['success' => false, 'error' => $conn->error]);
}