135 lines
3.7 KiB
JavaScript
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, "&")
|
|
.replace(/</g, "<")
|
|
.replace(/>/g, ">")
|
|
.replace(/"/g, """)
|
|
.replace(/'/g, "'");
|
|
}
|