HTML5의 가장 큰 특징 중 하나인 Canvas(캔버스)! Canvas에 그려진 도형(Shape)에 클릭 이벤트를 추가하려고 합니다. 어떻게하면 가능할까요? 아래에서 알아보세요.


! 캔버스 내부 도형에 클릭 이벤트를 추가하는 것은 불가능먼저 캔버스 내부 도형에 직접 이벤트를 추가하는 것은 어렵습니다... 즉 캔버스 내부에 원을 그렸다면 그 원에 이벤트를 직접 걸 수 없습니다. 그 이유는 DOM에 추가된 노드와 다르기 때문에 캔버스 도형은 그려지고 보이는 역말만 수행하기 때문입니다. 물론 방법이 존재합니다. 이는 아래에 자세히 적도록 하겠습니다.



# 캔버스 도형에 클릭 이벤트 추가하려면?위에 설명한 것처럼 도형에 직접 이벤트를 추가할 수 없지만 캔버스 태그는 이벤트를 발생할 수 있습니다. 이를 사용하는 방법으로 아래의 방법들이 사용됩니다.

  • 1. 캔버스 내부에 그려진 도형 범위를 기억하기
  • 2. 도형마다 다른 색을 부여하고 이를 확인하기

두 가지 방법 모두 몇 가지 조건이 필요합니다. 그 중 하나는 캔버스 태그에 이벤트를 추가하고 이벤트 발생시 클릭된 지점을 계산한다는 점입니다. 그럼 위 두 가지 방법을 대략 설명하자면..


! 1번의 방법도형을 그릴때 그려진 위치와 크기를 기록하여 클릭된 위치가 해당 도형의 범위에 포함되는지를 계산합니다. 이 방법은 도형이 겹치는 경우에 모든 도형에 이벤트를 실행할 수 있다는 점입니다. 다만 모든 도형의 크기와 위치를 기록해야한다는 점이 복잡하다는 단점을 가집니다.


! 2번의 방법도형이 가진 색을 이용하는 방법입니다. 뒤에 사용될 예제 역시 이 방법을 사용하여 구현하였는데 코드가 비교적 단순하고 적용이 쉽기 때문입니다. Canvas 태그의 특정 위치가 어떤 색을 가지고 있는지 불러올 수 있는데 이때 그려진 도형과 같은 색을 찾음으로써 이벤트를 발생하는 방법입니다.아래는 2번 방법으로 구현된 예제소스입니다. 클릭할 경우 현재 클릭된 도형이 어떤 색인지 보여주게됩니다.



# 캔버스 내부 도형 클릭 이벤트 예제보기현재 클릭된 도형이 어떤 색인지 보여주는 이번 예제는 위의 2번 방법인 색을 가지고 구분하게됩니다.
@ canvas_click.html
<canvas onclick="showColor(event);" width="200" height="200"></canvas>

@ canvas_click.js
var canvas = document.querySelector('canvas');
var ctx = canvas.getContext('2d');

ctx.fillStyle = 'rgb(255, 0, 0)';
ctx.fillRect(50, 50, 20, 20);

ctx.fillStyle = 'rgb(0, 255, 0);
ctx.fillRect(150, 150, 30, 30);


function showColor() {
  var canvas = document.querySelector('canvas');
  var ctx = canvas.getContext('2d');

  var x = event.offsetX;
  var y = event.offsetY;
  var color = ctx.getImageData(x, y, 1, 1).data;
  alert(color);
}

@ canvas_click.css
canvas { background-color: #f9f9f9; }

이제 위 코드를 실행하면 canvas가 나타나며 아래의 예제1과 같이 선택된 색을 보여주게됩니다. 이제 두 가지 의문이 생길 수 있습니다.

1. 만약 색이 모두 동일한 경우는 어떻게 구분?
2. 색 이외의 정보는 어떻게 알 수 있는가?

1 그리고 2번 문제를 해결하기 위해서 이제 위 코드에 조금 더 개발 로직을 추가할 것입니다. 먼저 서로 다른 색을 가질 수 있도록 랜덤 색상값을 구한 후 각 모양(Shape)에 추가하는 작업입니다... 이때 색상 값은 rgb값을 가지며 256 x 256 x 256 개의 값들을 가지므로 중복될 경우는 거의 겂다고 생각할 수 있습니다.


! 1번 문제 해결 방안이때 얻은 랜덤한 색이 Shape에 직접 적용되면 안되겠죠... 실제로 보여줄 캔버스 도형들이 알록달록한 색을 입히지 않을 것이기 때문입니다. 이 때문에 임의의 Canvas 태그를 추가로 만들고 이를 볼 수 없도록 합니다. 도형은 두 캔버스에 동일하게 그려주고 색상 값만 달리 적용하면 이벤트에서 불러온 색을 이때 만들어진 canvas와 비교하여 Shape의 좌표값 등을 가져올 수 있습니다.


! 2번 문제 해결 방안2번째인 색 이외의 값들을 가져오기 위해서 임의의 변수에 해당하는 shape 정보를 저장하는 것입니다. 예를들어 아래와 같이 변수 myShapes에 도형이 그려지는 시점에 특정 값들을 저장합니다. 아래는 가장 간단한 좌표 x, y를 저장합니다.
myShapes = [];

function drawShape() {
  var shape = {
    x: 10,
    y: 10,
    color: '255, 0, 0'
  }
  ...
  myShapes.push(shape);
};

이처럼 값들이 변수에 저장되면 나중에는 변수 myShapes에 아래처럼 값들이 추가되어 있겠죠.
myShapes = [
  {
    x: 20,
    y: 20,
    color: '15, 200, 90'
  },
  {
    x: 50,
    y: 50,
    color: '255, 0, 0'
  },
    ...,
  {
    x: 150,
    y: 150,
    color: '10, 100, 255'
  }
];

위에 저장된 각 도형의 색 값과 캔버스 엘리먼트의 클릭으로 얻은 색을 비교하면 해당하는 도형이 무엇인지 알 수 있게됩니다. 여기서는 해당 도형의 x, y값 등을 알 수 있게됩니다. 이 예제 소스는 추후에 업데이트 하도록 하겠습니다.



# 마치면서여기까지 캔버스 내부에 위치한 도형에 클릭 이벤트를 추가하는 방법을 알아봤습니다. 일반적인 DOM 이벤트와 비교하면 상당히 복잡하고 어렵지만 위에 제시한 방법은 잘 동작하고 성능에서도 비교적 괜찮게 나옵니다.

현재까지는 Canvas를 사용하는 방법보다는 SVG 등을 사용하는 방식이 더 많이 쓰이는데 Canvas의 다양한 API 기능들을 모든 브라우저에서 표현하기 어려운 부분도 그 이유이기도합니다. 하지만 최신 브라우저는 대부분 Canvas의 기능들을 지원하고 앞으로는 더 많은 기능들이 추가될 것이므로 Canvas의 다양한 방법들을 익혀두면 향후 많은 도움이 될 것입니다.

! 예제 1번