260719_6
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
import type { SurfaceBounds } from "./B04_wf1_Surface_Api_Fetch";
|
||||
|
||||
export const SURFACE_CAMERA_FOV = 50;
|
||||
const LIGHT_VIEWER_BACKGROUND = 0xf5f7f9;
|
||||
const DARK_VIEWER_BACKGROUND = 0x251f38;
|
||||
|
||||
export interface SurfaceCameraState {
|
||||
direction: [number, number, number];
|
||||
@@ -40,3 +42,36 @@ export function niceScaleDistance(roughMeters: number): number {
|
||||
const step = normalized <= 1 ? 1 : normalized <= 2 ? 2 : normalized <= 5 ? 5 : 10;
|
||||
return step * base;
|
||||
}
|
||||
|
||||
export function bindSurfaceViewerTheme(
|
||||
applyBackground: (color: string | number) => void,
|
||||
): () => void {
|
||||
const systemDarkTheme = window.matchMedia("(prefers-color-scheme: dark)");
|
||||
const update = (): void => {
|
||||
const theme = document.documentElement.getAttribute("data-theme");
|
||||
const dark = theme === "dark" || (theme !== "light" && systemDarkTheme.matches);
|
||||
if (!dark) {
|
||||
applyBackground(LIGHT_VIEWER_BACKGROUND);
|
||||
return;
|
||||
}
|
||||
const surfaceRaised = getComputedStyle(document.documentElement)
|
||||
.getPropertyValue("--color-surface-raised")
|
||||
.trim();
|
||||
applyBackground(
|
||||
surfaceRaised && CSS.supports("color", surfaceRaised)
|
||||
? surfaceRaised
|
||||
: DARK_VIEWER_BACKGROUND,
|
||||
);
|
||||
};
|
||||
const observer = new MutationObserver(update);
|
||||
observer.observe(document.documentElement, {
|
||||
attributes: true,
|
||||
attributeFilter: ["data-theme"],
|
||||
});
|
||||
systemDarkTheme.addEventListener("change", update);
|
||||
update();
|
||||
return () => {
|
||||
observer.disconnect();
|
||||
systemDarkTheme.removeEventListener("change", update);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -460,26 +460,31 @@
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.b04-surface__scale {
|
||||
.b04-surface__scale,
|
||||
.b04-map__scale {
|
||||
position: absolute;
|
||||
bottom: var(--spacing-16);
|
||||
left: var(--spacing-16);
|
||||
z-index: 2;
|
||||
height: var(--spacing-8);
|
||||
border: 2px solid var(--color-text);
|
||||
border: 2px solid var(--color-text-body);
|
||||
border-top: 0;
|
||||
color: var(--color-text);
|
||||
color: var(--color-text-body);
|
||||
filter: drop-shadow(0 1px 1px var(--color-surface-raised));
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.b04-surface__scale span {
|
||||
.b04-surface__scale span,
|
||||
.b04-map__scale span {
|
||||
position: absolute;
|
||||
bottom: var(--spacing-8);
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
white-space: nowrap;
|
||||
font-family: var(--font-body);
|
||||
font-size: var(--text-caption);
|
||||
font-weight: var(--font-weight-semibold);
|
||||
text-shadow: 0 1px 2px var(--color-surface-raised);
|
||||
}
|
||||
|
||||
/* --- 하단 2D 지도 --- */
|
||||
@@ -619,28 +624,6 @@
|
||||
background: var(--color-surface-raised);
|
||||
}
|
||||
|
||||
.b04-map__scale {
|
||||
position: absolute;
|
||||
bottom: var(--spacing-16);
|
||||
left: var(--spacing-16);
|
||||
z-index: 2;
|
||||
height: var(--spacing-8);
|
||||
border: 2px solid var(--color-text);
|
||||
border-top: 0;
|
||||
color: var(--color-text);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.b04-map__scale span {
|
||||
position: absolute;
|
||||
bottom: var(--spacing-8);
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
white-space: nowrap;
|
||||
font-size: var(--text-caption);
|
||||
font-weight: var(--font-weight-semibold);
|
||||
}
|
||||
|
||||
@media (max-width: 760px) {
|
||||
.b04-map__header {
|
||||
align-items: flex-start;
|
||||
|
||||
@@ -5,6 +5,7 @@ import { PLYLoader } from "three/examples/jsm/loaders/PLYLoader.js";
|
||||
import { API_BASE_URL } from "@config/config_frontend";
|
||||
import type { SurfaceBounds, SurfaceModelSummary } from "./B04_wf1_Surface_Api_Fetch";
|
||||
import {
|
||||
bindSurfaceViewerTheme,
|
||||
getTopFitDistance,
|
||||
niceScaleDistance,
|
||||
SURFACE_CAMERA_FOV,
|
||||
@@ -180,7 +181,9 @@ export function createSurfaceTerrainViewer(): SurfaceTerrainViewer {
|
||||
let loadGeneration = 0;
|
||||
|
||||
const scene = new THREE.Scene();
|
||||
scene.background = new THREE.Color(0xf5f7f9);
|
||||
const releaseTheme = bindSurfaceViewerTheme((color) => {
|
||||
scene.background = new THREE.Color(color);
|
||||
});
|
||||
|
||||
const camera = new THREE.PerspectiveCamera(SURFACE_CAMERA_FOV, 1, 0.01, 100000);
|
||||
const renderer = new THREE.WebGLRenderer({ canvas, antialias: true });
|
||||
@@ -543,6 +546,7 @@ export function createSurfaceTerrainViewer(): SurfaceTerrainViewer {
|
||||
cancelAnimationFrame(animationFrameId);
|
||||
clearMesh();
|
||||
clearContours();
|
||||
releaseTheme();
|
||||
controls.dispose();
|
||||
renderer.dispose();
|
||||
}
|
||||
@@ -670,6 +674,7 @@ export function createSurfaceTerrainViewer(): SurfaceTerrainViewer {
|
||||
dispose() {
|
||||
cancelAnimationFrame(animationFrameId);
|
||||
resizeObserver.disconnect();
|
||||
releaseTheme();
|
||||
clearMesh();
|
||||
clearContours();
|
||||
controls.dispose();
|
||||
|
||||
@@ -3,6 +3,7 @@ import * as THREE from "three";
|
||||
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
|
||||
import type { SurfaceBounds, SurfacePointCloudSampleResponse } from "./B04_wf1_Surface_Api_Fetch";
|
||||
import {
|
||||
bindSurfaceViewerTheme,
|
||||
getReferenceCenter,
|
||||
getTopFitDistance,
|
||||
niceScaleDistance,
|
||||
@@ -106,7 +107,9 @@ export function createSurfacePointCloudViewer(): SurfacePointCloudViewer {
|
||||
});
|
||||
renderer.setPixelRatio(Math.min(window.devicePixelRatio, RENDER_OPTIONS.maxPixelRatio));
|
||||
const scene = new THREE.Scene();
|
||||
scene.background = new THREE.Color(0xf5f7f9);
|
||||
const releaseTheme = bindSurfaceViewerTheme((color) => {
|
||||
scene.background = new THREE.Color(color);
|
||||
});
|
||||
const camera = new THREE.PerspectiveCamera(SURFACE_CAMERA_FOV, 1, 0.1, 22000);
|
||||
const orbit = new OrbitControls(camera, canvas);
|
||||
orbit.enableDamping = true;
|
||||
@@ -268,6 +271,7 @@ export function createSurfacePointCloudViewer(): SurfacePointCloudViewer {
|
||||
if (disposed) return;
|
||||
disposed = true;
|
||||
cancelAnimationFrame(animationFrame);
|
||||
releaseTheme();
|
||||
clearPoints();
|
||||
orbit.dispose();
|
||||
renderer.dispose();
|
||||
|
||||
@@ -12,6 +12,9 @@ import {
|
||||
type SectionStationMarker,
|
||||
} from "./B05_wf2_Route_UI_Markers";
|
||||
|
||||
const LIGHT_VIEWER_BACKGROUND = 0xf5f7fa;
|
||||
const DARK_VIEWER_BACKGROUND = 0x251f38;
|
||||
|
||||
function disposeObject(object: THREE.Object3D | null): void {
|
||||
object?.traverse((child) => {
|
||||
if (
|
||||
@@ -58,7 +61,32 @@ export function createRouteViewer(): RouteViewer {
|
||||
root.append(canvas, status);
|
||||
|
||||
const scene = new THREE.Scene();
|
||||
scene.background = new THREE.Color(0xf5f7fa);
|
||||
const systemDarkTheme = window.matchMedia("(prefers-color-scheme: dark)");
|
||||
|
||||
function updateSceneBackground(): void {
|
||||
const theme = document.documentElement.getAttribute("data-theme");
|
||||
const dark = theme === "dark" || (theme !== "light" && systemDarkTheme.matches);
|
||||
if (!dark) {
|
||||
scene.background = new THREE.Color(LIGHT_VIEWER_BACKGROUND);
|
||||
return;
|
||||
}
|
||||
const surfaceRaised = getComputedStyle(document.documentElement)
|
||||
.getPropertyValue("--color-surface-raised")
|
||||
.trim();
|
||||
scene.background = new THREE.Color(
|
||||
surfaceRaised && CSS.supports("color", surfaceRaised)
|
||||
? surfaceRaised
|
||||
: DARK_VIEWER_BACKGROUND,
|
||||
);
|
||||
}
|
||||
|
||||
const themeObserver = new MutationObserver(updateSceneBackground);
|
||||
themeObserver.observe(document.documentElement, {
|
||||
attributes: true,
|
||||
attributeFilter: ["data-theme"],
|
||||
});
|
||||
systemDarkTheme.addEventListener("change", updateSceneBackground);
|
||||
updateSceneBackground();
|
||||
const camera = new THREE.PerspectiveCamera(45, 1, 0.1, 100000);
|
||||
camera.position.set(100, 120, 100);
|
||||
const renderer = new THREE.WebGLRenderer({ canvas, antialias: true });
|
||||
@@ -335,6 +363,8 @@ export function createRouteViewer(): RouteViewer {
|
||||
dispose() {
|
||||
cancelAnimationFrame(frame);
|
||||
resizeObserver.disconnect();
|
||||
themeObserver.disconnect();
|
||||
systemDarkTheme.removeEventListener("change", updateSceneBackground);
|
||||
canvas.removeEventListener("pointerdown", handlePointerDown, true);
|
||||
canvas.removeEventListener("pointermove", handlePointerMove, true);
|
||||
canvas.removeEventListener("pointerup", handlePointerUp, true);
|
||||
|
||||
Reference in New Issue
Block a user