[js]canvas 그림판 만들기

eunalee·2023년 4월 21일
0

vanilla

목록 보기
2/2

✨ Drawing line

Draw with click event

	ctx.lineWidth= 2;

  const colors = [
      "red", "lime", "blue", "yellow"
  ]

  function onClick(event){
      ctx.beginPath();
      ctx.moveTo(0,0);
      const color = colors[Math.floor(Math.random()*colors.length)];
      ctx.strokeStyle = color;
      ctx.lineTo(event.offsetX, event.offsetY);
      ctx.stroke()
    
   canvas.addEventListener("click", onClick)
  }

lineWidth로 브러쉬 두께 잡아주고
lineTo로 클릭시, 그릴 위치 잡아준다.
OffsetX, offsetY는 console.log(event)했을때, 마우스 현 좌표 요소인걸 알 수 있다.

클릭이 아니라 마우스 따라오면서 그려지는걸 하고싶다면, event에서 "click" => "mousemove"

Drag to draw

  ctx.lineWidth= 2;
  let isPainting = false;

  function onMove(event){
      if(isPainting){
          ctx.lineTo(event.offsetX, event.offsetY);
          ctx.stroke();
          return;
      }
      ctx.moveTo(event.offsetX, event.offsetY); 
  }

  function onMouseDown(){
      isPainting = true;
  }

  function onMouseUp(){
      isPainting = false;
  }

  canvas.addEventListener("mousemove", onMove);
  canvas.addEventListener("mousedown", onMouseDown);
  canvas.addEventListener("mouseup", onMouseUp);

마우스를 누르고 이동 있을때는 선 그리기진행 (lineTo)
마우스 떼고 이동 있을때는 손만 이동중 (moveTo) -> 그래야 mousedown 이벤트 일어났을때, 곧바로 그 자리부터 그리기 시작이 되니까

하지만, 그리다가 캔버스 밖으로 뛰쳐나갔을때, onMouseUp 이벤트 실행이 안된다. 다시 마우스가 돌아왔을 때, 여전히 mouseDown상태라 계속 그리게된다.

'다'에서 뛰쳐나갔다가 들어오니까 계속 actvie 상태!

Solution1.

  canvas.addEventListener("mouseup", onMouseUp);
  canvas.addEventListener("mouseleave", onMouseUp)

이렇게 canvas 영역 떠나면 무조건 onMouseUp이벤트 발생시키게 하거나

Solution2.

  document.addEventListener("mouseup", onMouseUp);

document에서 일어나는 모든 mouseUp은 canvas안이든 밖이든 다 인식

Stroke width

우선 html에 선두께 선택하게 input만든다.

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

그리고는 javascript로 line-width id가진 element의 value값을 가져와서 ctx의 두께로 던져준다.

  const lineWidth = document.getElementById("line-width")

  canvas.width = 800;
  canvas.height = 800;

  ctx.lineWidth= lineWidth.value;

  function onLineWidthChange(event){
    ctx.lineWidth = event.target.value;
  }

  lineWidth.addEventListener("change", onLineWidthChange)

Change color

  <input id="color" type="color"/>

이경우, 팔레트 전체를 줘서 유저 마음대로 선택 가능하게

  const color = document.getElementById("color")
  
  function onColorChange(event){
    ctx.strokeStyle = event.target.value;
  }

  color.addEventListener("change", onColorChange)

위와 거의 동일하다.
color id갖는 element 데려와서 이번에는 stroke Color로 쓴다.

이미 색 주고 선택하게 하려면?

<input id="color" type="color"/>
    <div class="color-option" style="background-color: #1abc9c;" data-color="#1abc9c"></div>
    <div class="color-option" style="background-color: #3498db;" data-color="#3498db"></div>
    <div class="color-option" style="background-color: #34495e;" data-color="#34495e"></div>
    <div class="color-option" style="background-color: #27ae60;" data-color="#27ae60"></div>
    <div class="color-option" style="background-color: #8e44ad;" data-color="#8e44ad"></div>
    <div class="color-option" style="background-color: #f1c40f;" data-color="#f1c40f"></div>
    <div class="color-option" style="background-color: #e74c3c;" data-color="#e74c3c"></div>
    <div class="color-option" style="background-color: #95a5a6;" data-color="#95a5a6"></div>
    <div class="color-option" style="background-color: #d35400;" data-color="#d35400"></div>
    <div class="color-option" style="background-color: #bdc3c7;" data-color="#bdc3c7"></div>
    <div class="color-option" style="background-color: #2ecc71;" data-color="#2ecc71"></div>
    <div class="color-option" style="background-color: #e67e22;" data-color="#e67e22"></div>
