티스토리 뷰


* 이번에는 HTML5의 강력한 기능 중 하나인 <canvas> 태그에 대해서 알아보자.


2012/10/25 - [HTML5 튜토리얼] HTML5의 등장 배경과 여러 가지 개발 환경 및 현재 현황

2012/11/03 - [HTML5 튜토리얼] 기초 및 기본 구조, 프로그래밍상 기존의 HTML과 바뀐 점

2012/11/05 - [HTML5 튜토리얼] HTML5에 추가된 Element들 그리고 문서의 구조화


*<canvas> 소개

: <canvas>태그는 자바스크립트를 통해 다양한 그림을 그릴 수 있는 공간을 제공해준다. 해상도 독립적으로 SVG 그래픽을 활용하고 있어서 그래프를 그리거나 게임 그래픽이나 다른 기타 이미지를 실시간으로 그려서 사용할 수 있는 기능을 제공해준다.


: 기존의 HTML은 매우 정적인 느낌이라면, canvas는 이러한 정적인 느낌을 동적으로 느끼게 해줄 수 있는 HTML5의 커다란 기능 중 하나이다. 간단한 예로 다음의 사이트들을 한번씩 둘러보면 canvas의 그래픽 기능을 활용하면 어떤 것이 가능한지 알 수 있을 것이다.


* 아래 사이트들을 제대로 보려면 HTML5를 지원하는 최신 브라우져가 있어야한다. 크롬이나 Opera를 추천한다.

http://gyu.que.jp/jscloth/

http://bomomo.com/ - 크롬

http://www.tapper-ware.net/devel/js/JS.tinyDim/

http://www.html5rocks.com/en/tutorials/webgl/globe/

http://www.cuttherope.ie/


: 이 모든 것이 플래시 하나 없이 오로지 HTML5와 자바스크립트로만 개발된 것들이다. 물론 성능적인 제한 때문에 아직 완전한 게임까지는 무리이지만, 앞으로 그러한 가능성이 충분히 있다고 볼 수 있다. 위와 같이 다양한 기능들을 canvas에서 가지고 있기 때문에 canvas만 다룬 두꺼운 책이 있을 정도로 canvas는 깊이 들어가면 들어갈수록 심오하고 흥미로운 기능들을 가지고 있다. 여기서는 그러한 깊이 있는 기능을 이용하기 전에 기본적으로 알아야할 기능들에 대해서 살펴보기로 하자.


*<canvas> 시작하기

: 일단 w3c에서 제정하고 있는 <canvas>의 스펙을 한번 살펴보자

http://www.w3.org/TR/2011/WD-html5-20110525/the-canvas-element.html



: 기본 스펙은 위와 같다. width와 height를 나타내는 속성을 가지고 있으며, 함수로는 toDataURL, toBlob, getContext 함수를 가지고 있다. 여기서 가장 기본적으로 사용해야하는 것은 바로 getContext 함수로 자바스크립트에서 canvas의 context를 가져와서 그 context에 그림을 그리게 되는 것이다. 먼저 html태그에서 canvas태그를 넣어보자.


<canvas id="canvas1" height="400" width="400">This browser doesn't support canvas</canvas>


:위와 같이 <canvas>태그와 </canvas> 태그 사이에 텍스트를 넣으면 canvas가 호환되지 않는 브라우저에서는 그 텍스트가 보여질 것이다. 그리고 위의 DOM 객체를 가져와서 context를 뽑아낸 다음에 조작하면 된다.


var canvas = document.getElementById("canvas1");
var context = canvas.getContext("2d");


: 그리고 context를 가지고 여러 가지 도형이나 그림을 그리면 된다. 아래는 사각형을 그리거나 텍스트를 써 넣거나, 선을 그리는 기능을 하는 함수의 예이다.


context.fillRect(0,0,150,100);
context.fillText("Hello, HTML5!",155,110);

context.beginPath();
context.moveTo(0,100);
context.lineTo(300,100);

