/* ============================================================================= * B06_Section_UI_Section_Columns.ts * 횡단 카드 한 줄 카드 수 고르기 — 보기 칸 높이에 첫 줄 + 둘째 줄 절반이 들어가는 * 가장 적은 카드 수. 카드 폭은 최소~최대 폭 안(그림은 축척 그대로 · 폭만 바뀜). * ========================================================================== */ import { CROSS_CARD_CHROME, CROSS_GRID_GAP, CROSS_GRID_MAX_WIDTH, CROSS_GRID_MIN_WIDTH, } from "./B06_Section_UI_Section_Common"; export interface CrossColumns { columns: number; cardWidth: number; } const widthFor = (columns: number, viewWidth: number): number => Math.min(CROSS_GRID_MAX_WIDTH, (viewWidth - (columns - 1) * CROSS_GRID_GAP) / columns); /** * `heightsFor(cardWidth, count)` — 그 폭일 때 앞 `count` 장의 카드 자연 높이. * `viewHeight` 가 0 이하(숨김 · 아직 안 잰 칸)면 가장 큰 카드 쪽을 고른다. */ export function pickCrossColumns( viewWidth: number, viewHeight: number, heightsFor: (cardWidth: number, count: number) => number[], ): CrossColumns { const unit = CROSS_GRID_MIN_WIDTH + CROSS_GRID_GAP; const most = Math.max(1, Math.floor((viewWidth + CROSS_GRID_GAP) / unit)); const fewest = Math.min( most, Math.max(1, Math.ceil((viewWidth + CROSS_GRID_GAP) / (CROSS_GRID_MAX_WIDTH + CROSS_GRID_GAP))), ); for (let columns = fewest; columns < most; columns += 1) { const cardWidth = widthFor(columns, viewWidth); if (viewHeight <= 0) return { columns, cardWidth }; const heights = heightsFor(cardWidth, columns * 2); const first = Math.max(0, ...heights.slice(0, columns)) + CROSS_CARD_CHROME; const second = Math.max(0, ...heights.slice(columns)) + CROSS_CARD_CHROME; const needed = heights.length > columns ? first + CROSS_GRID_GAP + second / 2 : first; if (needed <= viewHeight) return { columns, cardWidth }; } return { columns: most, cardWidth: widthFor(most, viewWidth) }; }