auto: 2026-07-28 19:19 (EOMSANGDON-HOME)
This commit is contained in:
@@ -50,6 +50,9 @@ import {
|
|||||||
} from "./B05_wf2_Route_UI_IrregularStations";
|
} from "./B05_wf2_Route_UI_IrregularStations";
|
||||||
import type { SectionStation } from "../B06_wf3_ProfileCross/B06_wf3_ProfileCross_Api_Fetch";
|
import type { SectionStation } from "../B06_wf3_ProfileCross/B06_wf3_ProfileCross_Api_Fetch";
|
||||||
import "../B06_wf3_ProfileCross/B06_wf3_ProfileCross_UI_Style.css";
|
import "../B06_wf3_ProfileCross/B06_wf3_ProfileCross_UI_Style.css";
|
||||||
|
// SVG 차트 색상(.b06-chart__*)의 정의처는 _Style_Cross.css다. 이걸 빼면 B05로 바로 진입했을 때
|
||||||
|
// 배경 rect가 브라우저 기본 fill(검정)로 그려진다 — B06을 먼저 방문해야 정상으로 보이던 원인.
|
||||||
|
import "../B06_wf3_ProfileCross/B06_wf3_ProfileCross_UI_Style_Cross.css";
|
||||||
|
|
||||||
const COLLAPSED_KEY = "b05-route-profile-collapsed";
|
const COLLAPSED_KEY = "b05-route-profile-collapsed";
|
||||||
/** 정보 라인을 뺀 본문 세로를 그래프 40% : 테이블 60%로 나눈다(4:6, 6이 테이블). */
|
/** 정보 라인을 뺀 본문 세로를 그래프 40% : 테이블 60%로 나눈다(4:6, 6이 테이블). */
|
||||||
|
|||||||
@@ -374,6 +374,7 @@ function buildSelectedColumn(
|
|||||||
interval: number,
|
interval: number,
|
||||||
display: { station: number; cumulative: number },
|
display: { station: number; cumulative: number },
|
||||||
onAdjustStation?: (chainageM: number, deltaM: number) => void,
|
onAdjustStation?: (chainageM: number, deltaM: number) => void,
|
||||||
|
isIrregular = false,
|
||||||
): HTMLElement {
|
): HTMLElement {
|
||||||
const plan = interpolateSample(alignment.samples, chainage, "elevation_m");
|
const plan = interpolateSample(alignment.samples, chainage, "elevation_m");
|
||||||
const ground = interpolateSample(alignment.samples, chainage, "ground_elevation_m");
|
const ground = interpolateSample(alignment.samples, chainage, "ground_elevation_m");
|
||||||
@@ -419,7 +420,10 @@ function buildSelectedColumn(
|
|||||||
{ value: { text: curve ? curve.l_m.toFixed(2) : "" }, modifier: "" }, // 곡선 L
|
{ value: { text: curve ? curve.l_m.toFixed(2) : "" }, modifier: "" }, // 곡선 L
|
||||||
{ value: { text: curve ? curve.r_m.toFixed(1) : "" }, modifier: "" }, // 곡선 R
|
{ value: { text: curve ? curve.r_m.toFixed(1) : "" }, modifier: "" }, // 곡선 R
|
||||||
];
|
];
|
||||||
const column = element("div", "b05-profile-table__irregular-col");
|
const column = element(
|
||||||
|
"div",
|
||||||
|
`b05-profile-table__irregular-col${isIrregular ? " is-floating" : ""}`,
|
||||||
|
);
|
||||||
column.style.left = `${centerX}px`;
|
column.style.left = `${centerX}px`;
|
||||||
column.style.width = `${cellWidth}px`;
|
column.style.width = `${cellWidth}px`;
|
||||||
rows.forEach((row) => {
|
rows.forEach((row) => {
|
||||||
@@ -501,15 +505,20 @@ export function createProfileTable(options: ProfileTableOptions): HTMLElement {
|
|||||||
? alignment.stations.findIndex((row) => row.station_id === options.selectedStationId)
|
? alignment.stations.findIndex((row) => row.station_id === options.selectedStationId)
|
||||||
: -1;
|
: -1;
|
||||||
if (selectedIrregular) {
|
if (selectedIrregular) {
|
||||||
|
const centerX = x(selectedIrregular.chainage_m);
|
||||||
|
// 비정규 측점은 측점 격자와 무관한 위치라 오버레이가 좌우 이웃 셀을 반씩 덮어 값이 잘려
|
||||||
|
// 보인다. 겹치는 규칙 측점 셀을 숨겨 하이라이트 창이 깨끗한 자리에 뜨게 한다.
|
||||||
|
hideCoveredCells(table, centers, centerX, cellWidth);
|
||||||
table.append(
|
table.append(
|
||||||
buildSelectedColumn(
|
buildSelectedColumn(
|
||||||
selectedIrregular.chainage_m,
|
selectedIrregular.chainage_m,
|
||||||
alignment,
|
alignment,
|
||||||
x(selectedIrregular.chainage_m),
|
centerX,
|
||||||
cellWidth,
|
cellWidth,
|
||||||
stationInterval,
|
stationInterval,
|
||||||
display,
|
display,
|
||||||
options.onAdjustStation,
|
options.onAdjustStation,
|
||||||
|
true,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
} else if (selectedRegularIndex >= 0) {
|
} else if (selectedRegularIndex >= 0) {
|
||||||
@@ -522,8 +531,33 @@ export function createProfileTable(options: ProfileTableOptions): HTMLElement {
|
|||||||
stationInterval,
|
stationInterval,
|
||||||
display,
|
display,
|
||||||
options.onAdjustStation,
|
options.onAdjustStation,
|
||||||
|
false,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return table;
|
return table;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 하이라이트 열이 덮는 자리의 규칙 측점 값 셀을 숨긴다.
|
||||||
|
* 셀과 하이라이트 열 모두 폭 `cellWidth`를 중심 정렬로 쓰므로, 중심 간 거리가 `cellWidth`
|
||||||
|
* 미만이면 두 사각형이 겹친다. 겹치는 측점은 어차피 값이 잘려 읽을 수 없으므로 통째로 숨긴다.
|
||||||
|
*/
|
||||||
|
function hideCoveredCells(
|
||||||
|
table: HTMLElement,
|
||||||
|
centers: readonly number[],
|
||||||
|
columnCenter: number,
|
||||||
|
cellWidth: number,
|
||||||
|
): void {
|
||||||
|
const covered = new Set<number>();
|
||||||
|
centers.forEach((center, index) => {
|
||||||
|
if (Math.abs(center - columnCenter) < cellWidth) covered.add(index);
|
||||||
|
});
|
||||||
|
if (covered.size === 0) return;
|
||||||
|
table.querySelectorAll<HTMLElement>(".b05-profile-table__row").forEach((row) => {
|
||||||
|
const cells = row.querySelectorAll<HTMLElement>(
|
||||||
|
".b05-profile-table__cell, .b05-profile-table__curve",
|
||||||
|
);
|
||||||
|
covered.forEach((index) => cells[index]?.classList.add("is-covered"));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.b05-route__main {
|
.b05-route__main {
|
||||||
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -35,22 +36,28 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* 하단 종단 패널: 그래프 + 12행 도면 테이블을 담기 위해 화면 높이의 60%를 차지한다.
|
/* 하단 종단 패널: 그래프 + 12행 도면 테이블을 담기 위해 화면 높이의 60%를 차지한다.
|
||||||
|
3D 뷰포트를 밀어내지 않고 그 위를 덮는 오버레이로 띄운다 — 패널을 여닫아도 3D 뷰
|
||||||
|
크기가 변하지 않아 카메라 시점과 렌더 비용이 그대로 유지된다.
|
||||||
접기 핸들로 언제든 내릴 수 있어 3D 뷰를 전체 영역으로 볼 수 있다. */
|
접기 핸들로 언제든 내릴 수 있어 3D 뷰를 전체 영역으로 볼 수 있다. */
|
||||||
.b05-route-profile {
|
.b05-route-profile {
|
||||||
position: relative;
|
position: absolute;
|
||||||
|
z-index: 3;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex: 0 0 60vh;
|
height: 60vh;
|
||||||
flex: 0 0 60dvh;
|
height: 60dvh;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
border-top: 1px solid var(--color-border);
|
border-top: 1px solid var(--color-border);
|
||||||
background: var(--color-surface-raised);
|
background: var(--color-surface-raised);
|
||||||
transition: flex-basis var(--transition-fast);
|
transition: height var(--transition-fast);
|
||||||
}
|
}
|
||||||
|
|
||||||
.b05-route-profile.is-collapsed {
|
.b05-route-profile.is-collapsed {
|
||||||
flex-basis: 0;
|
height: 0;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -663,6 +670,22 @@
|
|||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 비정규(구조물) 측점은 측점 격자와 무관한 위치에 떠서, 이웃 셀을 가린 자리에 뜬다.
|
||||||
|
떠 있는 창임이 드러나게 그림자·굵은 테두리로 구분한다(규칙 측점은 격자와 일치해 불필요). */
|
||||||
|
.b05-profile-table__irregular-col.is-floating {
|
||||||
|
border-inline-width: 2px;
|
||||||
|
box-shadow:
|
||||||
|
0 0 0 1px var(--color-surface-raised),
|
||||||
|
0 4px 12px rgb(0 0 0 / 28%);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 하이라이트 창이 덮은 자리의 규칙 측점 값 셀 — 값이 잘려 읽을 수 없으므로 숨긴다.
|
||||||
|
자리(레이아웃)는 유지해야 세로 구분선 격자가 끊기지 않으므로 visibility로 감춘다. */
|
||||||
|
.b05-profile-table__cell.is-covered,
|
||||||
|
.b05-profile-table__curve.is-covered {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
.b05-profile-table__irregular-col-cell {
|
.b05-profile-table__irregular-col-cell {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex: 1 1 0;
|
flex: 1 1 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user