context.rect(0,0,300,200);

context.stroke();

context.closePath();


: context.stroke() 함수는 현재까지 설정한 그림들을 그리는 함수이고, beginPath는 선을 그릴때 시작하는 함수, closePath는 선을 그릴때 닫아서 시작점과 잇는 함수, fillRect는 채워진 사각형을 그리는 함수, rect는 윤곽선만 있는 사각형을 그리는 함수, clearRect는 사각형의 범위를 지우는 함수이다.


: 위의 내용을 구현한 소스는 아래와 같다.


<!DOCTYPE html>
<html lang="ko">
<head>
<script>
	window.onload=function()
	{
		var canvas = document.getElementById("canvas1");
		var context = canvas.getContext("2d");

		context.fillRect(0,0,150,100);
		context.fillText("Hello, HTML5!",155,110);
		context.beginPath();
		context.moveTo(170,200);
		context.lineTo(300,200);

		context.rect(0,0,400,400);

		context.stroke();

		context.closePath();
	};
</script>
</head>
<body>
<canvas id="canvas1" height="400" width="400">This browser doesn't support canvas</canvas>
</body>
</html>


: 그리고 위의 소스를 크롬에서 실행한 결과는 아래와 같다.



: fillRect로 채워진 사각형, fillText로 텍스트, moveTo로 시작점으로 간다음 lineTo로 이은 선, rect로 속이 빈 사각형을 그려준 모습니다.


* 중요

: 여기서 위의 자바스크립트는 window.onload=function(){...} 의 안에서 호출된 것을 볼 수 있다. 이것은 스크립트를 head에 놓는것이 통상적인데 위에서 아래로 컴파일/파싱을 하는 HTML의 특성상, 그냥 위에서 document.getElementById("canvas1")을 실행한다면 아래에 아직 canvas가 로드 되지 않았는데 호출을 하고 있는 셈이 된다. 따라서 페이지가 로드가 완전히 완료되고나서 스크립트를 실행하기 위하여 window.onload 이벤트에 붙여서 호출하는 것이 일반적이다.



* 사각형 그리기

: 사각형을 그리는 함수는 다음과 같다. 

  • strokeRect(x,y,w,h)
  • fillRect(x,y,w,h)
  • clearRect(x,y,w,h)

: 사각형의 테두리만 그리거나 채워진 사각형을 그리거나 사각형 공간을 지우는 함수를 각각 나타낸다. fillRect와 strokeRect의 결과는 아래와 같다.




* 선(Path)그리기

: 선을 그리는 방법은 beginPath로 Path의 시작을 알리고 moveTo로 시작 지점으로 이동한 다음, lineTo 등으로 선을 계속 이어가다가 마지막으로 stroke함수를 호출함으로써 선 그리기를 종료하게 되는 형태이다. 패스 그리기와 연관된 함수들은 다음과 같다.


  • beginPath() : 경로를 그리기 시작
  • moveTo(x,y) : 좌표로 경로를 그리지 않고 이동
  • lineTo(x,y) : 경로를 그리며 좌표로 이동
  • quadraticCurveTo(cpx, cpy, x, y): 중앙 포인트를 향해 굽는 곡선 그리기
                

  • bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y): 2개의 컨트롤 포인트를 가진 베지어 곡선 그리기
                
  • arcTo(x1,y1,x2,y2,radius): 두 점을 잇는 해당하는 반지름 만큼의 곡선을 그림
  • arc(x, y, radius, startAngle, endAngle, antiClockwise): 좌표를 중심으로 반지름 크기의 시작점부터 끝나는 점까지 잇는 곡선을 그림(반시계 또는 시계 방향 설정 가능)
  • closePath(): 현재까지 그린 패스의 끝점과 첫점 이어서 경로를 닫음
  • stroke(): 패스의 선을 그음
  • fill(): 경로의 내부를 색으로 채움

