웹 애플리케이션에서 특정 좌표에 점을 찍고 그 점들을 연결해 다각형을 만드는 기능은 매우 유용합니다. 특히, 사용자 상호작용을 통해 도형을 자유롭게 그릴 수 있는 기능은 사용자 경험을 한층 더 강화시킬 수 있습니다. 오늘은 이 기능을 HTML5 `<canvas>`와 SVG를 활용해 React에서 구현하는 방법을 알아보겠습니다. 이 두 가지 방법 모두 각자의 장점을 가지고 있어, 사용 목적에 따라 적절한 방법을 선택할 수 있습니다.
HTML5 `<canvas>`를 이용한 자유로운 다각형 그리기
먼저, HTML5 `<canvas>` 요소를 사용하여 클릭 이벤트에 따라 좌표를 저장하고, 이를 통해 다각형을 그리는 방법을 살펴보겠습니다. `<canvas>`는 픽셀 단위의 그래픽 작업을 수행하는 데 적합하며, 특히 실시간으로 사용자 상호작용이 중요한 경우에 많이 사용됩니다.
예시 코드
import React, { useRef, useState } from 'react';
const CanvasPolygonDrawer = () => {
const canvasRef = useRef(null);
const [points, setPoints] = useState([]);
// 캔버스 클릭 시 좌표를 추가
const handleCanvasClick = (e) => {
const canvas = canvasRef.current;
const rect = canvas.getBoundingClientRect();
// 마우스 클릭 위치를 캔버스 기준으로 변환
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
setPoints((prevPoints) => [...prevPoints, { x, y }]);
};
// 점과 선을 그림
const drawPolygon = () => {
const canvas = canvasRef.current;
const ctx = canvas.getContext('2d');
// 캔버스 초기화
ctx.clearRect(0, 0, canvas.width, canvas.height);
if (points.length > 1) {
ctx.beginPath();
ctx.moveTo(points[0].x, points[0].y);
// 좌표들을 연결하여 선을 그림
points.forEach((point, index) => {
if (index > 0) {
ctx.lineTo(point.x, point.y);
}
});
// 첫 좌표와 마지막 좌표 연결
ctx.closePath();
ctx.stroke();
}
// 각 좌표마다 점을 찍음
points.forEach((point) => {
ctx.beginPath();
ctx.arc(point.x, point.y, 3, 0, 2 * Math.PI);
ctx.fill();
});
};
// '완료' 버튼 클릭 시 도형 완성
const handleComplete = () => {
drawPolygon();
};
return (
<div>
<canvas
ref={canvasRef}
width={500}
height={500}
style={{ border: '1px solid black' }}
onClick={handleCanvasClick}
/>
<button onClick={handleComplete}>완료</button>
</div>
);
};
export default CanvasPolygonDrawer;
주요 동작 설명
- 캔버스 클릭: 사용자가 캔버스를 클릭할 때마다 클릭한 좌표를 배열에 저장합니다.
- 점 찍기 및 선 연결: 좌표마다 점을 찍고, 각 좌표를 연결해 선을 그립니다. 마지막 좌표와 첫 좌표를 연결해 도형을 완성합니다.
- 다각형 완성: ‘완료’ 버튼을 눌러 도형을 그리면, 클릭한 좌표들이 연결된 도형이 완성됩니다.
SVG를 이용한 자유로운 다각형 그리기
이제 SVG를 사용해 같은 기능을 구현하는 방법을 살펴보겠습니다. SVG는 벡터 기반이기 때문에 확대와 축소에 강하며, CSS로 스타일을 쉽게 제어할 수 있는 장점이 있습니다. 도형이나 선을 그리는 데 적합하며, 보다 고해상도의 결과를 얻고자 할 때 유용합니다.
예시 코드
import React, { useState } from 'react';
const SvgPolygonDrawer = () => {
const [points, setPoints] = useState([]);
// SVG 클릭 시 좌표 추가
const handleSvgClick = (e) => {
const svg = e.target;
const rect = svg.getBoundingClientRect();
// 클릭한 위치를 SVG 좌표로 변환
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
setPoints((prevPoints) => [...prevPoints, { x, y }]);
};
// 첫 번째 좌표와 마지막 좌표를 연결해 도형 완성
const handleComplete = () => {
setPoints((prevPoints) => [...prevPoints, prevPoints[0]]);
};
return (
<div>
<svg
width="500"
height="500"
style={{ border: '1px solid black' }}
onClick={handleSvgClick}
>
{/* 점 그리기 */}
{points.map((point, index) => (
<circle key={index} cx={point.x} cy={point.y} r="4" fill="black" />
))}
{/* 좌표들을 연결하는 선 */}
{points.length > 1 && (
<polyline
points={points.map((point) => `${point.x},${point.y}`).join(' ')}
fill="none"
stroke="black"
strokeWidth="2"
/>
)}
</svg>
<button onClick={handleComplete}>완료</button>
</div>
);
};
export default SvgPolygonDrawer;
주요 동작 설명
- SVG 클릭: 사용자가 SVG 영역을 클릭할 때마다 좌표를 배열에 저장합니다.
- 점과 선 그리기: 각 좌표마다 점을 그리며, 좌표를 연결해 선을 그립니다.
- 다각형 완성: ‘완료’ 버튼을 눌러 도형을 완성하며, 첫 좌표와 마지막 좌표를 자동으로 연결합니다.
결론
React로 특정 좌표에 점을 찍고 그 점들을 연결해 도형을 그리는 기능은 HTML5 `<canvas>`와 SVG를 통해 구현할 수 있습니다. `<canvas>`는 픽셀 기반의 작업을 다룰 때 유리하며, 실시간 상호작용에 최적화된 반면, SVG는 벡터 기반으로 확대 축소에 강하고 스타일 제어가 용이합니다. 두 방법 모두 각자의 장점을 가지고 있으니, 프로젝트의 특성에 맞게 적합한 방식을 선택하면 됩니다.
참고 자료
- MDN Web Docs, “CanvasRenderingContext2D”
- MDN Web Docs, “SVG `<polygon>` and `<polyline>`”