Files
Aislo/B06_Section/B06_Section_UI_Standard_Diagram.ts
T
eomsangdonandClaude Opus 5.5 e2b3a87828 refactor(B06): 줌 · 조정창 단추 · 머리 알약 · 알림 칩 · 접이 넷 · 띠 알림 · 빈 상태를 부품으로 (PLAN 553-2)
- 줌 [+ − ⤢] = 아이콘 단추 22 · 상세 [칸에 넣기] = 단추 22 · [여럿] = 켜기 칩 22 · 사이 금 지움
- 구조물 조정창 십자 · 9키 · 단 수 [-][+] = 아이콘 단추(선) 22 · ✕ = 고스트 · 옵션 연동 · 경사 = 켜기 칩 24(유입 · 유출 칸 꼴은 그대로)
- 카드 머리 단면유형 = 배지(정보) 20 · 구조물 = 배지(강조) 20
- 알림 칩 = 단추(고스트) 20(색만 경고 / 정보) · 측점 목록 날 단추 = 단추(고스트) 20
- 날 details 넷(변수 위치 안내 · 상세값 · 다른 프로젝트 불러오기 · 횡단 조정) = 접이 구역(ui-collapsible) · 가이드 장면 선택자 `details.` 뗌
- 측점 없는 구조물 줄 · 표준 미반영 알림 = 띠 알림(경고) — 날 색 #fff8e6 · #e0b872 · #7a5a12 · #8a6a22 · 폴백 #d98324 지움
- 빈 그림 자리 = 빈 상태 · 선 치수 글 옛 보라 이름 → --color-accent
- 흉내 DOM 시험 · 서버 Node 묶음이 끄는 파일이라 부품 함수 대신 클래스 · data-size 계약 + 부품 CSS 직접 실음(묶음 셋 빌드 정상)
- 시험 넷 기대 고침 — 108(닫기 클래스) · 179-1(줌 사이 금 규칙 없음) · 196-1(칩 클래스) · 207-1(칩 반경 = 부품)
- 그대로 둔 것 — 수량 산출표(b06-detail__qtable · B07 산출서 병합 칸 · 세로선 = 부품 표에 없는 꼴) · 조정창 고르기 · 암 절토 칸(작은 단 없음) · 조정창 · ⋯ · 측점 목록 떠 있는 판

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 23:08:13 +09:00

125 lines
5.4 KiB
TypeScript

