Files
planet/frontend/public/earth/js/legend.js
linkong 5bdb55f3f1
Some checks failed
ci / backend (push) Has been cancelled
ci / frontend (push) Has been cancelled
ci / delivery (push) Has been cancelled
release / images (push) Has been cancelled
release: bump version to 0.74.0
2026-06-30 13:52:52 +08:00

135 lines
3.7 KiB
JavaScript

import { createHUDPanel } from "./hud-panels.js";
import { getEarthLocale, translateText } from "./i18n.js";
const LEGEND_MODES = {
cables: { title: "海缆", compactTitleEn: "Cables" },
satellites: { title: "卫星", compactTitleEn: "Orbits" },
countryBoundaries: { title: "国界" },
computeCenters: { title: "算力" },
vessels: { title: "船只" },
bgp: { title: "BGP" },
};
let currentLegendMode = "cables";
let legendPanel = null;
let legendLocaleListenerBound = false;
let legendItemsByMode = {
cables: [],
satellites: [],
countryBoundaries: [],
computeCenters: [],
vessels: [],
bgp: [],
};
export function initLegend() {
const collapseBtn = document.getElementById("legend-collapse");
const legend = document.getElementById("legend");
if (collapseBtn && legend) {
legendPanel = createHUDPanel({
panel: legend,
header: ".legend-bar",
body: "#legend-body",
collapseBtn,
preferredDirection: "down",
expandLabel: "展开图例",
collapseLabel: "折叠图例",
});
collapseBtn.addEventListener("click", (e) => {
e.stopPropagation();
legendPanel?.setCollapsed(!(legendPanel?.isCollapsed() ?? false));
});
}
if (!legendLocaleListenerBound) {
legendLocaleListenerBound = true;
window.addEventListener("earth:locale-change", () => {
syncCurrentLabel(currentLegendMode);
renderLegend(currentLegendMode);
});
}
syncCurrentLabel(currentLegendMode);
renderLegend(currentLegendMode);
}
export function setLegendMode(mode) {
const nextMode = LEGEND_MODES[mode] ? mode : "cables";
currentLegendMode = nextMode;
syncCurrentLabel(nextMode);
renderLegend(nextMode);
}
export function getLegendMode() {
return currentLegendMode;
}
export function refreshLegend() {
renderLegend(currentLegendMode);
}
export function setLegendItems(mode, items) {
if (!LEGEND_MODES[mode]) return;
legendItemsByMode[mode] = Array.isArray(items) ? items : [];
if (mode === currentLegendMode) {
renderLegend(currentLegendMode);
}
}
function syncCurrentLabel(mode) {
const nextLabel = getLegendModeTitle(mode);
[document.getElementById("legend-current-label"), document.getElementById("mobile-situation-legend-mode")]
.forEach((labelEl) => {
if (labelEl) {
const translatedLabel = getEarthLocale() === "en-US" ? nextLabel : translateText(nextLabel);
labelEl.textContent = translatedLabel;
labelEl.dataset.i18nOriginalTitle = translatedLabel;
labelEl.title = translatedLabel;
}
});
}
function getLegendModeTitle(mode) {
const definition = LEGEND_MODES[mode] || LEGEND_MODES.cables;
if (getEarthLocale() === "en-US" && definition.compactTitleEn) {
return definition.compactTitleEn;
}
return definition.title;
}
function renderLegend(mode) {
const items = legendItemsByMode[mode] || [];
const html = items
.map(
(item) => {
const label = escapeLegendHtml(translateText(item.label));
return `
<div class="legend-item">
<span class="legend-dot legend-dot--${item.shape || "dot"}" style="background:${item.color}; color:${item.color}"></span>
<span class="legend-label" title="${label}">${label}</span>
</div>`;
},
)
.join("");
const desktopList = document.querySelector("#legend .legend-list");
if (desktopList) {
desktopList.innerHTML = html;
}
const mobileList = document.getElementById("mobile-situation-legend-list");
if (mobileList) {
mobileList.innerHTML = html;
}
}
function escapeLegendHtml(value) {
return String(value ?? "")
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#39;");
}