Initial commit

This commit is contained in:
2026-06-13 10:54:54 +07:00
commit fb63e876ea
41 changed files with 2473 additions and 0 deletions
+81
View File
@@ -0,0 +1,81 @@
<!DOCTYPE html>
<html lang="en">
<head>
<base target="_top">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Quick Start - Leaflet</title>
<link rel="shortcut icon" type="image/x-icon" href="docs/images/favicon.ico" />
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" crossorigin=""/>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin=""></script>
<style>
html, body {
height: 100%;
margin: 0;
}
.leaflet-container {
height: 400px;
width: 600px;
max-width: 100%;
max-height: 100%;
}
</style>
</head>
<body>
<div id="map" style="width: 600px; height: 400px;"></div>
<script>
const map = L.map('map').setView([51.505, -0.09], 13);
const tiles = L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
}).addTo(map);
const marker = L.marker([51.5, -0.09]).addTo(map)
.bindPopup('<b>Hello world!</b><br />I am a popup.').openPopup();
const circle = L.circle([51.508, -0.11], {
color: 'red',
fillColor: '#f03',
fillOpacity: 0.5,
radius: 500
}).addTo(map).bindPopup('I am a circle.');
const polygon = L.polygon([
[51.509, -0.08],
[51.503, -0.06],
[51.51, -0.047]
]).addTo(map).bindPopup('I am a polygon.');
const popup = L.popup()
.setLatLng([51.513, -0.09])
.setContent('I am a standalone popup.')
.openOn(map);
function onMapClick(e) {
popup
.setLatLng(e.latlng)
.setContent(`You clicked the map at ${e.latlng.toString()}`)
.openOn(map);
}
map.on('click', onMapClick);
</script>
</body>
</html>
+12
View File
@@ -0,0 +1,12 @@
<?php
$conn = new mysqli(
"sql306.infinityfree.com",
"if0_42162175",
"O7J3BDbiaJoXo2S",
"if0_42162175_spbu_db"
);
if ($conn->connect_error) {
die($conn->connect_error);
}
?>
+11
View File
@@ -0,0 +1,11 @@
<?php
include 'db.php';
$data = json_decode(file_get_contents("php://input"));
$id = $data->id;
$conn->query("DELETE FROM garis WHERE id=$id");
echo json_encode(["status"=>"deleted"]);
?>
+11
View File
@@ -0,0 +1,11 @@
<?php
include 'db.php';
$data = json_decode(file_get_contents("php://input"));
$id = $data->id;
$conn->query("DELETE FROM polygons WHERE id=$id");
echo json_encode(["status"=>"deleted"]);
?>
+13
View File
@@ -0,0 +1,13 @@
<?php
include 'db.php';
$result = $conn->query("SELECT * FROM garis");
$data = [];
while($row = $result->fetch_assoc()){
$data[] = $row;
}
echo json_encode($data);
?>
+13
View File
@@ -0,0 +1,13 @@
<?php
include 'db.php';
$result = $conn->query("SELECT * FROM polygons");
$data = [];
while($row = $result->fetch_assoc()){
$data[] = $row;
}
echo json_encode($data);
?>
+445
View File
@@ -0,0 +1,445 @@
<!DOCTYPE html>
<html lang="en">
<head>
<base target="_top">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>WebGIS - Jalan & Kavling</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" crossorigin=""/>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin=""></script>
<style>
html, body {
height: 100%;
margin: 0;
}
#map {
height: 100%;
}
.popup-card {
font-family: Arial, sans-serif;
width: 200px;
}
.popup-title {
font-weight: bold;
font-size: 16px;
margin-bottom: 6px;
}
.popup-item {
font-size: 13px;
margin: 2px 0;
}
.badge {
display: inline-block;
padding: 2px 6px;
border-radius: 6px;
font-size: 11px;
color: white;
}
.green { background: #28a745; }
.red { background: #dc3545; }
.popup-btn {
margin-top: 8px;
padding: 5px;
width: 100%;
border: none;
border-radius: 6px;
background: #007bff;
color: white;
cursor: pointer;
}
.popup-btn:hover {
background: #0056b3;
}
.form-card {
font-family: Arial, sans-serif;
width: 220px;
}
.form-title {
font-weight: bold;
font-size: 15px;
margin-bottom: 6px;
}
.form-group {
margin-bottom: 6px;
}
.form-group label {
font-size: 12px;
}
.form-group input,
.form-group select {
width: 100%;
padding: 4px;
border-radius: 5px;
border: 1px solid #ccc;
font-size: 12px;
}
.form-btn {
width: 100%;
padding: 6px;
border: none;
border-radius: 6px;
color: white;
cursor: pointer;
}
.btn-save { background: #28a745; }
.btn-update { background: #007bff; }
</style>
</head>
<body>
<div style="position:absolute; z-index:1000; background:white; padding:10px;">
<button onclick="startLine()">✏️ Line</button>
<button onclick="startPolygons()">🔺 Polygon</button>
<button onclick="finishShape()">✅ Selesai</button>
<button onclick="resetShape()">❌ Reset</button>
</div>
<div id="map"></div>
<script>
const map = L.map('map').setView([-0.055326, 109.349500], 13);
const tiles = L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
}).addTo(map);
let mode = null;
let points = [];
let tempLayer = null;
map.on('click', function(e) {
if (mode) {
points.push([e.latlng.lat, e.latlng.lng]);
if (tempLayer) {
map.removeLayer(tempLayer);
}
if (mode === 'line') {
tempLayer = L.polyline(points, { color: 'blue' }).addTo(map);
}
if (mode === 'polygons') {
tempLayer = L.polygon(points, { color: 'green' }).addTo(map);
}
}
});
function startLine() {
mode = 'line';
points = [];
alert("Mode LINE aktif");
}
function startPolygons() {
mode = 'polygons';
points = [];
alert("Mode POLYGON aktif");
}
function resetShape() {
points = [];
if (tempLayer) {
map.removeLayer(tempLayer);
tempLayer = null;
}
}
function finishShape() {
if (points.length < 2) {
alert("Titik belum cukup!");
return;
}
let shape;
let currentType = mode;
if (mode === 'line') {
shape = L.polyline(points, { color: 'blue', weight: 4 }).addTo(map);
}
if (mode === 'polygons') {
shape = L.polygon(points, { color: 'green', fillOpacity: 0.4 }).addTo(map);
}
fetch(currentType === 'line' ? 'simpan_line.php' : 'simpan_polygons.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
coordinates: points
})
})
.then(res => res.json())
.then(res => {
let id = res.id;
if (currentType === 'line') {
let panjang = hitungPanjang(points);
shape.bindPopup(`
<b>Atur Jalan</b><br>
<select id="status_${id}">
<option value="Nasional">Nasional</option>
<option value="Provinsi">Provinsi</option>
<option value="Kabupaten">Kabupaten</option>
</select>
<br><br>
Panjang: ${panjang} meter<br><br>
<button onclick="updateLine(${id})">✅ OK</button>
<button onclick="hapusShape(${id}, 'line')">🗑️ Hapus</button>
`);
} else {
let luas = hitungLuas(points);
shape.bindPopup(`
<b>Atur Kavling</b><br>
<select id="status_poly_${id}">
<option value="SHM">SHM</option>
<option value="HGB">HGB</option>
<option value="HGU">HGU</option>
<option value="HP">HP</option>
</select>
<br><br>
Luas: ${luas} m²<br><br>
<button onclick="updatePolygon(${id})">✅ OK</button>
<button onclick="hapusShape(${id}, 'polygons')">🗑️ Hapus</button>
`);
}
});
// reset
mode = null;
points = [];
if (tempLayer) {
map.removeLayer(tempLayer);
tempLayer = null;
}
alert("Shape selesai!");
}
function hapusShape(id, type) {
fetch(type === 'line' ? 'delete_line.php' : 'delete_polygons.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ id: id })
})
.then(() => location.reload());
}
function loadLines() {
fetch('get_line.php')
.then(res => res.json())
.then(data => {
data.forEach(d => {
let coords = JSON.parse(d.coordinates);
let color = getColor(d.status) || 'blue';
let line = L.polyline(coords, { color: color }).addTo(map);
let panjang = hitungPanjang(coords);
line.bindPopup(`
<b>Atur Jalan</b><br>
<select id="status_${d.id}">
<option value="Nasional" ${d.status === 'Nasional' ? 'selected' : ''}>Nasional</option>
<option value="Provinsi" ${d.status === 'Provinsi' ? 'selected' : ''}>Provinsi</option>
<option value="Kabupaten" ${d.status === 'Kabupaten' ? 'selected' : ''}>Kabupaten</option>
</select>
<br><br>
Panjang: ${panjang} meter<br><br>
<button onclick="updateLine(${d.id})">✅ OK</button>
<button onclick="hapusShape(${d.id}, 'line')">🗑️ Hapus</button>
`);
});
});
}
function normalizeCoords(raw) {
if (raw && raw.type === 'Polygon' && raw.coordinates) {
return raw.coordinates[0].map(p => [p[1], p[0]]);
}
if (raw && raw.type === 'LineString' && raw.coordinates) {
return raw.coordinates.map(p => [p[1], p[0]]);
}
if (Array.isArray(raw)) return raw;
return raw;
}
function loadPolygons() {
fetch('get_polygons.php')
.then(res => res.json())
.then(data => {
data.forEach(d => {
let raw = JSON.parse(d.coordinates);
let coords = normalizeCoords(raw);
if (!Array.isArray(coords) || coords.length < 3) return;
let color = getColorPolygon(d.status) || 'green';
let polygon = L.polygon(coords, {
color: color,
fillOpacity: 0.4
}).addTo(map);
let luas = hitungLuas(coords);
polygon.bindPopup(`
<b>Atur Kavling</b><br>
<select id="status_poly_${d.id}">
<option value="SHM" ${d.status === 'SHM' ? 'selected' : ''}>SHM</option>
<option value="HGB" ${d.status === 'HGB' ? 'selected' : ''}>HGB</option>
<option value="HGU" ${d.status === 'HGU' ? 'selected' : ''}>HGU</option>
<option value="HP" ${d.status === 'HP' ? 'selected' : ''}>HP</option>
</select>
<br><br>
Luas: ${luas} m²<br><br>
<button onclick="updatePolygon(${d.id})">✅ OK</button>
<button onclick="hapusShape(${d.id}, 'polygons')">🗑️ Hapus</button>
`);
});
});
}
loadLines();
loadPolygons();
function getColor(status) {
if (status === 'Nasional') return 'red';
if (status === 'Provinsi') return 'blue';
if (status === 'Kabupaten') return 'green';
}
function getColorPolygon(status) {
if (status === 'SHM') return 'green';
if (status === 'HGB') return 'blue';
if (status === 'HGU') return 'orange';
if (status === 'HP') return 'purple';
}
function hitungPanjang(points) {
let total = 0;
for (let i = 0; i < points.length - 1; i++) {
let p1 = L.latLng(points[i]);
let p2 = L.latLng(points[i + 1]);
total += p1.distanceTo(p2);
}
return total.toFixed(2);
}
function hitungLuas(points) {
if (!Array.isArray(points) || points.length < 3) return 0;
// Normalisasi: handle format [lat,lng] array maupun {lat,lng} object
let latlngs = points.map(p => {
if (Array.isArray(p)) return L.latLng(p[0], p[1]);
if (p.lat !== undefined) return L.latLng(p.lat, p.lng);
return L.latLng(p[0], p[1]);
});
return hitungLuasManual(latlngs).toFixed(2);
}
function hitungLuasManual(latlngs) {
// Shoelace formula aproximasi dalam meter persegi
const R = 6371000; // radius bumi meter
let area = 0;
let n = latlngs.length;
for (let i = 0; i < n; i++) {
let j = (i + 1) % n;
let xi = latlngs[i].lng * Math.PI / 180;
let yi = latlngs[i].lat * Math.PI / 180;
let xj = latlngs[j].lng * Math.PI / 180;
let yj = latlngs[j].lat * Math.PI / 180;
area += (xj - xi) * (2 + Math.sin(yi) + Math.sin(yj));
}
area = Math.abs(area) * R * R / 2;
return area;
}
function updateLine(id) {
let status = document.getElementById('status_' + id).value;
fetch('get_line.php')
.then(res => res.json())
.then(data => {
let d = data.find(item => item.id == id);
let coords = JSON.parse(d.coordinates);
let panjang = hitungPanjang(coords);
fetch('update_line.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
id: id,
status: status,
panjang: panjang
})
})
.then(() => {
alert("Data jalan berhasil diupdate!");
location.reload();
});
});
}
function updatePolygon(id) {
let status = document.getElementById('status_poly_' + id).value;
fetch('get_polygons.php')
.then(res => res.json())
.then(data => {
let d = data.find(item => item.id == id);
let coords = JSON.parse(d.coordinates);
let luas = hitungLuas(coords);
fetch('update_polygons.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
id: id,
status: status,
luas: luas
})
})
.then(() => {
alert("Status kavling berhasil diupdate!");
location.reload();
});
});
}
</script>
</body>
</html>
+20
View File
@@ -0,0 +1,20 @@
<?php
include 'db.php';
$data = json_decode(file_get_contents("php://input"));
$coords = json_encode($data->coordinates);
$status = $data->status;
$panjang = $data->panjang;
$sql = "INSERT INTO garis (coordinates, status, panjang)
VALUES ('$coords', '$status', '$panjang')";
$conn->query($sql);
echo json_encode([
"status"=>"ok",
"id"=>$conn->insert_id
]);
?>
+13
View File
@@ -0,0 +1,13 @@
<?php
include 'db.php';
$data = json_decode(file_get_contents("php://input"));
$coords = json_encode($data->coordinates);
$sql = "INSERT INTO polygons (coordinates) VALUES ('$coords')";
$conn->query($sql);
echo json_encode(["status"=>"ok"]);
?>
+14
View File
@@ -0,0 +1,14 @@
<?php
include 'db.php';
$data = json_decode(file_get_contents("php://input"));
$id = $data->id;
$status = $data->status;
$panjang = $data->panjang;
$conn->query("UPDATE garis
SET status='$status', panjang='$panjang'
WHERE id=$id");
echo json_encode(["status" => "success"]);
+14
View File
@@ -0,0 +1,14 @@
<?php
include 'db.php';
$data = json_decode(file_get_contents("php://input"));
$id = $data->id;
$status = $data->status;
$luas = $data->luas;
$conn->query("UPDATE polygons
SET status='$status', luas='$luas'
WHERE id=$id");
echo json_encode(["status" => "success"]);