Files
webgis-spbu/assets/js/map.js
T
2026-06-11 03:02:00 +07:00

1073 lines
22 KiB
JavaScript

let currentMarker = null;
let userMarker = null;
let userLat = null;
let userLng = null;
let markerData = {};
let routingControl = null;
let modeAdmin = true;
let currentObjekLayer = null;
let sedangMenggambar = false;
const markerHijau = new L.Icon({
iconUrl:
"https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-green.png",
shadowUrl:
"https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-shadow.png",
iconSize: [25, 41],
iconAnchor: [12, 41],
});
const markerMerah = new L.Icon({
iconUrl:
"https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-red.png",
shadowUrl:
"https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-shadow.png",
iconSize: [25, 41],
iconAnchor: [12, 41],
});
// 1. Inisialisasi Peta
let map = L.map("map").setView([-0.0263, 109.3425], 13);
L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png").addTo(map);
let markerGroup = L.layerGroup().addTo(map);
let drawnItems = new L.FeatureGroup();
map.addLayer(drawnItems);
let drawControl = new L.Control.Draw({
draw: {
marker: false,
polyline: true,
polygon: true,
rectangle: false,
circle: false,
circlemarker: false,
},
edit: {
featureGroup: drawnItems,
},
});
map.addControl(drawControl);
// TAMBAH DI SINI
map.on(L.Draw.Event.DRAWSTART, function () {
sedangMenggambar = true;
});
map.on(L.Draw.Event.DRAWSTOP, function () {
sedangMenggambar = false;
});
console.log("draw berhasil");
// 2. Load Marker Dari Database
loadSPBU();
loadObjekPeta();
function loadSPBU() {
markerGroup.clearLayers();
markerData = {};
currentMarker = null;
fetch("api/get_spbu.php")
.then((res) => res.json())
.then((data) => {
data.forEach((spbu) => {
let marker = L.marker([spbu.latitude, spbu.longitude], {
icon: spbu.buka_24_jam == 1 ? markerHijau : markerMerah,
draggable: false,
}).addTo(markerGroup);
marker.spbuData = spbu;
markerData[spbu.id] = marker;
marker.on("dragend", function () {
let pos = marker.getLatLng();
let latInput = document.getElementById("edit_lat");
let lngInput = document.getElementById("edit_lng");
if (latInput && lngInput) {
latInput.value = pos.lat;
lngInput.value = pos.lng;
}
alert("Posisi marker berubah, klik Simpan untuk menyimpan perubahan");
});
marker.bindPopup(`
<div class="w-56">
${
spbu.foto
? `
<img
src="uploads/spbu/${spbu.foto}?t=${Date.now()}"
class="w-full h-32 object-cover rounded mb-2">
`
: ""
}
<h3 class="font-bold text-lg">
${spbu.nama_spbu}
</h3>
<p class="mb-2">
${spbu.alamat}
</p>
<p class="mt-2">
Status :
${statusSPBU(spbu)}
</p>
<p>
Jam :
${spbu.buka_24_jam == 1 ? "24 Jam" : spbu.jam_buka + " - " + spbu.jam_tutup}
</p>
<p class="text-xs">
Lat : ${spbu.latitude}
</p>
<p class="text-xs mb-2">
Lng : ${spbu.longitude}
</p>
${
modeAdmin
? `
<div class="flex gap-2 mt-2">
<button
onclick="openEditById(${spbu.id})"
class="bg-yellow-500 text-white px-3 py-1 rounded">
Edit
</button>
<button
onclick="hapusSPBU(${spbu.id})"
class="bg-red-500 text-white px-3 py-1 rounded">
Hapus
</button>
</div>
`
: ""
}
</div>
`);
});
});
}
function statusSPBU(spbu) {
if (spbu.buka_24_jam == 1) {
return `
<span class="text-green-600 font-bold">
BUKA 24 JAM
</span>
`;
}
if (!spbu.jam_buka || !spbu.jam_tutup) {
return `
<span class="text-gray-500">
Jam belum diatur
</span>
`;
}
let now = new Date().toTimeString().substring(0, 5);
let buka = spbu.jam_buka.substring(0, 5);
let tutup = spbu.jam_tutup.substring(0, 5);
let bukaStatus = false;
if (buka < tutup) {
bukaStatus = now >= buka && now <= tutup;
} else {
bukaStatus = now >= buka || now <= tutup;
}
return bukaStatus
? `<span class="text-green-600 font-bold">BUKA</span>`
: `<span class="text-red-600 font-bold">TUTUP</span>`;
}
map.on("click", function (e) {
if (!modeAdmin) {
return;
}
if (sedangMenggambar) {
return;
}
if (
map._container.classList.contains("leaflet-draw-draw-polygon") ||
map._container.classList.contains("leaflet-draw-draw-polyline")
) {
return;
}
let lat = e.latlng.lat;
let lng = e.latlng.lng;
L.popup()
.setLatLng(e.latlng)
.setContent(
`
<div class="w-64">
<h3 class="font-bold mb-3">
Tambah SPBU
</h3>
<input
id="nama"
type="text"
placeholder="Nama SPBU"
class="border p-2 w-full mb-2 rounded">
<textarea
id="alamat"
placeholder="Alamat"
class="border p-2 w-full mb-2 rounded"></textarea>
<input
id="lat"
value="${lat}"
readonly
class="border p-2 w-full mb-2 rounded">
<input
id="lng"
value="${lng}"
readonly
class="border p-2 w-full mb-2 rounded">
<label class="block mb-1">
Jam Buka
</label>
<input
type="time"
id="jam_buka"
class="border p-2 w-full mb-2 rounded">
<label class="block mb-1">
Jam Tutup
</label>
<input
type="time"
id="jam_tutup"
class="border p-2 w-full mb-2 rounded">
<label
class="flex items-center gap-2 mb-2">
<input
type="checkbox"
id="buka_24_jam">
Buka 24 Jam
</label>
<input
type="file"
id="foto"
class="border p-2 w-full mb-2 rounded">
<img
id="previewFoto"
class="hidden w-full h-32 object-cover rounded mb-2">
<button
onclick="simpanSPBU()"
class="bg-green-500 text-white px-3 py-2 rounded w-full">
Simpan
</button>
</div>
`,
)
.openOn(map);
});
document.addEventListener("change", function (e) {
if (e.target.id !== "buka_24_jam") return;
let checked = e.target.checked;
document.getElementById("jam_buka").disabled = checked;
document.getElementById("jam_tutup").disabled = checked;
});
function simpanSPBU() {
let nama = document.getElementById("nama").value;
let alamat = document.getElementById("alamat").value;
let lat = document.getElementById("lat").value;
let lng = document.getElementById("lng").value;
let formData = new FormData();
formData.append("nama", nama);
formData.append("alamat", alamat);
formData.append("lat", lat);
formData.append("lng", lng);
let jamBuka = document.getElementById("jam_buka").value;
let jamTutup = document.getElementById("jam_tutup").value;
let buka24Jam = document.getElementById("buka_24_jam").checked ? 1 : 0;
formData.append("jam_buka", jamBuka);
formData.append("jam_tutup", jamTutup);
formData.append("buka_24_jam", buka24Jam);
let foto = document.getElementById("foto");
if (foto && foto.files.length > 0) {
formData.append("foto", foto.files[0]);
}
fetch("api/tambah_spbu.php", {
method: "POST",
body: formData,
})
.then((res) => res.json())
.then((data) => {
if (data.status == "success") {
alert("Data berhasil disimpan");
map.closePopup();
loadSPBU();
loadObjekPeta();
}
});
}
function openEdit(spbu) {
if (!modeAdmin) {
return;
}
if (currentMarker) {
currentMarker.dragging.disable();
}
document.getElementById("sidebar").classList.remove("hidden");
document.getElementById("edit_id").value = spbu.id;
document.getElementById("edit_nama").value = spbu.nama_spbu;
document.getElementById("edit_alamat").value = spbu.alamat;
document.getElementById("edit_foto").value = "";
let preview = document.getElementById("preview_edit_foto");
if (spbu.foto) {
preview.src = "uploads/spbu/" + spbu.foto + "?t=" + Date.now();
preview.classList.remove("hidden");
} else {
preview.src = "";
preview.classList.add("hidden");
}
document.getElementById("edit_jam_buka").value = spbu.jam_buka || "";
document.getElementById("edit_jam_tutup").value = spbu.jam_tutup || "";
document.getElementById("edit_24jam").checked = spbu.buka_24_jam == 1;
document.getElementById("edit_jam_buka").disabled = spbu.buka_24_jam == 1;
document.getElementById("edit_jam_tutup").disabled = spbu.buka_24_jam == 1;
document.getElementById("edit_lat").value = spbu.latitude;
document.getElementById("edit_lng").value = spbu.longitude;
currentMarker = markerData[spbu.id];
if (currentMarker) {
currentMarker.dragging.enable();
}
}
function openEditById(id) {
if (!modeAdmin) {
return;
}
let marker = markerData[id];
if (!marker) return;
openEdit(marker.spbuData);
}
function tutupSidebar() {
document.getElementById("sidebar").classList.add("hidden");
if (currentMarker) {
currentMarker.dragging.disable();
}
currentMarker = null;
}
function updateSPBU() {
if (!modeAdmin) {
return;
}
let formData = new FormData();
formData.append("id", document.getElementById("edit_id").value);
formData.append("nama", document.getElementById("edit_nama").value);
formData.append("alamat", document.getElementById("edit_alamat").value);
formData.append("lat", document.getElementById("edit_lat").value);
formData.append("lng", document.getElementById("edit_lng").value);
let foto = document.getElementById("edit_foto");
if (foto.files.length > 0) {
formData.append("foto", foto.files[0]);
}
formData.append("jam_buka", document.getElementById("edit_jam_buka").value);
formData.append("jam_tutup", document.getElementById("edit_jam_tutup").value);
formData.append(
"buka_24_jam",
document.getElementById("edit_24jam").checked ? 1 : 0,
);
fetch("api/edit_spbu.php", {
method: "POST",
body: formData,
})
.then((res) => res.json())
.then((data) => {
if (data.status == "success") {
alert("Data berhasil diperbarui");
tutupSidebar();
loadSPBU();
loadObjekPeta();
}
});
}
function hapusSPBU(id) {
if (!modeAdmin) {
return;
}
if (!confirm("Yakin hapus data ini?")) {
return;
}
fetch("api/hapus_spbu.php", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
id: id,
}),
})
.then((res) => res.json())
.then((data) => {
if (data.status == "success") {
alert("Data berhasil dihapus");
loadSPBU();
loadObjekPeta();
}
});
}
document.addEventListener("keyup", function (e) {
if (e.target.id !== "search_spbu") return;
let keyword = e.target.value.toLowerCase();
markerGroup.eachLayer(function (marker) {
let nama = (marker.spbuData.nama_spbu || "").toLowerCase();
if (nama.includes(keyword)) {
map.setView(marker.getLatLng(), 18);
marker.openPopup();
}
});
});
function cariSPBU() {
let keyword = document.getElementById("search_spbu").value.toLowerCase();
let ditemukan = false;
markerGroup.eachLayer(function (marker) {
let nama = (marker.spbuData.nama_spbu || "").toLowerCase();
if (nama.includes(keyword)) {
ditemukan = true;
map.setView(marker.getLatLng(), 18);
marker.openPopup();
}
});
if (!ditemukan) {
alert("SPBU tidak ditemukan");
}
}
function lokasiSaya() {
if (!navigator.geolocation) {
alert("Browser tidak mendukung geolocation");
return;
}
navigator.geolocation.getCurrentPosition(
function (position) {
let lat = position.coords.latitude;
let lng = position.coords.longitude;
userLat = lat;
userLng = lng;
if (userMarker) {
map.removeLayer(userMarker);
}
userMarker = L.circleMarker([lat, lng], {
radius: 10,
color: "#2563eb",
fillColor: "#2563eb",
fillOpacity: 1,
}).addTo(map);
userMarker.bindPopup(`
<b>Lokasi Anda</b>
<br>
Lat : ${lat}
<br>
Lng : ${lng}
`);
userMarker.openPopup();
map.setView([lat, lng], 16);
},
function () {
alert("Lokasi tidak dapat diakses");
},
);
}
function hitungJarak(lat1, lon1, lat2, lon2) {
const R = 6371;
const dLat = ((lat2 - lat1) * Math.PI) / 180;
const dLon = ((lon2 - lon1) * Math.PI) / 180;
const a =
Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos((lat1 * Math.PI) / 180) *
Math.cos((lat2 * Math.PI) / 180) *
Math.sin(dLon / 2) *
Math.sin(dLon / 2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return R * c;
}
function cariTerdekat() {
if (userLat === null) {
alert("Klik Lokasi Saya terlebih dahulu");
return;
}
let terdekat = null;
let jarakMin = Infinity;
markerGroup.eachLayer(function (marker) {
let lat = marker.getLatLng().lat;
let lng = marker.getLatLng().lng;
let jarak = hitungJarak(userLat, userLng, lat, lng);
if (jarak < jarakMin) {
jarakMin = jarak;
terdekat = marker;
}
});
if (terdekat) {
map.setView(terdekat.getLatLng(), 18);
terdekat.openPopup();
alert(
"SPBU terdekat: " +
terdekat.spbuData.nama_spbu +
"\nJarak: " +
jarakMin.toFixed(2) +
" km",
);
}
}
function getMarkerTerdekat() {
let terdekat = null;
let jarakMin = Infinity;
markerGroup.eachLayer(function (marker) {
let lat = marker.getLatLng().lat;
let lng = marker.getLatLng().lng;
let jarak = hitungJarak(userLat, userLng, lat, lng);
if (jarak < jarakMin) {
jarakMin = jarak;
terdekat = marker;
}
});
return terdekat;
}
function buatRuteTerdekat() {
if (userLat === null) {
alert("Klik Lokasi Saya terlebih dahulu");
return;
}
let marker = getMarkerTerdekat();
if (!marker) {
alert("Tidak ada SPBU ditemukan");
return;
}
if (routingControl) {
map.removeControl(routingControl);
}
routingControl = L.Routing.control({
show: false,
collapsible: true,
waypoints: [
L.latLng(userLat, userLng),
L.latLng(marker.getLatLng().lat, marker.getLatLng().lng),
],
router: L.Routing.osrmv1({
serviceUrl: "https://router.project-osrm.org/route/v1",
}),
routeWhileDragging: false,
addWaypoints: false,
draggableWaypoints: false,
}).addTo(map);
}
document.addEventListener("change", function (e) {
if (e.target.id !== "foto") return;
let file = e.target.files[0];
if (!file) return;
let preview = document.getElementById("previewFoto");
preview.src = URL.createObjectURL(file);
preview.classList.remove("hidden");
});
document.addEventListener("change", function (e) {
if (e.target.id !== "edit_foto") return;
let file = e.target.files[0];
if (!file) return;
let preview = document.getElementById("preview_edit_foto");
preview.src = URL.createObjectURL(file);
preview.classList.remove("hidden");
});
document.addEventListener("change", function (e) {
if (e.target.id !== "edit_24jam") return;
let checked = e.target.checked;
document.getElementById("edit_jam_buka").disabled = checked;
document.getElementById("edit_jam_tutup").disabled = checked;
});
function isBuka(spbu) {
if (spbu.buka_24_jam == 1) {
return true;
}
if (!spbu.jam_buka || !spbu.jam_tutup) {
return false;
}
let now = new Date().toTimeString().substring(0, 5);
let buka = spbu.jam_buka.substring(0, 5);
let tutup = spbu.jam_tutup.substring(0, 5);
if (buka < tutup) {
return now >= buka && now <= tutup;
}
return now >= buka || now <= tutup;
}
function filterSPBU() {
let filter = document.getElementById("filter_spbu").value;
markerGroup.clearLayers();
Object.values(markerData).forEach(function (marker) {
let spbu = marker.spbuData;
let tampil = false;
if (filter == "all") {
tampil = true;
}
if (filter == "24" && spbu.buka_24_jam == 1) {
tampil = true;
}
if (filter == "non24" && spbu.buka_24_jam == 0) {
tampil = true;
}
if (filter == "buka" && isBuka(spbu)) {
tampil = true;
}
if (filter == "tutup" && !isBuka(spbu)) {
tampil = true;
}
if (tampil) {
marker.addTo(markerGroup);
}
});
}
function toggleMode() {
modeAdmin = !modeAdmin;
let btn = document.getElementById("btnMode");
let banner = document.getElementById("bannerMode");
if (modeAdmin) {
banner.classList.add("hidden");
btn.innerHTML = "Pindah ke Mode Lihat";
btn.classList.remove("bg-green-600");
btn.classList.add("bg-blue-600");
status.className =
"bg-blue-100 text-blue-700 px-3 py-2 rounded font-semibold";
} else {
banner.classList.remove("hidden");
btn.innerHTML = "Masuk Mode Admin";
btn.classList.remove("bg-blue-600");
btn.classList.add("bg-yellow-600");
status.innerHTML = "View";
status.className =
"bg-yellow-100 text-yellow-700 px-3 py-2 rounded font-semibold";
tutupSidebar();
map.closePopup();
}
loadSPBU();
loadObjekPeta();
updateModeUI();
}
function updateModeUI() {
let status = document.getElementById("statusMode");
let banner = document.getElementById("bannerMode");
if (modeAdmin) {
status.innerHTML = "🔓 ADMIN";
banner.classList.add("hidden");
} else {
status.innerHTML = "👁️ VIEW";
banner.classList.remove("hidden");
}
}
function loadObjekPeta() {
fetch("api/get_objek.php")
.then((res) => res.json())
.then((data) => {
drawnItems.clearLayers();
data.forEach((obj) => {
let geo = JSON.parse(obj.geojson);
let layer = L.geoJSON(geo);
layer.eachLayer(function (l) {
l.objekId = obj.id;
l.on("click", function (e) {
L.DomEvent.stopPropagation(e);
l.bindPopup(`
<b>${obj.nama || "-"}</b>
<br>
${obj.deskripsi || "-"}
`);
l.openPopup();
});
l.on("dblclick", function (e) {
L.DomEvent.stopPropagation(e);
if (!modeAdmin) {
return;
}
openObjekSidebar(obj, l);
});
drawnItems.addLayer(l);
});
});
});
}
map.on(L.Draw.Event.CREATED, function (e) {
let layer = e.layer;
drawnItems.addLayer(layer);
currentObjekLayer = layer;
document.getElementById("sidebarObjek").classList.remove("hidden");
document.getElementById("objek_id").value = "";
document.getElementById("objek_nama").value = "";
document.getElementById("objek_deskripsi").value = "";
document.getElementById("objek_tipe").value = layer.toGeoJSON().geometry.type;
});
map.on("draw:edited", function (e) {
e.layers.eachLayer(function (layer) {
let geojson = JSON.stringify(layer.toGeoJSON());
fetch("api/update_objek.php", {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body: "id=" + layer.objekId + "&geojson=" + encodeURIComponent(geojson),
});
});
});
map.on("draw:deleted", function (e) {
e.layers.eachLayer(function (layer) {
fetch("api/hapus_objek.php", {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body: "id=" + layer.objekId,
});
});
});
function openObjekSidebar(obj, layer) {
currentObjekLayer = layer;
document.getElementById("sidebarObjek").classList.remove("hidden");
document.getElementById("objek_id").value = obj.id;
document.getElementById("objek_nama").value = obj.nama || "";
document.getElementById("objek_deskripsi").value = obj.deskripsi || "";
document.getElementById("objek_tipe").value = obj.tipe;
}
function tutupSidebarObjek() {
document.getElementById("sidebarObjek").classList.add("hidden");
currentObjekLayer = null;
}
function updateObjek() {
let id = document.getElementById("objek_id").value;
let nama = document.getElementById("objek_nama").value;
let deskripsi = document.getElementById("objek_deskripsi").value;
let tipe = document.getElementById("objek_tipe").value;
if (id == "") {
let geojson = JSON.stringify(currentObjekLayer.toGeoJSON());
fetch("api/simpan_objek.php", {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body:
"nama=" +
encodeURIComponent(nama) +
"&deskripsi=" +
encodeURIComponent(deskripsi) +
"&tipe=" +
tipe +
"&geojson=" +
encodeURIComponent(geojson),
})
.then((res) => res.json())
.then((data) => {
alert("Objek berhasil disimpan");
tutupSidebarObjek();
loadObjekPeta();
});
} else {
fetch("api/update_objek.php", {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body:
"id=" +
id +
"&nama=" +
encodeURIComponent(nama) +
"&deskripsi=" +
encodeURIComponent(deskripsi),
})
.then((res) => res.json())
.then((data) => {
alert("Objek berhasil diperbarui");
tutupSidebarObjek();
loadObjekPeta();
});
}
}