Initial commit
This commit is contained in:
@@ -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: '© <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>
|
||||
```
|
||||
@@ -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: '© <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>
|
||||
@@ -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);
|
||||
}
|
||||
?>
|
||||
@@ -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"]);
|
||||
?>
|
||||
@@ -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"]);
|
||||
?>
|
||||
@@ -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);
|
||||
?>
|
||||
@@ -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);
|
||||
?>
|
||||
@@ -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: '© <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>
|
||||
@@ -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
|
||||
]);
|
||||
?>
|
||||
|
||||
@@ -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"]);
|
||||
?>
|
||||
@@ -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"]);
|
||||
@@ -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"]);
|
||||
@@ -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: '© <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>
|
||||
@@ -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);
|
||||
}
|
||||
?>
|
||||
@@ -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"]);
|
||||
?>
|
||||
@@ -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"]);
|
||||
?>
|
||||
@@ -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);
|
||||
?>
|
||||
@@ -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);
|
||||
?>
|
||||
@@ -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: '© <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>
|
||||
@@ -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
|
||||
]);
|
||||
?>
|
||||
|
||||
@@ -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"]);
|
||||
?>
|
||||
@@ -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"]);
|
||||
@@ -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"]);
|
||||
@@ -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: '© <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>
|
||||
@@ -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);
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
include 'db.php';
|
||||
|
||||
$id = $_GET['id'];
|
||||
|
||||
$conn->query("DELETE FROM spbu WHERE id=$id");
|
||||
|
||||
echo json_encode(["status"=>"deleted"]);
|
||||
?>
|
||||
@@ -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"]);
|
||||
?>
|
||||
@@ -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"]);
|
||||
?>
|
||||
@@ -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);
|
||||
?>
|
||||
@@ -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);
|
||||
?>
|
||||
@@ -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);
|
||||
?>
|
||||
@@ -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: '© <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>
|
||||
@@ -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
|
||||
]);
|
||||
?>
|
||||
|
||||
@@ -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"]);
|
||||
?>
|
||||
@@ -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"]);
|
||||
?>
|
||||
@@ -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";
|
||||
@@ -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"]);
|
||||
?>
|
||||
@@ -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"]);
|
||||
@@ -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
@@ -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
@@ -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 */;
|
||||
Reference in New Issue
Block a user