\(@^0^@)/

[TIL] html5 canvas로 그림판을 만들어보자. 본문

TIL

[TIL] html5 canvas로 그림판을 만들어보자.

minjuuu 2022. 7. 28. 22:06
728x90

우선 결과물을 먼저 보도록 하자.
시간 날 때마다 기능을 조금씩 더 추가해보고, 리팩터링 할 예정이다.


마크업

마크업을 동적 생성으로 구현하면 더 좋았을 수도 있겠지만, 우선 canvas를 알아가는 것이 목표이기에 간편하게 html단에서 마크업을 구현하였다.

JS에서 활용하기 위해 아래의 tool들에 알맞은 dataset을 주었다.

<button class="tool-btn">
    <img src="./img/pencil.jpg" data-tool="pencil" />
</button>
<button class="tool-btn">
    <img src="./img/paint.jpg" data-tool="paint" />
</button>
<button class="tool-btn">
    <img src="./img/eraser.jpg" data-tool="eraser" />
</button>

 

예를 들어보면 연필의 경우 button안의 img태그에 data-tool="pencil"을 주었음.
이렇게 dataset을 사용하면, JS단에서 클릭이벤트를 활용하여 해당 이미지를 클릭할 경우 어떤 데이터인지 쉽게 알 수 있다.


스타일링

굵기를 선택하는 버튼의 경우에는 현재 div안에 button을 마크업 한 상태여서 button에 background 검정을 주고, height로 굵기를 구분하였음.

.liner-thin-btn {
    width: 35px;
    height: 1px;
    background-color: black;
}
.liner-normal-btn {
    width: 35px;
    height: 10px;
    margin-left: 15px;
    background-color: black;
}

색상을 선택하는 버튼의 경우에는 dataset을 이용하여 스타일링을 적용해주었다. data-color가 검정일 경우, 배경을 검정으로. 동적으로 생성한다면 조금 더 간결하게 만들 수 있을 것 같기도 한데, 현재는 뚜렷하게 떠오르지가 않는 상태임.

.color-btn[data-color="black"] {
    background-color: black;
}
.color-btn[data-color="gray"] {
    background-color: gray;
}


구현

1. canvas 구현하기 위해 두줄의 코드를 무조건적으로 생성해주기.

const canvas = document.querySelector(".canvas");
const ctx = canvas.getContext("2d");

 

2. canvas에 그림을 그리기 위해 canvas에 mousedown, mousemove, mouseup 세 개의 이벤트를 생성.

  • mousedown : 마우스 왼쪽 클릭을 할 경우 이벤트가 시작해야 하고 false였던 변수를 true로 준다.
  • mousemove : 해당 변수가 true일 경우 마우스를 이리저리 움직이면 이벤트가 발생해야 하고
  • mouseup : 마우스 왼쪽 클릭한 것을 떼면 mouseup 이벤트가 발생하면서  false가 되고, mousedown과 mousemove 이벤트가 닫혀야 함.
(function () {
    const canvas = document.querySelector(".canvas");
    const ctx = canvas.getContext("2d");
    let drawingMode;

    function startDrawHandler() {
        drawingMode = true;
    }

    function finishDrawHandler() {
        drawingMode = false;
    }

    function drawHandler(e) {
        if (!drawingMode) return;
    }

    canvas.addEventListener("mousedown", startDrawHandler);
    canvas.addEventListener("mousemove", drawHandler);
    canvas.addEventListener("mouseup", finishDrawHandler);
})();

3. mousemove 이벤트를 구현해보자.

  • 새로운 canvas 기능을 시작할 땐 beginPath()를 붙여주는 것이 좋음.
  • true일 경우 (mouseup일 경우)에만 이벤트가 작동되며, 해당 canvas의 높이와 길이에 사이즈 10의 동그란 원이 작성된다.
  • fill을 써주지 않는다면 그림이 그려지지 않는다. 그림을 그리기 위해서는 fill() 또는 stroke()를 적어주어야 하는데,
    둘의 차이점은 fill은 점을 채우고, stroke는 윤곽선을 그린다.

좌) fill() / 우) stroke()

function drawHandler(e) {
    if (!drawingMode) return;
    ctx.beginPath();
    ctx.arc(e.offsetX, e.offsetY, 10, 0, Math.PI * 2, false);
    ctx.fill();
}

 

4.  tools 중 하나를 클릭하면 해당 기능 구현하기.

  • 각 요소들을 select 해서 
const tools = document.querySelector(".tools");
const colors = document.querySelector(".color-btns");
const liners = document.querySelector(".width-liners");
  • 이벤트를 각각 생성해준다.
colors.addEventListener("click", setColor);
liners.addEventListener("click", setLiner);
tools.addEventListener("click", setTool);
  • 각각의 데이터를 저장할 변수를 만들어주고, 알맞은 초기값을 넣어준다.
let color = "black";
let liner = 10;
let tool = "pencil";
  • dataset을 이용하여 각각의 기능들을 넣어준다.
    • color일 경우 점을 채우는 스타일 색상을 변경해주고
    • eraser일 경우에는 canvas의 스타일 색상을 넣어주면, 지우개 기능을 할 수 있음.
    • 굵기인 liner의 경우에는 drawHandler의 arc함수에서 사이즈를 설정하는 부분에 알맞은 변수의 값을 할당해준다.
function setColor(e) {
    color = e.target.dataset.color;
    ctx.fillStyle = color;
}

function setTool(e) {
    tool = e.target.dataset.tool;
    if (tool === "eraser") ctx.fillStyle = "#eee";
}
function setLiner(e) {
    liner = e.target.dataset.liner;
}

function drawHandler(e) {
    ctx.arc(e.offsetX, e.offsetY, liner, 0, Math.PI * 2, false);
}

생각날 때마다 기능들 추가하기

1. 저장(이미지 다운로드) 기능 추가

지난번 이미지 에디터 구현할 때 사용했던 저장 기능을 추가해보았다.
현재 그림판에 다른 컴포넌트 추가 없이 그림판만 사용하고 있지만, 나중에 다른 기능들을 추가할지도 모르니 우선 그림판 전체를 감싸는 main태그를 html단에서 생성하여, 구현하는 js 쪽에서 불러왔다.

const $container = document.querySelector("main");

다운로드 버튼을 클릭하면, 이벤트가 생성되게 핸들러를 생성해주고

$download.addEventListener("click", download);

 

  • 지난번과 같이 사용자가 그림 그린 canvas을 url로 생성하여 url을 받고 
  • a태그를 이용해 href에 url을 넣고, 알맞은 파일명으로 저장한다.
  • 가장 바깥의 태그에 append 한 후, a태그가 클릭되도록 한다. 
  • 그 후, 바로 a태그가 삭제되도록 하면 다운로드 기능이 만들어진다.

지난번에 구현했던 기능들을 추가하는 것이라서, 쉽게 구현하였다.

 


[ 출처 및 참고 : https://www.youtube.com/watch?v=ovf8cbKtBH0 ,
https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D ]

728x90