HTML5

CANVAS란?

아거스 2010. 12. 9. 01:42
최근 HTM5가 이슈화 되면서 관련하여 많은 JavaScript API들이 공개되었다.
이 중 그래픽 이미지나 차트, 애니메이션 등을 동적으로 나타낼 수 있는 CANVAS API(이하 캔바스)에 대하여 알아보기로 한다.

캔바스는 애플의 MAC OS X의 웹킷 구성요소인 대시보드 위젯, 사파리 브라우저 등에 사용됨으로써 대중에게 알려지기 시작했으며 현재도 개발이 진행중인 API이다.

MS IE9 Beta를 비롯한 최신 브라우저에서 모두 지원하고 있으며 IE8 이하 버전에서는 exCanvas, html5canvas, uuCanvas 등의 JS Library를 사용하여 제한적 구현이 가능하다.

HTML5에는 캔바스와 유사한 기능을 하는 SVG(Scalable Vector Graphics)요소가 있다.
하지만 구현방법과 사용목적 등이 다르기 때문에 살펴보고 적재적소에 잘 활용할 필요가 있다.

우선 캔바스의 경우 비트맵 방식인데 반해 SVG의 경우는 이름에서 알 수 있듯이 벡터 방식으로 그래픽을 표현한다.
이에 따라 캔바스는 그래픽을 픽셀 단위로 처리하게 되며 보다 복잡한 작업을 더 빠른 속도로 처리가 가능하다.
물론 이러한 작업을 위해 자바스크립트 API가 존재한다.

SVG의 경우 벡터 방식을 취하기 때문에 해상도 또는 브라우저 창의 크기에 상관없이(풀 사이즈 또는 상대값 처리시) 깔끔한 그래픽 처리가 가능하다. 또한 마크업 언어이기 때문에 DOM에 접근 및 편집이 가능하다.
 
캔바스 2D API는 immediate-mode API이고 SVG는 retained-mode API라는 것도 알아두자.

캔바스와 SVG를 실사물에 비교하면 캔바스지와 색종이 공작으로 표현이 가능하다.


캔바스는 레이어 형태 없이 자바스크립트로만 드로잉하고 SVG는 정의된 마크업으로 레이어 형태의 그림을 그리지만 자바스크립트가 꼭 필요한 것은 아니다.

자 그럼 이제부터 캔바스에 대하여 조금 더 알아보도록 하자.

캔바스 요소

우선 캔바스를 사용하기 위해선 브라우저에서 캔바스지의 역할을 하는 캔바스 요소를 아래와 같이 작성해야 한다.

<canvas width="598" height="400" id="demo_canvas">
	이 브라우저는 CANVAS를 지원하지 않습니다.
</canvas>
width와 height 속성을 이용하여 캔바스의 크기를 600 X 400(픽셀)로 지정했다.
width와 height 속성은 필수값이 아니며 작성하지 않을 경우 기본 캔바스 크기는 300 X 150(픽셀)로 정해진다.
또한 캔바스 태그 내에 텍스트나 이미지를 삽입하여 대체 컨텐츠를 제공한다면 접근성 향상에 도움이 된다.

또한 자바스크립트상에서도 캔바스 지원 여부를 알 수 있다.
기본 메서드인 getContext의 유무로 판별할 수 있는데 아래와 같이 구분 지을 수 있다.

var c  = document.getElementById( "demo_canvas" );
if ( c.getContext ) {
	var ctx = c.getContext( "2d" );
	//캔바스를 지원하는 경우의 수행문
} else {
	//캔바스를 지원하지 않는 경우의 수행문
}

좌표체계

캔바스에서의 좌표체계는 다음과 같다.



캔바스 내에서 좌측 상단을 기준(x = 0, y = 0)으로 우측 아래로 갈수록 x와 y의 값이 증가한다.

기본 예제

"백문이 불여일타!"

궁극적으로 레퍼런스를 설명하기 보다는 코드 리뷰 및 필요한 내용을 살펴보는 방식으로 진행하도록 하겠다.

우선 현재 HTML WG에서 개발중인 HTML Canvas 2D Context API 명세이 있는 예제를 한 번 살펴보도록 하자.

http://dev.w3.org/html5/2dcontext/#examples

<canvas width="600" height="400"></canvas>

<script> 
	var context = document.getElementsByTagName('canvas')[0].getContext('2d');
	var lastX = context.canvas.width * Math.random();
	var lastY = context.canvas.height * Math.random();
	var hue = 0;

	function line() {
		context.save();
		context.translate(context.canvas.width/2, context.canvas.height/2);
		context.scale(0.9, 0.9);
		context.translate(-context.canvas.width/2, -context.canvas.height/2);
		context.beginPath();
		context.lineWidth = 5 + Math.random() * 10;
		context.moveTo(lastX, lastY);
		lastX = context.canvas.width * Math.random();
		lastY = context.canvas.height * Math.random();
		context.bezierCurveTo(
			context.canvas.width * Math.random(),
			context.canvas.height * Math.random(),
			context.canvas.width * Math.random(),
			context.canvas.height * Math.random(),
			lastX,
			lastY
		);

		hue = hue + 10 * Math.random();
		context.strokeStyle = 'hsl(' + hue + ', 50%, 50%)';
		context.shadowColor = 'white';
		context.shadowBlur = 10;
		context.stroke();
		context.restore();
	}
	setInterval(line, 50);

	function blank() {
	context.fillStyle = 'rgba(0,0,0,0.1)';
	context.fillRect(0, 0, context.canvas.width, context.canvas.height);
	}
	setInterval(blank, 40);
