ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 🖼 바닐라 JS로 그림 앱 만들기 : canvas, js 기능 구현 강의 기록
    Javascript 2023. 4. 10. 21:11

     

     

     

     

    서론

    노마드코더의 강의 중 하나인 바닐라 JS로 그림 앱 만들기 를 완강했다.

    공부 중에 새롭게 알게된 것, 기록해놔야겠다고 생각했던 것들 ... 을 모두 모아 기록해둔다.

    canvas는 정말 재미있는 기능이어서 매우 흥미로웠다! 꼭 활용해보고 싶다.

     

    🔗 MDN Canvas Tutorial 

     

     


     

     

     

    <canvas>

    HTML의 요소.

    보통 자바스크립트를 사용하여 그림을 그리는 데에 사용한다.

    ex) 그래프 그리기, 사진 합성, 애니메이션 만들기 ... 등 

     

    canvas 크기 지정

    // canvas
    const canvas = document.querySelector("canvas");
    
    // canvas width, height 지정
    canvas.width = 가로;
    canvas.height = 세로;

     

    canvas 렌더링 컨텍스트 지정

    // 렌더링 컨텍스트 타입을 지정 (ex. 2d, bitmaprenderer... )
    const ctx = canvas.getContext("2d");

    + WebGL (Javascript API) 을 사용하여 3D 그래픽 애플리케이션을 만들 수 있다. 🔗여기

     

    fillRect / strokeRect

    // fillRect => 함수가 실행되면 fill(채우기)이 실행된다 (시작x, 시작y, 채울w, 채울h) 
    // -----> fill, rect를 함께 담은 단축함수shortcut
    // strokeRect 는 fill 을 strok(선)으로만 바꾸면 같다. 
    // rect 만 있는 상태는 색상자체는 "투명"이라고 생각하자, 꼭 색이나 선을 채워줘야 한다
    
    ctx.fillRect(50, 50, 5, 5);
    // 는 밑과 같다.
    
    ctx.rect(50, 50, 5, 5);
    ctx.fill();

     

    beginPath()

    // beginPath()를 사용하면 사용하기 전과 후 경로가 분리된다.
    // 새로운 경로가 시작된다는 뜻.
    ctx.beginPath();

     

    moveTo / lineTo

    // moveTo : 브러쉬를 이동한다. (시작지점)
    ctx.moveTo(50,50);
    
    // lineTo : 선을 그린다 (설정한 곳으로 경로가 이어지며 점이 이동한다고 생각해보자)
    ctx.lineTo(150, 50);
    
    // 지금까지 이어둔 경로를 입맛에 맞춰 fill 혹은 stroke
    ctx.fill();
    ctx.stroke();

     


     

     

    스타일 지정하기

     

    1. 색상 지정

    // 색상 지정
    fillStyle = "color";
    strokeStyle = "color";
    // color에는 색상 이름, rgb, rgba, #코드 등이 들어갈 수 있음

     

    2. 선 두께 설정

    // 선 두께 설정
    // 설정을 이런식으로 변경하면 그 이후 선은 계속 똑같은 두께가 나오므로 주의한다.
    ctx.lineWidth = number;

     

    3. 선 모양 설정

    // 기본값은 네모 뾰족하게 나온다 ... 
    ctx.lineCap = "round" // 끝이 둥글게 표현
    // round, butt, square

    🔗 그밖의 스타일

     

     


     

     

     

    🤓 기능 구현

    0. 마우스를 누르고 있는가?

    마우스를 꾹~ 누르고 있는지를 판별한다. (true)

    마우스를 누르고 있다면 움직이는대로 그릴 것이고, 그렇지 않다면 계속해서 그리기 시작하는 좌표가 달라진다.

    let isPainting = false;
    
    function startPainting() {
      isPainting = true;
    }
    
    function cancelPainting() {
      isPainting = false;
    }
    
    canvas.addEventListener("mousedown", startPainting);
    canvas.addEventListener("mouseup", cancelPainting);

    mousedown 

    포인터가 요소 내부에 있을 때, 포인팅 장치 버튼을 눌렀을 때 mousedown 이벤트가 발생한다.

    mouseup 

    버튼을 누른 상태에서 요소 내부에 있는 상태에서 해제되었을 때 이벤트가 발생한다.

     

    💥 주의

    요소 외부에서 mouseup 이 되면 어떻게 될까?

    결론부터 말하자면, mouseup 이벤트가 일어나지 않는다. 요소 외부로 나갔기 때문이다.

    때문에 요소 외부로 나갔을 때의 이벤트, 함수를 설정해주어야 한다.

    // 포인터가 요소를 떠났을 때도 mouseup 때 실행되는 함수를 담는다.
    canvas.addEventListener("mouseleave", cancelPainting);

    mouseleave 는 말그대로 포인터가 요소의 밖으로 이동했을 때를 뜻한다.

     

    1. 브러쉬 이동, 그리기

    - 마우스를 누르지 않았을 때 : 브러쉬를 이동시키기만 한다. 

    - 마우스를 눌렀을 때 : 누른 좌표에서부터 움직이는 쪽으로 선을 긋는다.

    function onMove(event) {
    	// 마우스를 누른 상태
    	if(isPainting) {
    		ctx.lineTo(event.offsetX, event.offsetY);
            ctx.stroke();
            return;
    	}
        // 마우스를 눌렀다 뗐을 때 그 다음에 그릴 선의 경로를 새로 만들어 둔다.
        ctx.beginPath();
        
        // 마우스를 누르지 않고 이동만 하는 상태
        ctx.moveTo(event.offsetX, event.offsetY);
    }

     

    2. 브러쉬 두께 설정

    <input type="range" id="line-width" min="1" max="10" value="5" step="0.1" />

    range 타입의 input. 최저는 1 최대는 10 기본값은 5. 0.1씩 증가한다. 라는 정보가 담겨있다.

    function onLineWidthChange(event) {
      ctx.lineWidth = event.target.value;
    }
    
    lineWidth.addEventListener("change", onLineWidthChange);

     

    3. 브러쉬 컬러 설정

    function onColorClick(event) {
      const colorValue = event.target.dataset.color;
      ctx.strokeStyle = colorValue;
      ctx.fillStyle = colorValue;
      color.value = colorValue;
    }

     

    4. 채우기

    0~1에서 처럼 채우기 버튼을 만들고, 채우기 버튼이 클릭되어 있을 때(true) 캔버스를 클릭하면 캔버스 크기만큼 fillRect 해준다.

     

    5. 캔버스 모두 지우기

    두 가지 방법이 있다.

    첫 번째, 캔버스크기만큼 white로 채우는 방법

    두 번째, celarRect()를 사용하는 방법 

     

    첫 번째의 경우 4번을 참고해서 만들면 된다.

    두 번째의 경우는 기록해둔다.

    function allClear() {
      ctx.clearRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
    }

     

    6. 지우개

    5번의 첫 번째 방법에서 사용했던 것처럼 하얀색으로 덧칠해 지운다고 생각한다.

    function onEraserClick() {
      ctx.strokeStyle = "white";
    }

    선의 색상을 하얀색으로 바꿔주기만 하면 된다. 간단!

     

    7. 이미지 가져오기

    기본적으로 브라우저는 나의 파일들을 자기 맘대로 볼 수 없다.

    내가 파일을 업로드해야만 브라우저의 자바스크립트에게 보이게 된다.

    function onFileChange(event) {
      const file = event.target.files[0];
      const url = URL.createObjectURL(file); // url 요청
      const image = new Image(); // = <img src = "" />
      image.src = url;
      image.onload = function () {
        ctx.drawImage(image, 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
        fileInput.value = null; // 다른 이미지를 추가하고 싶을지도 모르므로!!
      };
    }
    
    fileInput.addEventListener("change", onFileChange);

     

    8. 텍스트 추가

    캔버스를 더블클릭했을 때, 그 좌표에 input에 적었던 텍스트가 찍힌다.

    function onDoubleClick(event) {
      const text = textInput.value;
      if (text !== "") {
        ctx.save(); // 현재 상태, 색상, 스타일 등 모든 것 저장
        ctx.lineWidth = 1;
        ctx.font = "48px serif"; // size, font-family 설정 가능
        ctx.fillText(text, event.offsetX, event.offsetY); // 클릭한 좌표
        // fillText, strokText 두 가지 버전이 있다.
        // 선 굵기 이전으로 되돌리기
        ctx.restore(); //* save() ~ restore() 사이에는 어떤 수정이 이루어져도 저장되지 않는다.
      }
    }
    
    canvas.addEventListener("dblclick", onDoubleClick);

    save() ~ restore() 

    현재 상태, 색상, 스타일 등 모든 것을 저장한다.

    이 사이에 어떤 수정이 이루어져도 저장되지 않는다. 

     

    9. 이미지 저장하기

    캔버스를 이미지로 저장한다.

    function onSaveClick() {
      const url = canvas.toDataURL(); // 이미지를 텍스트로 인코딩 해준다.
      const a = document.createElement("a");
      a.href = url;
      a.download = "myDrawing.png";
      a.click();
    }
    
    saveBtn.addEventListener("click", onSaveClick);

     

     

     

     

     

     

     

     

     

     

     

    댓글

Designed by Tistory.