Matrix3d ​​dinami c на скролле - PullRequest
0 голосов
/ 28 мая 2020

import React, { useState, useRef } from "react";
import { render } from "react-dom";
import styled from "styled-components";
import { useScrollData } from "scroll-data-hook";

const Menu = () => {
  const ref = useRef('myRef');
  const datas = ["Sao Paulo", "New-York", "Lisbonne", "Milan", "Paris"];
  const { direction } = useScrollData({
    onScrollEnd: () => {
      if (ref.current){
        Array.from(ref.current.children).forEach(el => {
        el.style.transform = `translate3d(0,0,0)`;
        el.style.transition = "transform 1s";
        })
      }
    }
  })

  const setTransformMatrix3d = ( matrix3d ) => {
    if (ref.current){
      Array.from(ref.current.children).forEach(el => {
        el.style.transition = "transform 1s";
        el.style.transform = matrix3d;
      })
    }
  };

  if (direction.y) {
    console.log(direction.y);
    let matrix =
      direction.y === "up"
        ? `matrix3d(1,0.09,0,0,0,1.1,0,0,0,0,1,0,0,0,0,1)`
        : `matrix3d(1,-0.09,0,0,0,1.1,0,0,0,0,1,0,0,0,0,1)`;
    setTransformMatrix3d({ matrix });
  }


  return (
    <Wrapper>
      <Ul ref={ref}>
        {datas.map((value, index) => (
          <Item key={index} value={value} />
        ))}
      </Ul>
    </Wrapper>
  );
};

export default Menu;

const Item = ( {...props} ) => {
  const [isHover, setIsHover] = useState(false);

  return (
    <Li>
      <Link>
        <ContainerMatrix
          onMouseOver={() => setIsHover(!isHover)}
          onMouseLeave={() => setIsHover(!isHover)}
        >
          <ContainerSpan>
            <Span isHover={isHover}>
              { props.value }
              <Mask className="mask" isHover={isHover} dataMask={props.value} />
            </Span>
          </ContainerSpan>
        </ContainerMatrix>
      </Link>
    </Li>
  );
};


const Wrapper = styled.section`
  transition: transform 100ms;
  will-change: transform;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-content: center;
  align-items: center;
  width: 100vw;
  height: 140vh;
  margin: auto;
  background-color : black;
`

const Link = styled.a`
  text-decoration: none;
  color: inherit;
  background-color: transparent;
`
const Ul = styled.ul`
  display: flex;
  flex-direction: column;
  align-items: center;
  align-content: center;
`

const ContainerMatrix = styled.div`
  transform: translate3d(0px, 0px, 0px);
  transition: transform 100ms;
  will-change: transform;
`

const Li = styled.li`
  transition: transform 2s;
  list-style: none;
  text-transform: uppercase;
`

const ContainerSpan = styled.span`
  position: relative;
  display: inline-block;
  margin: 0;
  color: hsla(0, 0%, 100%, 0.2);
  text-align: center;
  padding: 0 0.15em;
  line-height: 1.15;
  // background-color : red;
`

const Span = styled.span`
  line-height: 1.15;
  font-size: 8.5675vw;
  display: inline-block;
  transform: scaleY(${props => (props.isHover ? "1.1" : "1")}) translateY(${props => (props.isHover ? "-0.1em" : "0em")});
  transition: transform 1.25s cubic-bezier(0.23, 1, 0.32, 1),
    -webkit-transform 1.25s cubic-bezier(0.23, 1, 0.32, 1);
`

const Mask = styled.span.attrs({
  "aria-hidden": "true"
})`
    transform:  translate3d(0, ${props => (props.isHover ? "0%" : "100%")}, 0);
    display: block;
    overflow: hidden;
    transition: transform 1.5s cubic-bezier(.23,1,.32,1),opacity .75s linear,-webkit-transform 1.5s cubic-bezier(.23,1,.32,1);
    will-change: transform,opacity;
    position:absolute;  
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    display: block;
    pointer-events: none;


    &::before{
    content: '${props => props.dataMask}';
    transform:  translate3d(0,${props => (props.isHover ? "0%" : "-100%")}, 0);
    color: #fff;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    display: block;
    pointer-events: none;
    transition: opacity .75s linear,-webkit-transform 1.5s cubic-bezier(.23,1,.32,1);
    transition: transform 1.5s cubic-bezier(.23,1,.32,1),opacity .75s linear;
    will-change: transform,opacity;
}
`

Это мой первый пост о stackoverflow. Я работаю с React и пытаюсь найти (правильный) способ воспроизвести эффект на этой странице: https://www.rudolfson.com/. Я сделал цвет шрифта открытым, но я не знаю, как воспроизвести «волновой эффект» в текстовом контейнере с помощью свойства «transform: matrix3d», которое связывает при прокрутке. Я очень стараюсь уже 3 дня, но мне нужна помощь! Я думаю, что здесь используется скорость прокрутки, но я не уверен. Большое спасибо за ваш ответ и совет.

1 Ответ

0 голосов
/ 29 мая 2020

Грубый патч, чтобы заставить это работать.
Помещение преобразований на каждый li элемент значительно усложняет задачу. Намного проще просто применить его к внешнему ul, который я модифицировал.

Вам нужно будет ввести вычисления для высоты (и заменить -200), и код может быть чище. Но по большей части это работает. Я использовал matrix3d, которую Рудольф использует в качестве основы.

здесь: https://codesandbox.io/s/lucid-sky-hg2of

  const setTransformMatrix3d = matrix => {
    Array.from([ref.current]).map((el, index) => {
      el.style.transition = "transform 1s";
      el.style.transform = matrix;
    });
  };

  if (direction.y) {
    console.log(direction.y);
    let matrix =
      direction.y === "up"
        ? `matrix3d(1, 0.000174533, 0, 0, -0.000174533, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)`
        : `matrix3d(1, 0.000174533, 0, 0, -0.000174533, 1, 0, 0, 0, 0, 1, 0, 0, -200, 0, 1)`;
    setTransformMatrix3d(matrix);
  }

  useEffect(() => {
    window.addEventListener("scroll", setTransformMatrix3d);
    return () => {
      window.removeEventListener("scroll", setTransformMatrix3d);
    };
  }, []);
...