framer-motion#useMotionValue JavaScript Examples

The following examples show how to use framer-motion#useMotionValue. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: preview-area.js    From cards with MIT License 6 votes vote down vote up
PreviewScaler = ({ mainRef, ...props }) => {
  const motionMainWidth = useMotionValue(DEFAULT_MAIN_WIDTH)
  const springMainWidth = useTransform(
    motionMainWidth,
    [300, DEFAULT_MAIN_WIDTH],
    [0.3, 1]
  )
  const scale = useSpring(springMainWidth, {
    stiffness: 150,
    damping: 120,
    mass: 1.5
  })

  useEffect(() => {
    if (mainRef.current) {
      const onResize = () => motionMainWidth.set(getWidth(mainRef.current))

      onResize()

      const resizeObserver = new ResizeObserver(onResize)
      resizeObserver.observe(mainRef.current)

      window.addEventListener('resize', onResize)

      return () => {
        window.removeEventListener('resize', onResize)
        resizeObserver.disconnect()
      }
    }
  }, [mainRef, motionMainWidth])

  return <motion.div style={{ scale }} {...props} />
}
Example #2
Source File: Card.js    From gatsby-portfolio with BSD Zero Clause License 4 votes vote down vote up
// Animation built from https://codesandbox.io/s/spring-field-kvpnv?file=/src/Card.js

