fix(479 B06 횡단 정보 칸): 처음 빈 칸 · 암 정보는 암 점선 고를 때만 — 안 고름 암 갈래 · 그림 없는 카드 암 칸 · 죽은 buildRockBoundaryControl 걷음 · 시험 370-3 · 318 · 137 고쳐 씀
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -7,13 +7,8 @@
|
||||
* ========================================================================== */
|
||||
|
||||
import type { CrossSection } from "./B06_Section_Api_Fetch";
|
||||
import type { RockBoundaryControl } from "./B06_Section_UI_Cross_Design";
|
||||
import { buildCutSlopeControl, type CutSlopeControl } from "./B06_Section_UI_Cross_CutSlope";
|
||||
import {
|
||||
buildDesignControls,
|
||||
buildRockBoundaryControl,
|
||||
sectionModeLabel,
|
||||
} from "./B06_Section_UI_Cross_Design";
|
||||
import { buildDesignControls, sectionModeLabel } from "./B06_Section_UI_Cross_Design";
|
||||
import { type FillSlopeLength, fillSlopeLengths } from "./logic/B06_Section_UI_Cross_Fit";
|
||||
import {
|
||||
type DesignChangeHandler,
|
||||
@@ -159,27 +154,20 @@ export function appendCardHeader(
|
||||
card.append(header);
|
||||
}
|
||||
|
||||
/** 하단 정보행 — 왼쪽 = 선 공용 칸(370-3 · 안 고르면 암 경계선) · 오른쪽 = (암 지반일 때) 암 절토 경사. */
|
||||
/** 하단 정보행 — 왼쪽 = 선 공용 칸(370-3 · 안 고르면 빈 칸 · 479) · 오른쪽 = (암 지반일 때) 암 절토 경사. */
|
||||
export function appendCardFooter(
|
||||
card: HTMLElement,
|
||||
section: CrossSection,
|
||||
rockBoundary?: RockBoundaryControl,
|
||||
cutSlope?: CutSlopeControl,
|
||||
/** 설계선 고름 공용 칸(370-3 · `_Cross_Line_Cell`) — 있으면 왼쪽 칸(안 고르면 암 · 고르면 그 선). */
|
||||
/** 설계선 고름 공용 칸(370-3 · `_Cross_Line_Cell`) — 있으면 왼쪽 칸(안 고르면 빈 칸 · 고르면 그 선). */
|
||||
lineCell?: HTMLElement,
|
||||
): void {
|
||||
// 중심고는 그래프 Y축 라벨 상자로 옮김(318-2 · `_Cross_Axes`) — 하단 띠는 암 제어만 · 비어도 띠 높이 그대로
|
||||
// 중심고는 그래프 Y축 라벨 상자로 옮김(318-2 · `_Cross_Axes`) — 비어도 띠 높이 그대로
|
||||
const footer = document.createElement("footer");
|
||||
if (lineCell) {
|
||||
lineCell.classList.add("b06-cross-card__rockb");
|
||||
footer.append(lineCell);
|
||||
}
|
||||
// 암 경계선 제어는 하단 정보 행 왼쪽(318-2) — 암 지반만 · 설계선 고름이 없는 카드.
|
||||
else if (rockBoundary && section.design?.geometry_preset === "rock") {
|
||||
const rockControl = buildRockBoundaryControl(section, rockBoundary);
|
||||
rockControl.classList.add("b06-cross-card__rockb");
|
||||
footer.append(rockControl);
|
||||
}
|
||||
// 암 절토 경사(각도)는 암 측점에만 — 토사 측점은 암반이 없어 쓰이지 않는다
|
||||
// (2026-09-07 사용자 확정). 전체를 바꾸는 자리는 좌측 [표준 횡단면 설정]이다.
|
||||
if (cutSlope && section.design?.geometry_preset === "rock") {
|
||||
|
||||
@@ -28,7 +28,7 @@ export {
|
||||
} from "./B06_Section_UI_Cross_Design_Surface";
|
||||
export { appendCrossDesignOverlay } from "./B06_Section_UI_Cross_Design_Line";
|
||||
import { openCrossDetail, refreshCrossDetail } from "./B06_Section_UI_Cross_Detail";
|
||||
import { buildLineCell, rockCellState, type RockCellSpec } from "./B06_Section_UI_Cross_Line_Cell";
|
||||
import type { RockCellSpec } from "./B06_Section_UI_Cross_Line_Cell";
|
||||
|
||||
/** 넘침 정리 한 장 몫 — 쓰기·읽기·쓰기 세 토막으로 갈라 두어 프레임 단위로 묶는다. */
|
||||
interface ReflowCard {
|
||||
@@ -207,18 +207,7 @@ function toggle(
|
||||
return { wrap, button };
|
||||
}
|
||||
|
||||
/** 암 경계선 상/하/리셋 컨트롤 — 아래 띠 공용 칸(370-3 · `_Cross_Line_Cell`)의 「안 고름」 꼴. 설계선 고름이
|
||||
* 없는 카드(설계 없음)에서 띠 왼쪽 칸으로 씀. */
|
||||
export function buildRockBoundaryControl(
|
||||
section: CrossSection,
|
||||
control: RockBoundaryControl,
|
||||
): HTMLElement {
|
||||
const cell = buildLineCell();
|
||||
cell.show(rockCellState(rockCellSpec(section, control)));
|
||||
return cell.root;
|
||||
}
|
||||
|
||||
/** 암 경계선 칸 제원 — 공용 칸(안 고름 · 암 고름)이 같이 씀. */
|
||||
/** 암 경계선 칸 제원 — 공용 칸 암 고름(479 — 안 고르면 빈 칸). */
|
||||
export function rockCellSpec(section: CrossSection, control: RockBoundaryControl): RockCellSpec {
|
||||
return {
|
||||
legend: L("B06_Design_RockBoundary_Legend"),
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* 그려진 보라 선(`b06-chart__design-cross`)을 화면 좌표에서 m 로 되돌려 같은 방향 토막을
|
||||
* 직선 조각 하나로 합치고, 벽 · 본체 폴리곤에 가린 부분을 뺀 **보이는 조각**마다 투명 판정
|
||||
* 선을 구조물 판정면 아래에 깐다. 고르면 그 조각을 강조하고 아래 띠 공용 칸(370-3 · `_Cross_Line_Cell`)에
|
||||
* 제목 · 축에 맞는 버튼 · 치수 한 줄을 적는다(안 고르면 암 경계선 칸 · 떠 있는 선 조정창 · 우측 위 라벨 걷음).
|
||||
* 제목 · 축에 맞는 버튼 · 치수 한 줄을 적는다(안 고르면 빈 칸 · 479 · 떠 있는 선 조정창 · 우측 위 라벨 걷음).
|
||||
* 구역 판정(`crossZoneAt` · 도로 · 절토 · 성토)은 설계선 쉬프트(139-6)도 쓴다.
|
||||
* 고름 상태는 페이지에 한 칸(측점 + 조각 번호) — 카드를 다시 그려도 되살아난다.
|
||||
* 고른 조각 쪽 사면을 노견째 ◀ ↺ ▶ · 방향키 · 0.1 m 로 옮김(139-6 쉬프트 · 151-3 ·
|
||||
@@ -444,7 +444,7 @@ export function attachDesignLinePick(input: {
|
||||
toes?: ReturnType<typeof toePoints>;
|
||||
/** 있으면 쪽마다 노견 끝 = 원지반(절·성토 없음 · 379-1) — 손잡이 값 앞 알림. */
|
||||
bare?: ReturnType<typeof edgeOnGround>;
|
||||
/** 있으면 암 경계선 고름(키 `rock` · ▲▼↺ · 세로 끌기) · 안 고른 때 공용 칸 = 암(370-3). */
|
||||
/** 있으면 암 경계선 고름(키 `rock` · ▲▼↺ · 세로 끌기 · 370-3) · 안 고르면 빈 칸(479). */
|
||||
rock?: RockCellSpec;
|
||||
}): DesignLinePick {
|
||||
const { layer, design, x, toDisplayY } = input;
|
||||
@@ -627,33 +627,32 @@ export function attachDesignLinePick(input: {
|
||||
const toe = toeSide ? input.toes?.[toeSide] : null;
|
||||
const dims = piece ? pieceLabel(design, piece).replace("\n", " · ") : "";
|
||||
const bare = toeSide && input.bare?.[toeSide] ? "절·성토 없음 · " : ""; // 379-1
|
||||
// 아래 띠 공용 칸(370-3) — 안 고르면 암(암 지반만) · 고르면 그 선 제목 · 버튼 · 값 한 줄
|
||||
const state: LineCellState | null =
|
||||
onRock || (!chosen && rock)
|
||||
? rockCellState(rock as RockCellSpec)
|
||||
: onCenter
|
||||
? { title: "중심점", value: CENTER_HINT, buttons: {} }
|
||||
: toe
|
||||
? {
|
||||
title: `사면 이동 ${sideName}`,
|
||||
value: `${bare}노선에서 ${Math.abs(toe.offset_m).toFixed(2)}m${moved}`,
|
||||
buttons: shift ? sideways(true) : {},
|
||||
}
|
||||
: !piece
|
||||
? null
|
||||
: axis === "y"
|
||||
? { title: "노면 높이", value: `${dims} · ▲▼ = 종단 계획고`, buttons: {} }
|
||||
: axis === "depth" && side
|
||||
? {
|
||||
title: `소단 높이 ${sideName}`,
|
||||
value: `도로 아래 ${bermDepthOf(design, side).toFixed(1)}m · ${dims}`,
|
||||
buttons: berm ? lift : {},
|
||||
}
|
||||
: {
|
||||
title: `사면 이동 ${sideName}`,
|
||||
value: dims + moved,
|
||||
buttons: shift ? sideways(true) : {},
|
||||
};
|
||||
// 아래 띠 공용 칸(370-3) — 안 고르면 빈 칸(479) · 고르면 그 선 제목 · 버튼 · 값 한 줄
|
||||
const state: LineCellState | null = onRock
|
||||
? rockCellState(rock as RockCellSpec)
|
||||
: onCenter
|
||||
? { title: "중심점", value: CENTER_HINT, buttons: {} }
|
||||
: toe
|
||||
? {
|
||||
title: `사면 이동 ${sideName}`,
|
||||
value: `${bare}노선에서 ${Math.abs(toe.offset_m).toFixed(2)}m${moved}`,
|
||||
buttons: shift ? sideways(true) : {},
|
||||
}
|
||||
: !piece
|
||||
? null
|
||||
: axis === "y"
|
||||
? { title: "노면 높이", value: `${dims} · ▲▼ = 종단 계획고`, buttons: {} }
|
||||
: axis === "depth" && side
|
||||
? {
|
||||
title: `소단 높이 ${sideName}`,
|
||||
value: `도로 아래 ${bermDepthOf(design, side).toFixed(1)}m · ${dims}`,
|
||||
buttons: berm ? lift : {},
|
||||
}
|
||||
: {
|
||||
title: `사면 이동 ${sideName}`,
|
||||
value: dims + moved,
|
||||
buttons: shift ? sideways(true) : {},
|
||||
};
|
||||
cell.show(state);
|
||||
const open =
|
||||
onCenter ||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* B06_Section_UI_Cross_Line_Cell.ts
|
||||
* 횡단 카드 아래 띠 왼쪽 **공용 칸**(370-3) — 고른 선의 제목 · 축에 맞는 버튼 · 값 한 줄.
|
||||
*
|
||||
* · 안 고르면 암 경계선 ▲▼↺ · 값(암 지반만 · 토사는 빈 칸 · 띠 높이 그대로)
|
||||
* · 안 고르면 빈 칸(479 · 띠 높이 그대로)
|
||||
* · 고르면 그 선(노면 · 사면 · 소단 · 중심점 · 교차점 · 암) — `_Cross_Design_Pick` 이 상태를 넣음
|
||||
* · 버튼 다섯 칸(◀ ▲ ↺ ▼ ▶)은 한 벌 · 상태마다 보임 · 툴팁 · 동작만 바꿈 · 방향키는 보이는 슬롯만 찾음
|
||||
* · ▲▼ 길게 누름 = 0.5 초 뒤 0.1 초마다 반복(암 · B05 종단 선 제어 꼴)
|
||||
|
||||
@@ -680,6 +680,6 @@ export function createCrossSectionCard(
|
||||
card.append(chartWrap);
|
||||
}
|
||||
|
||||
appendCardFooter(card, section, rockBoundary, cutSlope, linePick?.cell); // 왼쪽 = 선 공용 칸(370-3)
|
||||
appendCardFooter(card, section, cutSlope, linePick?.cell); // 왼쪽 = 선 공용 칸(370-3)
|
||||
return card;
|
||||
}
|
||||
|
||||
@@ -400,7 +400,7 @@ const out = {};
|
||||
out.draftProfile = { samples: profile.samples, id: profile.id };
|
||||
}
|
||||
|
||||
// ── 2. 아래 띠(318-2 · 318-3) — 중심고 글 없음 · 암 경계 맨 왼쪽 · 토사도 띠 남음 ─────
|
||||
// ── 2. 아래 띠(318-2 · 318-3) — 중심고 글 없음 · 선 칸 없으면 암 절토만(479) · 토사도 띠 남음 ─
|
||||
{
|
||||
const control = (cls) => () => {
|
||||
const node = new FakeNode("div");
|
||||
@@ -410,7 +410,6 @@ const out = {};
|
||||
const load = makeLoader([B06("B06_Section_UI_Cross_Card_Chrome")], {
|
||||
"./B06_Section_UI_Cross_CutSlope": { buildCutSlopeControl: control("cutslope") },
|
||||
"./B06_Section_UI_Cross_Design": {
|
||||
buildRockBoundaryControl: control("rockb"),
|
||||
buildDesignControls: () => ({ bar: new FakeNode("div"), groundSegment: new FakeNode("div") }),
|
||||
sectionModeLabel: () => "",
|
||||
},
|
||||
@@ -424,7 +423,7 @@ const out = {};
|
||||
const { appendCardFooter } = load(B06("B06_Section_UI_Cross_Card_Chrome"));
|
||||
const footerOf = (preset) => {
|
||||
const card = new FakeNode("article");
|
||||
appendCardFooter(card, { center_z: 876.57, design: { geometry_preset: preset } }, {}, {});
|
||||
appendCardFooter(card, { center_z: 876.57, design: { geometry_preset: preset } }, {});
|
||||
return card.querySelector("footer");
|
||||
};
|
||||
const rock = footerOf("rock");
|
||||
@@ -440,7 +439,7 @@ const out = {};
|
||||
const cell = new FakeNode("div");
|
||||
cell.className = "linecell";
|
||||
const cellCard = new FakeNode("article");
|
||||
appendCardFooter(cellCard, { design: { geometry_preset: "rock" } }, {}, {}, cell);
|
||||
appendCardFooter(cellCard, { design: { geometry_preset: "rock" } }, {}, cell);
|
||||
out.footer.cell_classes = cellCard.querySelector("footer").children.map((kid) => kid.className);
|
||||
}
|
||||
|
||||
|
||||
@@ -226,7 +226,7 @@ function card(rockOn = true) {
|
||||
|
||||
const out = {};
|
||||
|
||||
// ① 안 고름 — 공용 칸 = 암 ▲▼↺ · 값 · 방향키는 안 먹음(종단 계획고로 그대로)
|
||||
// ① 안 고름 — 공용 칸 = 빈 칸(479) · 숨은 단추 눌러도 암 안 움직임 · 방향키는 종단 계획고로 그대로
|
||||
{
|
||||
const c = card();
|
||||
c.handle.setActive(null);
|
||||
@@ -283,7 +283,7 @@ const out = {};
|
||||
sent: c.offsets.slice(before),
|
||||
clickSwallowed: (winListeners.click ?? []).length === 1,
|
||||
};
|
||||
// 풀면 다시 암 칸 · 방향키 안 먹음
|
||||
// 풀면 빈 칸(479) · 방향키 안 먹음
|
||||
c.handle.setActive(null);
|
||||
out.released = { ...c.state(), upPassed: !press("ArrowUp") };
|
||||
// 사면을 고르면 그 선 칸(제목 · ◀↺▶ · 값 한 줄)
|
||||
|
||||
@@ -102,7 +102,9 @@ def test_카드_배선_하나만() -> None:
|
||||
assert "setLineActive(pickedLineAt(section.station_id));" in view # 다시 그려도 되살림
|
||||
# 치수 · 이동 = 아래 띠 왼쪽 공용 칸(370-3 · 옛 [+ − ⤢] 왼쪽 치수 · 떠 있는 이동 패널 걷음)
|
||||
assert "linePick.label" not in view and "linePick.panel" not in view
|
||||
assert "appendCardFooter(card, section, rockBoundary, cutSlope, linePick?.cell);" in view
|
||||
assert (
|
||||
"appendCardFooter(card, section, cutSlope, linePick?.cell);" in view
|
||||
) # 479 — 암 칸 인자 걷음
|
||||
css = _src("B06_Section/B06_Section_UI_Style_Cross_Areas.css")
|
||||
assert ".b06-chart__design-hit.is-active {" in css
|
||||
|
||||
|
||||
@@ -118,8 +118,8 @@ def test_footer_without_center_text(result: dict) -> None:
|
||||
footer = result["footer"]
|
||||
assert "중심고" not in footer["rock_text"]
|
||||
assert "876" not in footer["rock_text"]
|
||||
assert footer["rock_first"].split()[-1] == "b06-cross-card__rockb" # 암 경계 = 왼쪽 첫 칸
|
||||
assert footer["rock_classes"][-1].split()[-1] == "b06-cross-card__cutslope"
|
||||
# 479 — 선 공용 칸이 없는 암 카드 = 암 절토 칸만(암 경계 칸 따로 안 만듦)
|
||||
assert footer["rock_classes"] == ["cutslope b06-cross-card__cutslope"]
|
||||
assert footer["soil_exists"] and footer["soil_children"] == 0 # 토사도 띠는 남음(빈 띠)
|
||||
# 370-3 — 선 공용 칸 = 왼쪽 첫 칸(암 꼴 클래스) · 암 절토 경사 = 오른쪽 그대로
|
||||
assert footer["cell_classes"] == [
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
"""PLAN 370-3 — B06 암 경계선 고름 · 방향키 · 세로 끌기 · 아래 띠 공용 칸(요구 240-22).
|
||||
|
||||
479(요구 280-1) — 안 고르면 공용 칸 = 빈 칸 · 암 정보는 암 점선을 고를 때만.
|
||||
|
||||
짝: `B06_Section/B06_Section_UI_Cross_Design_Pick.ts`(rock 축 · 판정 선) ·
|
||||
`B06_Section/B06_Section_UI_Cross_Line_Cell.ts`(공용 칸) · `B06_Section_UI_Cross_Center.ts`(`bindAxisDrag`).
|
||||
실제 TS 를 `helper_370_3_rock_cell.cjs` 가 Node 로 돌린다.
|
||||
@@ -31,12 +33,11 @@ def out() -> dict:
|
||||
return json.loads(done.stdout)
|
||||
|
||||
|
||||
def test_안_고르면_공용_칸은_암_버튼과_값(out: dict) -> None:
|
||||
def test_안_고르면_공용_칸은_빈_칸(out: dict) -> None:
|
||||
idle = out["idle"]
|
||||
assert idle["title"] == "암 경계선" and idle["value"] == "-0.5m"
|
||||
assert idle["slots"] == ["up", "reset", "down"]
|
||||
assert idle["empty"] is True and idle["slots"] == [] # 479 — 암 지반도 빈 칸
|
||||
assert idle["upPassed"] is True # 안 고르면 ▲▼ = 종단 계획고 그대로
|
||||
assert idle["offsets"] == [0.1, -0.1] and idle["resets"] == 1
|
||||
assert idle["offsets"] == [] and idle["resets"] == 0 # 숨은 단추 눌러도 암 안 움직임
|
||||
|
||||
|
||||
def test_암_경계선_판정_선(out: dict) -> None:
|
||||
@@ -67,8 +68,8 @@ def test_세로_끌기는_놓을_때_한_번(out: dict) -> None:
|
||||
assert out["idleDrag"]["stopped"] is False # 안 고르면 끌기 아님
|
||||
|
||||
|
||||
def test_풀면_암_칸_사면_고르면_그_선_칸(out: dict) -> None:
|
||||
assert out["released"]["title"] == "암 경계선" and out["released"]["upPassed"]
|
||||
def test_풀면_빈_칸_사면_고르면_그_선_칸(out: dict) -> None:
|
||||
assert out["released"]["empty"] is True and out["released"]["upPassed"]
|
||||
slope = out["slope"]
|
||||
assert slope["title"] == "사면 이동 (좌)" and slope["slots"] == ["left", "reset", "right"]
|
||||
assert slope["value"].startswith("길이 ") and "\n" not in slope["value"]
|
||||
@@ -87,6 +88,7 @@ def test_배선_떠_있는_선_조정창_걷음() -> None:
|
||||
assert "rockBoundary && rockCellSpec(section, rockBoundary)" in view
|
||||
chrome = (B06 / "B06_Section_UI_Cross_Card_Chrome.ts").read_text(encoding="utf-8")
|
||||
assert "if (lineCell) {" in chrome
|
||||
assert "buildRockBoundaryControl" not in chrome # 479 — 그림 없는 암 카드도 빈 칸
|
||||
detail = (B06 / "B06_Section_UI_Cross_Detail_Pick.ts").read_text(encoding="utf-8")
|
||||
assert ".b06-chart__design-hit:not(.b06-chart__rock-hit)" in detail # 상세 표 강조에 안 섞임
|
||||
css = (B06 / "B06_Section_UI_Style_Cross.css").read_text(encoding="utf-8")
|
||||
|
||||
Reference in New Issue
Block a user