: 아래와 같은 테스트용 소스를 실행하면 결과 화면이 다음과 같다.

<!DOCTYPE html> <html lang="ko"> <head> <script> window.onload=function() { var canvas = document.getElementById("canvas1"); var context = canvas.getContext("2d"); context.beginPath(); context.moveTo(100,100); context.arcTo(200,100,200,200,100); context.lineTo(200,200); context.lineTo(100,200); context.quadraticCurveTo(50,200,50,150); context.bezierCurveTo(50,100,75,75,50,50); context.closePath(); context.stroke(); }; </script> </head> <body> <canvas id="canvas1" height="400" width="400">This browser doesn't support canvas</canvas> </body> </html>






* 선과 채우기 스타일

: 선의 색과 채우기의 스타일도 자바스크립트를 통해 설정할 수 있다. 채우기와 관련된 함수와 속성들은 아래와 같다.

  • strokeStyle
  • lineWidth
  • fillStyle
  • createLinearGradient()
  • createRadialGradient()
  • addColorStop()
  • createPattern()


: 아래는 텍스트와 선과 관련된 함수와 속성을 설정한 간단한 예이다.

		context.strokeStyle = 'blue';
		context.lineWidth = 3;
		context.font = 'italic 60px Calibri';
		context.strokeText('Hello World!', 20, 100);
		context.stroke();



: 위와 같이 소스 코드를 작성면 아래와 같이 선의 색, 선의 굵기, font의 종류와 크기 등이 설정된다.


: 아래는 createLinearGradient를 이용한 간단한 예이다.

		var grd = context.createLinearGradient(0, 0, canvas.width, canvas.height);
		// red
		grd.addColorStop(0, '#FF0000');   
		// blue
		grd.addColorStop(1, '#0000FF');
		context.fillStyle = grd;
		context.rect(0,0,canvas.width,canvas.height);
		context.fill();

		var textGrd = context.createLinearGradient(20, 100, 200, 200);
		// white
		textGrd.addColorStop(0, '#FFFFFF');   
		// black
		textGrd.addColorStop(1, '#000000');
		context.font = 'italic 60px Calibri';
		context.fillStyle = textGrd;
		context.fillText('Hello World!' , 20 , 100);


: 위의 소스를 실행하면 아래와 같이 나타난다. fillStyle을 특정 도형의 바탕 화면 뿐만아니라 텍스트에도 적용 가능한 것을 볼 수 있다. 이외에도 beginPath와 closePath로 이어진 선들도 fill()을 하여 채울수 있다.


: 다음은 또다른 fillStyle인 createPattern의 예를 살펴보자

		var imageObj = new Image();
		imageObj.onload = function() {
		var pattern = context.createPattern(imageObj, 'repeat');
			context.rect(0, 0, canvas.width, canvas.height);
			context.fillStyle = pattern;
			context.fill();
		};
		imageObj.src = 'http://www.ipadwallpapers.org/thumbs/horizontal_wood_pattern_ipad_wallpaper_png-t2.jpg';



: 위와 같이 이미지를 패턴으로 설정하는 소스코드를 실행하면 아래와 같이 실행된다. fillStyle을 바꾸는 것이기 때문에 위의 createLinearGradient와 똑같이 도형이나 텍스트의 fill()함수와 연동하여 사용 가능하다.


* 선그리기 관련 스타일

: 선그리기와 연관된 속성들이 다음과 같다.


    • lineCap = 'butt' (기본), 'round', 'square'
    • lineJoin = 'miter', 'round', 'bevel' (기본)
    • lineWidth


