260715_0
This commit is contained in:
@@ -3,11 +3,13 @@ import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
|
||||
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
|
||||
import { PLYLoader } from "three/examples/jsm/loaders/PLYLoader.js";
|
||||
import type { SurfaceModelSummary } from "./B04_wf1_Surface_Api_Fetch";
|
||||
import { API_BASE_URL } from "@config/config_frontend";
|
||||
import { fetchVWorldMeta, getVWorldMapUrl, fetchGisGeoJson } from "./B04_wf1_Surface_Api_Fetch";
|
||||
|
||||
export interface SurfaceTerrainViewer {
|
||||
root: HTMLElement;
|
||||
render: (projectId: string, models: readonly SurfaceModelSummary[]) => void;
|
||||
updateBgMap: (projectId: string, bgLayer: string) => void;
|
||||
updateGisLayer: (projectId: string, gisLayer: string) => void;
|
||||
dispose: () => void;
|
||||
}
|
||||
|
||||
@@ -263,6 +265,46 @@ export function createSurfaceTerrainViewer(): SurfaceTerrainViewer {
|
||||
scaleBar.append(scaleLabel);
|
||||
viewerArea.append(scaleBar);
|
||||
|
||||
// Elevation bounds legend bar overlay (I-403)
|
||||
const legendBar = document.createElement("div");
|
||||
legendBar.style.position = "absolute";
|
||||
legendBar.style.top = "16px";
|
||||
legendBar.style.right = "16px";
|
||||
legendBar.style.background = "rgba(255, 255, 255, 0.9)";
|
||||
legendBar.style.border = "1px solid #cbd5e1";
|
||||
legendBar.style.borderRadius = "6px";
|
||||
legendBar.style.padding = "8px";
|
||||
legendBar.style.width = "50px";
|
||||
legendBar.style.display = "none"; // hidden until contours are loaded
|
||||
legendBar.style.flexDirection = "column";
|
||||
legendBar.style.alignItems = "center";
|
||||
legendBar.style.zIndex = "10";
|
||||
legendBar.style.boxShadow = "0 2px 6px rgba(0,0,0,0.08)";
|
||||
legendBar.style.pointerEvents = "none";
|
||||
|
||||
const maxValSpan = document.createElement("span");
|
||||
maxValSpan.style.fontSize = "10px";
|
||||
maxValSpan.style.fontWeight = "bold";
|
||||
maxValSpan.style.color = "#b91c1c";
|
||||
maxValSpan.style.marginBottom = "4px";
|
||||
|
||||
const gradientDiv = document.createElement("div");
|
||||
gradientDiv.style.width = "12px";
|
||||
gradientDiv.style.height = "120px";
|
||||
gradientDiv.style.background =
|
||||
"linear-gradient(to bottom, #d60000 0%, #ff5100 25%, #e6a100 50%, #228b22 75%, #3a85ff 100%)";
|
||||
gradientDiv.style.borderRadius = "2px";
|
||||
gradientDiv.style.border = "1px solid #94a3b8";
|
||||
|
||||
const minValSpan = document.createElement("span");
|
||||
minValSpan.style.fontSize = "10px";
|
||||
minValSpan.style.fontWeight = "bold";
|
||||
minValSpan.style.color = "#1d4ed8";
|
||||
minValSpan.style.marginTop = "4px";
|
||||
|
||||
legendBar.append(maxValSpan, gradientDiv, minValSpan);
|
||||
viewerArea.append(legendBar);
|
||||
|
||||
// Three.js context variables
|
||||
let currentProjectId = "";
|
||||
let currentModelsList: readonly SurfaceModelSummary[] = [];
|
||||
@@ -324,6 +366,7 @@ export function createSurfaceTerrainViewer(): SurfaceTerrainViewer {
|
||||
}
|
||||
labelElements.forEach((el) => el.remove());
|
||||
labelElements.length = 0;
|
||||
legendBar.style.display = "none";
|
||||
}
|
||||
|
||||
const getFitParams = (object: THREE.Object3D) => {
|
||||
@@ -376,8 +419,7 @@ export function createSurfaceTerrainViewer(): SurfaceTerrainViewer {
|
||||
const match = currentModelsList.find((m) => {
|
||||
const typeMatches = m.model_type.toLowerCase() === activeMethod.toLowerCase();
|
||||
const pathContainsFilter =
|
||||
m.model_file_path &&
|
||||
m.model_file_path.toLowerCase().includes(activeFilter.toLowerCase());
|
||||
m.model_file_path && m.model_file_path.toLowerCase().includes(activeFilter.toLowerCase());
|
||||
return typeMatches && pathContainsFilter;
|
||||
});
|
||||
|
||||
@@ -471,7 +513,13 @@ export function createSurfaceTerrainViewer(): SurfaceTerrainViewer {
|
||||
});
|
||||
};
|
||||
|
||||
let minH = Infinity;
|
||||
let maxH = -Infinity;
|
||||
|
||||
data.contours.forEach((c: any) => {
|
||||
if (c.level < minH) minH = c.level;
|
||||
if (c.level > maxH) maxH = c.level;
|
||||
|
||||
const points = transform(c.coordinates);
|
||||
if (points.length < 2) return;
|
||||
|
||||
@@ -531,8 +579,18 @@ export function createSurfaceTerrainViewer(): SurfaceTerrainViewer {
|
||||
labelElements.push(labelDiv);
|
||||
}
|
||||
});
|
||||
|
||||
if (minH !== Infinity && maxH !== -Infinity) {
|
||||
const nearestMin10 = Math.round(minH / 10) * 10;
|
||||
const nearestMax10 = Math.round(maxH / 10) * 10;
|
||||
maxValSpan.textContent = `${nearestMax10}m`;
|
||||
minValSpan.textContent = `${nearestMin10}m`;
|
||||
legendBar.style.display = "flex";
|
||||
} else {
|
||||
legendBar.style.display = "none";
|
||||
}
|
||||
} catch (e) {
|
||||
// Contour loading failed or silent fail
|
||||
legendBar.style.display = "none";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -652,6 +710,12 @@ export function createSurfaceTerrainViewer(): SurfaceTerrainViewer {
|
||||
currentModelsList = models;
|
||||
updateSelectedModel();
|
||||
},
|
||||
updateBgMap(projectId, bgLayer) {
|
||||
// 포인트클라우드 뷰어와 인터페이스 조화를 위해 빈 껍데기 함수 정의
|
||||
},
|
||||
updateGisLayer(projectId, gisLayer) {
|
||||
// 포인트클라우드 뷰어와 인터페이스 조화를 위해 빈 껍데기 함수 정의
|
||||
},
|
||||
dispose() {
|
||||
cancelAnimationFrame(animationFrameId);
|
||||
resizeObserver.disconnect();
|
||||
|
||||
Reference in New Issue
Block a user