프론트엔드/인터랙티브

[Fabric.js + @use-gesture] 제스처로 객체 컨트롤하기

밀밀 킴 2024. 8. 29. 01:37
반응형

fabric.js에서는 객체를 이동하고, scale을 변경하고, 회전을 시키는 등의 컨트롤러를 제공한다. 

그런데 잘 생각해보면... 모바일 앱에서는 컨트롤러가 아니라 핀치 제스처를 사용하여 편집했을 것이다.

 

 

 

 

 

fabris.js v5의 이벤트엔 touch와 같은 터치스크린에 대응되는 이벤트들이 있었는데, (사용해본 적은 없다.)

v6에는 사라졌다. 

 

그래서 다른 라이브러리를 통합하여 사용하기로 했다. 

하나하나 직접 하려면 너무 힘들겠지만 라이브러리를 사용하면 비슷하게 구현할 수 있다.

 

const isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);

// ...


 fabric.InteractiveFabricObject.ownDefaults = {
      ...fabric.InteractiveFabricObject.ownDefaults,
      cornerStyle: 'circle',

      cornerStrokeColor: '#fff',
      cornerSize: 10,
      cornerColor: '#312CBF',
      padding: 10,
      transparentCorners: false,
      borderColor: '#312CBF',
      borderDashArray: [7],

      _controlsVisibility: {
        mt: false,
        mb: false,
        ml: false,
        mr: false,
      },

      ...(isMobile ? { controls: {} } : {}),
    };

모바일 여부에 따라 다르게 처리한다. 

controls: {} 이렇게 빈 배열로 설정하여 컨트롤러를 모바일에서 없앴다. 

 

그리고 나는 리액트로 개발을 하고 있기에 @use-gesture/react를 설치한 후 import 한다.

useGesture라는 hook을 사용해보겠다. (useXXX 식으로 개별적으로 사용해도 되고 useGesture를 통해 여러가지의 제스처를 한번에 설정할 수도 있다.)

핀치 제스처를 사용할 것이기 때문에 onPinch에 내용을 추가해준다.

 

다양한 state들이 제공되는데 자세한 것은 문서를 보면 된다.

여기서는 복잡한 계산을 할 필요 없이 'offset'을 사용하면 된다. 

offset 배열의 첫번째 요소는 scale, 두번째 요소는 angle. 구조분해할당으로 가져오자.

import { useGesture } from '@use-gesture/react';

const gesture = useGesture(
    {
      onDrag: () => {},
      onPinch: ({ offset: [scale, angle] }) => {
        setAngle(angle);
        setScale(scale);
      },

      onHover: () => {},
    },
    {}
  );
  
   <canvas
        style={{
          touchAction: 'none',
        }}
        ref={canvasElRef}
        {...gesture()}
      ></canvas>

 

fabric.js 타겟 canvas element에 바인딩

 

const setScale = (d: number) => {
    const objs = _getSelectedObjects();

    if (objs) {
      objs.forEach((obj) => {
        obj.scaleX = obj.scaleY = d;
      });
      fabricCanvas?.current?.renderAll();
    }
  };

  const setAngle = (angle: number) => {
    const objs = _getSelectedObjects();
    if (objs) {
      objs.forEach((obj) => {
        obj.angle = angle;
      });
      fabricCanvas?.current?.renderAll();
    }
  };

활성화(선택)된 객체의 값을 변경해준다. ^ㅡ^ 

아직 디자인은 못생겼다

 

vite + react인데

package.json 에서 dev에 host옵션을 추가한 후, 

pc와 휴대폰을 동일 와이파이로 접속하면 모바일웹을 테스트 할 수 있다.

 

핀치 제스처로 스케일과 앵글 변경이 가능하다.

 

그런데 살짝 사용감이 어색한 느낌이 드는데 이건 좀 더 연구를 해 보아야겠다. 😅 

(모바일 앱처럼 아주 매끄럽게는 안 되는데.... 기본적으로 드래그하면 좌표 이동이 되기 때문인가?)

 

기존에 마우스 위주로 기능을 만들어놓았기에 캔버스 자체의 줌인/줌아웃이 마우스휠로 되어있는데

모바일의 경우 핀치 인/아웃으로 변경하는 게 나을 것 같다.

그런데 캔버스 자체를 확대 축소할 필요가 없을 것 같기도 하고 디테일한 점은 일단 나중에 고쳐보도록 하겠다. ~_~!!

(이런 기능들은 개선하고자 하면 끝이 없다.)

반응형