perf(B06): 카드 기하를 두 번 계산하던 것을 한 번으로
행 높이를 재는 1차와 실제 그리는 2차가 같은 측점의 crossPlotMetrics 를 각각 계산했음. 측점 67곳 기준 3.2ms/장이라 진입에서 draw 자기 시간 213ms 의 대부분이었음 (보조 창 CPU 프로파일). - crossPlotMetrics 를 crossPlotBase(강제 높이 전) + crossPlotFromBase(높이만 얹기)로 가름. 기존 시그니처는 둘을 잇는 감싸개로 유지. - Section_View 1차에서 base 를 만들어 2차 카드에 그대로 넘김. - 1차 반폭도 카드가 실제로 쓰는 값(effectiveCardHalfWidth, 자동 줌아웃 포함)으로 맞춤 — 전에는 1차가 원래 반폭으로 재 카드·행 높이 기준이 어긋났음. - 쓰이지 않게 된 crossCardNaturalHeight 와 그 재수출 삭제. 자체검증(공용 브라우저) — 카드 67장·SVG 67개 그대로, 같은 행 카드 높이 통일 유지 (rowsUniform true), 높이 범위 292~1,119px. 시험 400 통과·17 건너뜀, typecheck 통과. 효과 수치는 보조 창의 격리된 프로젝트에서 3회 중앙값으로 재기로 함(내 창은 편차가 큼). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -35,10 +35,15 @@ import {
|
||||
type RevetOffsetControl,
|
||||
type RevetLinkControl,
|
||||
type StructureSpanControl,
|
||||
crossCardNaturalHeight,
|
||||
type CrossCardElement,
|
||||
type StationWidthControl,
|
||||
} from "./B06_Section_UI_Cross_View";
|
||||
import {
|
||||
type CrossPlotBase,
|
||||
crossPlotBase,
|
||||
effectiveCardHalfWidth,
|
||||
} from "./B06_Section_UI_Cross_View_Metrics";
|
||||
import { CROSS_HEIGHT } from "./B06_Section_UI_Section_Common";
|
||||
import { culvertLinkFor as culvertLink } from "./B06_Section_UI_Cross_Culvert_Wire";
|
||||
import type { CulvertLink } from "./B06_Section_UI_Cross_Culvert_Wire";
|
||||
import { longitudinalMinimumWidth } from "./B06_Section_UI_Longitudinal";
|
||||
@@ -405,7 +410,11 @@ export function createSectionView(
|
||||
return planZ - (section.design?.surface_drop_m ?? 0);
|
||||
};
|
||||
|
||||
const buildCrossCard = (section: CrossSection, forcedHeightPx?: number): HTMLElement =>
|
||||
const buildCrossCard = (
|
||||
section: CrossSection,
|
||||
forcedHeightPx?: number,
|
||||
plotBase?: CrossPlotBase | null,
|
||||
): HTMLElement =>
|
||||
createCrossSectionCard(
|
||||
section,
|
||||
section.station_id === selectedStationId,
|
||||
@@ -429,6 +438,7 @@ export function createSectionView(
|
||||
revetLink,
|
||||
ford,
|
||||
box,
|
||||
plotBase,
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -583,16 +593,22 @@ export function createSectionView(
|
||||
if (detail.cross_sections.length) {
|
||||
// 1차: 각 카드의 자연 높이(250px 바닥 적용) 측정 → 같은 행(columnCount 단위) 최댓값을 행 높이로.
|
||||
const sections = detail.cross_sections;
|
||||
const naturalHeights = sections.map((section) =>
|
||||
crossCardNaturalHeight(
|
||||
// 여기서 만든 기하를 2차에서 **그대로 넘긴다** — 예전에는 같은 측점을 두 번 계산했고
|
||||
// 그것이 진입에서 `draw` 자기 시간의 대부분이었다(2026-09-06 CPU 프로파일).
|
||||
// 반폭도 카드가 실제로 쓰는 값(`effectiveCardHalfWidth`, 자동 줌아웃 포함)으로 맞춰
|
||||
// 재 둔다 — 카드·행 높이가 어긋나지 않는다.
|
||||
const plotBases = sections.map((section) =>
|
||||
crossPlotBase(
|
||||
section,
|
||||
currentExaggeration,
|
||||
cachedCardWidth,
|
||||
// 개별 표시 반폭이 있으면 그 폭 기준으로 높이를 재야 카드·행 높이가 맞는다.
|
||||
stationWidth?.widthFor(section) ?? currentCrossHalfWidth,
|
||||
effectiveCardHalfWidth(section, stationWidth?.widthFor(section) ?? currentCrossHalfWidth),
|
||||
designElevationAt(detail.longitudinal.design_profiles, section.chainage_m),
|
||||
),
|
||||
);
|
||||
const naturalHeights = plotBases.map((base) =>
|
||||
Math.max(base?.naturalHeight ?? CROSS_HEIGHT, CROSS_HEIGHT),
|
||||
);
|
||||
// 2차: 행별 최댓값으로 강제 높이를 정해 같은 행 카드를 동일 높이로 렌더한다.
|
||||
for (let start = 0; start < sections.length; start += columnCount) {
|
||||
const rowHeight = Math.max(...naturalHeights.slice(start, start + columnCount));
|
||||
@@ -602,7 +618,7 @@ export function createSectionView(
|
||||
index += 1
|
||||
) {
|
||||
cachedRowHeight.set(sections[index].station_id, rowHeight);
|
||||
grid.append(buildCrossCard(sections[index], rowHeight));
|
||||
grid.append(buildCrossCard(sections[index], rowHeight, plotBases[index]));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user