mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-23 19:49:50 +02:00
auto scroll on drag in tier list
This commit is contained in:
1 parent
9fc8a8e2a2
commit
082a756f1b
1 file changed
+53
-18
@@ -1,14 +1,16 @@
|
|||||||
import type { TankDefinition } from '@blitzkit/core';
|
import type { TankDefinition } from "@blitzkit/core";
|
||||||
import { Box } from '@radix-ui/themes';
|
import { Box } from "@radix-ui/themes";
|
||||||
import {
|
import {
|
||||||
useCallback,
|
useCallback,
|
||||||
useEffect,
|
useEffect,
|
||||||
useRef,
|
useRef,
|
||||||
type PointerEvent as ReactPointerEvent,
|
type PointerEvent as ReactPointerEvent,
|
||||||
} from 'react';
|
} from "react";
|
||||||
import { TierList } from '../../stores/tierList';
|
import { TierList } from "../../stores/tierList";
|
||||||
import { TankCard } from '../TankCard';
|
import { TankCard } from "../TankCard";
|
||||||
import { tierListCardElements, tierListRowElements } from './Table/constants';
|
import { tierListCardElements, tierListRowElements } from "./Table/constants";
|
||||||
|
|
||||||
|
const SCROLL_ZONE = 1 / 3;
|
||||||
|
|
||||||
type TierListTileProps = {
|
type TierListTileProps = {
|
||||||
tank: TankDefinition;
|
tank: TankDefinition;
|
||||||
@@ -26,6 +28,33 @@ type TierListTileProps = {
|
|||||||
export function TierListTile(props: TierListTileProps) {
|
export function TierListTile(props: TierListTileProps) {
|
||||||
const card = useRef<HTMLDivElement>(null);
|
const card = useRef<HTMLDivElement>(null);
|
||||||
const lastPosition = useRef({ x: 0, y: 0 });
|
const lastPosition = useRef({ x: 0, y: 0 });
|
||||||
|
const autoScroll = useRef(false);
|
||||||
|
const lastT = useRef(0);
|
||||||
|
|
||||||
|
const autoScrollLoop = useCallback(() => {
|
||||||
|
if (!autoScroll.current) return;
|
||||||
|
|
||||||
|
let scrollSpeed = 0;
|
||||||
|
const v = lastPosition.current.y / window.innerHeight;
|
||||||
|
|
||||||
|
if (v <= SCROLL_ZONE) {
|
||||||
|
scrollSpeed = v / SCROLL_ZONE - 1;
|
||||||
|
} else if (v >= 1 - SCROLL_ZONE) {
|
||||||
|
scrollSpeed = 1 - (1 - v) / SCROLL_ZONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
const t = performance.now();
|
||||||
|
const dt = t - lastT.current;
|
||||||
|
lastT.current = t;
|
||||||
|
|
||||||
|
window.scrollBy({
|
||||||
|
behavior: "instant",
|
||||||
|
top: scrollSpeed * dt,
|
||||||
|
});
|
||||||
|
|
||||||
|
requestAnimationFrame(autoScrollLoop);
|
||||||
|
}, []);
|
||||||
|
|
||||||
const handlePointerDown = useCallback(
|
const handlePointerDown = useCallback(
|
||||||
(event: ReactPointerEvent<HTMLSpanElement>) => {
|
(event: ReactPointerEvent<HTMLSpanElement>) => {
|
||||||
if (!card.current) return;
|
if (!card.current) return;
|
||||||
@@ -34,22 +63,26 @@ export function TierListTile(props: TierListTileProps) {
|
|||||||
|
|
||||||
const rect = card.current.getBoundingClientRect();
|
const rect = card.current.getBoundingClientRect();
|
||||||
|
|
||||||
card.current.style.position = 'fixed';
|
card.current.style.position = "fixed";
|
||||||
card.current.style.cursor = 'grabbing';
|
card.current.style.cursor = "grabbing";
|
||||||
card.current.style.zIndex = '1';
|
card.current.style.zIndex = "1";
|
||||||
card.current.style.left = `${rect.left}px`;
|
card.current.style.left = `${rect.left}px`;
|
||||||
card.current.style.top = `${rect.top}px`;
|
card.current.style.top = `${rect.top}px`;
|
||||||
|
|
||||||
lastPosition.current = { x: event.clientX, y: event.clientY };
|
lastPosition.current = { x: event.clientX, y: event.clientY };
|
||||||
|
|
||||||
window.scrollTo({ behavior: 'smooth', top: 124 });
|
window.scrollTo({ behavior: "instant", top: 124 });
|
||||||
|
|
||||||
window.addEventListener('pointermove', handlePointerMove);
|
window.addEventListener("pointermove", handlePointerMove);
|
||||||
window.addEventListener('pointerup', handlePointerUp);
|
window.addEventListener("pointerup", handlePointerUp);
|
||||||
|
|
||||||
TierList.mutate((draft) => {
|
TierList.mutate((draft) => {
|
||||||
draft.dragging = true;
|
draft.dragging = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
autoScroll.current = true;
|
||||||
|
lastT.current = performance.now();
|
||||||
|
autoScrollLoop();
|
||||||
},
|
},
|
||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
@@ -141,12 +174,14 @@ export function TierListTile(props: TierListTileProps) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
card.current.style.position = 'static';
|
card.current.style.position = "static";
|
||||||
card.current.style.zIndex = 'unset';
|
card.current.style.zIndex = "unset";
|
||||||
card.current.style.cursor = 'grab';
|
card.current.style.cursor = "grab";
|
||||||
|
|
||||||
window.removeEventListener('pointermove', handlePointerMove);
|
window.removeEventListener("pointermove", handlePointerMove);
|
||||||
window.removeEventListener('pointerup', handlePointerUp);
|
window.removeEventListener("pointerup", handlePointerUp);
|
||||||
|
|
||||||
|
autoScroll.current = false;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -168,7 +203,7 @@ export function TierListTile(props: TierListTileProps) {
|
|||||||
data-tile-index={props.isPlaced ? props.tileIndex : undefined}
|
data-tile-index={props.isPlaced ? props.tileIndex : undefined}
|
||||||
data-tile-id={props.tank.id}
|
data-tile-id={props.tank.id}
|
||||||
onPointerDown={handlePointerDown}
|
onPointerDown={handlePointerDown}
|
||||||
style={{ cursor: 'grab', touchAction: 'none' }}
|
style={{ cursor: "grab", touchAction: "none" }}
|
||||||
>
|
>
|
||||||
<TankCard noLink tank={props.tank} />
|
<TankCard noLink tank={props.tank} />
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
Reference in new issue
Block a user