naver / egjs-axes

A module used to change the information of user action entered by various input devices such as touch screen or mouse into the logical virtual coordinates.
https://naver.github.io/egjs-axes/
MIT License
179 stars 31 forks source link

feat: add react-axes #192

Closed malangfox closed 2 years ago

malangfox commented 2 years ago

Details

This adds react-axes which provides useAxes hook that can be used in react.

Example

function App() {
  const box = createRef<HTMLDivElement>();
  const container = createRef<HTMLDivElement>();
  const area = createRef<HTMLDivElement>();
  const axes = useAxes(
    {
      rotateX: {
        range: [0, 360],
        circular: true,
      },
      rotateY: {
        range: [0, 360],
        circular: true,
      },
    },
    {
      deceleration: 0.0024,
    }
  );

  axes.onChange(({ pos }) => {
    if (box.current && container.current) {
      box.current.style[
        "transform"
      ] = `rotateY(${pos.rotateX}deg) rotateX(${pos.rotateY}deg)`;
    }
  }, []);

  useEffect(() => {
    axes
      .connect("rotateX rotateY", new PanInput(area))
      .connect("rotateX rotateY", new MoveKeyInput(area, { scale: [10, -10] }));
  }, []);

  return (
    ...
  );
}

I'm thinking of ways to improve it so that it doesn't use the useEffect hook when attaching InputType. I'd love to get some advice on which usage to provide.

daybrush commented 2 years ago

@malangfox

How can I use it without using useEffect? Can it be used as properties.


const { roateX } = useAxes(...);

return <div style={{ transform: `rotateX(${rotateX}deg` }}></div>;
malangfox commented 2 years ago

@daybrush

I thought of ways to support the initial setup such as connect, setTo of Axes without using useEffect. So I added onInit, which is executed only once for the first time when the useAxes hook is initialized.

After implementing onInit, the code above can be written as follows.

function App() {
  const box = createRef<HTMLDivElement>();
  const container = createRef<HTMLDivElement>();
  const area = createRef<HTMLDivElement>();
  const axes = useAxes(
    {
      rotateX: {
        range: [0, 360],
        circular: true,
      },
      rotateY: {
        range: [0, 360],
        circular: true,
      },
    },
    {
      deceleration: 0.0024,
    },
    {
      rotateX: 0,
      rotateY: 0,
    },
    (axes) => {
      axes
        .connect("rotateX rotateY", new PanInput(area))
        .connect("rotateX rotateY", new MoveKeyInput(area, { scale: [10, -10] }));
      axes.setTo({
        rotateX: 40,
        rotateY: 315,
      }, 200);
    }
  );

  axes.onChange(({ pos }) => {
    if (box.current && container.current) {
      box.current.style[
        "transform"
      ] = `rotateY(${pos.rotateX}deg) rotateX(${pos.rotateY}deg)`;
    }
  }, []);

  return (
    ...
  );
}
malangfox commented 2 years ago

New interface has been added so that the names of each axis can be used as reactive properties corresponding to the actual coordinate values. You can use the existing onChange, but if you use reactive properties, you can implement it like this:

function App() {
  const box = createRef<HTMLDivElement>();
  const container = createRef<HTMLDivElement>();
  const area = createRef<HTMLDivElement>();
  const { rotateX, rotateY } = useAxes(
    {
      rotateX: {
        range: [0, 360],
        circular: true,
      },
      rotateY: {
        range: [0, 360],
        circular: true,
      },
    },
    {
      deceleration: 0.0024,
    },
    {
      rotateX: 0,
      rotateY: 0,
    },
    (axes) => {
      axes
        .connect("rotateX rotateY", new PanInput(area))
        .connect(
          "rotateX rotateY",
          new MoveKeyInput(area, { scale: [10, -10] })
        );
      axes.setTo(
        {
          rotateX: 40,
          rotateY: 315,
        },
        200
      );
    }
  );

  return (
    <div className="App">
      <div id="box" ref={box} style={{ transform: `rotateY(${rotateX}deg) rotateX(${rotateY}deg)` }}>
            ....
      </div>
    </div>
  );
}

In addition, there are plans to add interfaces that allow user to skip using new PanInput or axes.connect etc.