From 7cad25bb7f43985a108ff804290720bdecca8cb1 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Fri, 9 Oct 2026 19:06:37 +0900 Subject: [PATCH] =?UTF-8?q?feat(CAD):=20=ED=9C=A0=20=3D=20=EB=8A=98=20?= =?UTF-8?q?=EC=A4=8C(=EC=BB=A4=EC=84=9C=20=EC=A4=91=EC=8B=AC)=20=C2=B7=20?= =?UTF-8?q?=ED=9C=A0=20=EC=B2=98=EB=A6=AC=EB=A5=BC=20input-wheel.ts=20?= =?UTF-8?q?=EB=A1=9C=20=EB=96=BC=EA=B8=B0(153-3)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 마우스 · 트랙패드 판정 지움 — 확대율 100 % 아닌 화면에서 휠이 팬으로 먹히던 것 - 트랙패드 두 손가락 팬 없어짐 · 팬 = 가운데 단추 끌기 - vitest input-wheel.test.ts Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01TNMXVCZXMpHpVvqmFkeChL --- .../src/inputController/input-controller.ts | 47 ++----------------- .../src/inputController/input-wheel.test.ts | 33 +++++++++++++ .../src/inputController/input-wheel.ts | 24 ++++++++++ 3 files changed, 61 insertions(+), 43 deletions(-) create mode 100644 B07_DesignDetail/openwebcad/src/inputController/input-wheel.test.ts create mode 100644 B07_DesignDetail/openwebcad/src/inputController/input-wheel.ts diff --git a/B07_DesignDetail/openwebcad/src/inputController/input-controller.ts b/B07_DesignDetail/openwebcad/src/inputController/input-controller.ts index dd3c6c21c..bc2957016 100644 --- a/B07_DesignDetail/openwebcad/src/inputController/input-controller.ts +++ b/B07_DesignDetail/openwebcad/src/inputController/input-controller.ts @@ -1,13 +1,7 @@ import { Point } from '@flatten-js/core'; import { compact, round } from 'es-toolkit'; import { Actor } from 'xstate'; -import { - PINCH_ZOOM_EXPONENT, - SNAP_POINT_DISTANCE, - WHEEL_LINE_PX, - WHEEL_PAGE_PX, - WHEEL_ZOOM_EXPONENT, -} from '../App.consts.ts'; +import { SNAP_POINT_DISTANCE } from '../App.consts.ts'; import { MouseButton } from '../App.types.ts'; import { describeCommand, @@ -66,6 +60,7 @@ import { isPlainSpace, } from './ime-sink.ts'; import { drawInputField } from './input-field-draw.ts'; +import { wheelZoom } from './input-wheel.ts'; import { ABSOLUTE_POINT_REGEXP, ABSOLUTE_POLAR_REGEXP, @@ -277,30 +272,8 @@ export class InputController { public handleMouseWheel(evt: WheelEvent) { // 확대는 도면만 — 트랙패드 핀치(ctrl+휠)가 브라우저 전체를 키우던 것을 막는다. evt.preventDefault(); - const drawController = getScreenCanvasDrawController(); - // deltaY 단위를 픽셀로 맞춘다 — 브라우저에 따라 줄(1)·쪽(2) 단위로 오기도 한다. - const unitPx = evt.deltaMode === 1 ? WHEEL_LINE_PX : evt.deltaMode === 2 ? WHEEL_PAGE_PX : 1; - const deltaX = evt.deltaX * unitPx; - const deltaY = evt.deltaY * unitPx; - - // 핀치(ctrl+휠)는 기기와 무관하게 확대. - if (evt.ctrlKey) { - if (deltaY !== 0) drawController.zoomScreen(-deltaY, PINCH_ZOOM_EXPONENT); - return; - } - - // 트랙패드 두 손가락 이동은 팬 — 문서를 스크롤하듯 화면이 손가락 반대로 간다. - if (!isMouseWheel(evt)) { - drawController.panScreen(-deltaX, deltaY); - return; - } - - if (deltaY === 0) { - return; // We can't zoom by zero delta - } - // Aislo: wheel direction is inverted on purpose - pulling the wheel zooms in, pushing - // zooms out, matching the B04/B05 maps and the B06 cross sections (2026-08-02). - drawController.zoomScreen(-deltaY, WHEEL_ZOOM_EXPONENT); + const zoom = wheelZoom(evt); + if (zoom) getScreenCanvasDrawController().zoomScreen(zoom.delta, zoom.exponent); } public handleMouseDown(evt: MouseEvent) { @@ -643,15 +616,3 @@ export class InputController { }); } } - -/** - * 마우스 휠인지 트랙패드인지 가른다. 마우스 휠은 한 칸이 정해진 크기(Chrome 100px, - * 일부 브라우저 120px)로 딱 떨어지고 가로 델타가 없다. 트랙패드는 손가락이 움직인 - * 만큼 잔 델타를 보내고 가로 델타도 함께 온다. 줄·쪽 단위(deltaMode≠0)는 휠뿐이다. - */ -function isMouseWheel(evt: WheelEvent): boolean { - if (evt.deltaMode !== 0) return true; - if (evt.deltaX !== 0) return false; - const step = Math.abs(evt.deltaY); - return step !== 0 && (step % 100 === 0 || step % 120 === 0); -} diff --git a/B07_DesignDetail/openwebcad/src/inputController/input-wheel.test.ts b/B07_DesignDetail/openwebcad/src/inputController/input-wheel.test.ts new file mode 100644 index 000000000..3bc6389ce --- /dev/null +++ b/B07_DesignDetail/openwebcad/src/inputController/input-wheel.test.ts @@ -0,0 +1,33 @@ +import { describe, expect, it } from 'vitest'; +import { + PINCH_ZOOM_EXPONENT, + WHEEL_LINE_PX, + WHEEL_PAGE_PX, + WHEEL_ZOOM_EXPONENT, +} from '../App.consts.ts'; +import { wheelZoom } from './input-wheel.ts'; + +const wheel = (deltaY: number, deltaMode = 0, ctrlKey = false) => + wheelZoom({ deltaY, deltaMode, ctrlKey }); + +describe('CAD 휠 = 늘 줌(153-3)', () => { + it('100 · 120 배수가 아닌 델타(확대율 90 % · 110 % · 트랙패드 잔 델타)도 줌', () => { + for (const deltaY of [100, 120, 111.1, 90.9, 4, -100, -111.1, -4]) { + expect(wheel(deltaY)).toEqual({ delta: -deltaY, exponent: WHEEL_ZOOM_EXPONENT }); + } + }); + + it('줄 · 쪽 단위는 픽셀로 환산', () => { + expect(wheel(3, 1)).toEqual({ delta: -3 * WHEEL_LINE_PX, exponent: WHEEL_ZOOM_EXPONENT }); + expect(wheel(-1, 2)).toEqual({ delta: WHEEL_PAGE_PX, exponent: WHEEL_ZOOM_EXPONENT }); + }); + + it('ctrl+휠(핀치)은 핀치 지수', () => { + expect(wheel(-7, 0, true)).toEqual({ delta: 7, exponent: PINCH_ZOOM_EXPONENT }); + }); + + it('델타 0 은 안 움직임', () => { + expect(wheel(0)).toBeNull(); + expect(wheel(0, 0, true)).toBeNull(); + }); +}); diff --git a/B07_DesignDetail/openwebcad/src/inputController/input-wheel.ts b/B07_DesignDetail/openwebcad/src/inputController/input-wheel.ts new file mode 100644 index 000000000..f6ea49e8b --- /dev/null +++ b/B07_DesignDetail/openwebcad/src/inputController/input-wheel.ts @@ -0,0 +1,24 @@ +import { + PINCH_ZOOM_EXPONENT, + WHEEL_LINE_PX, + WHEEL_PAGE_PX, + WHEEL_ZOOM_EXPONENT, +} from '../App.consts.ts'; + +/** + * 휠 한 번 → 화면 확대(`zoomScreen` 인자). 휠은 늘 줌 · 커서 자리 고정(153-3) — 마우스 · 트랙패드를 + * 가르지 않는다(옛 판정은 확대율 ≠ 100 % 등에서 휠을 팬으로 오판). 팬 = 가운데 단추 끌기. + * null = 델타 0 이라 안 움직임. + */ +export function wheelZoom( + evt: Pick +): { delta: number; exponent: number } | null { + // deltaY 단위를 픽셀로 맞춘다 — 브라우저에 따라 줄(1)·쪽(2) 단위로 오기도 한다. + const unitPx = evt.deltaMode === 1 ? WHEEL_LINE_PX : evt.deltaMode === 2 ? WHEEL_PAGE_PX : 1; + const deltaY = evt.deltaY * unitPx; + if (deltaY === 0) return null; + // Aislo: wheel direction is inverted on purpose - pulling the wheel zooms in, pushing + // zooms out, matching the B04/B05 maps and the B06 cross sections (2026-08-02). + // 핀치(ctrl+휠)는 델타가 잘아 지수만 크게. + return { delta: -deltaY, exponent: evt.ctrlKey ? PINCH_ZOOM_EXPONENT : WHEEL_ZOOM_EXPONENT }; +}