279 lines
8.1 KiB
JavaScript
279 lines
8.1 KiB
JavaScript
// Inisialisasi Peta
|
||
const map = L.map("map", { zoomControl: false }).setView(
|
||
[-0.0263, 109.3425],
|
||
13,
|
||
);
|
||
|
||
// ===== Toast Notification =====
|
||
window.showToast = function (message, type = "success", duration = 3500) {
|
||
const icons = { success: "✅", error: "❌", info: "ℹ️", warning: "⚠️" };
|
||
const container = document.getElementById("toastContainer");
|
||
if (!container) return;
|
||
|
||
const toast = document.createElement("div");
|
||
toast.className = `toast toast-${type}`;
|
||
toast.innerHTML = `<span class="toast-icon">${icons[type] || "ℹ️"}</span><span>${message}</span>`;
|
||
container.appendChild(toast);
|
||
|
||
setTimeout(() => {
|
||
toast.classList.add("hiding");
|
||
toast.addEventListener("animationend", () => toast.remove());
|
||
}, duration);
|
||
};
|
||
|
||
// Custom Zoom Control Logic
|
||
document.getElementById("zoomInBtn").addEventListener("click", function () {
|
||
map.zoomIn();
|
||
});
|
||
document.getElementById("zoomOutBtn").addEventListener("click", function () {
|
||
map.zoomOut();
|
||
});
|
||
|
||
// Base Map dari OpenStreetMap
|
||
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
|
||
attribution:
|
||
'© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
|
||
}).addTo(map);
|
||
|
||
// Inisialisasi FeatureGroups untuk masing-masing layer
|
||
const parsilLayer = L.featureGroup().addTo(map);
|
||
|
||
const searchInput = document.getElementById("searchInput");
|
||
const searchClear = document.getElementById("searchClear");
|
||
|
||
if (searchInput) {
|
||
searchInput.addEventListener("focus", function () {
|
||
if (typeof window.deactivateAddMode === "function")
|
||
window.deactivateAddMode();
|
||
});
|
||
|
||
searchInput.addEventListener("input", function () {
|
||
const val = this.value.toLowerCase();
|
||
if (val.length > 0) {
|
||
searchClear.style.visibility = "visible";
|
||
window.showSearchResults(val);
|
||
} else {
|
||
searchClear.style.visibility = "hidden";
|
||
document.getElementById("searchResults").style.display = "none";
|
||
}
|
||
});
|
||
}
|
||
|
||
if (searchClear) {
|
||
searchClear.addEventListener("click", function () {
|
||
searchInput.value = "";
|
||
searchClear.style.visibility = "hidden";
|
||
document.getElementById("searchResults").style.display = "none";
|
||
searchInput.focus();
|
||
});
|
||
}
|
||
|
||
window.showSearchResults = function (query) {
|
||
const resultsContainer = document.getElementById("searchResults");
|
||
if (!resultsContainer) return;
|
||
resultsContainer.innerHTML = "";
|
||
let results = [];
|
||
|
||
if (typeof parsilLayer !== "undefined") {
|
||
parsilLayer.eachLayer((layer) => {
|
||
if (
|
||
layer.parsilData &&
|
||
layer.parsilData.nama &&
|
||
layer.parsilData.nama.toLowerCase().includes(query)
|
||
) {
|
||
results.push({
|
||
type: "Parsil",
|
||
nama: layer.parsilData.nama,
|
||
layer: layer,
|
||
});
|
||
}
|
||
});
|
||
}
|
||
|
||
if (results.length === 0) {
|
||
resultsContainer.innerHTML =
|
||
'<div style="padding: 10px 15px; color: #666; font-size: 14px;">Tidak ada hasil</div>';
|
||
} else {
|
||
results.forEach((res) => {
|
||
const item = document.createElement("div");
|
||
item.style.padding = "10px 15px";
|
||
item.style.cursor = "pointer";
|
||
item.style.borderBottom = "1px solid #eee";
|
||
item.style.fontSize = "14px";
|
||
item.innerHTML = `<strong>${res.type}:</strong> ${res.nama}`;
|
||
item.addEventListener(
|
||
"mouseenter",
|
||
() => (item.style.backgroundColor = "#f8f9fa"),
|
||
);
|
||
item.addEventListener(
|
||
"mouseleave",
|
||
() => (item.style.backgroundColor = "white"),
|
||
);
|
||
item.addEventListener("click", () => {
|
||
if (res.layer instanceof L.Marker) {
|
||
map.setView(res.layer.getLatLng(), 17);
|
||
} else if (res.layer.getBounds) {
|
||
map.fitBounds(res.layer.getBounds());
|
||
}
|
||
res.layer.openPopup();
|
||
resultsContainer.style.display = "none";
|
||
});
|
||
resultsContainer.appendChild(item);
|
||
});
|
||
}
|
||
resultsContainer.style.display = "block";
|
||
};
|
||
|
||
// UI Logic: Custom Layer Control Toggle
|
||
const layerBtn = document.getElementById("layerBtn");
|
||
const layerPanel = document.getElementById("layerPanel");
|
||
|
||
if (layerBtn && layerPanel) {
|
||
layerBtn.addEventListener("click", function () {
|
||
if (typeof window.deactivateAddMode === "function")
|
||
window.deactivateAddMode();
|
||
layerPanel.style.display =
|
||
layerPanel.style.display === "block" ? "none" : "block";
|
||
});
|
||
}
|
||
|
||
// Sembunyikan layer panel saat klik di peta
|
||
map.on("click", function () {
|
||
if (layerPanel) layerPanel.style.display = "none";
|
||
});
|
||
|
||
// Logic untuk Toggle Layer Visibility
|
||
const setupLayerToggle = (id, layer) => {
|
||
const el = document.getElementById(id);
|
||
if (el) {
|
||
el.addEventListener("change", function (e) {
|
||
e.target.checked ? map.addLayer(layer) : map.removeLayer(layer);
|
||
});
|
||
}
|
||
};
|
||
|
||
setupLayerToggle("layerParsil", parsilLayer);
|
||
|
||
// --- Sub-layer Toggle (expand/collapse) ---
|
||
window.toggleSubLayer = function (subId, iconEl) {
|
||
const sub = document.getElementById(subId);
|
||
if (!sub) return;
|
||
const isHidden = sub.style.display === "none";
|
||
sub.style.display = isHidden ? "" : "none";
|
||
iconEl.classList.toggle("collapsed", !isHidden);
|
||
};
|
||
|
||
// --- Sub-layer Filter ---
|
||
window.applySubFilter = function (type) {
|
||
if (type === "spbu") {
|
||
const checked = [...document.querySelectorAll(".sub-spbu:checked")].map(
|
||
(el) => el.value === "1",
|
||
);
|
||
spbuLayer.eachLayer((layer) => {
|
||
if (layer.spbuData === undefined) return;
|
||
if (checked.includes(layer.spbuData.is_24_jam)) {
|
||
layer.getElement &&
|
||
layer.getElement() &&
|
||
(layer.getElement().style.display = "");
|
||
} else {
|
||
layer.getElement &&
|
||
layer.getElement() &&
|
||
(layer.getElement().style.display = "none");
|
||
}
|
||
});
|
||
} else if (type === "jalan") {
|
||
const checked = [...document.querySelectorAll(".sub-jalan:checked")].map(
|
||
(el) => el.value,
|
||
);
|
||
jalanLayer.eachLayer((layer) => {
|
||
if (!layer.jalanData) return;
|
||
if (checked.includes(layer.jalanData.status)) {
|
||
layer.getElement &&
|
||
layer.getElement() &&
|
||
(layer.getElement().style.display = "");
|
||
} else {
|
||
layer.getElement &&
|
||
layer.getElement() &&
|
||
(layer.getElement().style.display = "none");
|
||
}
|
||
});
|
||
} else if (type === "parsil") {
|
||
const checked = [...document.querySelectorAll(".sub-parsil:checked")].map(
|
||
(el) => el.value,
|
||
);
|
||
parsilLayer.eachLayer((layer) => {
|
||
if (!layer.parsilData) return;
|
||
if (checked.includes(layer.parsilData.status)) {
|
||
layer.getElement &&
|
||
layer.getElement() &&
|
||
(layer.getElement().style.display = "");
|
||
} else {
|
||
layer.getElement &&
|
||
layer.getElement() &&
|
||
(layer.getElement().style.display = "none");
|
||
}
|
||
});
|
||
}
|
||
};
|
||
|
||
// --- Modal Logic ---
|
||
const unifiedModal = document.getElementById("unifiedModal");
|
||
const modalTitle = document.getElementById("modalTitle");
|
||
const modalBody = document.getElementById("modalBody");
|
||
|
||
window.openModal = function (title, bodyHTML, saveCallback) {
|
||
if (!unifiedModal) return;
|
||
modalTitle.textContent = title;
|
||
modalBody.innerHTML = bodyHTML;
|
||
unifiedModal.classList.add("show");
|
||
|
||
const currentSaveBtn = document.getElementById("modalSaveBtn");
|
||
if (currentSaveBtn) {
|
||
const newSaveBtn = currentSaveBtn.cloneNode(true);
|
||
currentSaveBtn.parentNode.replaceChild(newSaveBtn, currentSaveBtn);
|
||
newSaveBtn.addEventListener("click", saveCallback);
|
||
}
|
||
};
|
||
|
||
window.closeModal = function () {
|
||
if (unifiedModal) unifiedModal.classList.remove("show");
|
||
};
|
||
|
||
const confirmModal = document.getElementById("confirmModal");
|
||
const confirmMessage = document.getElementById("confirmMessage");
|
||
|
||
window.openConfirmModal = function (msg, confirmCallback) {
|
||
if (!confirmModal) return;
|
||
confirmMessage.textContent = msg;
|
||
confirmModal.classList.add("show");
|
||
|
||
const currentYesBtn = document.getElementById("confirmYesBtn");
|
||
if (currentYesBtn) {
|
||
const newYesBtn = currentYesBtn.cloneNode(true);
|
||
currentYesBtn.parentNode.replaceChild(newYesBtn, currentYesBtn);
|
||
newYesBtn.addEventListener("click", function () {
|
||
confirmModal.classList.remove("show");
|
||
confirmCallback();
|
||
});
|
||
}
|
||
};
|
||
|
||
window.closeConfirmModal = function () {
|
||
if (confirmModal) confirmModal.classList.remove("show");
|
||
};
|
||
|
||
window.currentAddMode = null; // 'spbu', 'jalan', 'parsil'
|
||
window.activateAddMode = function (mode) {
|
||
if (window.currentAddMode === mode) {
|
||
window.deactivateAddMode();
|
||
return;
|
||
}
|
||
window.currentAddMode = mode;
|
||
document.getElementById("map").style.cursor = "crosshair";
|
||
};
|
||
|
||
window.deactivateAddMode = function () {
|
||
window.currentAddMode = null;
|
||
document.getElementById("map").style.cursor = "";
|
||
};
|