function Card(props) {
  const ref = useRef();
  const [hover, setHover] = useState(false);
  const [tapped, setTapped] = useState(false);
  const [visibleState, setVisibleState] = useState("initial");
  let width = 888;
  let height = 962;

  // Middle point in 2d space
  const centerPoint = [width / 2, height / 2];
  const xy = useMotionValue(centerPoint);

  // How much should we rotate?
  // const tx = 0.003; if you want to play around with how it rotates.
  const tx = -0.0035;

  // Get rotateY
  const transformX = interpolate([0, width], [width * tx, width * tx * -1]);
  const rotateY = useTransform(xy, ([x]) => transformX(x));

  // Get rotateX
  const transformY = interpolate(
    [0, height],
    [height * tx * -1, height * tx * 1]
  );
  const rotateX = useTransform(xy, ([, y]) => transformY(y));

  const config = {
    stiffness: 200,
    damping: 25
  };

  // Get our spring values
  const springX = useSpring(rotateX, config);
  const springY = useSpring(rotateY, config);

  function onMouseOver(e) {
    if (tapped) return;
    const rect = e.target.getBoundingClientRect();
    xy.set([e.clientX - rect.left, e.clientY - rect.top]);
  }

  function hoverStart() {
    setHover(true);
    props.onProjectEnter();
  }

  function hoverEnd() {
    setHover(false);
    props.onProjectLeave();
  }

  useEffect(() => {
    // If not hovering, reset to the centerpoint.
    if (!hover) {
      xy.set(centerPoint);
    }
  }, [hover, xy, centerPoint]);

  return (
    <Link to={props.link}>
      <div className={`${styles.cardPerspectiveWrapper}`}>
          <motion.div 
            className={`${styles.contentWrapper}`}
            style={{
              scale: 1,
              rotateX: springX,
              rotateY: springY
            }}
            onTapCancel={(e) => {
              setTapped(false);
              onMouseOver(e);
            }}
            onTapStart={() => {
              setTapped(true);
            }}
            onTap={(e) => {
              setTapped(false);
            }}
            onHoverStart={hoverStart}
            onHoverEnd={hoverEnd}
            onMouseMove={onMouseOver}
          >
            <div className={`${styles.card} ${styles[props.color]}`}>
              <div className={`${styles.figure} ${styles[props.alignment]}`}>
                <img src={props.image} alt={props.imageAlt} className={styles.image} />
              </div>
              <h6 className={styles.title}>{props.title}</h6>
            </div>
          </motion.div>
        </div>
      </Link>
  )
}
Example #3
Source File: FeaturedCard.js    From gatsby-portfolio with BSD Zero Clause License 4 votes vote down vote up
function FeaturedCard(props) {
  const ref = useRef();
  const [hover, setHover] = useState(false);
  const [tapped, setTapped] = useState(false);

  // Same as card component but wider values here for the bigger card.
  let width = 1800;
  let height = 962;

  // Middle point in 2d space
  const centerPoint = [width / 2, height / 2];
  const xy = useMotionValue(centerPoint);

  // How much should we rotate?
  const tx = 0.0015;
  

  // Get rotateY
  const transformX = interpolate([0, width], [width * tx, width * tx * -1]);
  const rotateY = useTransform(xy, ([x]) => transformX(x));

  // Get rotateX
  const transformY = interpolate(
    [0, height],
    [height * tx * -1, height * tx * 1]
  );
  const rotateX = useTransform(xy, ([, y]) => transformY(y));

  const config = {
    stiffness: 200,
    damping: 25
  };

  // Get our spring values
  const springX = useSpring(rotateX, config);
  const springY = useSpring(rotateY, config);

  function onMouseOver(e) {
    if (tapped) return;
    const rect = e.target.getBoundingClientRect();
    xy.set([e.clientX - rect.left, e.clientY - rect.top]);
  }

  function hoverStart() {
    setHover(true);
    props.onProjectEnter();
  }

  function hoverEnd() {
    setHover(false);
    props.onProjectLeave();
  }

  useEffect(() => {
    // If not hovering, reset to the centerpoint.
    if (!hover) {
      xy.set(centerPoint);
    }
  }, [hover, xy, centerPoint]);

  // fix this link
  return (
    <Link to={props.link} className={`${styles.featured}`}>
    <div className={`${styles.cardPerspectiveWrapper} ${styles.featured}`}>
      <motion.div 
        className={`${styles.contentWrapper}`}
        style={{
          scale: 1,
          rotateX: springX,
          rotateY: springY
        }}
        onTapCancel={(e) => {
          setTapped(false);
          onMouseOver(e);
        }}
        onTapStart={() => {
          setTapped(true);
        }}
        onTap={(e) => {
          setTapped(false);
        }}
        onHoverStart={hoverStart}
        onHoverEnd={hoverEnd}
        onMouseMove={onMouseOver}
      >
        <div className={`${styles.card} ${styles.featuredContent} ${styles[props.color]}`}>
          <div className={`${styles.figure} ${styles[props.alignment]}`}>
            <img src={props.image} alt={styles.imageAlt} className={styles.image} />
          </div>
          <h6 className={styles.title}>{props.title}</h6>
        </div>
      </motion.div>
    </div>
    </Link>
  )
}
Example #4
Source File: About.js    From webappdevtest with MIT License 4 votes vote down vote up
export function About(props) {
    let {handleAboutClose, desktopSize} = props
    let containerVariants = {
        open: {opacity: 1, transition: {type: 'spring', damping: 16, staggerChildren: 0.2}},
        close: {opacity: 0, transition: {ease: 'easeOut', duration: 1}}
    }
    let contentVariants = {
        open: {opacity: 1, y: 0},
        close: {opacity: 0, y: 50}
    }
    let scrollValue = useMotionValue(0);
    let touchStart = 0;
    let touchEnd = 0;
    const aboutContent = useRef(null);
    useEffect(()=> {
        aboutContent.current.addEventListener('touchstart', function(e){touchStart=e.changedTouches[0].clientY})
        aboutContent.current.addEventListener('touchend', function(e) {
            touchEnd = e.changedTouches[0].clientY;
            if(scrollValue.get() <= 0 && touchEnd > touchStart) {
                touchStart = 0;
                touchEnd = 0;
                handleAboutClose();
            }
        });
    }, [])

    return(
        <AnimatePresence>
            <motion.div
                className = "aboutContainer"
                variants = {containerVariants}
                initial = "close"
                animate = "open"
                exit= "close"
            >
                <motion.div
                    className = "aboutBGscreen"
                    variants = {containerVariants}
                    onClick = {() => handleAboutClose()}
                />
                <motion.div
                    className = "aboutContent"
                    variants = {contentVariants}
                    ref = {aboutContent}
                    onScroll = {(e) => {scrollValue.set(e.nativeEvent.target.scrollTop)}}
                >
                    <div className="aboutContentHeader">
                        <h1>Somethings</h1>
                        <button className="close_btn" onClick={() => handleAboutClose()}><img src={close}  alt="close button" /></button>
                    </div>
                    <div className="aboutContentBody">
                        <p>
                            <span style={{fontWeight: "bold"}}>Yaba Daba Doo! </span>
                          Some stuff!
                                          </p>
                        <a href="https://twitter.com/hackergram" className="aboutCardContainer" target="_blank" onClick={()=> Event("UserAction", "Navigated to Twitter", window.innerWidth > desktopSize ? "DESKTOP": "MOBILE")}>
                            <motion.div
                                className="aboutCard"
                                initial={{scale: 1}}
                                whileHover = {{scale: 1.03}}
                            >
                                <img src={twitterlogo}/>
                                <div>
                                    <p className="smalltext">Reach out to us:</p>
                                    <p className="socialLink">@hackergram</p>
                                </div>
                            </motion.div>
                        </a>
                        <a href="https://github.com/hackergram/webappdevtest" className="aboutCardContainer" target="_blank" onClick={()=> Event("UserAction", "Navigated to Github", window.innerWidth > desktopSize ? "DESKTOP": "MOBILE")}>
                            <motion.div
                                className="aboutCard"
                                initial={{scale: 1}}
                                whileHover = {{scale: 1.03}}
                            >
                                <img src={githublogo}/>
                                <div>
                                    <p className="smalltext">Contribute to the project:</p>
                                    <p className="socialLink">Github Repo</p>
                                </div>
                            </motion.div>
                        </a>
                        <div className="aboutHGcontent">

                        </div>
                    </div>
                </motion.div>
            </motion.div>
        </AnimatePresence>
    )
}
Example #5
Source File: CityDetailView.js    From webappdevtest with MIT License 4 votes vote down vote up
export function CityDetailView(props) {
    const {selectedCity, videoData, onCityDetailClose, desktopSize } = props;
    let currentScrollValue = useMotionValue(0);
    let touchStart = 0;
    let touchEnd = 0;
    const cityDetailViewEl = useRef(null)
    // let prevScrollValue = useMotionValue(0);
    const containerAnimControls = useAnimation();
    const headerAnimControls = useAnimation();
    const bodyAnimControls = useAnimation();

    const closeTransition = {ease: 'easeOut', duration: 0.2}
    const openTransition = {type: 'spring', damping: 16}

    const variants = {
        open: (window.innerWidth > desktopSize) ? {width: '30em', top: 0, transition: openTransition}:{width: 'calc(var(--vw, 1vw) * 100)', top: 'calc(var(--vh, 1vh) * 20)', transition: openTransition},
        close: (window.innerWidth > desktopSize) ? {width: 0, top: 0, y: 0, transition: closeTransition} : {width: 'calc(var(--vw, 1vw) * 100)', top: 'calc(var(--vh, 1vh) * 100)', y: 0, transition: closeTransition}
    }

    const childVariants = {
        open: {opacity: 1, y: 0, transition: {ease: 'easeOut'}}, close: {opacity: 0, y: 10, transition: {ease: 'linear'}}
    }

    const scrollToTop = {top: 0, transition:{ease:'linear', duration: 0.2}}

    const handleInOutAnimation = async () => {
        if(selectedCity) {
            containerAnimControls.start(variants.open)
            await headerAnimControls.start(childVariants.open)
            bodyAnimControls.start(childVariants.open)
        }
        else { 
            await headerAnimControls.start(childVariants.close)
            await bodyAnimControls.start(childVariants.close)
            containerAnimControls.start(variants.close)
        }
    }

    useEffect(()=> {
        cityDetailViewEl.current.scrollTo(0,0);
        handleInOutAnimation();
        cityDetailViewEl.current.addEventListener('touchstart', function(e){touchStart=e.changedTouches[0].clientY})
        cityDetailViewEl.current.addEventListener('touchend', function(e) {
        touchEnd = e.changedTouches[0].clientY;
        if(currentScrollValue.get() <= 0 && touchEnd > touchStart) {
            onCityDetailClose();
            touchStart = 0;
            touchEnd = 0;
        }
        });

        // window.addEventListener('wheel', function() {
        //     setTimeout(()=> {
        //         if(currentScrollValue.get() === prevScrollValue.get()) {
        //             onCityDetailClose();
        //             prevScrollValue.set(0)
        //         }
        //         else {
        //             prevScrollValue.set(currentScrollValue.get())
        //         }
        //     }, 500)
        // })
    }, [selectedCity])

    return (
        <AnimatePresence>
            <motion.div
                className="cityDetailView"
                ref = {cityDetailViewEl}
                variants={variants}
                initial="close"
                exit="close"
                animate = {containerAnimControls}
                onScroll = {(e) => {
                    currentScrollValue.set(e.nativeEvent.target.scrollTop);
                    if(currentScrollValue.get() > 0) {
                        containerAnimControls.start(scrollToTop)
                    }
                }}
                style={{height: 'calc(var(--vh, 1vh) * 100)', overflow: 'scroll', scrollBehavior: 'smooth', overscrollBehaviorY: 'none'}}
            >   
                <motion.div 
                    className="cityDetailView_Header" 
                    variants={childVariants}
                    initial="close"
                    animate = {headerAnimControls}
                >
                    <h1>{selectedCity}</h1>
                    <button className="close_btn" onClick={(e) => onCityDetailClose(e)}>
                        <img src={close} alt="close icon" />
                    </button>
                </motion.div>
                <motion.div 
                    className="cityDetailView_videoList" 
                    variants={childVariants}
                    initial="close"
                    animate={bodyAnimControls}
                    
                >
                    {videoData[selectedCity].blocks.slice(0).reverse().map((videoObj, index) => {
                        if(videoObj.link.indexOf('twitter.com') !== -1) {
                            let id = videoObj.link.split(/\/?\//)[4].split('?')[0];
                            return (
                                <div className="linkCard" key={id + index}>
                                    <p>{videoObj.date}</p>
                                    <h2>{videoObj.caption}</h2>
                                    <TwitterVideoEmbed id={id} 
                                        onLoad={e => {if(e){e.style.display = "inline-block"}}} 
                                    />
                                </div>
                            )
                        }
                        else if(videoObj.link.indexOf('instagram.com') !== -1) {
                            
                            return (
                                <div className="linkCard" key={videoObj.link+ index}>
                                    <p>{videoObj.date}</p>
                                    <h2>{videoObj.caption}</h2>
                                    <InstagramEmbed url={videoObj.link} 
                                        onLoad={e => {if(e){e.style.display = "inline-block"}}} 
                                    />
                                </div>
                            )
                        }

                        else {
                            return (
                                <div className="linkCard" key={index}>
                                    <p>{videoObj.date}</p>
                                    <h2>{videoObj.caption}</h2>
                                    <a href={videoObj.link} target="_blank" className='rawLink'>{videoObj.link} </a>
                                </div>
                            )
                        }   
                    })}
                </motion.div>  
              
            </motion.div>
        </AnimatePresence>
    )
}