: lineCap을 보여주는 예는 아래와 같다.

      context.lineWidth = 20;
      context.strokeStyle = '#0000ff';

      // butt line cap (top line)
      context.beginPath();
      context.moveTo(100, canvas.height / 2 - 50);
      context.lineTo(canvas.width - 200, canvas.height / 2 - 50);
      context.lineCap = 'butt';
      context.stroke();

      // round line cap (middle line)
      context.beginPath();
      context.moveTo(100, canvas.height / 2);
      context.lineTo(canvas.width - 200, canvas.height / 2);
      context.lineCap = 'round';
      context.stroke();

      // square line cap (bottom line)
      context.beginPath();
      context.moveTo(100, canvas.height / 2 + 50);
      context.lineTo(canvas.width - 200, canvas.height / 2 + 50);
      context.lineCap = 'square';
      context.stroke();



: 위의 소스를 실행하면 아래와 같은 결과로 lineCap의 서로 다른 결과를 확인할 수 있다.



: 아래는 lineJoin의 결과를 보여주는 예이다.

      // set line width for all lines
      context.lineWidth = 25;

      // miter line join (left)
      context.beginPath();
      context.moveTo(99, 150);
      context.lineTo(149, 50);
      context.lineTo(199, 150);
      context.lineJoin = 'miter';
      context.stroke();

      // round line join (middle)
      context.beginPath();
      context.moveTo(239, 150);
      context.lineTo(289, 50);
      context.lineTo(339, 150);
      context.lineJoin = 'round';
      context.stroke();

      // bevel line join (right)
      context.beginPath();
      context.moveTo(379, 150);
      context.lineTo(429, 50);
      context.lineTo(479, 150);
      context.lineJoin = 'bevel';
      context.stroke();



: 위의 소스를 실행하면 아래와 같이 lineJoin의 다른 특성들을 살펴볼 수 있다.



* 텍스트 관련 속성과 함수

: 텍스트와 관련된 속성과 함수는 아래와 같다.

    • font
    • fillText()
    • strokeText()
    • textAlign = 'center', 'right', 'left'
    • textBaseline = 'top', 'haning', 'middle', 'alphabetic', 'ideographic', 'bottom'
    • measureText()


: 아래는 textBaseline과 measureText()를 이용하여 각 textBaseline위치를 알아보는 간단한 예이다.

      var x = 10;
      var y = canvas.height / 2;

      context.beginPath();
      context.moveTo(x,y);
      context.lineTo(canvas.width - 10, y);
      context.stroke();

      context.font = 'bold 20pt Calibri';

      context.textBaseline = 'middle';
      context.fillText('middle', x, y);
      x += context.measureText('middle').width;
      context.textBaseline = 'top';
      context.fillText('top', x, y);
      x += context.measureText('top').width;
      context.textBaseline = 'bottom';
      context.fillText('bottom', x, y);
      x += context.measureText('bottom').width;
      context.textBaseline = 'alphabetic';
      context.fillText('alphabetic', x, y);
      x += context.measureText('alphabetic').width;
      context.textBaseline = 'hanging';
      context.fillText('hanging', x, y);
      x += context.measureText('hanging').width;
      context.textBaseline = 'ideographic';
      context.fillText('ideographic', x, y);


: 위의 소스를 실행하면 아래와 같이 baseline을 기준으로 텍스트가 어디에 위치하게 되는지 알 수 있다.



* 이미지 관련 함수

: 이미지와 관련된 함수는 아래와 같다.

  • drawImage(dx, dy)
  • drawImage(dx, dy, dw, dh)
  • drawImage(sx, sy, sw, sh, dx, dy, dw, dh)

: 첫번째 함수는 이미지의 크기를 그대로 쓰면서 이미지의 캔버스 위의 위치만 설정하는 것이고, 두번째 함수는 이미지의 크기도 설정해주면서 전체 이미지를 캔버스 위에 그리는 함수이다.


: 세번째는 대상 이미지의 일부분을 crop해서 가져온다는 개념으로 아래와 같이 source 이미지의 일부분을 캔버스위에 해당하는 크기에 맞춰서 끼워넣는 것이다.




