Initial commit
This commit is contained in:
@@ -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>
|
||||
Reference in New Issue
Block a user