</script>
가장 먼저 getContext() 메서드를 사용하여 2D 컨텍스트를 생성했다.(4 라인)
이 때 context가 CanvasRenderingContext2D객체의 인스턴스로 사용되었으며
색상 지정을 위한 hue 변수와 마지막 위치값을 가지는 lastX, lastY 변수를 설정했다.(5~7 라인)
context.canvas는 해당 요소를 가리키며 contenxt.canvas.width는 캔바스의 너비를 반환하게 된다.

위 예제에는 두 개의 함수가 존재하는것을 볼 수 있는데 line 함수는 컨텍스트에 랜덤한 형태의 선을 그리며 blank 함수는 컨텍스트를 초기화하는 역할을 하게 된다.
위 두 함수는 setInterval로 50ms, 40ms로 각각 반복되는 것을 알 수 있다.(32, 38 라인)

그럼 blank 함수를 먼저 살펴보자.

fillStyle 프로퍼티는 모양의 채울 색을 정의한다. 예제에서는 rgba형식으로 작성했지만 웹에서 색상을 표기하는 여러방식을 사용할 수 있다.(예. black, #000, hsl(0, 100%, 50%) 등)
위에서 사용된 rgba형식은 빨강(0~255), 녹색(0~255), 파랑(0~255), 불투명도(0~1 : 0 = 투명)순으로 작성한다. 즉 투명도가 10%인 검은색으로 채우겠다는 얘기이다.
또한 fillStyle 프로퍼티를 작성하지 않을 경우 기본적으로 검은색이 지정되는 것도 알아두자.

fillStyle 프로퍼티를 작성했지만 캔바스에 검은색은 찾아볼 수 없다.
검은색 물감을 붓에 묻혀도 캔바스지에 칠하지 않으면 무슨 소용인가!!
fill 메서드는 캔바스지에 그려진 모양을 지정색으로 채우는 역할을 한다.

fillRect 메서드는 메서드명에서 유추할 수 있듯이 사각형 모양을 채우는 역할을 하며 각 인자로 x좌표, y좌표, 너비, 높이를 넘긴다.
이렇게 예제 35, 36라인은 캔바스의 전체 영역을 검은색(불투명도 10%)로 채우게 되는 것이다.

그렇다면 요번에는 line 함수를 살펴보자.

10라인과 33라인의 save와 restore 메서드가 눈에 띄는데 현재 컨텍스트의 상태를 저장하고 복원하는 역할을 하게 된다.
복잡한 그래픽을 구현하다 보면 반복 사용되는 컨텍스트의 상태가 반드시 있기 마련인데 이런 경우 위의 메서드를 활용하면 유용하다.
이 두 메서드의 경우는 드로잉 스테이트 스택을 사용하기 때문에 LIFO로 동작하는것도 알아두자.

11라인의 translate 메서드는각 인자로 x좌표, y좌표를 받아 해당 좌표로 변경할 경우 사용된다. 예제에서는 x=300, y=300으로 옮긴 후
12라인의 scale 메서드로 90% 축소, 13라인에서 다시 x=-300, y=-300으로 좌표를 변경하는 것을 알 수 있다.

14라인에서는 beginPath라는 메서드를 사용하는데 캔바스에서 Path(이하 '패스'라고 함)는 중요한 개념 중 하나이다.
"패스"는 선들로 이루어진 전체 모양을 말하며 패스를 구성하는 각각의 선을 "서브패스"라고 한다.
패스를 비유하자면 땅따먹기(?) 게임과 비교 할 수 있으며 웹 개발이나 디자인을 해본 분이라면 이미지맵의 coords 속성과 유사하다.
중요한것은 패스는 실질적으로 그래픽으로써 표시되지 않고 위에서 설명했던 fill이나 stroke 같은 메서드를 호출할 때에 비로서 그래픽으로 표현이 된다.

beginPath 메서드는 패스를 그리기 시작한다는 의미이며 기존의 패스는 모두 초기화 된다.

15라인의 lineWidth 프로퍼티는 선의 굵기를 나타내며 픽셀단위로 작성할 수 있다.

16라인의 moveTo 메서드는 서브패스를 그릴 시작점으로 좌표를 이동시킨다.
예제에서는 lastX, lastY로 좌표를 이동 후 lastX, lastY 값을 새롭게 정의하는 것을 볼 수 있다.

19~26라인까지 정의되어 있는 bezierCurveTo 메서드는 3차 베지어 곡선을 그리는 기능을 수행하며 2차 베지어 곡선을 그리는 메서드는 quadraticCurveTo 이다.

베지어 곡선에 대한 보다 자세한 내용은 베지어 곡선 위키피디아 문서를 참고하기 바란다.

29라인의 strokeStyle은 선의 스타일을 지정하며 기본적으로 검은색이고 위에서 설명한 fillStyle과 같이 여러 색상 표기 방식을 사용할 수 있는데 예제에서는 hsl방식을 사용했다.

hsl방식에서 색상은 아래와 같이 도수로 작성하는 특징을 가지고 있으니 참고하길 바란다.




즉 예제 코드를 실행해보면 stroke의 색상은 빨강 -> 녹색 -> 파랑 -> 빨강... 방향으로 변화시키는 것을 알 수 있다.

30, 31라인의 shadowColor와 shadowBlur 프로퍼티는 각각 그림자의 색상과 그림자의 흐림 정도를 나타낸다.

32라인의 stroke 메서드를 호출함으로써 이제까지의 패스를 선 그래픽으로 표현하게 되며,

33라인의 restore 메서드로 기존 컨텍스트의 상태로 복원시킨다.

위의 예제를 실행 시켜보면 아래와 같은 그래픽 요소를 볼 수 있다.

canvas요소를 지원하지 않는 브라우저 입니다.

다음 포스팅에서는 오늘 다루지 않은 메서드나 프로퍼티를 살펴보고 캔바스를 다룰 때 주의해야 하는 부분에 대해 알아보도록 하겠다.