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
+73
View File
@@ -0,0 +1,73 @@
<!DOCTYPE html>
<html lang="en">
<head>
<base target="_top">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Map - Universitas Tanjungpura</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;
padding: 0;
}
#map {
height: 100%;
width: 100%;
}
</style>
</head>
<body>
<div id="map"></div>
<script>
const map = L.map('map').setView([-0.0553, 109.3495], 16);
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([-0.0553, 109.3495]).addTo(map)
.bindPopup('<b>Tugu Bambu Runcing</b><br />Universitas Tanjungpura, Pontianak').openPopup();
const circle = L.circle([-0.0553, 109.3495], {
color: 'red',
fillColor: '#f03',
fillOpacity: 0.5,
radius: 100
}).addTo(map).bindPopup('Area Tugu Bambu Runcing');
const polygon = L.polygon([
[-0.0548, 109.3490],
[-0.0558, 109.3488],
[-0.0560, 109.3502]
]).addTo(map).bindPopup('Area Kampus Untan');
const popup = L.popup()
.setLatLng([-0.0553, 109.3495])
.setContent('Tugu Bambu Runcing - Untan')
.openOn(map);
function onMapClick(e) {
popup
.setLatLng(e.latlng)
.setContent(`Koordinat: ${e.latlng.toString()}`)
.openOn(map);
}
map.on('click', onMapClick);
</script>
</body>
</html>
```
+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"]);
+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);
?>
+292
View File
@@ -0,0 +1,292 @@
<!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%; }
#toolbar {
position: absolute;
z-index: 1000;
top: 10px;
left: 50px;
background: white;
padding: 8px 12px;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0,0,0,0.2);
display: flex;
gap: 6px;
}
#toolbar button {
padding: 6px 12px;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 13px;
background: #f0f0f0;
}
#toolbar button:hover { background: #ddd; }
#toolbar button.active { background: #007bff; color: white; }
</style>
</head>
<body>
<div id="toolbar">
<button id="btnLine" onclick="startLine()">✏️ Line</button>
<button id="btnPoly" 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);
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;
// ========== DRAWING ==========
map.on('click', function(e) {
if (!mode) return;
points.push([e.latlng.lat, e.latlng.lng]);
if (tempLayer) map.removeLayer(tempLayer);
if (mode === 'line') {
tempLayer = L.polyline(points, { color: 'blue', dashArray: '5,5' }).addTo(map);
} else if (mode === 'polygons') {
tempLayer = L.polygon(points, { color: 'green', dashArray: '5,5' }).addTo(map);
}
});
function startLine() {
mode = 'line';
points = [];
document.getElementById('btnLine').classList.add('active');
document.getElementById('btnPoly').classList.remove('active');
alert("Mode LINE aktif. Klik di peta untuk menambah titik.");
}
function startPolygons() {
mode = 'polygons';
points = [];
document.getElementById('btnPoly').classList.add('active');
document.getElementById('btnLine').classList.remove('active');
alert("Mode POLYGON aktif. Klik di peta untuk menambah titik.");
}
function resetShape() {
mode = null;
points = [];
if (tempLayer) { map.removeLayer(tempLayer); tempLayer = null; }
document.getElementById('btnLine').classList.remove('active');
document.getElementById('btnPoly').classList.remove('active');
}
function finishShape() {
if (!mode) { alert("Pilih mode Line atau Polygon terlebih dahulu!"); return; }
if (points.length < 2) { alert("Titik belum cukup!"); return; }
let currentType = mode;
let savedPoints = [...points];
let shape;
if (currentType === 'line') {
shape = L.polyline(savedPoints, { color: 'blue', weight: 4 }).addTo(map);
} else {
shape = L.polygon(savedPoints, { 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: savedPoints })
})
.then(res => res.json())
.then(res => {
let id = res.id;
if (currentType === 'line') {
let panjang = hitungPanjang(savedPoints);
shape.bindPopup(popupLine(id, '', panjang)).openPopup();
} else {
let luas = hitungLuas(savedPoints);
shape.bindPopup(popupPolygon(id, '', luas)).openPopup();
}
});
// Reset
mode = null; points = [];
if (tempLayer) { map.removeLayer(tempLayer); tempLayer = null; }
document.getElementById('btnLine').classList.remove('active');
document.getElementById('btnPoly').classList.remove('active');
}
// ========== POPUP ==========
function popupLine(id, status, panjang) {
return `
<div style="font-family:Arial;width:200px;">
<b>🛣️ Data Jalan</b><br><br>
<label style="font-size:12px;">Status Jalan:</label>
<select id="status_${id}" style="width:100%;padding:4px;margin:4px 0 8px;">
<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>
<div style="font-size:12px;margin-bottom:8px;">📏 Panjang: <b>${panjang} m</b></div>
<button onclick="updateLine(${id})" style="width:100%;padding:5px;background:#007bff;color:white;border:none;border-radius:5px;cursor:pointer;margin-bottom:4px;">✅ Update</button>
<button onclick="hapusShape(${id},'line')" style="width:100%;padding:5px;background:#dc3545;color:white;border:none;border-radius:5px;cursor:pointer;">🗑️ Hapus</button>
</div>`;
}
function popupPolygon(id, status, luas) {
return `
<div style="font-family:Arial;width:200px;">
<b>🏘️ Data Kavling</b><br><br>
<label style="font-size:12px;">Status Lahan:</label>
<select id="status_poly_${id}" style="width:100%;padding:4px;margin:4px 0 8px;">
<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>
<div style="font-size:12px;margin-bottom:8px;">📐 Luas: <b>${luas} m²</b></div>
<button onclick="updatePolygon(${id})" style="width:100%;padding:5px;background:#007bff;color:white;border:none;border-radius:5px;cursor:pointer;margin-bottom:4px;">✅ Update</button>
<button onclick="hapusShape(${id},'polygons')" style="width:100%;padding:5px;background:#dc3545;color:white;border:none;border-radius:5px;cursor:pointer;">🗑️ Hapus</button>
</div>`;
}
// ========== LOAD DATA ==========
function loadLines() {
fetch('get_line.php')
.then(res => res.json())
.then(data => {
data.forEach(d => {
let coords = JSON.parse(d.coordinates);
let color = getColorLine(d.status) || 'blue';
let panjang = hitungPanjang(coords);
L.polyline(coords, { color, weight: 4 }).addTo(map)
.bindPopup(popupLine(d.id, d.status, panjang));
});
});
}
function loadPolygons() {
fetch('get_polygons.php')
.then(res => res.json())
.then(data => {
data.forEach(d => {
let coords = normalizeCoords(JSON.parse(d.coordinates));
if (!Array.isArray(coords) || coords.length < 3) return;
let color = getColorPolygon(d.status) || 'green';
let luas = hitungLuas(coords);
L.polygon(coords, { color, fillOpacity: 0.4 }).addTo(map)
.bindPopup(popupPolygon(d.id, d.status, luas));
});
});
}
loadLines();
loadPolygons();
// ========== CRUD ==========
function hapusShape(id, type) {
if (!confirm("Yakin ingin menghapus?")) return;
fetch(type === 'line' ? 'delete_line.php' : 'delete_polygons.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ id })
}).then(() => location.reload());
}
function updateLine(id) {
let status = document.getElementById('status_' + id).value;
fetch('get_line.php').then(r => r.json()).then(data => {
let coords = JSON.parse(data.find(d => d.id == id).coordinates);
let panjang = hitungPanjang(coords);
fetch('update_line.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ id, status, 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(r => r.json()).then(data => {
let coords = normalizeCoords(JSON.parse(data.find(d => d.id == id).coordinates));
let luas = hitungLuas(coords);
fetch('update_polygons.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ id, status, luas })
}).then(() => { alert("Status kavling berhasil diupdate!"); location.reload(); });
});
}
// ========== HELPERS ==========
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 getColorLine(status) {
if (status === 'Nasional') return 'red';
if (status === 'Provinsi') return 'blue';
if (status === 'Kabupaten') return 'green';
return 'gray';
}
function getColorPolygon(status) {
if (status === 'SHM') return 'green';
if (status === 'HGB') return 'blue';
if (status === 'HGU') return 'orange';
if (status === 'HP') return 'purple';
return 'gray';
}
function hitungPanjang(points) {
let total = 0;
for (let i = 0; i < points.length - 1; i++) {
total += L.latLng(points[i]).distanceTo(L.latLng(points[i + 1]));
}
return total.toFixed(2);
}
function hitungLuas(points) {
if (!Array.isArray(points) || points.length < 3) return 0;
let latlngs = points.map(p => Array.isArray(p) ? L.latLng(p[0], p[1]) : L.latLng(p.lat, p.lng));
const R = 6371000;
let area = 0, n = latlngs.length;
for (let i = 0; i < n; i++) {
let j = (i + 1) % n;
let xi = latlngs[i].lng * Math.PI / 180, yi = latlngs[i].lat * Math.PI / 180;
let xj = latlngs[j].lng * Math.PI / 180, yj = latlngs[j].lat * Math.PI / 180;
area += (xj - xi) * (2 + Math.sin(yi) + Math.sin(yj));
}
return (Math.abs(area) * R * R / 2).toFixed(2);
}
</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"]);
+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);
}
?>
+9
View File
@@ -0,0 +1,9 @@
<?php
include 'db.php';
$id = $_GET['id'];
$conn->query("DELETE FROM spbu 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 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 spbu");
$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 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);
?>
+611
View File
@@ -0,0 +1,611 @@
<!DOCTYPE html>
<html lang="en">
<head>
<base target="_top">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Map SPBU</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;
}
#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);
let layer24 = L.layerGroup();
let layerNon24 = L.layerGroup();
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([-0.055326, 109.349500]).addTo(map)
.bindPopup('<b>Hello world!</b><br />I am a popup.').openPopup();
const circle = L.circle([-0.055326, 109.349500], {
color: 'red',
fillColor: '#f03',
fillOpacity: 0.5,
radius: 200
}).addTo(map).bindPopup('I am a circle.');
const polygon = L.polygon([
[-0.054817, 109.349522],
[-0.055520, 109.349915],
[-0.055349, 109.348959]
]).addTo(map).bindPopup('I am a polygon.');
let mode = null;
let points = [];
let tempLayer = null;
let shapes = [];
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);
}
} else {
tampilForm('tambah', e.latlng.lat, e.latlng.lng);
}
});
// LOAD DATA
function loadData() {
fetch('get.php')
.then(res => res.json())
.then(data => {
data.forEach(d => {
let marker = L.marker([d.lat, d.lng]);
if (d.buka_24jam === 'Ya') {
marker.addTo(layer24);
} else {
marker.addTo(layerNon24);
}
marker.bindPopup(`
<div class="popup-card">
<div class="popup-title">⛽ ${d.nama}</div>
<div class="popup-item">📞 ${d.no_hp}</div>
<div class="popup-item">
🕒 24 Jam:
<span class="badge ${d.buka_24jam === 'Ya' ? 'green' : 'red'}">
${d.buka_24jam}
</span>
</div>
<div class="popup-item">
🔥 Ramai:
<span class="badge ${d.ramai === 'Ya' ? 'green' : 'red'}">
${d.ramai}
</span>
</div>
<div style="display:flex; gap:5px; margin-top:8px;">
<button class="popup-btn" style="background:#ffc107;"
onclick="editData(${d.id}, '${d.nama}', '${d.no_hp}', '${d.buka_24jam}', '${d.ramai}', ${d.lat}, ${d.lng})">
✏️ Edit
</button>
<button class="popup-btn" style="background:#dc3545;"
onclick="hapus(${d.id})">
🗑️ Hapus
</button>
</div>
</div>
`);
});
});
}
// CLICK MAP → INPUT
function tampilForm(mode, lat, lng, data = null) {
let isEdit = mode === 'edit';
let form = `
<div class="form-card">
<div class="form-title">
${isEdit ? '✏️ Edit SPBU' : ' Tambah SPBU'}
</div>
<div class="form-group">
<label>Nama</label>
<input id="nama" value="${data ? data.nama : ''}">
</div>
<div class="form-group">
<label>No HP</label>
<input id="no_hp" value="${data ? data.no_hp : ''}">
</div>
<div class="form-group">
<label>24 Jam</label>
<select id="buka">
<option ${data?.buka_24jam === 'Ya' ? 'selected' : ''}>Ya</option>
<option ${data?.buka_24jam === 'Tidak' ? 'selected' : ''}>Tidak</option>
</select>
</div>
<div class="form-group">
<label>Ramai</label>
<select id="ramai">
<option ${data?.ramai === 'Ya' ? 'selected' : ''}>Ya</option>
<option ${data?.ramai === 'Tidak' ? 'selected' : ''}>Tidak</option>
</select>
</div>
<button class="form-btn ${isEdit ? 'btn-update' : 'btn-save'}"
onclick="${isEdit
? `updateData(${data.id})`
: `simpan(${lat}, ${lng})`}">
${isEdit ? 'Update' : 'Simpan'}
</button>
</div>
`;
L.popup()
.setLatLng([lat, lng])
.setContent(form)
.openOn(map);
}
// SIMPAN
function simpan(lat, lng) {
let data = {
nama: document.getElementById('nama').value,
no_hp: document.getElementById('no_hp').value,
buka_24jam: document.getElementById('buka').value,
ramai: document.getElementById('ramai').value,
lat: lat,
lng: lng
};
fetch('tambah.php', {
method: 'POST',
body: JSON.stringify(data)
})
.then(() => location.reload());
}
// DELETE
function hapus(id) {
fetch('delete.php?id=' + id)
.then(() => location.reload());
}
function editData(id, nama, no_hp, buka, ramai, lat, lng) {
let data = {
id: id,
nama: nama,
no_hp: no_hp,
buka_24jam: buka,
ramai: ramai
};
tampilForm('edit', lat, lng, data);
}
function updateData(id) {
let data = {
id: id,
nama: document.getElementById('nama').value,
no_hp: document.getElementById('no_hp').value,
buka_24jam: document.getElementById('buka').value,
ramai: document.getElementById('ramai').value
};
fetch('update.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
})
.then(res => res.text())
.then(res => {
alert("Data berhasil diupdate!");
location.reload();
});
}
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; // 🔥 SIMPAN DULU
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 {
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>
<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 loadPolygons() {
fetch('get_polygons.php')
.then(res => res.json())
.then(data => {
data.forEach(d => {
let coords = JSON.parse(d.coordinates);
let color = getColorPolygon(d.status) || 'green';
let polygon = L.polygon(coords, {
color: color,
fillOpacity: 0.4
}).addTo(map);
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>
<button onclick="updatePolygon(${d.id})">✅ OK</button>
<button onclick="hapusShape(${d.id}, 'polygons')">🗑️ Hapus</button>
`);
});
});
}
loadData();
loadLines();
loadPolygons();
layer24.addTo(map);
layerNon24.addTo(map);
L.control.layers(null, {
"SPBU 24 Jam": layer24,
"SPBU Tidak 24 Jam": layerNon24
}).addTo(map);
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 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('update_polygons.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
id: id,
status: status
})
})
.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"]);
?>
+12
View File
@@ -0,0 +1,12 @@
<?php
include 'db.php';
$data = json_decode(file_get_contents("php://input"));
$sql = "INSERT INTO spbu (nama, no_hp, lat, lng, buka_24jam, ramai)
VALUES ('$data->nama', '$data->no_hp', '$data->lat', '$data->lng', '$data->buka_24jam', '$data->ramai')";
$conn->query($sql);
echo json_encode(["status"=>"ok"]);
?>
+22
View File
@@ -0,0 +1,22 @@
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
echo "<pre>";
var_dump(mysqli_get_client_info());
$conn = mysqli_connect(
"127.0.0.1",
"root",
"",
"spbu_db",
3307
);
if (!$conn) {
die(mysqli_connect_error());
}
echo "BERHASIL";
+16
View File
@@ -0,0 +1,16 @@
<?php
include 'db.php';
$data = json_decode(file_get_contents("php://input"));
$sql = "UPDATE spbu SET
nama='$data->nama',
no_hp='$data->no_hp',
buka_24jam='$data->buka_24jam',
ramai='$data->ramai'
WHERE id=$data->id";
$conn->query($sql);
echo json_encode(["status"=>"updated"]);
?>
+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"]);
+233
View File
@@ -0,0 +1,233 @@
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Tugas Pemrograman Web</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap" rel="stylesheet" />
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--bg: #f7f7f5;
--surface: #ffffff;
--border: #e4e2db;
--border-hover: #c8c5bc;
--text-primary: #1a1a18;
--text-secondary: #6b6b65;
--text-muted: #9b9b94;
--badge-db-bg: #e6f4ed;
--badge-db-text: #1d6b3e;
--badge-no-bg: #e8f0fb;
--badge-no-text: #1a4ea0;
--accent-1: #ddeeff;
--accent-1-icon: #1a6bc0;
--accent-2: #d8f4e8;
--accent-2-icon: #1a7a45;
--accent-3: #fef3d8;
--accent-3-icon: #9a6500;
--accent-4: #fce8e8;
--accent-4-icon: #b83232;
}
body {
font-family: 'Inter', sans-serif;
background: var(--bg);
color: var(--text-primary);
min-height: 100vh;
padding: 48px 24px 80px;
}
.container {
max-width: 860px;
margin: 0 auto;
}
.eyebrow {
font-size: 11px;
font-weight: 600;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--text-muted);
margin-bottom: 8px;
}
h1 {
font-size: 28px;
font-weight: 600;
color: var(--text-primary);
margin-bottom: 8px;
letter-spacing: -0.02em;
}
.subtitle {
font-size: 15px;
color: var(--text-secondary);
margin-bottom: 40px;
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
gap: 14px;
}
.card {
display: block;
text-decoration: none;
background: var(--surface);
border: 1px solid var(--border);
border-radius: 14px;
padding: 20px;
transition: border-color 0.18s, transform 0.15s;
}
.card:hover {
border-color: var(--border-hover);
transform: translateY(-2px);
}
.icon-wrap {
width: 40px;
height: 40px;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 16px;
}
.icon-wrap svg {
width: 20px;
height: 20px;
}
.card-label {
font-size: 10px;
font-weight: 600;
letter-spacing: 0.06em;
text-transform: uppercase;
color: var(--text-muted);
margin-bottom: 5px;
}
.card-title {
font-size: 15px;
font-weight: 600;
color: var(--text-primary);
line-height: 1.4;
margin-bottom: 10px;
}
.card-desc {
font-size: 13px;
color: var(--text-secondary);
line-height: 1.6;
margin-bottom: 16px;
}
.badge {
display: inline-block;
font-size: 11px;
font-weight: 500;
padding: 3px 9px;
border-radius: 6px;
}
.badge-db { background: var(--badge-db-bg); color: var(--badge-db-text); }
.badge-no { background: var(--badge-no-bg); color: var(--badge-no-text); }
.footer-note {
margin-top: 28px;
font-size: 13px;
color: var(--text-muted);
display: flex;
align-items: center;
gap: 6px;
}
.dot {
width: 5px; height: 5px;
border-radius: 50%;
background: var(--border-hover);
display: inline-block;
}
@media (max-width: 500px) {
.grid { grid-template-columns: 1fr; }
h1 { font-size: 22px; }
}
</style>
</head>
<body>
<div class="container">
<p class="eyebrow">Mata Kuliah</p>
<h1>Pemrograman Web</h1>
<p class="subtitle">Kumpulan tugas praktikum — WebGIS berbasis Leaflet.js</p>
<div class="grid">
<a href="Pertemuan01/" class="card">
<div class="icon-wrap" style="background: var(--accent-1);">
<svg viewBox="0 0 24 24" fill="none" stroke="var(--accent-1-icon)" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
<path d="M12 21c-4-4-7-7.5-7-11a7 7 0 0 1 14 0c0 3.5-3 7-7 11z"/>
<circle cx="12" cy="10" r="2.5"/>
</svg>
</div>
<p class="card-label">Pertemuan 01</p>
<p class="card-title">Peta Leaflet dengan Titik Lokasi UNTAN</p>
<p class="card-desc">Implementasi peta interaktif menggunakan Leaflet.js, marker default dipindah ke koordinat Universitas Tanjungpura.</p>
<span class="badge badge-no">Tanpa Database</span>
</a>
<a href="Pertemuan02/" class="card">
<div class="icon-wrap" style="background: var(--accent-2);">
<svg viewBox="0 0 24 24" fill="none" stroke="var(--accent-2-icon)" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
<polygon points="3,19 9,5 15,15 19,9 21,19"/>
</svg>
</div>
<p class="card-label">Pertemuan 02</p>
<p class="card-title">Menggambar Line dan Polygon pada Peta</p>
<p class="card-desc">Menambahkan fitur menggambar garis dan area poligon di atas peta, dengan data disimpan ke database.</p>
<span class="badge badge-db">Dengan Database</span>
</a>
<a href="Pertemuan03/" class="card">
<div class="icon-wrap" style="background: var(--accent-3);">
<svg viewBox="0 0 24 24" fill="none" stroke="var(--accent-3-icon)" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
<path d="M12 20h9"/>
<path d="M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z"/>
</svg>
</div>
<p class="card-label">Pertemuan 03</p>
<p class="card-title">Atribut Jenis pada Line dan Polygon</p>
<p class="card-desc">Pengembangan pertemuan 2 — setiap line dan polygon kini bisa diisi keterangan jenisnya saat disimpan ke database.</p>
<span class="badge badge-db">Dengan Database</span>
</a>
<a href="Pertemuan04/" class="card">
<div class="icon-wrap" style="background: var(--accent-4);">
<svg viewBox="0 0 24 24" fill="none" stroke="var(--accent-4-icon)" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
<path d="M3 6l3 1m0 0l-3 9a5 5 0 0 0 6.98.99M6 7l3.99 12M6 7l6-2m6 2l3-1m-3 1l-3.99 12a5 5 0 0 1-6.98.99M17 7l-6-2m0 0l-1 3"/>
</svg>
</div>
<p class="card-label">Pertemuan 04</p>
<p class="card-title">Layer SPBU: Titik, 24 Jam & Non-24 Jam</p>
<p class="card-desc">Menambahkan titik SPBU ke peta dengan dua layer terpisah — buka 24 jam dan tidak — yang bisa ditampilkan/disembunyikan.</p>
<span class="badge badge-db">Dengan Database</span>
</a>
</div>
<p class="footer-note">
4 pertemuan
<span class="dot"></span>
1 database bersama
<span class="dot"></span>
Leaflet.js
</p>
</div>
</body>
</html>
+141
View File
@@ -0,0 +1,141 @@
-- phpMyAdmin SQL Dump
-- version 5.2.1
-- https://www.phpmyadmin.net/
--
-- Host: 127.0.0.1:3307
-- Waktu pembuatan: 11 Jun 2026 pada 15.19
-- Versi server: 10.4.32-MariaDB
-- Versi PHP: 8.2.12
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
START TRANSACTION;
SET time_zone = "+00:00";
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8mb4 */;
--
-- Database: `spbu_db`
--
-- --------------------------------------------------------
--
-- Struktur dari tabel `garis`
--
CREATE TABLE `garis` (
`id` int(11) NOT NULL,
`coordinates` text DEFAULT NULL,
`status` varchar(50) DEFAULT NULL,
`panjang` double DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
--
-- Dumping data untuk tabel `garis`
--
INSERT INTO `garis` (`id`, `coordinates`, `status`, `panjang`) VALUES
(4, '[[-0.042614932899552066,109.33897376060487],[-0.042057033576748226,109.33959603309631],[-0.042057033576748226,109.33959603309631]]', 'Kabupaten', 92.93),
(5, '[[-0.015707015794464818,109.36280250549318],[-0.024976729555612715,109.36254501342775],[-0.02901077146547321,109.36160087585449],[-0.0321006758108682,109.36005592346193],[-0.03424644266299124,109.35670852661133],[-0.03716468550421756,109.3517303466797],[-0.04128455758476972,109.34580802917482],[-0.042057033576748226,109.34494972229005],[-0.04626273606199181,109.34237480163576],[-0.04626273606199181,109.34237480163576]]', 'Provinsi', 4438.68),
(6, '[[-0.03716468550421756,109.33499336242677],[-0.034332273336096036,109.3383836746216]]', '', 0);
-- --------------------------------------------------------
--
-- Struktur dari tabel `polygons`
--
CREATE TABLE `polygons` (
`id` int(11) NOT NULL,
`coordinates` text DEFAULT NULL,
`status` varchar(50) DEFAULT NULL,
`luas` double DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
--
-- Dumping data untuk tabel `polygons`
--
INSERT INTO `polygons` (`id`, `coordinates`, `status`, `luas`) VALUES
(1, '[[-0.04107954850956947,109.33617889881135],[-0.04164247166797875,109.3359696865082],[-0.04186764093026616,109.33652758598329],[-0.04134224598402135,109.33674216270448],[-0.04131007894636634,109.33674216270448]]', 'HGB', 4522.78),
(2, '{\"type\":\"Polygon\",\"coordinates\":[[[109.33680653572083,-0.04155339471819016],[109.33666706085206,-0.04182145336393277],[109.33696746826173,-0.04200373324252326],[109.33707475662233,-0.0417463969431915]]]}', NULL, NULL),
(3, '[[-0.04349469720803964,109.34812545776369],[-0.04461049582840643,109.34726715087892],[-0.04619836306659037,109.34941291809082],[-0.04510402213589856,109.3502712249756]]', NULL, NULL);
-- --------------------------------------------------------
--
-- Struktur dari tabel `spbu`
--
CREATE TABLE `spbu` (
`id` int(11) NOT NULL,
`nama` varchar(100) DEFAULT NULL,
`no_hp` varchar(20) DEFAULT NULL,
`buka_24jam` varchar(10) DEFAULT NULL,
`ramai` varchar(10) DEFAULT NULL,
`lat` double DEFAULT NULL,
`lng` double DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
--
-- Dumping data untuk tabel `spbu`
--
INSERT INTO `spbu` (`id`, `nama`, `no_hp`, `buka_24jam`, `ramai`, `lat`, `lng`) VALUES
(1, 'SPBU 1', '001', 'Tidak', 'Ya', -0.044906177737876, 109.3367421627),
(2, 'SPBU Imam Bonjol', '002', 'Ya', 'Ya', -0.046984846560675, 109.35455739498),
(3, 'SPBU Paris 1', '003', 'Ya', 'Ya', -0.055442708104727, 109.36264157295),
(4, 'SPBU Ahmad Yani', '004', 'Tidak', 'Ya', -0.064348204151511, 109.35621500015);
--
-- Indexes for dumped tables
--
--
-- Indeks untuk tabel `garis`
--
ALTER TABLE `garis`
ADD PRIMARY KEY (`id`);
--
-- Indeks untuk tabel `polygons`
--
ALTER TABLE `polygons`
ADD PRIMARY KEY (`id`);
--
-- Indeks untuk tabel `spbu`
--
ALTER TABLE `spbu`
ADD PRIMARY KEY (`id`);
--
-- AUTO_INCREMENT untuk tabel yang dibuang
--
--
-- AUTO_INCREMENT untuk tabel `garis`
--
ALTER TABLE `garis`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=7;
--
-- AUTO_INCREMENT untuk tabel `polygons`
--
ALTER TABLE `polygons`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=4;
--
-- AUTO_INCREMENT untuk tabel `spbu`
--
ALTER TABLE `spbu`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=5;
COMMIT;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;