: 블로그에 올라와있는 사진을 대상으로 간단한 예제를 구현해보면 아래와 같다.

      var imageObj = new Image();

      imageObj.onload = function() {
        // draw cropped image
        var sourceX = 300;
        var sourceY = 300;
        var sourceWidth = 200;
        var sourceHeight = 200;
        var destWidth = sourceWidth;
        var destHeight = sourceHeight;
        var destX = canvas.width / 2 - destWidth / 2;
        var destY = canvas.height / 2 - destHeight / 2;

        context.drawImage(imageObj, sourceX, sourceY, sourceWidth, sourceHeight, destX, destY, destWidth, destHeight);
      };
      imageObj.src = 'https://t1.daumcdn.net/cfile/tistory/1525D93D4F669AA62B';



: 그럼 아래와 같이 이미지의 일부분이 크롭된 것을 알 수 있다.




* 캔버스 뷰포인트 변경

: 캔버스의 뷰포인트를 그래픽에서 처럼 매트릭스를 이용해서 변환할 수 있다. 이러한 뷰포인트 변경과 연관된 함수는 아래와 같다. 아래의 함수들을 전부 context 객체에서 부르게 된다.

    • scale(x, y)
    • rotate(angle)
    • translate(x, y)
    • transform(m11, m12, m21, m22, dx, dy)
    • setTransform(m11, m12, m21, m22, dx, dy)
    • save()
    • restore()

:위의 scale과 rotate등을 적용하려면 아래와 같이 구현할 수 있다.

      var imageObj = new Image();

      imageObj.onload = function() {
        // draw cropped image
        var sourceX = 300;
        var sourceY = 300;
        var sourceWidth = 200;
        var sourceHeight = 200;
        var destWidth = sourceWidth;
        var destHeight = sourceHeight;
        var destX = canvas.width / 2 - destWidth / 2;
        var destY = canvas.height / 2 - destHeight / 2;

        context.rotate(0.5);
        context.scale(0.5,0.7);
        context.drawImage(imageObj, sourceX, sourceY, sourceWidth, sourceHeight, destX, destY, destWidth, destHeight);
      };
      imageObj.src = 'https://t1.daumcdn.net/cfile/tistory/1525D93D4F669AA62B';

: 위 처럼 이미지를 그리기 전에 뷰포인트를 변환해보면 아래와 같이 결과가 달라진다.




* 캔버스 기초를 마치며

: 이렇게 html5 상에서도 다양한 SVG 를 지원하는 그래픽 함수들이 생겨나게 되었다. 기존에 이미지나 플래시에 의존하던 html이 이제는 독립적으로 html과 자바스크립트만으로 다양한 화려한 그래픽 효과를 표현할 수 있게 된것이다. 이렇게 html5가 표준화가 진행되고 모바일 기기에서 flash가 퇴출되면서 웹디자이너들을 기존과 같은 flash와 포토샵 뿐만아니라 이러한 html과 자바스크립트, 거기에 더 화려하고 기능이 많아진 css까지 골고루 알아야할 시대가 올지도 모른다는 생각이 들게 된다.


: 위의 함수들은 기본적인 기능들만 소개했는데 이후 더 자세한 응용방법과 활용방법에 대해 다룰 기회가 생기면 더 깊게 들어가보도록 하겠다. (특히 뷰포인트 변경 함수들이 깊게 파고들어갈만한 주제이다.) 이 캔버스라는 기능이 생긴것 하나만으로 하지만 일단은 전체적인 HTML5의 튜토리얼 리뷰부터 할 것 같다.


: 다음에는 더 편해진 Video와 Audio에 대해서 알아보도록 하자.



* 다음편

2012/11/23 - [HTML5 튜토리얼] Video와 Audio 태그 기본

2012/12/03 - [HTML5 튜토리얼] 새로운 form element 들

2016/05/04 - [HTML5 튜토리얼] Web storage (localStorage, sessionStorage)

2017/01/09 - [HTML5 튜토리얼] navigator.geolocation 위치 정보 수집 API


끝.


공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함