feat(B06): 확대 상태 팬으로 캐시 보유 범위까지 열람
- 도형(지반선·면적 밴드·설계선·암 경계선)을 표시 반폭으로 자르지 않고 **캐시 보유 전 구간**으로 그린다. 표시 반폭 밖은 기존 clip이 가리므로 원배율 화면은 그대로다. - 팬 한계(clampPan)를 그려진 범위까지 확장 — 배율 1에서는 종전대로 이동 0으로 묶고, 확대 상태에서만 캐시 끝까지 가운데 버튼 드래그로 끌어다 볼 수 있다. - 축 눈금은 팬 상태를 역산해 다시 그리므로(_UI_Cross_Axes) X·Y 값이 따라 움직인다. 자체검증: node tmp/tests/test_cross_pan_bounds.mjs (배율 1 고정, 2배에서 좌우 한계가 캐시 끝과 일치, 범위 밖 이탈 없음, content 없을 때 옛 규칙 유지), test_cross_axes_zoom.mjs 재실행, tsc --noEmit 통과. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -327,9 +327,13 @@ export function createCrossSectionCard(
|
||||
clipGroup.append(plotLayer);
|
||||
svg.append(clip, clipGroup);
|
||||
|
||||
// 그리기는 **캐시 보유 전 구간**으로 한다 — 표시 반폭 밖은 clip으로 가려 두고, 확대
|
||||
// 상태의 가운데 버튼 팬으로 끌어다 본다(2026-08-23 사용자 지시). 축 눈금은 팬을 따라
|
||||
// 다시 그려지므로(_UI_Cross_Axes) 값이 어긋나지 않는다.
|
||||
const drawSamples = section.samples;
|
||||
const segments: string[] = [];
|
||||
let current: string[] = [];
|
||||
for (const sample of sourceSamples) {
|
||||
for (const sample of drawSamples) {
|
||||
if (!validElevation(sample)) {
|
||||
if (current.length > 1) segments.push(current.join(" "));
|
||||
current = [];
|
||||
@@ -352,7 +356,7 @@ export function createCrossSectionCard(
|
||||
setBandActive = appendCrossAreaBands(
|
||||
plotLayer,
|
||||
section.design,
|
||||
sourceSamples,
|
||||
drawSamples,
|
||||
x,
|
||||
toDisplayY,
|
||||
toggleArea,
|
||||
@@ -375,14 +379,14 @@ export function createCrossSectionCard(
|
||||
section.design,
|
||||
x,
|
||||
toDisplayY,
|
||||
sourceSamples,
|
||||
drawSamples,
|
||||
culvertLayout?.designTrim ?? undefined,
|
||||
);
|
||||
// 암 경계선은 지면선(지반선) 복사 + 오프셋 — 계획선 기준이 아님에 유의.
|
||||
if (rockBoundary && section.design.geometry_preset === "rock") {
|
||||
appendRockBoundaryOverlay(
|
||||
plotLayer,
|
||||
sourceSamples,
|
||||
drawSamples,
|
||||
rockBoundary.offsetFor(section),
|
||||
x,
|
||||
toDisplayY,
|
||||
@@ -483,6 +487,20 @@ export function createCrossSectionCard(
|
||||
// 확대·축소 버튼, 드래그 팬, 더블클릭 원복(E-5). 도형 레이어 transform + non-scaling-stroke.
|
||||
const chartWrap = document.createElement("div");
|
||||
chartWrap.className = "b06-cross-card__chart-wrap";
|
||||
// 팬 한계로 쓸 **그려진 범위** — 캐시 전 구간의 좌우 끝과 표고 상·하단.
|
||||
const drawnOffsets = drawSamples.map((sample) => sample.offset_m ?? 0);
|
||||
const drawnDisplayY = drawSamples
|
||||
.filter(validElevation)
|
||||
.map((sample) => y(elevationMid + (sample.elevation_m - elevationMid) * exaggeration));
|
||||
const contentBounds =
|
||||
drawnOffsets.length && drawnDisplayY.length
|
||||
? {
|
||||
x: x(Math.max(...drawnOffsets)),
|
||||
width: x(Math.min(...drawnOffsets)) - x(Math.max(...drawnOffsets)),
|
||||
y: Math.min(...drawnDisplayY),
|
||||
height: Math.max(...drawnDisplayY) - Math.min(...drawnDisplayY),
|
||||
}
|
||||
: undefined;
|
||||
const zoomPan = attachZoomPan(
|
||||
svg,
|
||||
plotLayer,
|
||||
@@ -493,6 +511,7 @@ export function createCrossSectionCard(
|
||||
cardZoomStates.set(section.station_id, state);
|
||||
renderAxes(state);
|
||||
},
|
||||
contentBounds,
|
||||
);
|
||||
// 절·성토 면적값은 그래프 중상단 오버레이로 표시(E-4). 값 칸은 항상 강조 토글이다.
|
||||
const readout = buildAreaReadout(section.design, toggleArea);
|
||||
|
||||
Reference in New Issue
Block a user