From 8237c7ed27d093fb99eeb3ea575b2f57a899fffe Mon Sep 17 00:00:00 2001 From: que01 Date: Fri, 7 Aug 2026 13:51:47 +0800 Subject: [PATCH] feat(preview): add transparent building mode --- scripts/lib/area-preview.js | 1 + scripts/lib/cesium-preview.js | 58 ++++++++++++++++++++++++++++++++++ scripts/test-preview-assets.js | 3 ++ 3 files changed, 62 insertions(+) diff --git a/scripts/lib/area-preview.js b/scripts/lib/area-preview.js index ea7af1c..472ea41 100644 --- a/scripts/lib/area-preview.js +++ b/scripts/lib/area-preview.js @@ -50,6 +50,7 @@ function cesiumPreviewHtml(glbName, metadataName, routeName, vehicleModelName, a + diff --git a/scripts/lib/cesium-preview.js b/scripts/lib/cesium-preview.js index 75e536b..5a08cfd 100644 --- a/scripts/lib/cesium-preview.js +++ b/scripts/lib/cesium-preview.js @@ -8,6 +8,7 @@ const toggleCruise = document.getElementById("toggleCruise"); const toggleFollow = document.getElementById("toggleFollow"); const toggleScene = document.getElementById("toggleScene"); + const toggleBuildingGhost = document.getElementById("toggleBuildingGhost"); const toggleRoutes = document.getElementById("toggleRoutes"); const toggleVehicles = document.getElementById("toggleVehicles"); const toggleSignals = document.getElementById("toggleSignals"); @@ -287,8 +288,54 @@ const hasSemanticAssets = semanticAssets(assets).length > 0; const sceneLabel = toggleScene.closest("label"); let viewMode = "scene"; + let buildingGhostActive = false; + + async function setBuildingGhost(enabled) { + const roads = assets.find((asset) => asset.id === "roads"); + const buildings = assets.find((asset) => asset.id === "buildings"); + const main = assets.find((asset) => asset.id === "main"); + if (!roads || !buildings || !main) { + toggleBuildingGhost.checked = false; + toggleBuildingGhost.disabled = true; + return; + } + if (enabled) { + const loaded = await Promise.all([ + loadAsset(viewer, roads, placement), + loadAsset(viewer, buildings, placement), + ]); + if (!loaded[0] || !loaded[1]) { + toggleBuildingGhost.checked = false; + setStatus("Building transparency unavailable"); + return; + } + main.model.show = false; + roads.model.show = true; + buildings.model.show = true; + buildings.model.color = Cesium.Color.WHITE.withAlpha(0.22); + buildings.model.colorBlendMode = Cesium.ColorBlendMode.REPLACE; + buildings.model.colorBlendAmount = 1.0; + for (const asset of liveAssets(assets)) { + if (asset.id !== "main") asset.model.show = asset.category === "dynamic" || asset.category === "countdown" + ? toggleSignals.checked : asset.model.show; + } + buildingGhostActive = true; + setStatus("Buildings transparent"); + } else { + for (const asset of semanticAssets(assets)) { + if (asset.model) asset.model.show = false; + } + main.model.show = toggleScene.checked; + for (const asset of liveAssets(assets)) { + if (asset.id !== "main") asset.model.show = toggleSignals.checked; + } + buildingGhostActive = false; + setStatus("Buildings opaque"); + } + } toggleScene.addEventListener("change", () => { + if (buildingGhostActive) return; for (const asset of liveAssets(assets)) { asset.model.show = toggleScene.checked; if (asset.toggle) asset.toggle.checked = toggleScene.checked; @@ -316,6 +363,13 @@ toggleDiagnostics.addEventListener("change", () => { diagnosticsEl.classList.toggle("hidden", !toggleDiagnostics.checked); }); + toggleBuildingGhost.addEventListener("change", () => { + void setBuildingGhost(toggleBuildingGhost.checked); + }); + if (!semanticAssets(assets).some((asset) => asset.id === "roads") || + !semanticAssets(assets).some((asset) => asset.id === "buildings")) { + toggleBuildingGhost.disabled = true; + } async function setViewMode(nextMode) { if (nextMode === viewMode) return; @@ -329,6 +383,10 @@ if (sceneLabel) sceneLabel.classList.toggle("hidden", inspecting); if (!inspecting) { + if (buildingGhostActive) { + toggleBuildingGhost.checked = false; + await setBuildingGhost(false); + } for (const asset of semanticAssets(assets)) { if (asset.model) asset.model.show = false; } diff --git a/scripts/test-preview-assets.js b/scripts/test-preview-assets.js index f99a321..4f2d646 100644 --- a/scripts/test-preview-assets.js +++ b/scripts/test-preview-assets.js @@ -124,6 +124,7 @@ assert.match(html, /"glbName":"scene\\u003c\\u0026\\u003e\.glb"/); assert.match(html, /"vehicleModelNames":\["car-a\.gltf","truck-a\.gltf"\]/); assert.match(html, /"trafficSignalsName":"traffic-signals\.json"/); assert.match(html, /id="toggleSignals"/); +assert.match(html, /id="toggleBuildingGhost"/); assert.match(html, /id="viewMode"/); assert.match(html, /data-view-mode="inspect"/); assert.match(html, /id="semanticToggles" class="control-subgroup hidden"/); @@ -137,6 +138,8 @@ assert.match(previewRuntime, /asset\.category === "dynamic"/); assert.match(previewRuntime, /TrafficSignalDynamic_/); assert.match(previewRuntime, /TrafficSignalDynamic_\$\{nodeKey\}_countdown_\$\{String\(value\)\.padStart\(2, "0"\)\}/); assert.match(previewRuntime, /ColorBlendMode\.REPLACE/); +assert.match(previewRuntime, /setBuildingGhost/); +assert.match(previewRuntime, /buildings\.model\.color = Cesium\.Color\.WHITE\.withAlpha\(0\.22\)/); assert.match(previewRuntime, /asset\.category === "countdown"/); assert.doesNotMatch(previewRuntime, /createCountdownDigits/); assert.doesNotMatch(previewRuntime, /digitMap/);