diff options
| author | bobzel <zzzman@gmail.com> | 2024-05-16 19:52:13 -0400 |
|---|---|---|
| committer | bobzel <zzzman@gmail.com> | 2024-05-16 19:52:13 -0400 |
| commit | 69e286b504c2f1bbef7d489dc675b9e54ef8d983 (patch) | |
| tree | b8243dab1a93aced50bab0cbf0e9da3e08e58f07 /src/client/views/nodes/trails/SlideEffect.tsx | |
| parent | 56917559cf47bba35740571e97845295dd63b424 (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.tsx | 402 |
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 } |
