260723_7
This commit is contained in:
@@ -135,6 +135,8 @@ def generate_sections(
|
||||
long_z, long_valid = sampler.sample_xy(long_xy)
|
||||
|
||||
station_chainage = _chainages(total, options.station_interval_m, options.include_endpoint)
|
||||
# 규칙(격자) 측점 chainage 집합 — 비정규와 겹칠 때 규칙 측점을 우선 판정하는 데 쓴다.
|
||||
regular_rounded = {round(float(value), 6) for value in station_chainage}
|
||||
# 비정규 측점(구조물)을 격자 측점 배열에 병합한다. 정렬·중복 제거만 하면 이후 접선·횡단
|
||||
# 샘플링이 전부 이 배열을 따라 자동으로 확장된다. 어느 측점이 비정규인지는 chainage로 판별.
|
||||
extras = {
|
||||
@@ -183,7 +185,8 @@ def generate_sections(
|
||||
kind = "bp"
|
||||
elif abs(float(value) - total) <= 1e-6:
|
||||
kind = "ep"
|
||||
elif rounded in extras:
|
||||
elif rounded in extras and rounded not in regular_rounded:
|
||||
# 격자와 겹치지 않는 비정규 측점만 irregular. 규칙 격자와 겹치면 규칙 측점 우선.
|
||||
kind = "irregular"
|
||||
else:
|
||||
kind = "regular"
|
||||
@@ -213,7 +216,8 @@ def generate_sections(
|
||||
"azimuth_deg": round(azimuth, 6),
|
||||
"frame": frame,
|
||||
}
|
||||
if kind == "irregular":
|
||||
# 구조물은 kind와 무관하게 부착한다(규칙 격자와 겹쳐 regular가 돼도 구조물 정보는 유지).
|
||||
if rounded in extras:
|
||||
station["structure"] = extras[rounded]
|
||||
stations.append(station)
|
||||
|
||||
|
||||
@@ -72,8 +72,9 @@ export function createIrregularStationsSection(
|
||||
callbacks: IrregularStationsCallbacks,
|
||||
): IrregularStationsSection {
|
||||
const root = document.createElement("section");
|
||||
root.className = "b05-route__panel-section";
|
||||
root.className = "b05-route__panel-section ui-collapsible";
|
||||
const heading = document.createElement("h3");
|
||||
heading.className = "ui-collapsible__title";
|
||||
heading.textContent = "비정규 측점 (구조물)";
|
||||
const body = document.createElement("div");
|
||||
body.className = "b05-route__panel-body";
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
type IrregularStationsSection,
|
||||
} from "./B05_wf2_Route_UI_IrregularStations";
|
||||
import { type ButtonVariant, createButton } from "@ui/ui_template_elements";
|
||||
import { attachCollapsible } from "@ui/ui_template_collapsible";
|
||||
import { currentLanguageIndex, ui_locales } from "@ui/ui_template_locale";
|
||||
|
||||
export interface RoutePanelValues {
|
||||
@@ -71,8 +72,9 @@ function L(key: keyof typeof ui_locales): string {
|
||||
|
||||
function section(title: string): { root: HTMLElement; body: HTMLElement } {
|
||||
const root = document.createElement("section");
|
||||
root.className = "b05-route__panel-section";
|
||||
root.className = "b05-route__panel-section ui-collapsible";
|
||||
const heading = document.createElement("h3");
|
||||
heading.className = "ui-collapsible__title";
|
||||
heading.textContent = title;
|
||||
const body = document.createElement("div");
|
||||
body.className = "b05-route__panel-body";
|
||||
@@ -355,15 +357,9 @@ export function createRoutePanel(callbacks: PanelCallbacks) {
|
||||
actionRow,
|
||||
);
|
||||
|
||||
// 컨테이너 제목(h3) 클릭 시 본문을 접거나 편다(제목은 남긴다). 본문 안의 details 등 별도
|
||||
// 접힘 항목은 손대지 않으므로 열려 있으면 그대로 보인다.
|
||||
root.addEventListener("click", (event) => {
|
||||
const heading = (event.target as HTMLElement).closest("h3");
|
||||
const container = heading?.parentElement;
|
||||
if (heading && container?.classList.contains("b05-route__panel-section")) {
|
||||
container.classList.toggle("is-collapsed");
|
||||
}
|
||||
});
|
||||
// 컨테이너 제목 행 전체 클릭 시 본문을 접거나 편다(공용 collapsible). 내부 details 등 별도
|
||||
// 접힘 항목은 손대지 않는다.
|
||||
attachCollapsible(root);
|
||||
|
||||
return {
|
||||
root,
|
||||
|
||||
@@ -292,6 +292,11 @@ function buildCurveRows(options: ProfileTableOptions, centers: number[]): HTMLEl
|
||||
if (curve.omitted) cell.classList.add("is-omitted");
|
||||
});
|
||||
}
|
||||
// 선택된 규칙 측점 열의 곡선 셀도 함께 하이라이트한다.
|
||||
if (station.station_id && station.station_id === options.selectedStationId) {
|
||||
lengthCell.classList.add("is-selected");
|
||||
radiusCell.classList.add("is-selected");
|
||||
}
|
||||
placeCell(lengthRow, centers[index], lengthCell);
|
||||
placeCell(radiusRow, centers[index], radiusCell);
|
||||
});
|
||||
@@ -458,8 +463,12 @@ export function createProfileTable(options: ProfileTableOptions): HTMLElement {
|
||||
spec.unit,
|
||||
);
|
||||
// 값이 없는 측점(절토고/성토고 중 한쪽)도 빈 칸을 만들어야 세로 구분선이 끊기지 않는다.
|
||||
alignment.stations.forEach((_station, stationIndex) => {
|
||||
alignment.stations.forEach((station, stationIndex) => {
|
||||
const cell = element("span", "b05-profile-table__cell", spec.cell(stationIndex));
|
||||
// 선택된 규칙 측점은 그 열의 값 셀을 하이라이트한다(비정규 측점의 값 열 강조와 통일).
|
||||
if (station.station_id && station.station_id === options.selectedStationId) {
|
||||
cell.classList.add("is-selected");
|
||||
}
|
||||
placeCell(row, centers[stationIndex], cell);
|
||||
});
|
||||
table.append(row);
|
||||
|
||||
@@ -211,33 +211,11 @@
|
||||
background: var(--color-surface-raised);
|
||||
}
|
||||
|
||||
/* 제목 행 클릭 접기/펼치기는 공용 collapsible(ui_template_theme.css)에서 처리한다. */
|
||||
.b05-route__panel-section h3 {
|
||||
margin: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: var(--spacing-8);
|
||||
color: var(--color-text);
|
||||
font-size: var(--text-body-sm);
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
/* 접기/펼침 상태를 제목 우측 캐럿으로 표시(이 기능이 있음을 알린다). 펼침 ▾ / 접힘 ▸. */
|
||||
.b05-route__panel-section h3::after {
|
||||
content: "▾";
|
||||
flex: 0 0 auto;
|
||||
color: var(--color-text-muted);
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
.b05-route__panel-section.is-collapsed h3::after {
|
||||
content: "▸";
|
||||
}
|
||||
|
||||
/* 제목 클릭으로 접힌 컨테이너: 본문만 감추고 제목은 남긴다. */
|
||||
.b05-route__panel-section.is-collapsed .b05-route__panel-body {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.b05-route__panel-body,
|
||||
@@ -577,6 +555,16 @@
|
||||
border-right: 1px solid var(--color-border);
|
||||
}
|
||||
|
||||
/* 선택된 규칙 측점 열의 값·곡선 셀 하이라이트(비정규 측점 값 열 강조와 같은 색). */
|
||||
.b05-profile-table__cell.is-selected,
|
||||
.b05-profile-table__curve.is-selected {
|
||||
background: color-mix(
|
||||
in srgb,
|
||||
var(--color-royal-amethyst, rgb(109 40 217)) 14%,
|
||||
var(--color-surface)
|
||||
);
|
||||
}
|
||||
|
||||
.b05-profile-table__row.is-cut .b05-profile-table__cell {
|
||||
color: rgb(220 38 38);
|
||||
}
|
||||
|
||||
@@ -141,7 +141,18 @@ export function createCrossSectionCard(
|
||||
: section.kind === "bp"
|
||||
? L("B06_Profile_View_Kind_BP")
|
||||
: L("B06_Profile_View_Kind_Station");
|
||||
header.append(title, kind);
|
||||
// kind 라벨(일반측점/BP/EP) 좌측에 구조물 정보를 표기(비정규 측점이 확정 시 실어온 값).
|
||||
const meta = document.createElement("div");
|
||||
meta.className = "b06-cross-card__meta";
|
||||
if (section.structure) {
|
||||
const structure = document.createElement("span");
|
||||
structure.className = "b06-cross-card__structure";
|
||||
structure.textContent = section.structure;
|
||||
structure.title = `구조물: ${section.structure}`;
|
||||
meta.append(structure);
|
||||
}
|
||||
meta.append(kind);
|
||||
header.append(title, meta);
|
||||
card.append(header);
|
||||
if (onDesignChange) card.append(buildDesignControls(section, onDesignChange));
|
||||
|
||||
|
||||
@@ -240,6 +240,16 @@
|
||||
font-size: var(--text-body-sm);
|
||||
}
|
||||
|
||||
/* 비정규 측점의 구조물 라벨 — kind(일반측점/BP/EP) 좌측에 자수정색 pill로 표기. */
|
||||
.b06-cross-card__structure {
|
||||
padding: 1px 6px;
|
||||
border-radius: var(--radius-pills);
|
||||
background: color-mix(in srgb, var(--color-royal-amethyst, rgb(109 40 217)) 16%, transparent);
|
||||
color: var(--color-royal-amethyst, rgb(109 40 217));
|
||||
font-size: var(--text-caption);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.b06-cross-card > footer {
|
||||
border-top: 1px solid var(--color-border);
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
* ========================================================================== */
|
||||
|
||||
import "./B07_wf4_DesignDetail_UI_Style.css";
|
||||
import { attachCollapsible } from "@ui/ui_template_collapsible";
|
||||
import { ui_locales, currentLanguageIndex } from "@ui/ui_template_locale";
|
||||
import {
|
||||
createButton,
|
||||
@@ -136,9 +137,10 @@ function buildDrawingSidePanel(
|
||||
for (const [label, kind, items] of groups) {
|
||||
if (!items.length) continue;
|
||||
const section = document.createElement("section");
|
||||
section.className = "b07-drawing-group";
|
||||
section.className = "b07-drawing-group ui-collapsible";
|
||||
section.dataset.kind = kind;
|
||||
const sectionTitle = document.createElement("h3");
|
||||
sectionTitle.className = "ui-collapsible__title";
|
||||
sectionTitle.textContent = `${label} ${items.length}`;
|
||||
section.append(sectionTitle);
|
||||
for (const drawing of items) {
|
||||
@@ -159,6 +161,7 @@ function buildDrawingSidePanel(
|
||||
}
|
||||
panel.append(section);
|
||||
}
|
||||
attachCollapsible(panel);
|
||||
return panel;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/* =============================================================================
|
||||
* ui_template_collapsible.ts
|
||||
* 페이지 공용 "접기 컨테이너" 동작. (B05 컨테이너 템플릿 기준으로 재사용)
|
||||
*
|
||||
* 규칙:
|
||||
* - 컨테이너에 `ui-collapsible`, 그 제목 요소에 `ui-collapsible__title` 클래스를 준다.
|
||||
* - 제목 **행 전체**를 클릭하면 컨테이너에 `is-collapsed`가 토글되어, 제목을 뺀 나머지 직속
|
||||
* 자식이 숨겨진다(펼침 ▾ / 접힘 ▸ 캐럿은 공용 CSS가 그린다).
|
||||
* - 컨테이너 내부의 별도 접힘 항목(`<details>` 등)은 건드리지 않는다.
|
||||
*
|
||||
* 스타일은 전역 `ui_template_theme.css`에 있어 어떤 페이지에서도 클래스만 붙이면 동작한다.
|
||||
* ========================================================================== */
|
||||
|
||||
/** root 아래 `.ui-collapsible__title` 클릭을 위임 처리해 해당 컨테이너를 접거나 편다. */
|
||||
export function attachCollapsible(root: HTMLElement): void {
|
||||
root.addEventListener("click", (event) => {
|
||||
const title = (event.target as HTMLElement).closest<HTMLElement>(".ui-collapsible__title");
|
||||
const container = title?.closest<HTMLElement>(".ui-collapsible");
|
||||
if (title && container) container.classList.toggle("is-collapsed");
|
||||
});
|
||||
}
|
||||
@@ -331,6 +331,33 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* ─── 공용 접기 컨테이너 (ui_template_collapsible.ts) ─────────────────────────
|
||||
컨테이너에 `ui-collapsible`, 제목에 `ui-collapsible__title`을 주면 제목 행 전체가
|
||||
클릭 영역이 되고, 접히면 제목을 뺀 직속 자식이 숨겨진다. 펼침 ▾ / 접힘 ▸ 캐럿 표시. */
|
||||
.ui-collapsible__title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: var(--spacing-8, 8px);
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.ui-collapsible__title::after {
|
||||
content: "▾";
|
||||
flex: 0 0 auto;
|
||||
color: var(--color-text-muted);
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
.ui-collapsible.is-collapsed > .ui-collapsible__title::after {
|
||||
content: "▸";
|
||||
}
|
||||
|
||||
.ui-collapsible.is-collapsed > :not(.ui-collapsible__title) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
|
||||
Reference in New Issue
Block a user