Hides the permanent hazards layer deppending on the zoom level in WME, with a configurable threshold.
// ==UserScript==
// @name WME PH Utils
// @namespace https://github.com/georgenqueiroz
// @version 0.1
// @description Hides the permanent hazards layer deppending on the zoom level in WME, with a configurable threshold.
// @author George Queiroz (georgenqueiroz)
// @match https://www.waze.com/editor*
// @match https://*.waze.com/*/editor*
// @match https://*.waze.com/editor*
// @license MIT
// @run-at document-idle
// @grant none
// ==/UserScript==
(function() {
'use strict';
const SCRIPT_ID = "wme_ph_utils";
const SCRIPT_NAME = "WME PH Utils";
const STORAGE_KEY = "wme_ph_utils_zoom_threshold";
const STORAGE_KEY_SHOW_ZOOM = "wme_ph_utils_show_zoom_level";
const TRANSLATIONS = {
en: {
lbl_Show_Zoom_Level: "Show zoom level",
lbl_Zoom_Level: "Zoom level",
lbl_Show_PermanentHazards_From_Zoom: "Show permanent hazards from zoom ",
lbl_Settings: "Settings"
},
pt: {
lbl_Show_Zoom_Level: "Mostrar nível de zoom",
lbl_Zoom_Level: "Nível de zoom",
lbl_Show_PermanentHazards_From_Zoom: "Mostrar permanent hazards a partir do zoom ",
lbl_Settings: "Configurações"
}
};
let wmeSdk = null;
let selectedZoomThreshold = parseInt(localStorage.getItem(STORAGE_KEY)) || 14;
let showZoomLevelPref = localStorage.getItem(STORAGE_KEY_SHOW_ZOOM) !== "false"; // True by default
let zoomDisplayTimeout = null;
let zoomDisplayElement = null;
window.SDK_INITIALIZED.then(init);
function _t(key) {
const locale = wmeSdk.Settings.getLocale().localeCode.toLowerCase();
const lang = locale.startsWith('pt') ? 'pt' : 'en';
let text = TRANSLATIONS[lang][key] || key;
return text;
}
async function init() {
wmeSdk = getWmeSdk({
scriptId: SCRIPT_ID,
scriptName: SCRIPT_NAME
});
if (wmeSdk.Sidebar) {
await renderTab(wmeSdk);
}
createZoomDisplay();
bindEvents();
}
function createZoomDisplay() {
const mapContainer = document.querySelector('#map') || document.body;
zoomDisplayElement = document.createElement('div');
zoomDisplayElement.id = 'wme-ph-utils-zoom-display';
zoomDisplayElement.style.cssText = `
position: absolute;
bottom: 3%;
left: 50%;
transform: translate(-50%, -50%);
background-color: rgba(51, 51, 51, 0.85);
color: white;
padding: 8px 16px;
border-radius: 20px;
font-family: "Waze-Boing", sans-serif;
font-size: 14px;
z-index: 1000;
pointer-events: none;
display: none;
transition: opacity 0.3s ease;
white-space: nowrap;
`;
mapContainer.appendChild(zoomDisplayElement);
}
function showZoomToast(zoom) {
if (!zoomDisplayElement || !showZoomLevelPref) return;
clearTimeout(zoomDisplayTimeout);
zoomDisplayElement.innerText = `${_t("lbl_Zoom_Level")}: ${zoom}`;
zoomDisplayElement.style.display = 'block';
zoomDisplayElement.style.opacity = '1';
zoomDisplayTimeout = setTimeout(() => {
zoomDisplayElement.style.opacity = '0';
setTimeout(() => { zoomDisplayElement.style.display = 'none'; }, 300);
}, 3000); // The zoom level will be hidden after 3 seconds
}
function bindEvents() {
wmeSdk.Events.on({
eventName: "wme-map-zoom-changed",
eventHandler: () => {
const z = wmeSdk.Map.getZoomLevel();
showZoomToast(z);
checkHazardVisibility(z);
},
});
checkHazardVisibility();
}
async function checkHazardVisibility(zoom) {
if (!wmeSdk.LayerSwitcher || !wmeSdk.Map) return;
try {
const currentZoom = zoom || wmeSdk.Map.getZoomLevel();
if (currentZoom === null) return;
const shouldBeVisible = currentZoom >= selectedZoomThreshold;
await wmeSdk.LayerSwitcher.setHazardsLayerCheckboxChecked({ isChecked: shouldBeVisible });
} catch (err) {
console.error(`${SCRIPT_NAME}: Error while trying to interact with LayerSwitcher`, err);
}
}
async function renderTab(wmeSdk) {
try {
const result = await wmeSdk.Sidebar.registerScriptTab({
scriptId: SCRIPT_ID,
title: SCRIPT_NAME,
content: "<div>Carregando...</div>"
});
const { tabLabel, tabPane } = result;
tabLabel.innerText = SCRIPT_NAME;
let zoomOptions = '';
for (let i = 14; i <= 21; i++) {
const selected = i === selectedZoomThreshold ? 'selected' : '';
zoomOptions += `<option value="${i}" ${selected}>${i}</option>`;
}
tabPane.innerHTML = `
<div style="padding: 15px; display: flex; flex-direction: column; gap: 15px; font-family: 'Waze-Boing', sans-serif;">
<h4 style="margin: 0; color: #202020; border-bottom: 1px solid #000000; padding-bottom: 5px;">${_t("lbl_Settings")}</h4>
<div style="font-size: 13px; display: flex; align-items: center; gap: 8px;">
<input type="checkbox" id="show_zoom_level" ${showZoomLevelPref ? 'checked' : ''}>
<label for="show_zoom_level" style="font-weight: normal; margin: 0; cursor: pointer;">${_t("lbl_Show_Zoom_Level")}</label>
</div>
<div style="font-size: 13px; display: flex; align-items: center;">
<label style="font-weight: normal; margin: 0;">${_t("lbl_Show_PermanentHazards_From_Zoom")}</label>
<select id="ph_zoom_level" style="margin-left: 5px;">${zoomOptions}</select>
</div>
</div>`;
tabPane.querySelector('#show_zoom_level').addEventListener('change', (e) => {
showZoomLevelPref = e.target.checked;
localStorage.setItem(STORAGE_KEY_SHOW_ZOOM, showZoomLevelPref);
// Se desmarcar enquanto o toast está visível, oculta imediatamente
if (!showZoomLevelPref && zoomDisplayElement) {
zoomDisplayElement.style.display = 'none';
zoomDisplayElement.style.opacity = '0';
}
});
tabPane.querySelector('#ph_zoom_level').addEventListener('change', (e) => {
selectedZoomThreshold = parseInt(e.target.value, 10);
localStorage.setItem(STORAGE_KEY, selectedZoomThreshold);
checkHazardVisibility();
});
} catch (e) {
console.error(`${SCRIPT_NAME}: Erro ao registrar tab`, e);
}
}
})();