Add option to pause spinning in showcase

This commit is contained in:
2023-09-17 02:49:12 +01:00
parent 9fbfd1ff1c
commit fd3ed81f93
2 changed files with 48 additions and 6 deletions
+37 -6
View File
@@ -1,10 +1,12 @@
import { CoinProps } from "@/types/coin";
import { Canvas, MeshProps, useFrame } from "@react-three/fiber";
import { Suspense, useEffect, useRef, useState } from "react";
import { Suspense, useCallback, useEffect, useRef, useState } from "react";
import { CoinInstance } from "@/components/coin";
import { Mesh } from "three";
import { BanknoteInstance } from "@/components/banknote";
import { InfoBox } from "./info-box";
import { OrbitControls } from "@react-three/drei";
import { OrbitControls as OrbitControlsType } from "three-stdlib";
type Props = {
category: "coins" | "banknotes";
@@ -13,16 +15,21 @@ type Props = {
const SpinninType = ({
isSelected,
isSpinning,
category,
typeProps,
...props
}: { typeProps: CoinProps; isSelected?: boolean } & MeshProps &
}: {
typeProps: CoinProps;
isSelected?: boolean;
isSpinning?: boolean;
} & MeshProps &
Pick<Props, "category">) => {
const ref = useRef<Mesh>(null!);
const Instance = category === "banknotes" ? BanknoteInstance : CoinInstance;
useFrame((_state, delta) => {
if (!isSelected) {
if (!isSelected || !isSpinning) {
return;
}
@@ -66,7 +73,8 @@ const Row = ({
category,
types,
selectedIndex,
}: Props & { selectedIndex: number }) => {
isSpinning,
}: Props & { selectedIndex: number; isSpinning?: boolean }) => {
const ref = useRef<Mesh>(null!);
const spacing = category === "banknotes" ? 8 : 6;
@@ -91,6 +99,7 @@ const Row = ({
<Suspense key={type.id} fallback={null}>
<SpinninType
category={category}
isSpinning={isSpinning}
isSelected={selectedIndex === index}
typeProps={type}
position={[index * spacing, 1, 0]}
@@ -105,6 +114,18 @@ const Row = ({
export const Showcase = (props: Props) => {
const [selectedIndex, selectIndex] = useState(0);
const [isSpinning, setIsSpinning] = useState(true);
const orbitControlsRef = useRef<OrbitControlsType>(null!);
const toggleSpin = useCallback(() => {
setIsSpinning((value) => {
if (!value) {
orbitControlsRef.current?.setAzimuthalAngle(0);
orbitControlsRef.current?.setPolarAngle(Math.PI / 2);
return true;
}
return false;
});
}, []);
useEffect(() => {
const onKeyDown = ({ key }: KeyboardEvent) => {
@@ -115,11 +136,13 @@ export const Showcase = (props: Props) => {
return selectIndex((value) =>
Math.min(value + 1, props.types.length - 1),
);
case " ":
return toggleSpin();
}
};
document.addEventListener("keydown", onKeyDown);
return () => document.removeEventListener("keydown", onKeyDown);
}, [props.types.length]);
}, [props.types.length, toggleSpin]);
return (
<>
@@ -127,7 +150,13 @@ export const Showcase = (props: Props) => {
<color attach="background" args={["#111"]} />
<ambientLight />
<directionalLight position={[0, 0.125, 1]} />
<Row {...props} selectedIndex={selectedIndex} />
<directionalLight position={[0, 0.125, -1]} />
<Row {...props} selectedIndex={selectedIndex} isSpinning={isSpinning} />
<OrbitControls
ref={orbitControlsRef}
enableRotate={!isSpinning}
enablePan={false}
/>
</Canvas>
<InfoBox
@@ -135,6 +164,8 @@ export const Showcase = (props: Props) => {
type={props.types[selectedIndex]}
selectIndex={selectIndex}
selectedIndex={selectedIndex}
isSpinning={isSpinning}
toggleSpin={toggleSpin}
maxIndex={props.types.length - 1}
/>
</>
+11
View File
@@ -7,12 +7,16 @@ export const InfoBox = ({
maxIndex,
selectIndex,
selectedIndex,
isSpinning,
toggleSpin,
}: {
category: "banknotes" | "coins";
type: CoinProps;
maxIndex: number;
selectIndex: Dispatch<SetStateAction<number>>;
selectedIndex: number;
isSpinning: boolean;
toggleSpin: () => void;
}) => {
return (
<div
@@ -55,6 +59,13 @@ export const InfoBox = ({
)}
</div>
<button
style={{ fontSize: "1.2rem", marginBottom: "8px" }}
onClick={toggleSpin}
>
{isSpinning ? "⏸️" : "▶️"}
</button>
<div
style={{
width: 128,