janky animation engine for approve/deny
This commit is contained in:
parent
f52e3e9723
commit
18e41566b4
@ -9,7 +9,7 @@
|
|||||||
<link href="https://fonts.googleapis.com/css2?family=Roboto+Condensed:ital,wght@0,100..900;1,100..900&display=swap" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/css2?family=Roboto+Condensed:ital,wght@0,100..900;1,100..900&display=swap" rel="stylesheet">
|
||||||
<title>React Redux App</title>
|
<title>React Redux App</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body oncontextmenu="return false;">
|
||||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
<script type="module" src="/src/main.tsx"></script>
|
<script type="module" src="/src/main.tsx"></script>
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
import { useState } from 'react';
|
import { useEffect, useRef, useState } from 'react';
|
||||||
|
import { useAppSelector } from 'src/redux/hooks';
|
||||||
|
import { getGazesAndKeys } from 'src/redux/slices/gazeSlice';
|
||||||
import type { ApproveDenyButtonElement as ApproveDenyButtonElementType } from 'src/types/element';
|
import type { ApproveDenyButtonElement as ApproveDenyButtonElementType } from 'src/types/element';
|
||||||
|
|
||||||
type ApproveDenyButtonElementProps = {
|
type ApproveDenyButtonElementProps = {
|
||||||
@ -24,8 +26,10 @@ type KeyframeParameters = {
|
|||||||
tinyDotOpacity: number,
|
tinyDotOpacity: number,
|
||||||
approveButtonPosition: number,
|
approveButtonPosition: number,
|
||||||
approveButtonOpacity: number,
|
approveButtonOpacity: number,
|
||||||
|
approveArrowOpacity: number,
|
||||||
denyButtonPosition: number,
|
denyButtonPosition: number,
|
||||||
denyButtonOpacity: number,
|
denyButtonOpacity: number,
|
||||||
|
denyArrowOpacity: number,
|
||||||
};
|
};
|
||||||
|
|
||||||
const INITIAL_KEYFRAME: KeyframeParameters = {
|
const INITIAL_KEYFRAME: KeyframeParameters = {
|
||||||
@ -37,8 +41,10 @@ const INITIAL_KEYFRAME: KeyframeParameters = {
|
|||||||
tinyDotOpacity: 0.8,
|
tinyDotOpacity: 0.8,
|
||||||
approveButtonPosition: 1,
|
approveButtonPosition: 1,
|
||||||
approveButtonOpacity: 1,
|
approveButtonOpacity: 1,
|
||||||
|
approveArrowOpacity: 1,
|
||||||
denyButtonPosition: 0,
|
denyButtonPosition: 0,
|
||||||
denyButtonOpacity: 1,
|
denyButtonOpacity: 1,
|
||||||
|
denyArrowOpacity: 1,
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
const KEYFRAMES_APPROVE = [
|
const KEYFRAMES_APPROVE = [
|
||||||
@ -52,13 +58,15 @@ const KEYFRAMES_APPROVE = [
|
|||||||
bigCircleRadius: SIZES.bigCircle,
|
bigCircleRadius: SIZES.bigCircle,
|
||||||
bigCircleGradientStart: 0x646464,
|
bigCircleGradientStart: 0x646464,
|
||||||
bigCircleGradientEnd: 0x00C007,
|
bigCircleGradientEnd: 0x00C007,
|
||||||
smallTurqoiseCirclePosition: 0.5,
|
smallTurqoiseCirclePosition: 0.7,
|
||||||
smallTurqoiseCircleOpacity: 1,
|
smallTurqoiseCircleOpacity: 1,
|
||||||
tinyDotOpacity: 0.8,
|
tinyDotOpacity: 0.8,
|
||||||
approveButtonPosition: 1,
|
approveButtonPosition: 1,
|
||||||
approveButtonOpacity: 1,
|
approveButtonOpacity: 1,
|
||||||
|
approveArrowOpacity: 1,
|
||||||
denyButtonPosition: 0,
|
denyButtonPosition: 0,
|
||||||
denyButtonOpacity: 1,
|
denyButtonOpacity: 1,
|
||||||
|
denyArrowOpacity: 0.2,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -72,8 +80,10 @@ const KEYFRAMES_APPROVE = [
|
|||||||
tinyDotOpacity: 0,
|
tinyDotOpacity: 0,
|
||||||
approveButtonPosition: 0.5,
|
approveButtonPosition: 0.5,
|
||||||
approveButtonOpacity: 1,
|
approveButtonOpacity: 1,
|
||||||
|
approveArrowOpacity: 0,
|
||||||
denyButtonPosition: 0,
|
denyButtonPosition: 0,
|
||||||
denyButtonOpacity: 0,
|
denyButtonOpacity: 0,
|
||||||
|
denyArrowOpacity: 0,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -87,8 +97,10 @@ const KEYFRAMES_APPROVE = [
|
|||||||
tinyDotOpacity: 0,
|
tinyDotOpacity: 0,
|
||||||
approveButtonPosition: 0.5,
|
approveButtonPosition: 0.5,
|
||||||
approveButtonOpacity: 1,
|
approveButtonOpacity: 1,
|
||||||
|
approveArrowOpacity: 0,
|
||||||
denyButtonPosition: 0,
|
denyButtonPosition: 0,
|
||||||
denyButtonOpacity: 0,
|
denyButtonOpacity: 0,
|
||||||
|
denyArrowOpacity: 0,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
@ -104,13 +116,15 @@ const KEYFRAMES_DENY = [
|
|||||||
bigCircleRadius: SIZES.bigCircle,
|
bigCircleRadius: SIZES.bigCircle,
|
||||||
bigCircleGradientStart: 0x646464,
|
bigCircleGradientStart: 0x646464,
|
||||||
bigCircleGradientEnd: 0xBC2503,
|
bigCircleGradientEnd: 0xBC2503,
|
||||||
smallTurqoiseCirclePosition: 0.5,
|
smallTurqoiseCirclePosition: 0.3,
|
||||||
smallTurqoiseCircleOpacity: 1,
|
smallTurqoiseCircleOpacity: 1,
|
||||||
tinyDotOpacity: 0.8,
|
tinyDotOpacity: 0.8,
|
||||||
approveButtonPosition: 1,
|
approveButtonPosition: 1,
|
||||||
approveButtonOpacity: 1,
|
approveButtonOpacity: 1,
|
||||||
|
approveArrowOpacity: 0.2,
|
||||||
denyButtonPosition: 0,
|
denyButtonPosition: 0,
|
||||||
denyButtonOpacity: 1,
|
denyButtonOpacity: 1,
|
||||||
|
denyArrowOpacity: 1,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -124,8 +138,10 @@ const KEYFRAMES_DENY = [
|
|||||||
tinyDotOpacity: 0,
|
tinyDotOpacity: 0,
|
||||||
approveButtonPosition: 1,
|
approveButtonPosition: 1,
|
||||||
approveButtonOpacity: 0,
|
approveButtonOpacity: 0,
|
||||||
|
approveArrowOpacity: 0,
|
||||||
denyButtonPosition: 0.5,
|
denyButtonPosition: 0.5,
|
||||||
denyButtonOpacity: 1,
|
denyButtonOpacity: 1,
|
||||||
|
denyArrowOpacity: 0,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -139,8 +155,10 @@ const KEYFRAMES_DENY = [
|
|||||||
tinyDotOpacity: 0,
|
tinyDotOpacity: 0,
|
||||||
approveButtonPosition: 1,
|
approveButtonPosition: 1,
|
||||||
approveButtonOpacity: 0,
|
approveButtonOpacity: 0,
|
||||||
|
approveArrowOpacity: 0,
|
||||||
denyButtonPosition: 0.5,
|
denyButtonPosition: 0.5,
|
||||||
denyButtonOpacity: 1,
|
denyButtonOpacity: 1,
|
||||||
|
denyArrowOpacity: 0,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
@ -157,6 +175,8 @@ const KEYFRAMES_DENY = [
|
|||||||
// - 2: pos turqoise circle left of entire button, "deny" in middle of button, button red
|
// - 2: pos turqoise circle left of entire button, "deny" in middle of button, button red
|
||||||
// - 3: no turqoise circle, "deny" in middle of button, button red
|
// - 3: no turqoise circle, "deny" in middle of button, button red
|
||||||
|
|
||||||
|
const FRAMETIME = 1.0 / 60.0;
|
||||||
|
|
||||||
const ApproveDenyButtonElement = ({
|
const ApproveDenyButtonElement = ({
|
||||||
element,
|
element,
|
||||||
}: ApproveDenyButtonElementProps) => {
|
}: ApproveDenyButtonElementProps) => {
|
||||||
@ -166,6 +186,78 @@ const ApproveDenyButtonElement = ({
|
|||||||
const buttonStyle = { fontSize: w * SIZES.fontSize, height: w * SIZES.button - 2, lineHeight: `${w * SIZES.button - 2}px`, width: w * SIZES.sideLabel };
|
const buttonStyle = { fontSize: w * SIZES.fontSize, height: w * SIZES.button - 2, lineHeight: `${w * SIZES.button - 2}px`, width: w * SIZES.sideLabel };
|
||||||
|
|
||||||
const [state, setState] = useState(INITIAL_KEYFRAME);
|
const [state, setState] = useState(INITIAL_KEYFRAME);
|
||||||
|
const [animation, setAnimation] = useState<"approve" | "deny" | undefined>(undefined);
|
||||||
|
const [time, setTime] = useState(0);
|
||||||
|
const intervalRef = useRef<any>(undefined); // this is really just `number | undefined` but typescript is stoopid
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let intervalHandle: any;
|
||||||
|
|
||||||
|
const animationTick = () => {
|
||||||
|
setState({...state, bigCircleRadius: state.bigCircleRadius + 0.01});
|
||||||
|
setTime(prevTime => {
|
||||||
|
const newTime = prevTime + FRAMETIME;
|
||||||
|
if (newTime >= 1000) {
|
||||||
|
stopAnimation();
|
||||||
|
}
|
||||||
|
return newTime;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
if (animation) {
|
||||||
|
intervalRef.current = setInterval(animationTick, FRAMETIME);
|
||||||
|
} else {
|
||||||
|
if (intervalRef.current !== undefined) {
|
||||||
|
clearInterval(intervalRef.current);
|
||||||
|
intervalRef.current = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (intervalRef.current !== undefined) {
|
||||||
|
clearInterval(intervalRef.current);
|
||||||
|
intervalRef.current = undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
//const [intervalHandle, setIntervalHandle] = useState<number | undefined>(undefined);
|
||||||
|
//const [time, setTime] = useState(0);
|
||||||
|
|
||||||
|
//const animationTick = (action: "approve" | "deny") => {
|
||||||
|
// setTime(time + FRAMETIME);
|
||||||
|
// setState({...state, bigCircleRadius: state.bigCircleRadius * 1.1})
|
||||||
|
// if (time >= 1) {
|
||||||
|
// setAnimation(undefined);
|
||||||
|
// clearInterval(intervalHandle);
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
const stopAnimation = () => {
|
||||||
|
setState(INITIAL_KEYFRAME);
|
||||||
|
setAnimation(undefined);
|
||||||
|
if (intervalRef.current !== undefined) {
|
||||||
|
clearInterval(intervalRef.current);
|
||||||
|
intervalRef.current = undefined;
|
||||||
|
}
|
||||||
|
setTime(0);
|
||||||
|
};
|
||||||
|
|
||||||
|
const gazeAndKeys = useAppSelector(getGazesAndKeys);
|
||||||
|
useEffect(() => {
|
||||||
|
for (const i of gazeAndKeys) {
|
||||||
|
if (animation !== "deny" && i.keyPress === "0") { // left mouse button
|
||||||
|
setAnimation("deny");
|
||||||
|
return;
|
||||||
|
} else if (animation !== "approve" && i.keyPress === "2") { // right mouse button
|
||||||
|
setAnimation("approve");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!gazeAndKeys.some(x => x.keyPress === "0") && !gazeAndKeys.some(x => x.keyPress === "2")) {
|
||||||
|
stopAnimation();
|
||||||
|
}
|
||||||
|
}, [gazeAndKeys]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@ -187,8 +279,8 @@ const ApproveDenyButtonElement = ({
|
|||||||
</div>
|
</div>
|
||||||
<svg className="" style={{ width: w, height: w * SIZES.button, marginTop: -w * SIZES.button }}>
|
<svg className="" style={{ width: w, height: w * SIZES.button, marginTop: -w * SIZES.button }}>
|
||||||
<clipPath id="clip">
|
<clipPath id="clip">
|
||||||
<rect />
|
|
||||||
</clipPath>
|
</clipPath>
|
||||||
|
<circle cx={10} cy={10} r={state.bigCircleRadius * 100} fill="red" />
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -16,6 +16,7 @@ export function useMouseButtonDown() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
function handleMouseButtonDown(ev: MouseEvent) {
|
function handleMouseButtonDown(ev: MouseEvent) {
|
||||||
//console.log('Mouse button pressed: ' + ev.button);
|
//console.log('Mouse button pressed: ' + ev.button);
|
||||||
|
ev.preventDefault();
|
||||||
if (ev.button === 0 || ev.button === 1 || ev.button === 2 || ev.button === 3 ) {
|
if (ev.button === 0 || ev.button === 1 || ev.button === 2 || ev.button === 3 ) {
|
||||||
setMouseButtDown(ev.button.toString());
|
setMouseButtDown(ev.button.toString());
|
||||||
//console.log('Mouse button pressed: ' + ev.button);
|
//console.log('Mouse button pressed: ' + ev.button);
|
||||||
|
Loading…
Reference in New Issue
Block a user