- 여러 층 머리(null = 세로 합침 · 같은 앞머리 = 가로 합침) · 단위 줄 · 합계 줄 · 틀고정 · 열 너비 끌기 - 셀 편집은 M01 startEdit 그대로 · 화살표 · Tab · Enter · F2 · 바로 치기 · Delete 비움 - 줄 더하기 · 지우기 · master 는 열 더하기 · 지우기 · 손 입력 열 · 식 · 들어갈 것 · 일위대가 줄 - project 는 바인딩 · 계산 열 잠금 · 손 열만 입력 · 전구간 줄 맨 위 · 쪽줄 50 으로 쪽(쪽마다 머리 · 합계 마지막 쪽) - 고칠 때마다 같은 TS 풀이로 즉시 다시 그림 · onChange 로 문서를 넘김(자동저장 없음) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tjoit7rxvpLMM7cafeVTo1
62 lines
2.0 KiB
TypeScript
62 lines
2.0 KiB
TypeScript
/* =============================================================================
|
|
* ui_template_sheet_header.ts
|
|
* 여러 층 머리 짜기 — 열마다 `머리`(층 수만큼 글) → 층마다 칸(colspan · rowspan).
|
|
*
|
|
* `null` = 위 칸과 합침(세로) · 모자란 층도 `null` 로 채움(위 칸이 늘어남).
|
|
* 옆 열과 그 층까지 앞머리가 모두 같고 아래 합침 모양도 같으면 가로로 합침.
|
|
* ========================================================================== */
|
|
|
|
import type { SheetColumn } from "./ui_template_sheet_types";
|
|
|
|
export interface HeadCell {
|
|
level: number;
|
|
col: number;
|
|
colspan: number;
|
|
rowspan: number;
|
|
label: string;
|
|
}
|
|
|
|
export function headDepth(cols: SheetColumn[], layers?: string[]): number {
|
|
return Math.max(1, layers?.length ?? 0, ...cols.map((c) => c.머리.length));
|
|
}
|
|
|
|
/** 층마다 칸 목록 — 앞 층부터. */
|
|
export function layoutHead(cols: SheetColumn[], depth: number): HeadCell[][] {
|
|
const paths = cols.map((c) =>
|
|
Array.from({ length: depth }, (_, i) => (i === 0 ? (c.머리[0] ?? "") : (c.머리[i] ?? null))),
|
|
);
|
|
const span = (j: number, i: number): number => {
|
|
let k = i + 1;
|
|
while (k < depth && paths[j][k] === null) k += 1;
|
|
return k - i;
|
|
};
|
|
const samePrefix = (a: number, b: number, i: number): boolean =>
|
|
paths[a].slice(0, i + 1).every((label, lv) => label === paths[b][lv]);
|
|
|
|
const levels: HeadCell[][] = [];
|
|
for (let i = 0; i < depth; i += 1) {
|
|
const cells: HeadCell[] = [];
|
|
let j = 0;
|
|
while (j < cols.length) {
|
|
if (paths[j][i] === null) {
|
|
j += 1;
|
|
continue;
|
|
}
|
|
const rowspan = span(j, i);
|
|
let colspan = 1;
|
|
while (
|
|
j + colspan < cols.length &&
|
|
paths[j + colspan][i] !== null &&
|
|
samePrefix(j, j + colspan, i) &&
|
|
span(j + colspan, i) === rowspan
|
|
) {
|
|
colspan += 1;
|
|
}
|
|
cells.push({ level: i, col: j, colspan, rowspan, label: paths[j][i] as string });
|
|
j += colspan;
|
|
}
|
|
levels.push(cells);
|
|
}
|
|
return levels;
|
|
}
|