/* =============================================================================
* B06_Section_UI_Standard_Diagram.ts
* 표준 횡단면 설정 패널의 "변수 위치 안내" 모식도.
*
* 설정 패널의 각 편집값(노폭·노견·측구·절토/성토 경사·횡단경사)이 횡단면의 어느
* 위치를 의미하는지 라벨로 표시하는 스키매틱 SVG다. 실제 비율이 아니라 위치 안내용이며,
* config 값과 무관한 고정 도형이다(값은 패널 입력에서 편집).
* ========================================================================== */
import { currentLanguageIndex, ui_locales } from "@ui/ui_template_locale";
const SVG_NS = "http://www.w3.org/2000/svg";
function L(key: keyof typeof ui_locales): string {
return ui_locales[key][currentLanguageIndex];
}
function node(tag: string, attrs: Record<string, string | number>, cls?: string): SVGElement {
const el = document.createElementNS(SVG_NS, tag);
for (const [k, v] of Object.entries(attrs)) el.setAttribute(k, String(v));
if (cls) el.setAttribute("class", cls);
return el;
}
function text(x: number, y: number, value: string, cls: string, anchor = "middle"): SVGElement {
const t = node("text", { x, y, "text-anchor": anchor }, cls);
t.textContent = value;
return t;
}
/**
* 편절편성(좌 절토·우 성토) 표준 단면 모식도를 만든다. 좌표는 위치 안내 전용 고정값.
* 좌표 규약(+offset=좌)에 맞춰 절토측(측구 방향)을 왼쪽에 둔다.
*/
export function buildStandardDiagram(): HTMLElement {
// 부품 접이 구역(553-2) — 제목 줄 누름은 패널 attachCollapsible 위임이 받음
const wrap = document.createElement("section");
wrap.className = "ui-collapsible b06-std__diagram";
const summary = document.createElement("h4");
summary.className = "ui-collapsible__title b06-std__diagram-summary";
summary.textContent = L("B06_Std_Diagram_Title");
summary.title = L("B06_Std_Diagram_Toggle");
wrap.append(summary);
// 세로로 긴 형태(300×260) — 사면·측구·라벨 간 여백을 넉넉히 둔다.
const svg = node("svg", {
viewBox: "0 0 300 260",
role: "img",
"aria-label": L("B06_Std_Diagram_Title"),
}) as SVGSVGElement;
svg.setAttribute("class", "b06-std__diagram-svg");
// 지반선(원지반) — 좌측 높고 우측 낮은 사면. 절토/성토의 배경.
svg.append(
node("polyline", { points: "10,60 95,122 205,138 290,210", fill: "none" }, "b06-diag__ground"),
);
// 노면(노견 포함): 위치 안내 모식도라 횡단경사는 반영하지 않고 수평으로 그린다(D-7).
const roadLeft = 95;
const roadRight = 205;
const shoulderL = 108; // 노견 좌 경계
const shoulderR = 192; // 노견 우 경계
const roadY = 128;
svg.append(
node(
"polyline",
{ points: `${roadLeft},${roadY} ${roadRight},${roadY}`, fill: "none" },
"b06-diag__road",
),
);
// 노견 경계 눈금(좌/우)
svg.append(
node("line", { x1: shoulderL, y1: roadY - 5, x2: shoulderL, y2: roadY + 5 }, "b06-diag__tick"),
node("line", { x1: shoulderR, y1: roadY - 5, x2: shoulderR, y2: roadY + 5 }, "b06-diag__tick"),
);
// 중심선(계획고): 노면 중앙 수직 파선. 라벨 행(y=104)은 비워 노폭 라벨과 겹치지 않게 끊는다.
const centerX = (roadLeft + roadRight) / 2;
svg.append(
node("line", { x1: centerX, y1: 38, x2: centerX, y2: 96 }, "b06-diag__center"),
node("line", { x1: centerX, y1: 112, x2: centerX, y2: 162 }, "b06-diag__center"),
);
// 측구(절토측=좌): 노면 좌끝에서 아래로 파는 사다리꼴.
// 깊이는 기존 16 대비 약 60%(10)로 낮추고, 좌·우 벽 기울기를 4.5로 동일하게 맞춰
// 상단(80~95)과 하단(84.5~90.5)의 중심이 모두 87.5가 되도록 좌우 대칭을 유지한다.
const ditchDepth = 10;
const ditchWallInset = 4.5;
svg.append(
node(
"polygon",
{
points: `${roadLeft},${roadY} ${roadLeft - ditchWallInset},${roadY + ditchDepth} ${roadLeft - 15 + ditchWallInset},${roadY + ditchDepth} ${roadLeft - 15},${roadY}`,
},
"b06-diag__ditch",
),
);
// 절토 사면(좌): 측구 바깥에서 원지반까지 상향.
svg.append(node("line", { x1: roadLeft - 15, y1: roadY, x2: 26, y2: 66 }, "b06-diag__cut"));
// 성토 사면(우): 노면 우끝에서 원지반까지 하향.
svg.append(node("line", { x1: roadRight, y1: roadY, x2: 278, y2: 210 }, "b06-diag__fill"));
// 노견 좌 · 노폭 · 노견 우를 한 행(y=104)에 나란히 둔다. 노견 라벨은 바깥쪽 끝이 아니라
// 중앙 노폭 라벨 옆까지 안쪽으로 당겨 세 라벨이 중심(150) 기준 대칭이 되게 한다.
const labelLineY = 104;
svg.append(
text(centerX - 22, labelLineY, L("B06_Std_Diagram_ShoulderL"), "b06-diag__label-sm", "end"),
text(centerX, labelLineY, L("B06_Std_Diagram_Road"), "b06-diag__label"),
text(centerX + 22, labelLineY, L("B06_Std_Diagram_ShoulderR"), "b06-diag__label-sm", "start"),
);
// 나머지 라벨.
svg.append(
text(centerX, 30, L("B06_Std_Diagram_Center"), "b06-diag__label"),
text(roadLeft - 23, roadY + 24, L("B06_Std_Diagram_Ditch"), "b06-diag__label-sm", "middle"),
text(46, 54, L("B06_Std_Diagram_Cut"), "b06-diag__label-sm", "middle"),
text(252, 196, L("B06_Std_Diagram_Fill"), "b06-diag__label-sm", "middle"),
);
// 모식도 설명 글은 [?] 설명서 `B06/표준_횡단면.md` 로 옮김(54-2)
wrap.append(svg);
return wrap;
}