refactor(b06): 횡단 카드 렌더러 기능별 나눔 — 조정창 두 벌 · 지반선 · 팬 범위 분리(137-1)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018jonfdxn1Xit9bdkNJpE4G
This commit is contained in:
2026-10-09 14:49:19 +09:00
co-authored by Claude Opus 5.5
parent c0cf0ab90a
commit 06e6fbebff
3 changed files with 214 additions and 127 deletions
+41 -1
View File
@@ -6,7 +6,7 @@
import type { CrossSection } from "./B06_Section_Api_Fetch";
import { computeStructureAreas, type DesignTrim } from "@util/common_util_cross_structure_areas";
import { CROSS_PAD, L, svgElement, svgText } from "./B06_Section_UI_Section_Common";
import { CROSS_PAD, L, svgElement, svgText, validElevation } from "./B06_Section_UI_Section_Common";
type Sample = CrossSection["samples"][number];
@@ -124,3 +124,43 @@ export function applyStructureAreas(
design.cut_soil_area_m2 = Number(areas.cutSoilAreaM2.toFixed(4));
}
}
/** 원지반선 — 끊긴 샘플(무효 표고)마다 폴리선을 나눠 그린다. `toY` = 표고 → 화면 y(배율 반영). */
export function appendGroundProfile(
plotLayer: SVGElement,
samples: Sample[],
x: (offset: number) => number,
toY: (elevation: number) => number,
): void {
const segments: string[] = [];
let current: string[] = [];
for (const sample of samples) {
if (!validElevation(sample)) {
if (current.length > 1) segments.push(current.join(" "));
current = [];
continue;
}
current.push(`${x(sample.offset_m ?? 0)},${toY(sample.elevation_m)}`);
}
if (current.length > 1) segments.push(current.join(" "));
segments.forEach((points) =>
plotLayer.append(svgElement("polyline", { points, class: "b06-chart__cross-profile" })),
);
}
/** 팬 한계로 쓸 **그려진 범위** — 캐시 전 구간의 좌우 끝과 표고 상 · 하단(없으면 undefined). */
export function drawnContentBounds(
samples: Sample[],
x: (offset: number) => number,
toY: (elevation: number) => number,
): { x: number; width: number; y: number; height: number } | undefined {
const offsets = samples.map((sample) => sample.offset_m ?? 0);
const displayY = samples.filter(validElevation).map((sample) => toY(sample.elevation_m));
if (!offsets.length || !displayY.length) return undefined;
return {
x: x(Math.max(...offsets)),
width: x(Math.min(...offsets)) - x(Math.max(...offsets)),
y: Math.min(...displayY),
height: Math.max(...displayY) - Math.min(...displayY),
};
}