aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes/trails/SlideEffect.tsx
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2024-05-16 19:52:13 -0400
committerbobzel <zzzman@gmail.com>2024-05-16 19:52:13 -0400
commit69e286b504c2f1bbef7d489dc675b9e54ef8d983 (patch)
treeb8243dab1a93aced50bab0cbf0e9da3e08e58f07 /src/client/views/nodes/trails/SlideEffect.tsx
parent56917559cf47bba35740571e97845295dd63b424 (diff)
refactor/cleanup of pres animations. changed effects to start halfway through a zoom transition.
Diffstat (limited to 'src/client/views/nodes/trails/SlideEffect.tsx')
-rw-r--r--src/client/views/nodes/trails/SlideEffect.tsx402
1 files changed, 80 insertions, 322 deletions
diff --git a/src/client/views/nodes/trails/SlideEffect.tsx b/src/client/views/nodes/trails/SlideEffect.tsx
index 03cd88f45..00039e3cb 100644
--- a/src/client/views/nodes/trails/SlideEffect.tsx
+++ b/src/client/views/nodes/trails/SlideEffect.tsx
@@ -5,358 +5,116 @@ import { Doc } from '../../../../fields/Doc';
import { NumCast } from '../../../../fields/Types';
import { PresEffect, PresEffectDirection } from './PresEnums';
import './SlideEffect.scss';
+import { emptyFunction } from '../../../../Utils';
interface SlideEffectProps {
- // pass in doc to extract width, height, bg
- doc?: Doc;
+ doc?: Doc; // pass in doc to extract width, height, bg
dir: PresEffectDirection;
presEffect: PresEffect;
- // stiffness (figma) = tension (react-spring)
- tension: number;
- // damping (figma) = friction (react-spring)
- friction: number;
- mass: number;
+ springSettings: {
+ stiffness: number;
+ damping: number;
+ mass: number;
+ };
children: React.ReactNode;
infinite?: boolean;
+ startOpacity?: number; // set to zero to linearly fade in while animating
}
const DEFAULT_WIDTH = 40;
const PREVIEW_OFFSET = 60;
const ACTUAL_OFFSET = 200;
-const infiniteOptions = {
- loop: true,
- delay: 500,
-};
/**
* This component wraps around the doc to create an effect animation, and also wraps the preview animations
* for the effects as well.
*/
-export default function SpringAnimation({ doc, dir, friction, tension, mass, presEffect, children, infinite }: SlideEffectProps) {
- const [springs, api] = useSpring(
- () => ({
- from: {
- x: 0,
- y: 0,
- opacity: 0,
- scale: 1,
- },
- config: {
- tension,
- friction,
- mass,
- },
- onStart: () => {},
- onRest: () => {},
- }),
- [tension, friction, mass]
- );
- const [ref, inView] = useInView({
- once: true,
- });
-
- const zoomConfig = {
- from: {
- scale: 0,
- x: 0,
- y: 0,
- opacity: 1,
- },
- to: {
- scale: 1,
- x: 0,
- y: 0,
- opacity: 1,
- config: {
- tension: tension,
- friction: friction,
- mass: mass,
- },
- },
+export default function SpringAnimation({ doc, dir, springSettings, presEffect, children, infinite, startOpacity }: SlideEffectProps) {
+ const expandConfig = {
+ to: { scale: 1, x: 0, y: 0 },
+ from: { scale: 0, x: 0, y: 0 },
};
-
const fadeConfig = {
- from: {
- opacity: 0,
- scale: 1,
- x: 0,
- y: 0,
- },
- to: {
- opacity: 1,
- scale: 1,
- x: 0,
- y: 0,
- config: {
- tension: tension,
- friction: friction,
- mass: mass,
- },
- },
+ to: { x: 0, y: 0 },
+ from: { x: 0, y: 0 },
};
-
const rotateConfig = {
- from: {
- x: 0,
- },
- to: {
- x: 360,
- config: {
- tension: tension,
- friction: friction,
- mass: mass,
- },
- },
+ to: { x: 360, y: 0 },
+ from: { x: 0, y: 0 },
};
-
- const getBounceConfigFrom = () => {
- switch (dir) {
- case PresEffectDirection.Left:
- return {
- from: {
- opacity: 0,
- x: infinite ? -PREVIEW_OFFSET : -ACTUAL_OFFSET,
- y: 0,
- },
- };
- case PresEffectDirection.Right:
- return {
- from: {
- opacity: 0,
- x: infinite ? PREVIEW_OFFSET : ACTUAL_OFFSET,
- y: 0,
- },
- };
- case PresEffectDirection.Top:
- return {
- from: {
- opacity: 0,
- x: 0,
- y: infinite ? -PREVIEW_OFFSET : -ACTUAL_OFFSET,
- },
- };
- case PresEffectDirection.Bottom:
- return {
- from: {
- opacity: 0,
- x: 0,
- y: infinite ? PREVIEW_OFFSET : ACTUAL_OFFSET,
- },
- };
- default:
- // no movement for center
- return {
- from: {
- opacity: 0,
- x: 0,
- y: 0,
- },
- };
- }
- };
-
- const bounceConfig = {
- ...getBounceConfigFrom(),
- to: [
- {
- opacity: 1,
- x: 0,
- y: 0,
- config: {
- tension: tension,
- friction: friction,
- mass: mass,
- },
- },
- ],
- };
-
const flipConfig = {
- from: {
- x: 0,
- },
- to: {
- x: 180,
- config: {
- tension: tension,
- friction: friction,
- mass: mass,
- },
- },
+ to: { x: 180, y: 0 },
+ from: { x: 0, y: 0 },
};
-
- // only left and right for now
- const getRollConfigFrom = () => {
- switch (dir) {
- case PresEffectDirection.Left:
- return {
- from: {
- opacity: 0,
- x: -100,
- y: -120,
- },
- };
- case PresEffectDirection.Right:
- return {
- from: {
- opacity: 0,
- x: 100,
- y: 120,
- },
- };
- case PresEffectDirection.Top:
- return {
- from: {
- opacity: 0,
- x: -100,
- y: -120,
- },
- };
- case PresEffectDirection.Bottom:
- return {
- from: {
- opacity: 0,
- x: -100,
- y: -120,
- },
- };
- default:
- // no movement for center
- return {
- from: {
- opacity: 0,
- x: 0,
- y: 0,
- },
- };
- }
+ const bounceConfig = {
+ to: { x: 0, y: 0 },
+ from: (() => {
+ const offset = infinite ? PREVIEW_OFFSET : ACTUAL_OFFSET;
+ switch (dir) {
+ case PresEffectDirection.Left: return { x: -offset, y: 0, };
+ case PresEffectDirection.Right: return { x: offset, y: 0, };
+ case PresEffectDirection.Top: return { x: 0, y: -offset, };
+ case PresEffectDirection.Bottom:return { x: 0, y: offset, };
+ default: return { x: 0, y: 0, }; // no movement for center
+ }})(), // prettier-ignore
};
-
const rollConfig = {
- ...getRollConfigFrom(),
- to: {
- opacity: 1,
- x: 0,
- y: 0,
- config: {
- tension: tension,
- friction: friction,
- mass: mass,
- },
- },
+ to: { x: 0, y: 0 },
+ from: (() => {
+ switch (dir) {
+ case PresEffectDirection.Left: return { x: -100, y: -120, };
+ case PresEffectDirection.Right: return { x: 100, y: 120, };
+ case PresEffectDirection.Top: return { x: -100, y: -120, };
+ case PresEffectDirection.Bottom: return { x: -100, y: -120, };
+ default: return { x: 0, y: 0, }; // no movement for center
+ }})(), // prettier-ignore
};
- // Switch animation depending on slide effect
- const startAnimation = () => {
- api.stop();
- let config: any = zoomConfig;
+ // prettier-ignore
+ const effectConfig = (() => {
switch (presEffect) {
- case PresEffect.Bounce:
- config = bounceConfig;
- break;
- case PresEffect.Zoom:
- config = zoomConfig;
- break;
- case PresEffect.Rotate:
- config = rotateConfig;
- break;
- case PresEffect.Fade:
- config = fadeConfig;
- break;
- case PresEffect.Flip:
- config = flipConfig;
- break;
- case PresEffect.Roll:
- config = rollConfig;
- break;
- case PresEffect.Lightspeed:
- break;
- default:
- break;
- }
-
- if (infinite) {
- config = { ...config, ...infiniteOptions };
- }
+ case PresEffect.Fade: return fadeConfig;
+ case PresEffect.Bounce: return bounceConfig;
+ case PresEffect.Rotate: return rotateConfig;
+ case PresEffect.Flip: return flipConfig;
+ case PresEffect.Roll: return rollConfig;
+ case PresEffect.Lightspeed: return { from: {}, to: {} };
+ case PresEffect.Expand:
+ default: return expandConfig;
+ } // prettier-ignore
+ })();
- api.start(config);
- };
-
- const getRenderDoc = () => {
- switch (presEffect) {
- case PresEffect.Rotate:
- return (
- <animated.div ref={ref} style={{ transform: to(springs.x, val => `rotate(${val}deg)`) }}>
- {children}
- </animated.div>
- );
- case PresEffect.Flip:
- return (
- // Pass in doc dimensions
- <div className="flip-container" ref={ref}>
- {dir === PresEffectDirection.Bottom || dir === PresEffectDirection.Top ? (
- <>
- <animated.div
- className="flip-side flip-back"
- style={{
- transform: to(springs.x, val => `perspective(600px) rotateX(${val}deg)`),
- width: doc ? NumCast(doc.width) : DEFAULT_WIDTH,
- height: doc ? NumCast(doc.height) : DEFAULT_WIDTH,
- backgroundColor: infinite ? '#a825ff' : 'rgb(223, 223, 223);',
- }}
- />
- <animated.div
- className="flip-side flip-front"
- style={{ transform: to(springs.x, val => `perspective(600px) rotateX(${val}deg)`), rotateX: '180deg', width: doc ? NumCast(doc.width) : DEFAULT_WIDTH, height: doc ? NumCast(doc.height) : DEFAULT_WIDTH }}>
- {children}
- </animated.div>
- </>
- ) : (
- <>
- <animated.div
- className="flip-side flip-back"
- style={{ transform: to(springs.x, val => `perspective(600px) rotateY(${val}deg)`), width: doc ? NumCast(doc.width) : DEFAULT_WIDTH, height: doc ? NumCast(doc.height) : DEFAULT_WIDTH }}
- />
- <animated.div
- className="flip-side flip-front"
- style={{ transform: to(springs.x, val => `perspective(600px) rotateY(${val}deg)`), rotateY: '180deg', width: doc ? NumCast(doc.width) : DEFAULT_WIDTH, height: doc ? NumCast(doc.height) : DEFAULT_WIDTH }}>
- {children}
- </animated.div>
- </>
- )}
- </div>
- );
- case PresEffect.Roll:
- return (
- <animated.div ref={ref} style={{ opacity: springs.opacity, transform: to([springs.x, springs.y], (val, val2) => `translate3d(${val}%, 0, 0) rotate3d(0, 0, 1, ${val2}deg)`) }}>
- {children}
- </animated.div>
- );
- default:
- return (
- <animated.div
- ref={ref}
- style={{
- ...springs,
- }}>
- {children}
- </animated.div>
- );
- }
- };
-
- useEffect(() => {
- if (infinite || !inView) return;
- setTimeout(() => {
- startAnimation();
- }, 100);
- }, [inView]);
+ const [springs, api] = useSpring(
+ () => ({
+ to: { ...effectConfig.to, opacity: 1 },
+ from: { ...effectConfig.from, opacity: startOpacity ?? 1 },
+ config: { tension: springSettings.stiffness, friction: springSettings.damping, mass: springSettings.mass },
+ onStart: emptyFunction,
+ onRest: emptyFunction,
+ }),
+ [springSettings]
+ );
+ const [ref, inView] = useInView({
+ once: true,
+ });
useEffect(() => {
- if (infinite) {
- startAnimation();
+ if (inView) {
+ api.start({ loop: infinite, delay: infinite ? 500 : 0 });
}
- }, [presEffect, tension, friction, mass]);
-
- return <div>{getRenderDoc()}</div>;
+ }, [inView]);
+ const animatedDiv = (style: any) => (
+ <animated.div ref={ref} style={{ ...style, opacity: to(springs.opacity, val => `${val}`) }}>
+ {children}
+ </animated.div>
+ );
+ const [width, height] = [NumCast(doc?.width, DEFAULT_WIDTH), NumCast(doc?.height, DEFAULT_WIDTH)];
+ const flipAxis = dir === PresEffectDirection.Bottom || dir === PresEffectDirection.Top ? 'X' : 'Y';
+ const [rotateX, rotateY] = flipAxis === 'X' ? ['180deg', undefined] : [undefined, '180deg'];
+ switch (presEffect) {
+ case PresEffect.Flip: return animatedDiv({ transform: to(springs.x, val => `perspective(600px) rotate${flipAxis}(${val}deg)`), width, height, rotateX, rotateY })
+ case PresEffect.Rotate:return animatedDiv({ transform: to(springs.x, val => `rotate(${val}deg)`) });
+ case PresEffect.Roll: return animatedDiv({ transform: to([springs.x, springs.y], (val, val2) => `translate3d(${val}%, 0, 0) rotate3d(0, 0, 1, ${val2}deg)`) });
+ default: return animatedDiv(springs);
+ } // prettier-ignore
}