fix(B05): 종단 새 창 최대화 때 휠 이동 — 스크롤러가 놓인 창의 화면 틀 · 시계 사용(230-1)
메인 창 requestAnimationFrame 은 새 창 최대화로 메인 창이 가려지면 멈춤 · 휠은 막히고 이동 0. 휠 이동 · 끌기 뒤 클릭 삼킴 · 글자 선택 풀기 · 스크롤 뒤 다시 그리기 시계를 ownerDocument.defaultView 로. 새 시험 test_230_1_popout_wheel(가려진 메인 창 · 새 창 보통 · 최대화 · 원래 창). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01F3mdb91125mPoC6tpsQx4P
This commit is contained in:
@@ -37,16 +37,25 @@ const BASE_FRAME_MS = 1000 / 60;
|
||||
* 쓰면 한 번에 목표까지 튄다. */
|
||||
const MAX_FRAME_MS = 64;
|
||||
|
||||
/** 스크롤러가 지금 놓인 창 — 종단을 새 창으로 빼면 그 창이다(230-1).
|
||||
* 메인 창 전역 `requestAnimationFrame` 을 쓰면, 새 창을 최대화해 메인 창이 가려질 때
|
||||
* 브라우저가 메인 창 프레임을 멈춰 휠 이동이 한 걸음도 안 나갔다. */
|
||||
function viewOf(scroller: HTMLElement): Window {
|
||||
return scroller.ownerDocument.defaultView ?? window;
|
||||
}
|
||||
|
||||
export function attachWheelHorizontalScroll(scroller: HTMLElement): void {
|
||||
let target = -1;
|
||||
/** 우리가 마지막으로 써 넣은 값 — 남이 자리를 옮겼는지 가리는 데 쓴다. */
|
||||
let applied = -1;
|
||||
let frame = 0;
|
||||
/** `frame` 을 받아 둔 창 — 걷을 때도 같은 창에서 걷는다. */
|
||||
let frameView: Window = window;
|
||||
/** 직전 프레임 시각 — 좁히는 양을 **흐른 시간**에 맞추는 데 쓴다. */
|
||||
let lastFrameAt = 0;
|
||||
|
||||
function stop(): void {
|
||||
if (frame) cancelAnimationFrame(frame);
|
||||
if (frame) frameView.cancelAnimationFrame(frame);
|
||||
frame = 0;
|
||||
target = -1;
|
||||
applied = -1;
|
||||
@@ -72,7 +81,7 @@ export function attachWheelHorizontalScroll(scroller: HTMLElement): void {
|
||||
const ratio = 1 - Math.pow(1 - EASE, elapsed / BASE_FRAME_MS);
|
||||
scroller.scrollLeft = scroller.scrollLeft + rest * ratio;
|
||||
applied = scroller.scrollLeft;
|
||||
frame = requestAnimationFrame(step);
|
||||
frame = frameView.requestAnimationFrame(step);
|
||||
}
|
||||
|
||||
scroller.addEventListener(
|
||||
@@ -89,7 +98,8 @@ export function attachWheelHorizontalScroll(scroller: HTMLElement): void {
|
||||
target = next;
|
||||
if (!frame) {
|
||||
applied = scroller.scrollLeft;
|
||||
frame = requestAnimationFrame(step);
|
||||
frameView = viewOf(scroller);
|
||||
frame = frameView.requestAnimationFrame(step);
|
||||
}
|
||||
event.preventDefault();
|
||||
},
|
||||
@@ -128,7 +138,7 @@ export function attachWheelHorizontalScroll(scroller: HTMLElement): void {
|
||||
};
|
||||
scroller.addEventListener("click", swallow, { capture: true, once: true });
|
||||
// 클릭이 안 오는 경우(휠 버튼 등)를 대비해 다음 프레임에 걷어낸다.
|
||||
requestAnimationFrame(() =>
|
||||
viewOf(scroller).requestAnimationFrame(() =>
|
||||
scroller.removeEventListener("click", swallow, { capture: true }),
|
||||
);
|
||||
}
|
||||
@@ -164,7 +174,7 @@ export function attachWheelHorizontalScroll(scroller: HTMLElement): void {
|
||||
// 끄는 동안 글자가 파랗게 잡히지 않게 한다. 포인터 잡기를 미룬 뒤로 브라우저가
|
||||
// 기본 글자 선택을 시작했다(2026-09-06 사용자 지적). 이미 잡힌 것도 푼다.
|
||||
scroller.style.userSelect = "none";
|
||||
window.getSelection()?.removeAllRanges();
|
||||
viewOf(scroller).getSelection()?.removeAllRanges();
|
||||
}
|
||||
scroller.scrollLeft = dragLeft - dx;
|
||||
scroller.scrollTop = dragTop - dy;
|
||||
|
||||
Reference in New Issue
Block a user