[Canvas] 이미지 에디터 만들기 1: 캔버스에 이미지 띄우기
⭐️ konva.js 설치
react프로젝트에 konva.js를 설치해준다.
- npm install konva
⭐️ 빈 div 엘리먼트 준비
export default function Canvas() {
return (
<>
<div id='container'></div>
</>
);
}
⭐️ Stage, layer 준비
Konva.js를 이용해 캔버스 위에 이미지를 띄우기 위해서는
기본적으로 Stage와 Layer가 필요하다.
Stage는 캔버스이고,
Layer는 포토샵의 레이어와 마찬가지로 캔버스 위에 레이어를 하나 까는 것이다.
필요에 따라 이 Layer는 여러겹 올릴 수 있다.
일단 기본적으로 하나의 레이어가 필수로 필요하다.
initialize함수를 추가한다.
여기서 Stage를 초기화 할 때 container에는 div의 id값을 전달해주고,
캔버스 사이즈인 width, height를 전달한다. 여기까지 하면 div엘리먼트에 캔버스가 주입된다.
그 다음은 layer를 생성하여 stage에 올려준다. (stage.add)
import { useCallback, useEffect, useRef } from 'react';
import Konva from 'konva';
import { Stage } from 'konva/lib/Stage';
import { Layer } from 'konva/lib/Layer';
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);
/* 1. Stage와 Layer를 생성. 계속 재사용 될 객체를 ref에 넣어준다. */
const initialize = useCallback(() => {
const stage = new Konva.Stage({
container: 'container', // <div id='container'></div>의 id와 연결
width: CANVAS_SIZE,
height: CANVAS_SIZE,
});
stageRef.current = stage;
const layer = new Konva.Layer();
layerRef.current = layer;
stage.add(layer);
}, []);
useEffect(() => {
if (!source) return;
initialize();
}, [initialize]);
return <div id='container'></div>;
}
⭐️ 이미지 띄우기 (최종코드)
drawImage함수를 추가한다.
미리 준비해둔 이미지(source)를 layer에 추가해주는 함수이다.
이미지가 로드되지 않을 경우 사용자에게 alert를 보여주기 위해서 try-catch문을 사용했다.
초기화할 이미지 정보를 imageOpt에 정의한 뒤
new Konva.Iamge 생성자 함수에 인자로 전달해준다.
width, height는 이미지 크기이고 image는 load된 이미지 객체, id는 전달하지 않아도 상관없다.
여기서 draggable에 true값을 할당하면 캔버스 위의 이미지를 마우스로 여기저기 움직일 수 있게 된다.
이미지의 width, height가 캔버스의 크기보다 크면
당연히 이미지가 잘리기 때문에 이 부분은
추후 캔버스 사이즈에 맞게 이미지를 축소하는 함수를 추가해 줄 예정이다.
new Konva.Image로 생성 된 이미지 객체를 레이어에 추가해준다. (layerRef.current.add)
그리고 추후 이미지 객체를 조작해야 하기 때문에
이미지 객체도 ref에 저장해둔다. (imageRef.current = defaultImage)
import { useCallback, useEffect, useRef } from 'react';
import Konva from 'konva';
import { Stage } from 'konva/lib/Stage';
import { Layer } from 'konva/lib/Layer';
import { Node } from 'konva/lib/Node';
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);
/* 1. Stage와 Layer를 생성 */
const initialize = useCallback(() => {
const stage = new Konva.Stage({
container: 'container', // <div id='container'></div>의 id와 연결
width: CANVAS_SIZE,
height: CANVAS_SIZE,
});
stageRef.current = stage;
const layer = new Konva.Layer();
layerRef.current = layer;
stage.add(layer);
}, []);
/* 2. 위에서 생성한 Layer위에 이미지 객체를 올려주기. */
const drawImage = useCallback(async () => {
if (layerRef.current) {
const imageObj = new Image();
imageObj.src = source;
try {
await new Promise((resolve, reject) => {
imageObj.onload = resolve;
imageObj.onerror = reject;
});
const imageOpt = {
width: CANVAS_SIZE,
height: CANVAS_SIZE,
image: imageObj,
id: 'imageId',
draggable: true, //true로 설정 시 캔버스 내에서 이미지를 여기저기 옮길 수 있다.
};
const defaultImage = new Konva.Image(imageOpt);
imageRef.current = defaultImage;
layerRef?.current?.add(defaultImage);
} catch (error) {
alert('이미지 로드에 실패했다!');
}
}
}, []);
/* 3. DOM이 렌더 된 뒤에 실행되어야 하므로 useEffect안에서 initialize, drawImage를 순서대로 실행해준다. */
useEffect(() => {
if (!source) return;
initialize();
drawImage();
}, [initialize, drawImage]);
return <div id='container'></div>;
}
⭐️ 최종 코드 깃헙에서 보기
아래의 레포를 clone받은 뒤 9733d88커밋으로 체크아웃 하면 여기까지의 코드를 볼 수 있다.
https://github.com/seoulsaram/canvas-search
GitHub - seoulsaram/canvas-search
Contribute to seoulsaram/canvas-search development by creating an account on GitHub.
github.com
'프론트엔드' 카테고리의 다른 글
[Canvas] 이미지 에디터 만들기 3 : 이미지 회전 기능 구현 (0) | 2024.08.26 |
---|---|
[Canvas] 이미지 에디터 만들기 2 : 이미지 바운딩 박스 구현 (0) | 2024.08.26 |
HTML Canvas로 이미지 편집기 만들기 (feat. Konva.js) (0) | 2024.08.26 |
[HTML] 당신이 몰랐을 수도 있는 시맨틱 태그들 구조 편 (1) | 2023.11.17 |
리덕스 아키텍처 Best practice (1) | 2023.11.03 |