Coding/JavsScript 삽질기2019. 11. 26. 01:35

소개:  https://chobocho.tistory.com/2461396

실행하기: http://www.chobocho.com/javascript/painter.html

전체 소스코드: https://github.com/chobocho/painter

 

경고  

  • 주인장은 자바스크립트 초보입니다.  

  • 자바스크립트 고수의 비급을 원하시는 분은 다른 자료를 참고 하시기 바랍니다.  

  • 과도한 기대는 과도한 실망을 가져옵니다.    

  • 본 강의는 자바스크립트만 사용합니다.  

  • 크롬에서의 동작만 보장 합니다.  

  • Canvas 기초 사용법은 구글링하시면 친절한 강의가 많습니다

 

4.1 Drawing state


그림판에서 사각형을 그리고자 할 때, 

먼저 시작 점에서 마우스의 왼쪽 버튼을 누르고,  

원하는 크기로 마우스를 드래그 하고, 

마우스의 왼쪽 버튼 누르기를 중단하면 화면에 사각형이 그려집니다.  

이 것을 State Diagram을 표현하면 아래와 같습니다.  

mouse 동작에 따라서, down, up, move에 연결된 함수를 호출 하도록 합니다.  

 

4.2 Double buffering

 

마우스를 도형을 그릴 때, 화면의 깜박임을 없애기 위해서 아래와 같이 bufCanvas 객체를 사용합니다.

그리는 마우스가 움직임에 따라 업데이트해서 그려야하는 화면을 bufCtx에 미리 그린 후 

이 화면을 cvs에 복사하여, 깜박임을 제거 합니다.

var cvs;
var canvas;

var bufCanvas;
var bufCtx;


function onLoadPage() {
  canvas = document.getElementById("canvas");
  cvs = canvas.getContext("2d");

  bufCanvas = document.createElement("canvas");
  bufCanvas.width = canvas.width;
  bufCanvas.height = canvas.height;
  bufCtx = bufCanvas.getContext("2d");
}

 

4.3 선 그리기 구현

아래와 같이 직선을 그리는 동작을 구현 합니다.

function Painter() {
    this.shape = new Shape("Line");
    this.shape.mouseAction = new MouseAction(lineMouseUp, lineMouseDown, lineMouseMove);
}
function MouseAction(mouseUp, mouseDown, mouseMove) {
    this.up = mouseUp;
    this.down = mouseDown;
    this.move = mouseMove;
}

마우스를 클릭하면, 캔버스에서 마우스의 절대 좌표를 기억합니다.

그리고 현재 canvas의 그려진 이미지를 bufCtx에 복사해 둡니다.

function lineMouseDown(event) {
  if (painter.isDraw()) {
    return;
  }
  bufCtx.drawImage(canvas, 0, 0);
  var startPos = getMousePosition(event);
  painter.shape.point.x = startPos.X;
  painter.shape.point.y = startPos.Y;
  painter.setDrawMode(true);
}

마우스를 움직이면, 클릭했을 때 기억한 시작점부터, 현재의 마우스 위치로 직선을 그립니다.

clearRect() 함수를 불러주는 이슈는, delay()를 주기 위해서입니다.

원인은 모르겠으나, canvas가 제대로 업데이트 되지 않는 문제가 있어서 

clearRect() 함수를 한 번 호출해주어 약간의 delay()를 주어서 해결했습니다.

(원인을 아시분은 댓글로 지도 부탁드립니다. 굽신굽신;;)

function lineMouseMove(event) {
  if (!painter.isDraw()) {
    return;
  }
  
  var currentPos = getMousePosition(event);
  cvs.beginPath();
  // Need a delay
  cvs.clearRect(0, 0, canvas.width, canvas.height);
  cvs.drawImage(bufCanvas, 0, 0);

  cvs.strokeStyle = painter.shape.color;
  cvs.moveTo(painter.shape.point.x, painter.shape.point.y);
  cvs.lineTo(currentPos.X, currentPos.Y);
  cvs.closePath();
  cvs.stroke();
}

마우스가 캔버스를 벗어나거나, 버튼에서 손가락을 때면, 

bufCtx에 저장해둔 이미지 위에, 선을 그립니다.

그리고 그 bufCtx 이미지를 canvas에 덮어 씁니다.

function lineMouseUp(event) {
  if (!painter.isDraw()) {
    return;
  }

  var currentPos = getMousePosition(event);
  bufCtx.beginPath();
  bufCtx.strokeStyle = painter.shape.color;
  bufCtx.moveTo(painter.shape.point.x, painter.shape.point.y);
  bufCtx.lineTo(currentPos.X, currentPos.Y);
  bufCtx.closePath();
  bufCtx.stroke();
  cvs.drawImage(bufCanvas, 0, 0);

  painter.setDrawMode(false);
}

나머지 원, 네모, 세모도 동일한 원리로 구현 합니다.

여기까지 소스는 아래와 같습니다.

https://github.com/chobocho/painter/blob/master/doc/tutorial/004/src/painter.js

Posted by chobocho