Upload files to "tugas02"
This commit is contained in:
@@ -0,0 +1,25 @@
|
|||||||
|
# Project 2 - WebGIS Manajemen Jalan dan Tanah
|
||||||
|
|
||||||
|
Project ini khusus untuk mengelola data spasial berbentuk:
|
||||||
|
|
||||||
|
- Polyline untuk jalan.
|
||||||
|
- Polygon untuk tanah/kavling.
|
||||||
|
|
||||||
|
## Database
|
||||||
|
|
||||||
|
Import file `database.sql` ke phpMyAdmin. Database yang dibuat adalah:
|
||||||
|
|
||||||
|
`webgis_jalan_tanah_p2`
|
||||||
|
|
||||||
|
Tabel utama:
|
||||||
|
|
||||||
|
`data_spasial`
|
||||||
|
|
||||||
|
## Cara Menjalankan
|
||||||
|
|
||||||
|
1. Letakkan folder ini di `htdocs`.
|
||||||
|
2. Jalankan Apache dan MySQL.
|
||||||
|
3. Import `database.sql`.
|
||||||
|
4. Buka `http://localhost/webgis_pisah/project_02_webgis_jalan_tanah/`.
|
||||||
|
5. Gunakan tool polyline untuk menambah jalan.
|
||||||
|
6. Gunakan tool polygon untuk menambah tanah/kavling.
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
<?php
|
||||||
|
include 'connect.php';
|
||||||
|
header('Content-Type: application/json; charset=utf-8');
|
||||||
|
|
||||||
|
$action = $_GET['action'] ?? '';
|
||||||
|
|
||||||
|
if ($action === 'tampil') {
|
||||||
|
$sql = "SELECT * FROM tugas02_data_spasial ORDER BY id DESC";
|
||||||
|
$result = $conn->query($sql);
|
||||||
|
$data = [];
|
||||||
|
|
||||||
|
while ($row = $result->fetch_assoc()) {
|
||||||
|
$data[] = $row;
|
||||||
|
}
|
||||||
|
|
||||||
|
echo json_encode($data);
|
||||||
|
}
|
||||||
|
elseif ($action === 'simpan') {
|
||||||
|
$nama = trim($_POST['nama'] ?? '');
|
||||||
|
$jenis_objek = $_POST['jenis_objek'] ?? '';
|
||||||
|
$status = $_POST['status'] ?? '';
|
||||||
|
$ukuran = floatval($_POST['ukuran'] ?? 0);
|
||||||
|
$geojson = $_POST['geojson'] ?? '';
|
||||||
|
|
||||||
|
if ($nama === '' || $jenis_objek === '' || $geojson === '') {
|
||||||
|
echo json_encode(["status" => "error", "message" => "Nama, jenis objek, dan geometri wajib diisi."]);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$stmt = $conn->prepare("INSERT INTO tugas02_data_spasial (nama, jenis_objek, status, ukuran, geojson) VALUES (?, ?, ?, ?, ?)");
|
||||||
|
$stmt->bind_param("sssds", $nama, $jenis_objek, $status, $ukuran, $geojson);
|
||||||
|
|
||||||
|
if ($stmt->execute()) {
|
||||||
|
echo json_encode(["status" => "success"]);
|
||||||
|
} else {
|
||||||
|
echo json_encode(["status" => "error", "message" => $stmt->error]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$stmt->close();
|
||||||
|
}
|
||||||
|
elseif ($action === 'hapus') {
|
||||||
|
$id = intval($_POST['id'] ?? 0);
|
||||||
|
|
||||||
|
if ($id <= 0) {
|
||||||
|
echo json_encode(["status" => "error", "message" => "ID tidak valid."]);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$stmt = $conn->prepare("DELETE FROM tugas02_data_spasial WHERE id = ?");
|
||||||
|
$stmt->bind_param("i", $id);
|
||||||
|
|
||||||
|
if ($stmt->execute()) {
|
||||||
|
echo json_encode(["status" => "success"]);
|
||||||
|
} else {
|
||||||
|
echo json_encode(["status" => "error", "message" => $stmt->error]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$stmt->close();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
echo json_encode(["status" => "error", "message" => "Action tidak dikenali."]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$conn->close();
|
||||||
|
?>
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
$host = getenv('DB_HOST') ?: 'localhost';
|
||||||
|
$user = getenv('DB_USER') ?: 'root';
|
||||||
|
$pass = getenv('DB_PASS') ?: '';
|
||||||
|
$db = getenv('DB_NAME') ?: 'webgis_tugas_sig';
|
||||||
|
$port = (int)(getenv('DB_PORT') ?: 3306);
|
||||||
|
|
||||||
|
$conn = new mysqli($host, $user, $pass, $db, $port);
|
||||||
|
|
||||||
|
if ($conn->connect_error) {
|
||||||
|
http_response_code(500);
|
||||||
|
die(json_encode([
|
||||||
|
"status" => "error",
|
||||||
|
"message" => "Koneksi database gagal: " . $conn->connect_error
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
|
||||||
|
$conn->set_charset('utf8mb4');
|
||||||
|
?>
|
||||||
@@ -0,0 +1,268 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="id">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Project 2 - WebGIS Jalan dan Tanah</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>
|
||||||
|
body { margin: 0; font-family: Arial, sans-serif; }
|
||||||
|
#map { height: 100vh; width: 100%; }
|
||||||
|
.title-box {
|
||||||
|
position: absolute; top: 10px; left: 55px; z-index: 999;
|
||||||
|
background: white; padding: 10px 14px; border-radius: 6px;
|
||||||
|
box-shadow: 0 2px 10px rgba(0,0,0,.2);
|
||||||
|
}
|
||||||
|
.title-box h3 { margin: 0 0 4px; }
|
||||||
|
.title-box p { margin: 0; font-size: 13px; color: #555; }
|
||||||
|
.popup-form label { font-weight: bold; font-size: 13px; }
|
||||||
|
.popup-form input, .popup-form select {
|
||||||
|
width: 100%; padding: 7px; margin: 4px 0 9px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
.popup-form input[readonly] { background: #eee; }
|
||||||
|
.popup-form button, .btn-delete {
|
||||||
|
border: 0; padding: 7px 12px; border-radius: 4px; cursor: pointer;
|
||||||
|
background: #0d6efd; color: white;
|
||||||
|
}
|
||||||
|
.btn-delete { background: #dc3545; }
|
||||||
|
.legend {
|
||||||
|
background: rgba(255,255,255,.95); padding: 10px 14px;
|
||||||
|
border-radius: 6px; box-shadow: 0 2px 10px rgba(0,0,0,.2);
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="title-box">
|
||||||
|
<h3>Project 2 - Jalan dan Tanah</h3>
|
||||||
|
<p>Gunakan polyline untuk jalan dan polygon untuk tanah/kavling.</p>
|
||||||
|
</div>
|
||||||
|
<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>
|
||||||
|
const map = L.map('map').setView([-0.0227, 109.3425], 13);
|
||||||
|
|
||||||
|
const osm = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||||
|
attribution: '© OpenStreetMap contributors'
|
||||||
|
}).addTo(map);
|
||||||
|
|
||||||
|
const satellite = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', {
|
||||||
|
attribution: 'Tiles © Esri'
|
||||||
|
});
|
||||||
|
|
||||||
|
const jalanLayer = new L.FeatureGroup().addTo(map);
|
||||||
|
const tanahLayer = new L.FeatureGroup().addTo(map);
|
||||||
|
|
||||||
|
L.control.layers(
|
||||||
|
{ 'OpenStreetMap': osm, 'Satellite': satellite },
|
||||||
|
{ '🛣️ Data Jalan': jalanLayer, '🟩 Data Tanah/Kavling': tanahLayer },
|
||||||
|
{ collapsed: false }
|
||||||
|
).addTo(map);
|
||||||
|
|
||||||
|
const drawControl = new L.Control.Draw({
|
||||||
|
edit: false,
|
||||||
|
draw: {
|
||||||
|
marker: false,
|
||||||
|
polyline: true,
|
||||||
|
polygon: true,
|
||||||
|
rectangle: false,
|
||||||
|
circle: false,
|
||||||
|
circlemarker: false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
map.addControl(drawControl);
|
||||||
|
|
||||||
|
map.on(L.Draw.Event.CREATED, function (e) {
|
||||||
|
const layer = e.layer;
|
||||||
|
const type = e.layerType;
|
||||||
|
const geojson = JSON.stringify(layer.toGeoJSON().geometry);
|
||||||
|
|
||||||
|
if (type === 'polyline') {
|
||||||
|
const panjang = hitungPanjangPolyline(layer.getLatLngs());
|
||||||
|
showForm(layer.getBounds().getCenter(), 'Jalan', geojson, panjang.toFixed(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type === 'polygon') {
|
||||||
|
const luas = L.GeometryUtil.geodesicArea(layer.getLatLngs()[0]);
|
||||||
|
showForm(layer.getBounds().getCenter(), 'Tanah', geojson, luas.toFixed(2));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function hitungPanjangPolyline(latlngs) {
|
||||||
|
let total = 0;
|
||||||
|
for (let i = 0; i < latlngs.length - 1; i++) {
|
||||||
|
total += map.distance(latlngs[i], latlngs[i + 1]);
|
||||||
|
}
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
function showForm(latlng, jenisObjek, geojson, ukuran) {
|
||||||
|
let statusOptions = '';
|
||||||
|
let labelUkuran = '';
|
||||||
|
|
||||||
|
if (jenisObjek === 'Jalan') {
|
||||||
|
statusOptions = `
|
||||||
|
<option value="Jalan Nasional">Jalan Nasional</option>
|
||||||
|
<option value="Jalan Provinsi">Jalan Provinsi</option>
|
||||||
|
<option value="Jalan Kota/Kabupaten">Jalan Kota/Kabupaten</option>
|
||||||
|
<option value="Jalan Lingkungan">Jalan Lingkungan</option>
|
||||||
|
`;
|
||||||
|
labelUkuran = 'Panjang Jalan (meter)';
|
||||||
|
} else {
|
||||||
|
statusOptions = `
|
||||||
|
<option value="SHM">SHM</option>
|
||||||
|
<option value="HGB">HGB</option>
|
||||||
|
<option value="HGU">HGU</option>
|
||||||
|
<option value="Hak Pakai">Hak Pakai</option>
|
||||||
|
<option value="Belum Bersertifikat">Belum Bersertifikat</option>
|
||||||
|
`;
|
||||||
|
labelUkuran = 'Luas Tanah (meter persegi)';
|
||||||
|
}
|
||||||
|
|
||||||
|
const html = `
|
||||||
|
<div class="popup-form">
|
||||||
|
<h3>Tambah Data ${jenisObjek}</h3>
|
||||||
|
<label>Nama ${jenisObjek}</label>
|
||||||
|
<input type="text" id="nama" placeholder="Contoh: Jalan Ahmad Yani / Tanah Kavling A">
|
||||||
|
|
||||||
|
<label>Status</label>
|
||||||
|
<select id="status">${statusOptions}</select>
|
||||||
|
|
||||||
|
<label>${labelUkuran}</label>
|
||||||
|
<input type="text" id="ukuran" value="${ukuran}" readonly>
|
||||||
|
|
||||||
|
<input type="hidden" id="jenis_objek" value="${jenisObjek}">
|
||||||
|
<textarea id="geojson" style="display:none">${geojson}</textarea>
|
||||||
|
<button onclick="simpanData()">Simpan</button>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
L.popup({ minWidth: 290 }).setLatLng(latlng).setContent(html).openOn(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
function simpanData() {
|
||||||
|
const nama = document.getElementById('nama').value.trim();
|
||||||
|
const jenis_objek = document.getElementById('jenis_objek').value;
|
||||||
|
const status = document.getElementById('status').value;
|
||||||
|
const ukuran = document.getElementById('ukuran').value;
|
||||||
|
const geojson = document.getElementById('geojson').value;
|
||||||
|
|
||||||
|
if (!nama) {
|
||||||
|
alert('Nama data wajib diisi!');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('nama', nama);
|
||||||
|
formData.append('jenis_objek', jenis_objek);
|
||||||
|
formData.append('status', status);
|
||||||
|
formData.append('ukuran', ukuran);
|
||||||
|
formData.append('geojson', geojson);
|
||||||
|
|
||||||
|
fetch('api.php?action=simpan', { method: 'POST', body: formData })
|
||||||
|
.then(res => res.json())
|
||||||
|
.then(data => {
|
||||||
|
if (data.status === 'success') {
|
||||||
|
map.closePopup();
|
||||||
|
loadData();
|
||||||
|
} else {
|
||||||
|
alert(data.message || 'Gagal menyimpan data.');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => alert('Gagal terhubung ke server.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadData() {
|
||||||
|
jalanLayer.clearLayers();
|
||||||
|
tanahLayer.clearLayers();
|
||||||
|
|
||||||
|
fetch('api.php?action=tampil')
|
||||||
|
.then(res => res.json())
|
||||||
|
.then(data => {
|
||||||
|
data.forEach(item => {
|
||||||
|
if (!item.geojson) return;
|
||||||
|
|
||||||
|
const geometry = JSON.parse(item.geojson);
|
||||||
|
const warna = getWarna(item.jenis_objek, item.status);
|
||||||
|
const layer = L.geoJSON(geometry, {
|
||||||
|
style: {
|
||||||
|
color: warna,
|
||||||
|
weight: item.jenis_objek === 'Jalan' ? 5 : 2,
|
||||||
|
fillColor: warna,
|
||||||
|
fillOpacity: 0.45
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const satuan = item.jenis_objek === 'Jalan' ? 'meter' : 'm²';
|
||||||
|
layer.bindPopup(`
|
||||||
|
<b>${item.nama}</b><br>
|
||||||
|
<b>Jenis:</b> ${item.jenis_objek}<br>
|
||||||
|
<b>Status:</b> ${item.status}<br>
|
||||||
|
<b>Ukuran:</b> ${Number(item.ukuran).toFixed(2)} ${satuan}<br><br>
|
||||||
|
<button class="btn-delete" onclick="hapusData(${item.id})">Hapus</button>
|
||||||
|
`);
|
||||||
|
layer.bindTooltip(item.nama);
|
||||||
|
|
||||||
|
if (item.jenis_objek === 'Jalan') jalanLayer.addLayer(layer);
|
||||||
|
if (item.jenis_objek === 'Tanah') tanahLayer.addLayer(layer);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getWarna(jenis, status) {
|
||||||
|
if (jenis === 'Jalan') {
|
||||||
|
if (status === 'Jalan Nasional') return '#e74c3c';
|
||||||
|
if (status === 'Jalan Provinsi') return '#f39c12';
|
||||||
|
if (status === 'Jalan Kota/Kabupaten') return '#2ecc71';
|
||||||
|
return '#34495e';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status === 'SHM') return '#27ae60';
|
||||||
|
if (status === 'HGB') return '#2980b9';
|
||||||
|
if (status === 'HGU') return '#f1c40f';
|
||||||
|
if (status === 'Hak Pakai') return '#8e44ad';
|
||||||
|
return '#7f8c8d';
|
||||||
|
}
|
||||||
|
|
||||||
|
function hapusData(id) {
|
||||||
|
if (!confirm('Yakin ingin menghapus data ini?')) return;
|
||||||
|
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('id', id);
|
||||||
|
|
||||||
|
fetch('api.php?action=hapus', { method: 'POST', body: formData })
|
||||||
|
.then(res => res.json())
|
||||||
|
.then(data => {
|
||||||
|
if (data.status === 'success') {
|
||||||
|
map.closePopup();
|
||||||
|
loadData();
|
||||||
|
} else {
|
||||||
|
alert(data.message || 'Gagal menghapus data.');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const legend = L.control({ position: 'bottomright' });
|
||||||
|
legend.onAdd = function () {
|
||||||
|
const div = L.DomUtil.create('div', 'legend');
|
||||||
|
div.innerHTML = `
|
||||||
|
<b>Legenda</b><br>
|
||||||
|
<span style="color:#e74c3c">━━</span> Jalan Nasional<br>
|
||||||
|
<span style="color:#f39c12">━━</span> Jalan Provinsi<br>
|
||||||
|
<span style="color:#2ecc71">━━</span> Jalan Kota/Kabupaten<br>
|
||||||
|
<span style="color:#27ae60">■</span> Tanah SHM<br>
|
||||||
|
<span style="color:#2980b9">■</span> Tanah HGB<br>
|
||||||
|
<span style="color:#f1c40f">■</span> Tanah HGU<br>
|
||||||
|
<span style="color:#8e44ad">■</span> Hak Pakai
|
||||||
|
`;
|
||||||
|
return div;
|
||||||
|
};
|
||||||
|
legend.addTo(map);
|
||||||
|
|
||||||
|
loadData();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user