Skip to content

Commit

Permalink
漫画のスクロールを改善
Browse files Browse the repository at this point in the history
  • Loading branch information
cp-20 committed Mar 24, 2024
1 parent e2c8e8d commit d9e04b2
Showing 1 changed file with 30 additions and 36 deletions.
66 changes: 30 additions & 36 deletions workspaces/app/src/features/viewer/components/ComicViewerCore.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,38 +30,36 @@ function getScrollToLeft({

// 画面に表示されているページの中心と、スクロールビューの中心との差分を計算する
// 世界は我々の想像する以上に変化するため、2 ** 12 回繰り返し観測する
for (let times = 0; times < 2 ** 12; times++) {
for (const [idx, child] of children.entries()) {
const nthChild = idx + 1;
const elementClientRect = child.getBoundingClientRect();

// 見開き2ページの場合は、scroll-margin で表示領域にサイズを合わせる
const scrollMargin =
pageCountParView === 2
? {
// 奇数ページのときは左側に1ページ分の幅を追加する
left: nthChild % 2 === 0 ? pageWidth : 0,
// 偶数ページのときは右側に1ページ分の幅を追加する
right: nthChild % 2 === 1 ? pageWidth : 0,
}
: { left: 0, right: 0 };

// scroll-margin の分だけ広げた範囲を計算する
const areaClientRect = {
bottom: elementClientRect.bottom,
left: elementClientRect.left - scrollMargin.left,
right: elementClientRect.right + scrollMargin.right,
top: elementClientRect.top,
};

const areaCenterX = (areaClientRect.left + areaClientRect.right) / 2;
// ページの中心をスクロールビューの中心に合わせるための移動距離
const candidateScrollToLeft = areaCenterX - scrollViewCenterX;

// もっともスクロール量の少ないものを選ぶ
if (Math.abs(candidateScrollToLeft) < Math.abs(scrollToLeft)) {
scrollToLeft = candidateScrollToLeft;
}
for (const [idx, child] of children.entries()) {
const nthChild = idx + 1;
const elementClientRect = child.getBoundingClientRect();

// 見開き2ページの場合は、scroll-margin で表示領域にサイズを合わせる
const scrollMargin =
pageCountParView === 2
? {
// 奇数ページのときは左側に1ページ分の幅を追加する
left: nthChild % 2 === 0 ? pageWidth : 0,
// 偶数ページのときは右側に1ページ分の幅を追加する
right: nthChild % 2 === 1 ? pageWidth : 0,
}
: { left: 0, right: 0 };

// scroll-margin の分だけ広げた範囲を計算する
const areaClientRect = {
bottom: elementClientRect.bottom,
left: elementClientRect.left - scrollMargin.left,
right: elementClientRect.right + scrollMargin.right,
top: elementClientRect.top,
};

const areaCenterX = (areaClientRect.left + areaClientRect.right) / 2;
// ページの中心をスクロールビューの中心に合わせるための移動距離
const candidateScrollToLeft = areaCenterX - scrollViewCenterX;

// もっともスクロール量の少ないものを選ぶ
if (Math.abs(candidateScrollToLeft) < Math.abs(scrollToLeft)) {
scrollToLeft = candidateScrollToLeft;
}
}

Expand Down Expand Up @@ -128,7 +126,6 @@ const ComicViewerCore: React.FC<Props> = ({ episode }) => {
let scrollToLeftWhenScrollEnd = 0;

const handlePointerDown = (ev: PointerEvent) => {
rerender();
const scrollView = ev.currentTarget as HTMLDivElement;
isPressed = true;
scrollView.style.cursor = 'grabbing';
Expand All @@ -137,7 +134,6 @@ const ComicViewerCore: React.FC<Props> = ({ episode }) => {
};

const handlePointerMove = (ev: PointerEvent) => {
rerender();
if (isPressed) {
const scrollView = ev.currentTarget as HTMLDivElement;
scrollView.scrollBy({
Expand All @@ -149,7 +145,6 @@ const ComicViewerCore: React.FC<Props> = ({ episode }) => {
};

const handlePointerUp = (ev: PointerEvent) => {
rerender();
const scrollView = ev.currentTarget as HTMLDivElement;
isPressed = false;
scrollView.style.cursor = 'grab';
Expand All @@ -167,7 +162,6 @@ const ComicViewerCore: React.FC<Props> = ({ episode }) => {
abortController.signal.addEventListener('abort', () => window.clearTimeout(scrollEndTimer), { once: true });

const handleScrollEnd = (ev: Pick<Event, 'currentTarget'>) => {
rerender();
const scrollView = ev.currentTarget as HTMLDivElement;

// マウスが離されるまではスクロール中とみなす
Expand Down

0 comments on commit d9e04b2

Please sign in to comment.