캔버스 객체(context)에 대해서 상태(state)를 유지하는 코드가 많다.
const ref = useRef(null);
const [ctx, setCtx] = useState(); //캔버스 컨텍스트를 useState로 상태관리
useEffect(()=>{
const canvas = ref.current
const context = canvas.getContext('2d')
setCtx(context)
}, [])
<canvas ref={canvasRef} > </canvas>
캔버스에 직접 그림을 그리는 기능을 위해서는 엘리먼트에 이벤트를 붙여주면 쉽게 가능하다.
-자바스크립트의 돔(dom)에 접근하는 네이티브코드를 쓰지 않고 아래처럼 간결하게 쓰는 것이 낫지않나 라고 생각한다.
const canvasRef = useRef(null);
useEffect(() => {
const canvas = canvasRef.current;
setCtx(canvas.getContext('2d'));
}, [])
const canvasEventListener = (event, type) => {
console.log(event, type)
}
return ( //마우스 이벤트 정의
<canvas ref={canvasRef}
onMouseDown={(event) => { canvasEventListener(event, 'down') }}
onMouseMove={(event) => { canvasEventListener(event, 'move') }}
onMouseLeave={(event) => { canvasEventListener(event, 'leave') }}
onMouseUp={(event) => { canvasEventListener(event, 'up') }}
>
</canvas>
)
const canvasEventListener = (event, type) => {
let x = event.clientX - event.target.offsetLeft; //x축
let y = event.clientY - event.target.offsetTop; //y축
}
ctx.lineJoin = 'round'; //중복되는 요런곳
ctx.lineWidth = 3; //중복되는 요런곳
ctx.strokeStyle = 'red' //중복되는 요런곳
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.closePath();
ctx.stroke();
아래는 이러한 부분을 고려하여 작성된 코드 이다.
const canvasRef = useRef(null);
const array = []
useEffect(() => {
const canvas = canvasRef.current;
const context = canvas.getContext('2d');
context.lineJoin = 'round'; //중복되는 속성은 1번으로 끝내게 합니다.
context.lineWidth = 3; //중복되는 속성은 1번으로 끝내게 합니다.
context.strokeStyle = 'blue' //중복되는 속성은 1번으로 끝내게 합니다.
setCtx(context);
}, [])
const canvasEventListener = (event, type) => {
let x = event.clientX - event.target.offsetLeft;
let y = event.clientY - event.target.offsetTop;
if (type === 'move') {
if (array.length === 0) {
array.push({ x, y })
} else {
ctx.save() //다른 스타일 또는 속성을 줄 수 있으므로 항상 save를 합니다.
ctx.beginPath();
ctx.moveTo(array[array.length - 1].x, array[array.length - 1].y);
ctx.lineTo(x, y);
ctx.closePath();
ctx.stroke();
ctx.restore() //작업이 끝나면 기존 스타일 또는 속성으로 되돌려 줍니다.
array.push({ x, y })
}
} else if (type === 'leave') {
ctx.save()
while (array.length) array.pop();
ctx.clearRect(0, 0, 2580, 2580)
ctx.restore()
array라는 배열은 마우스가 움직 일 때 좌표값을 넣기위한 값 이다.
moveTo 함수는 캔버스의 위치로 좌표값을 옮기는 기능이며, lineTo 함수는 moveTo 한 곳에서부터 선을 그리는 기능 이다.
type이라는 변수에 각각의 마우스 이벤트 종류가 존재하여 "움직일때" 와 "벗어날때" 를 구분지어서 효과를 부여 해 보았다.
아래는 최종 완성된 코드 이다.
import React, { useRef, useEffect, useState } from 'react'
const defaultStyle = { border: '1px solid gray', display: 'inline-block', margin: '1rem' }
function Main(arg) {
const [ctx, setCtx] = useState();
const canvasRef = useRef(null);
const array = []
useEffect(() => {
const canvas = canvasRef.current;
const context = canvas.getContext('2d');
context.lineJoin = 'round';
context.lineWidth = 3;
context.strokeStyle = 'blue'
setCtx(context);
}, [])
const canvasEventListener = (event, type) => {
let x = event.clientX - event.target.offsetLeft;
let y = event.clientY - event.target.offsetTop;
if (type === 'move') {
if (array.length === 0) {
array.push({ x, y })
} else {
ctx.save()
ctx.beginPath();
ctx.moveTo(array[array.length - 1].x, array[array.length - 1].y);
ctx.lineTo(x, y);
ctx.closePath();
ctx.stroke();
ctx.restore()
array.push({ x, y })
}
} else if (type === 'leave') {
ctx.save()
ctx.clearRect(0, 0, 2580, 2580)
ctx.restore()
}
}
return (
<div className='container' >
<canvas ref={canvasRef} style={defaultStyle}
onMouseDown={(event) => { canvasEventListener(event, 'down') }}
onMouseMove={(event) => { canvasEventListener(event, 'move') }}
onMouseLeave={(event) => { canvasEventListener(event, 'leave') }}
onMouseUp={(event) => { canvasEventListener(event, 'up') }}
>
</canvas>
</div>
);
}
export default Main;