diff --git a/B05_wf2_Route/B05_wf2_Route_UI_IrregularStations.ts b/B05_wf2_Route/B05_wf2_Route_UI_IrregularStations.ts index c62e35fc..d93ae65e 100644 --- a/B05_wf2_Route/B05_wf2_Route_UI_IrregularStations.ts +++ b/B05_wf2_Route/B05_wf2_Route_UI_IrregularStations.ts @@ -113,7 +113,8 @@ export function createIrregularStationsSection( help.textContent = "구조물을 설치할 위치를 측점번호+잔여거리로 추가합니다. 목록에서 고르면 수정·삭제할 수 있습니다."; - body.append(field("구조물", structureField), stationRow, actions, list, help); + // 측점번호/잔여거리를 최상단에 둔다(위치가 먼저, 그다음 구조물). + body.append(stationRow, field("구조물", structureField), actions, list, help); const stations: IrregularStation[] = []; let editingId: string | null = null; diff --git a/B05_wf2_Route/B05_wf2_Route_UI_Page.ts b/B05_wf2_Route/B05_wf2_Route_UI_Page.ts index db1bafca..26f30f4b 100644 --- a/B05_wf2_Route/B05_wf2_Route_UI_Page.ts +++ b/B05_wf2_Route/B05_wf2_Route_UI_Page.ts @@ -291,6 +291,11 @@ export async function renderB05Route(root: HTMLElement): Promise { /** 비정규 측점 목록 변경 → 3D·그래프·테이블에 반영(프론트 프리뷰, 백엔드 미전송). */ function applyIrregularStations(stations: IrregularStation[]): void { + // 위치가 바뀌거나 삭제된 비정규 측점의 옛 chainage에 남은 계획고 편집(유령 변화점)을 지운다. + const nextKeys = new Set(stations.map((station) => station.chainage_m.toFixed(3))); + irregularStations + .filter((station) => !nextKeys.has(station.chainage_m.toFixed(3))) + .forEach((station) => profilePanel.resetStationEdit(station.chainage_m)); irregularStations = stations; if (currentSectionDetail) renderStationLines(currentSectionDetail); profilePanel.setIrregularStations(stations); diff --git a/B05_wf2_Route/B05_wf2_Route_UI_Profile_Panel.ts b/B05_wf2_Route/B05_wf2_Route_UI_Profile_Panel.ts index a295bcab..1c4b1847 100644 --- a/B05_wf2_Route/B05_wf2_Route_UI_Profile_Panel.ts +++ b/B05_wf2_Route/B05_wf2_Route_UI_Profile_Panel.ts @@ -31,6 +31,7 @@ import type { import { adjustStation, buildAlignment, + chainageKey, emptyEdits, setCurveRadius, shiftSegment, @@ -570,6 +571,16 @@ export function createRouteProfilePanel( irregularStations = stations; draw(); }, + /** + * 특정 chainage의 계획고 편집(station_offset·curve_radii)을 지운다. + * 비정규 측점을 옮기거나 지울 때 옛 위치에 남는 편집(유령 변화점)을 청소하는 데 쓴다. + */ + resetStationEdit(chainageM: number) { + const key = chainageKey(chainageM); + const edits = store.edits(); + if (edits.station_offsets[key] === undefined && edits.curve_radii[key] === undefined) return; + store.resetStation(chainageM); + }, isDirty: () => store.dirty(), /** [확정] 직전에 호출한다. 편집이 없으면 아무 것도 하지 않는다. */ async save(): Promise { diff --git a/B05_wf2_Route/B05_wf2_Route_UI_Style.css b/B05_wf2_Route/B05_wf2_Route_UI_Style.css index 237e0f45..41361acd 100644 --- a/B05_wf2_Route/B05_wf2_Route_UI_Style.css +++ b/B05_wf2_Route/B05_wf2_Route_UI_Style.css @@ -213,12 +213,28 @@ .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;