From 5d4737210ab9b9c28f4ee71ce92894f953c4e26f Mon Sep 17 00:00:00 2001 From: umsangdon Date: Sat, 31 Oct 2026 20:12:48 +0900 Subject: [PATCH] =?UTF-8?q?feat(D03=20=EA=B8=8B=EA=B8=B0):=20=EA=B8=B0?= =?UTF-8?q?=EB=B3=B8=EA=B0=92=20=EA=B8=B8=EC=9D=B4=C2=B7=EA=B8=B0=EC=9A=B8?= =?UTF-8?q?=EA=B8=B0=20=EA=B3=A0=EC=A0=95=20=C2=B7=20=EB=B2=84=ED=8A=BC=20?= =?UTF-8?q?=EC=9E=90=EC=9C=A0=EC=A7=80=EC=A0=95=20=EC=98=A4=EB=A5=B8?= =?UTF-8?q?=EC=AA=BD=20=C2=B7=20Tab=20=EB=B0=A9=EC=8B=9D=20=EB=B0=94?= =?UTF-8?q?=EA=BF=88=20=C2=B7=20=EC=95=88=20=EC=93=B0=EB=8A=94=20=EC=B9=B8?= =?UTF-8?q?=20=EC=88=A8=EA=B9=80=20(PLAN=20625-1=20=C2=B7=20=EC=9A=94?= =?UTF-8?q?=EA=B5=AC=20530=20=C2=B7=20531)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 방식 차례 = 자유지정 · 길이·기울기 고정 / 길이 고정 · 기울기 고정 · 「자유」 → 「자유지정」 - 긋기 처음 방식 = 길이·기울기 고정(기억 안 함) - Tab(긋는 중) = 자유지정 ↔ 길이·기울기 고정 · 등록부 plan.drawKind · 긋기 아닐 때 = 초점 이동 그대로 - 길이 · 기울기 칸 = 방식에 안 쓰면 숨김 · 막힘 = 권한 없음만 - 지도 안내 글 Tab · Shift 줄 · 겹 hover 에 shift 인자(625-2 몫) Co-Authored-By: Claude Opus 5.5 --- A00_Common/key_registry.ts | 2 ++ D03_PlanAnalysis/D03_PlanAnalysis_UI_Draw.ts | 14 ++++++++++++-- D03_PlanAnalysis/D03_PlanAnalysis_UI_DrawPanel.ts | 15 +++++++++------ D03_PlanAnalysis/D03_PlanAnalysis_UI_Map.ts | 6 ++++-- D03_PlanAnalysis/D03_PlanAnalysis_UI_Style.css | 4 ++++ 5 files changed, 31 insertions(+), 10 deletions(-) diff --git a/A00_Common/key_registry.ts b/A00_Common/key_registry.ts index c460cc0ff..1074f20e8 100644 --- a/A00_Common/key_registry.ts +++ b/A00_Common/key_registry.ts @@ -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), diff --git a/D03_PlanAnalysis/D03_PlanAnalysis_UI_Draw.ts b/D03_PlanAnalysis/D03_PlanAnalysis_UI_Draw.ts index 7d18054d1..64ee4a4a1 100644 --- a/D03_PlanAnalysis/D03_PlanAnalysis_UI_Draw.ts +++ b/D03_PlanAnalysis/D03_PlanAnalysis_UI_Draw.ts @@ -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"); diff --git a/D03_PlanAnalysis/D03_PlanAnalysis_UI_DrawPanel.ts b/D03_PlanAnalysis/D03_PlanAnalysis_UI_DrawPanel.ts index 18b8214d7..20c2de8cc 100644 --- a/D03_PlanAnalysis/D03_PlanAnalysis_UI_DrawPanel.ts +++ b/D03_PlanAnalysis/D03_PlanAnalysis_UI_DrawPanel.ts @@ -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 = { - 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(); diff --git a/D03_PlanAnalysis/D03_PlanAnalysis_UI_Map.ts b/D03_PlanAnalysis/D03_PlanAnalysis_UI_Map.ts index 0681865f2..de6d27bda 100644 --- a/D03_PlanAnalysis/D03_PlanAnalysis_UI_Map.ts +++ b/D03_PlanAnalysis/D03_PlanAnalysis_UI_Map.ts @@ -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(); }); }); diff --git a/D03_PlanAnalysis/D03_PlanAnalysis_UI_Style.css b/D03_PlanAnalysis/D03_PlanAnalysis_UI_Style.css index 2ca1ca5ff..5694f0d85 100644 --- a/D03_PlanAnalysis/D03_PlanAnalysis_UI_Style.css +++ b/D03_PlanAnalysis/D03_PlanAnalysis_UI_Style.css @@ -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;