refactor(B05,B06): B05_wf2_Route -> B05_Profile, B06_wf3_ProfileCross -> B06_Section 동시 개명
- 한몸으로 동작하는 두 페이지라 한 커밋으로 처리 (상호 참조 다수) - B05 37파일 + B06 20파일 접두사 개명 (git mv, 이력 보존) - 참조 치환 91파일: import 경로, 라우트 슬러그(b05-profile/b06-section), 라우트 키(B05_PROFILE/B06_SECTION), B03 자동 체인, storage 상수, pyproject 제외 경로 - 로직 변경 없음. typecheck·백엔드 import 검증 통과 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
/* =============================================================================
|
||||
* 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 {
|
||||
const wrap = document.createElement("details");
|
||||
wrap.className = "b06-std__diagram";
|
||||
wrap.open = true;
|
||||
const summary = document.createElement("summary");
|
||||
summary.className = "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"),
|
||||
);
|
||||
|
||||
wrap.append(svg);
|
||||
const caption = document.createElement("p");
|
||||
caption.className = "b06-std__diagram-caption";
|
||||
caption.textContent = L("B06_Std_Diagram_Caption");
|
||||
wrap.append(caption);
|
||||
return wrap;
|
||||
}
|
||||
Reference in New Issue
Block a user