[Canvas] 이미지 에디터 만들기 3 : 이미지 회전 기능 구현

profile
마릴린벅시
2024. 8. 26. 17:06프론트엔드

 

 

완성 화면

 

이번엔 이미지 회전 기능을 구현해보자.

캔버스의 회전 방식은 객체의 중앙 축을 중심으로 객체를 회전 시키는 방식이 아니다.

자세한 내용은 이 링크를 참고하자.

어쨌든 캔버스 회전 방식대로 회전시키면 이미지가 제자리에서 회전하는게 아니라 원을 그리며 회전한다.

우리는 이미지 중심축을 기준으로 이미지가 회전하도록 만들 것이다.



⭐️ 이미지 회전 함수 구현

일단 canvas의 회전 방식이 어떻게 동작하는지 보기 위해

Konva의 Node에 내장된 rotate함수를 사용해보자.

import { useCallback, useEffect, useRef, useState } from 'react';
import Konva from 'konva';
import { Stage } from 'konva/lib/Stage';
import { Layer } from 'konva/lib/Layer';
import { Node } from 'konva/lib/Node';
import { Transformer } from 'konva/lib/shapes/Transformer';

const CANVAS_SIZE = 512;

export default function Canvas2() {
  const source = '/images/bottle.jpeg';
  const stageRef = useRef<Stage | null>(null);
  const layerRef = useRef<Layer | null>(null);
  const imageRef = useRef<Node | null>(null);
  const transformerRef = useRef<Transformer | null>(null);

  const [degree, setDegree] = useState(0);

  //...이전 코드 생략


  function rotateImage() {
    if (imageRef.current) {
      imageRef.current.rotate(90);
      setDegree(degree + 90);
    }
  }

  //...다음 코드 생략

  return (
    <section id='canvas_container'>
      <div
        id='container'
        onMouseEnter={onFocus}
        onMouseLeave={onFocusOut}
        onTouchStart={onFocus}
      ></div>
      <div className='btn_container'>
        <button className='rotate_btn' onClick={rotateImage}>
          회전하기
        </button>
      </div>
    </section>
  );
}

 

보는 바와 같이 이미지의 top-left부분을 중심축으로 회전하기 때문에

이미지가 원을 그리며 회전한다. 

 

 

⭐️ 회전할 각도를 구하는 함수 구현

이제 우리가 원하는 방식으로 회전하도록 만들기 위해 rotateImage함수를 수정해보자.

rotateAroundCenter함수를 추가해준다. 여기 계산식에는 삼각함수등 어려운 개념이 들어간다.

canvas를 잘 다루려면 여러분들이 수학을 공부해야 하는 이유다. 

하지만 우리에겐 구글링과 gpt가 있어서 괜찮다. 

import { useCallback, useEffect, useRef, useState } from 'react';
import Konva from 'konva';
import { Stage } from 'konva/lib/Stage';
import { Layer } from 'konva/lib/Layer';
import { Node } from 'konva/lib/Node';
import { Transformer } from 'konva/lib/shapes/Transformer';
import { rotateAroundCenter } from '../utils/image.utils';

const CANVAS_SIZE = 512;

export default function Canvas2() {
  const source = '/images/bottle.jpeg';
  const stageRef = useRef<Stage | null>(null);
  const layerRef = useRef<Layer | null>(null);
  const imageRef = useRef<Node | null>(null);
  const transformerRef = useRef<Transformer | null>(null);

  const [degree, setDegree] = useState(0);

  //..이전코드 생략

  function rotateImage() {
    if (imageRef.current) {
      //변경할 이미지 객체, 변경할 각을 인자로 전달
      rotateAroundCenter(imageRef.current, degree + 90);
      
      //현재 각도를 저장. 이 때 다음 각도가 360일 경우 0도로 초기화해주고
      //아직 360가 아닐 경우 현재 각에 90도를 더해준다.
      setDegree(degree + 90 === 360 ? 0 : degree + 90);
    }
  }

  //..다음코드 생략

  return (
    <section id='canvas_container'>
      <div
        id='container'
        onMouseEnter={onFocus}
        onMouseLeave={onFocusOut}
        onTouchStart={onFocus}
      ></div>
      <div className='btn_container'>
        <button className='rotate_btn' onClick={rotateImage}>
          회전하기
        </button>
      </div>
    </section>
  );
}



//주어진 점을 원점을 기준으로 지정된 각도(라디안)만큼 회전시킨 좌표를 리턴.
const rotatePoint = ({ x, y }: { x: number; y: number }, rad: number) => {
  const rcos = Math.cos(rad);
  const rsin = Math.sin(rad);
  return { x: x * rcos - y * rsin, y: y * rcos + x * rsin };
};

//Node 객체를 특정 각도로 회전시키고, 회전 후에도 그 중심이 고정되도록 위치를 조정함.
export function rotateAroundCenter(node: Node, rotation: number) {
  const topLeft = {
    x: -(node.width() * node.scaleX()) / 2,
    y: -(node.height() * node.scaleY()) / 2,
  };
  const current = rotatePoint(topLeft, Konva.getAngle(node.rotation()));
  const rotated = rotatePoint(topLeft, Konva.getAngle(rotation));
  const dx = rotated.x - current.x,
    dy = rotated.y - current.y;

  node.rotation(rotation);
  node.x(node.x() + dx);
  node.y(node.y() + dy);
}

 

 

여기까지 따라왔다면 이미지가 정상적으로 회전하는 것을 볼 수 있다.

 

⭐️ 최종 코드 깃헙에서 보기

아래의 레포를 clone받은 뒤 4c75fc3커밋으로 체크아웃 하면 여기까지의 코드를 볼 수 있다.

https://github.com/seoulsaram/canvas-search

 

GitHub - seoulsaram/canvas-search

Contribute to seoulsaram/canvas-search development by creating an account on GitHub.

github.com

 

 

 

반응형