.color-option{
    width: 50px;
    height: 50px;
    cursor: pointer;
}

이렇게 주면은 일단 화면에 나타나긴해.

그리고서는 javascript로 가서 색 선택 했을때, data-color를 브러쉬 색으로 쓰게 만들자.

살짝 복잡!

1. class="color-option"가진 애들 불러오기

  const colorOption = Array.from(document.getElementsByClassName("color-option"));

getElementsByClassName으로 데려오면, 같은 class값 가진 애들이 다 오긴 하지만, Array가 아니라서 쓰기 더러워.
Array.from으로 오는 값들을 array로 정리해 놓는거야.

2. 각각 onclick 이벤트 주기

  colorOption.forEach(color=> color.addEventListener("click", onColorClick))

이미지 색상자 하나 누를 때 마다 반응 일어나길 바라니까!

3. dataset color => brush color

function onColorClick(event){
    //console.dir(event.target) 으로 하면은 dataset안에 color로 들어가 있는걸 발견!
    ctx.strokeStyle = event.target.dataset.color;
    // ctx.fillStyle = event.target.dataset.color);
}

html에서처럼 "data-어쩌고" 이렇게 값을 주면, dataset안에 "어쩌고":"렐렐렐" 이렇게 들어가.
이 렐렐렐을 갖다 strokeStyle로 쓰는거지.

마지막으로,

	color.value = event.target.dataset.color

이걸 onColorClick안에 넣어주면, 유저가 색상자 선택했을때, 가장 왼쪽 색선택 박스가 바뀌게 할 수 있어.

Canvas 브러쉬 or 페인트통

똑딱버튼 만들기

  <button id="mode-btn">Fill</button> 

이 버튼으로 붓<->페인팅통 똑딱똑딱한다.

  const modeBtn = document.getElementById("mode-btn");
  
  function onModeClick(){
    if(isFilling){
        isFilling = false;
        modeBtn.innerText="fill";
    }else{
        isFilling=true;
        modeBtn.innerText="draw";
    }
  }

  modeBtn.addEventListener("click", onModeClick);

배경 채우기

  function onCanvasClick(){
    if(isFilling){
        ctx.fillRect(0,0,800,800);
    }
  }

  canvas.addEventListener("click",onCanvasClick);

만약에 isFilling버튼이 켜있으면은 채우기 고고

지우개

완전 밀기

  const destroyBtn = document.getElementById("destroy-btn");

  function onDestroyClick(){
    ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
  }

부분 지우개

  const eraserBtn = document.getElementById("eraser-btn");
  
  let backColor = "turquoise";

  function onCanvasClick(){
    if(isFilling){
        ctx.fillRect(0,0,800,800);
        backColor = ctx.fillStyle;
    }
  }

  function onEraser(){
    isFilling = false;
    ctx.strokeStyle = backColor;
}

default값으로 turquoise를 주긴 했지만은, 이전에 배경 채우기 한 경력이 있다면은 그걸 쓰기위해 backColor
is filling 주는거는, brush/paint 중 paint 선택인 상태에서 지우개 들어간다면, brush처럼 부분적으로 지우기가 안되거든.

전체 지우개

function onDestroyClick(){
    ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
    backColor = "turquoise";
}

저장

function onSave(){
    const url = canvas.toDataURL();
    const a = document.createElement("a");
    console.log(url);
    a.href = url
    a.download = "myDrawing.png"
    a.click();
}

다음 스텝은 저 url로 firebase에 저장할 수 있는가 실험

profile
coucou!

0개의 댓글