feat(D03 긋기): 기본값 길이·기울기 고정 · 버튼 자유지정 오른쪽 · Tab 방식 바꿈 · 안 쓰는 칸 숨김 (PLAN 625-1 · 요구 530 · 531)

- 방식 차례 = 자유지정 · 길이·기울기 고정 / 길이 고정 · 기울기 고정 · 「자유」 → 「자유지정」
- 긋기 처음 방식 = 길이·기울기 고정(기억 안 함)
- Tab(긋는 중) = 자유지정 ↔ 길이·기울기 고정 · 등록부 plan.drawKind · 긋기 아닐 때 = 초점 이동 그대로
- 길이 · 기울기 칸 = 방식에 안 쓰면 숨김 · 막힘 = 권한 없음만
- 지도 안내 글 Tab · Shift 줄 · 겹 hover 에 shift 인자(625-2 몫)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-31 20:12:48 +09:00
co-authored by Claude Opus 5.5
parent 689727fc98
commit 5d4737210a
5 changed files with 31 additions and 10 deletions
+2
View File
@@ -138,6 +138,8 @@ export const KEY_ACTIONS: readonly KeyAction[] = [
A("plan.redo", "plan", ["Ctrl+Shift+Z", "Ctrl+Y"], ["다시", "Redo"]),
A("plan.drawFinish", "plan", ["Enter"], ["그리기 끝", "Finish drawing"]),
A("plan.drawBack", "plan", ["Backspace"], ["그리기 마지막 점 빼기", "Drawing: remove last point"]),
A("plan.drawKind", "plan", ["Tab"], ["긋는 중 방식 자유지정 ↔ 길이·기울기 고정", "Drawing: free ↔ length + slope"]),
A("plan.drawBetween", "plan", ["Shift 누른 채"], ["길이·기울기 고정 긋는 중 부채꼴 사이 기울기 자리(길이 그대로)", "Drawing: pick between-slope on fan (length kept)"], F),
A("plan.delete", "plan", ["Delete"], ["고른 노드 · 선 · 구역 · 전체 · 마커 지움", "Delete picked node · segment · region · all · marker"]),
A("plan.escape", "plan", ["Escape"], ["그리기 취소 · 고름 풀기 · 재기 끝", "Cancel drawing · clear selection · end measure"], F),
A("plan.zoom", "plan", ["휠"], ["커서 자리 확대 · 축소", "Zoom at cursor"], F),
+12 -2
View File
@@ -16,7 +16,7 @@
* 긋기는 해를 안 물음(585-3) — 새 선 = 사업연도 시작 해 · 갈래 = 붙은 자리 구간 해 · 이어 긋기 = 끝 구간이 늘어남 ·
* 여러 해 = 다 그은 뒤 그리기 칸 「연도 구역 마커」를 선 위로 끌어 구역을 나누고 속성 판에서 해를 고름.
* 고르기 · 고치기 · 마커(쉴 때) = `D03_PlanAnalysis_UI_Edit`.
* 키 = Enter 끝 · Esc 이번 긋기 취소 · Backspace 마지막 점 빼기(설정 창 단축키 표 D03 줄).
* 키 = Enter 끝 · Esc 이번 긋기 취소 · Backspace 마지막 점 빼기 · Tab 방식 바꿈(설정 창 단축키 표 D03 줄).
* 셈 = 562-1 짝(`logic/D03_PlanAnalysis_Draw`) · 꼴 다루기 = `logic/D03_PlanAnalysis_Plan` ·
* 값을 바꾸면 `commit(다음 꼴)` 한 번 = 되돌리기 한 걸음(스택 · 캐시 = 페이지).
* ========================================================================== */
@@ -120,7 +120,8 @@ export function createPlanDraw(params: PlanDrawParams): PlanDraw {
let strokeStart: PlanNetwork | null = null; // Esc 로 돌아갈 꼴
let preview: DrawPreview | null = null;
let candidates: Vertex[] = [];
let kind: DrawConstraint = "free";
let kind: DrawConstraint = "both"; // 625-1 · 기억 안 함(B9)
let hoverAt: { px: number; py: number; map: ScreenMap } | null = null; // Tab 뒤 미리보기 다시
let lengthM = DRAW_DEFAULT_LENGTH_M;
let slopePct = DRAW_DEFAULT_SLOPE_PCT;
// 다시 긋기 — 선 id · 앞 · 뒤 꺾임점 · 새로 찍은 속 점 · 그 기록
@@ -472,9 +473,11 @@ export function createPlanDraw(params: PlanDrawParams): PlanDraw {
return false;
},
hover(px, py, map) {
hoverAt = { px, py, map };
preview = mode === "draw" ? previewAt(px, py, map) : null;
},
leave() {
hoverAt = null;
preview = null;
},
};
@@ -501,6 +504,13 @@ export function createPlanDraw(params: PlanDrawParams): PlanDraw {
panelState();
},
key(event) {
// Tab = 자유지정 ↔ 길이·기울기 고정(단독 고정이면 길이·기울기로 · 625-1) · 긋기 아닐 때 = 초점 이동
if (mode === "draw" && keyIs(event, "plan.drawKind")) {
kind = kind === "both" ? "free" : "both";
kindFields.set({ kind });
if (hoverAt) preview = previewAt(hoverAt.px, hoverAt.py, hoverAt.map);
return true;
}
if (mode === "draw" && keyIs(event, "plan.drawFinish")) {
if (span) showToast("다시 긋기는 뒤 노드에 붙어야 끝 — 취소했습니다.", "info");
setMode("idle");
@@ -2,8 +2,9 @@
* D03_PlanAnalysis_UI_DrawPanel.ts
* D03 좌측 「그리기」 칸 몸(PLAN 599-1 · 599-4 · 요구 463-10 · 22) — [긋기] · 연도 구역 마커 · 긋기 방식 칸.
*
* 방식 칸 `createDrawKindFields` = 마디 고름 2 × 2(자유 · 길이 고정 · 기울기 고정 · 길이·기울기 고정) +
* 길이 · 기울기 두 열(기울기 아래 ≈ °) — 그리기 칸 · 노드 판(598-4)이 같은 부품을 씀.
* 방식 칸 `createDrawKindFields` = 마디 고름 2 × 2(자유지정 · 길이·기울기 고정 / 길이 고정 · 기울기 고정 ·
* 625-1) + 길이 · 기울기 두 열(기울기 아래 ≈ °) — 방식에 안 쓰는 칸은 숨김(막힘 = 권한 없음만) ·
* 그리기 칸 · 노드 판(598-4)이 같은 부품을 씀.
* 연도 구역 마커 = 끌어 선 위에 놓기(`YEAR_MARK_DRAG` · 받음 = `D03_PlanAnalysis_UI_Edit` drop).
* 설명 글 없음(요구 463-6) — 칸 오류 · ≈ ° 값만.
* ========================================================================== */
@@ -29,10 +30,10 @@ export interface DrawKindValue {
}
export const DRAW_KIND_LABELS: Record<DrawConstraint, string> = {
free: "자유",
free: "자유지정",
both: "길이·기울기 고정",
length: "길이 고정",
slope: "기울기 고정",
both: "길이·기울기 고정",
};
export interface DrawKindFields {
@@ -118,8 +119,10 @@ export function createDrawKindFields(opts: {
function fieldsState(): void {
for (const button of segment.root.querySelectorAll("button")) button.disabled = disabled;
lengthField.input.disabled = disabled || value.kind === "free" || value.kind === "slope";
slopeField.input.disabled = disabled || value.kind === "free" || value.kind === "length";
lengthField.input.disabled = slopeField.input.disabled = disabled;
fields.hidden = value.kind === "free";
lengthField.root.hidden = value.kind === "slope";
slopeColumn.hidden = value.kind === "length";
}
degText();
fieldsState();
+4 -2
View File
@@ -101,7 +101,7 @@ export interface PlanMapLayer {
base?: boolean;
draw: (context: CanvasRenderingContext2D, map: ScreenMap) => void;
press?: (px: number, py: number, map: ScreenMap, button: 0 | 2, shift: boolean) => boolean;
hover?: (px: number, py: number, map: ScreenMap) => void;
hover?: (px: number, py: number, map: ScreenMap, shift: boolean) => void;
release?: (map: ScreenMap) => void;
/** 「연도 마커」를 끌고 지나감(참 = 받을 겹) · 놓음(참 = 받음) — 585-3. */
dragOver?: (px: number, py: number, map: ScreenMap) => boolean;
@@ -210,6 +210,8 @@ export function createPlanMap(events: PlanMapEvents): PlanMap {
"Enter = 긋기 끝",
"Esc = 긋기 취소",
"Backspace = 마지막 점 빼기",
"Tab(긋는 중) = 자유지정 ↔ 길이·기울기 고정",
"Shift 누른 채(길이·기울기 고정) = 부채꼴 사이 기울기 자리 · 길이 그대로",
"[다시 긋기] = 앞 노드부터 긋고 뒤 노드에 붙으면 끝",
"누름 = 노드 · 선 고름 · 다시 누름 = 선 → 구역 → 전체로 넓힘",
"Shift+누름 = 선 더함 · 뺌",
@@ -458,7 +460,7 @@ export function createPlanMap(events: PlanMapEvents): PlanMap {
perfTime("plan:pointermove", () => {
const [px, py] = at(event);
const map = screenMap();
for (const layer of layers) layer.hover?.(px, py, map);
for (const layer of layers) layer.hover?.(px, py, map, event.shiftKey);
drawTop();
});
});
@@ -192,6 +192,10 @@
align-items: start;
}
.d03-plan__draw-fields[hidden] {
display: none;
}
.d03-plan__draw-fields .ui-field {
margin: 0;
min-width: 0;