복잡한 선이나 도형 그리기 HTML5



 

복잡한 선이나 도형 그리기

 

 

 

패스(Path)의 개념

- 캔버스의 API를 사용하여 그려진 선들의 집합

- 패스를 구성하는 하나하나의 선을 '서브패스'라고 함

- '서브패스'는 두 개 이상의 점을 직선(혹은 곡선)으로 연결한 하나의 선

 

패스를 이용한 그래픽 표현순서

- 1. beginPath()로 패스 그리기 시작

- 2. 캔버스의 API를 이용하여 패스 그리기

- 3. stroke() / fill()을 이용하여 그래픽을 화면에 표시

 

서브패스를 그리기 위한 API

- moveTo(x, y) : 서브 패스를 그리기 시작할 좌표로 이동(시작 좌표 설정)

- lineTo(x, y) : 현재 좌표와 지정한 좌표를 연결하는 직선을 그린다. 현재좌표는 (x, y)로 이동한다.

예제를 통해 살펴보자.

 

 

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE> HTML5 TEST </TITLE>
</HEAD>
<BODY>
 <canvas id="canvas1" width="300" height="300"></canvas>

 

 <SCRIPT LANGUAGE="JavaScript">
 <!--
 var canvas = document.getElementById("canvas1");
 var context = canvas.getContext("2d");

 

 context.beginPath();

 context.moveTo(0, 0);
 context.lineTo(canvas.width, canvas.height);
 context.stroke();
 //-->
 </SCRIPT>

</BODY>
</HTML>

 

캔버스를 생성하여, 그리기 컨텍스트까지 자바스크립트를 통해 얻어온다.

그리고 beginPath()를 이용해서 그리기를 시작하며, moveTo()를 이용하여 시작좌표값을 설정한다.

lineTo()를 이용해 캔버스의 너비와 높이만큼의 목적지 좌표를 지정하고 stroke() 메서드를 이용하여 선분을 그어준다.

 

이전 예제에선 빼먹었지만, HTML5가 모든 브라우저에서 지원되는게 아니므로 아래와 같이 지원여부에 따라 조건문을 주는것이 좋겠다.

 

if (canvas.getContext){  
  var ctx = canvas.getContext('2d');  
  // drawing code here  
} else {  
  // canvas-unsupported code here  


결과는 아래와 같다 (동일한 결과이므로, 사라피 브라우저의 결과만 보겠다)

 

 

 

직선 하나 그리는건 매우 쉽다. 곡선은 어떻게 하나?

 

 

베지에 곡선을 그리는 API

- quadraticCurveTo(cpx, cpy, x, y)

2차 베지에 곡선을 그린다. 현재 위치와 인수로 전달된 좌표 (x, y)를 연결하는 곡선을 그리고 곡선의 커브는 (cpx, cpy)의 좌표에 따라 결정된다.

 

 

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE> HTML5 TEST </TITLE>
</HEAD>
<BODY>
 <canvas id="canvas1" width="300" height="300"></canvas>

 

 <SCRIPT LANGUAGE="JavaScript">
 <!--
 var canvas = document.getElementById("canvas1");
 var context = canvas.getContext("2d");

 

 context.beginPath();

 context.moveTo(0, 0);
 context.quadraticCurveTo(50, 100, 100, 0);
 context.stroke();
 //-->
 </SCRIPT>

</BODY>
</HTML>

 

 

2차 베지어 곡선을 그리는 예제코드이다. 실행해보자.

 

 

위 그림에서처럼, 2차 베지어 곡선이 출력되었다. 이것은 마치 어도비 일러스트레이터에서의 백터그래픽을 그리는것과 같다.

이 곡선이 그려지는 원리를 살펴보자.

 

 

그림만 봐도 이해가 되었을거라 믿는다.

좀 더 어드밴스한 코드를 살펴보자. 나도 지금 처음 해본다 -_-;

위의 예제코드에서 아래의 빨간부분 한 라인만 교체한 것이다.

 

 

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE> HTML5 TEST </TITLE>
</HEAD>
<BODY>
 <canvas id="canvas1" width="300" height="300"></canvas>

 <SCRIPT LANGUAGE="JavaScript">
 <!--
 var canvas = document.getElementById("canvas1");
 var context = canvas.getContext("2d");

 

 context.beginPath();

 context.moveTo(0, 0);
 context.bezierCurveTo(0, 100, 100, 0, 100, 100);
 context.stroke();
 //-->
 </SCRIPT>

</BODY>
</HTML>

 

요놈이 무언지 살펴보자

- bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)

   3차 베지에 곡선을 그린다. 제어점은 인수로 전달된 세 곳의 좌표와 현재 좌표가 된다.

  

흠... 뭔가 어려워 보이는데?

그렇지 않다. 결과를 살펴보고, 위처럼 자세히 살펴보자.

 

 

예제를 실행한 결과이다. (응?)

가이드를 좀 보고 이해해보자.

 

 

오호라~ 이제 좀 알것 같다. 알것 같긴한데 막상 쓸려면 보고 해봐야겠다는 생각이 든다;;; 털썩;;;

악. 점점 더 복잡해지는 느낌이 든다. 이번엔 원호를 그려보자.

원호가 사람이냐고? 아.. 아니... 그.. .그게 아니고...

원은 알지? 원의 일부를 잘라내어 그려논거 그게 바로 원호라는거란다.

그래도 모르면 실행결과를 보면 알거다 -_-;

 

 

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE> HTML5 TEST </TITLE>
</HEAD>
<BODY>
 <canvas id="canvas1" width="300" height="300"></canvas>

 <SCRIPT LANGUAGE="JavaScript">
 <!--
 var canvas = document.getElementById("canvas1");
 var context = canvas.getContext("2d");

 

 context.beginPath();

 context.moveTo(0, 100);
 context.arcTo(25, 25, 100, 100, 25);
 context.stroke();
 //-->
 </SCRIPT>

</BODY>
</HTML>

 

 

종전의 예제에서 바뀐 부분만 빨간색으로 표시하였다.

시작점을 약간 수정하였고, 사용된 메서드가 달라졌다. 아크투가 뭐지?

 

- arcTo(x1, y1, x2, y2, radius)

직선과 이에 접하는 원호를 그린다. 현재 좌표와 (x1, y1)을 연결하는 직선, 그리고 (x1, y1)과 (x2, y2)를 연결하는 직선이 있고, 그 두 직선을 동시에 접하는 반지름(radius)의 원이 있다고 가정한다. (접점은 두개가 된다)

이 메서드는 현재 좌표에서 처음 접점까지를 연결하는 직선과 두개의 접점을 연결하는 원호를 그리면서 종료된다.

아. 말이 어렵다. 결과를 보자.

 

 

응? 어떻게 그려진거지?

가이드와 함께 보면 좀 더 이해가 쉬울것 같다.

 

 

 

계속해서 진도 나가보자.

이번엔 직선을 제외한 원호만을 그려보자. 프로토타입은 아래와 같다.

 

- arc(x, y, radius, startAngle, endAngle, anticlockwise);

이 메서드를 이용하여 완벽한 원을 그릴수도 있고, 원의 일부... 즉 원호만 그릴수도 있다.

(x, y)는 원의 중심이 되며 radius는 알다시피 반지름의 값이다. startAngle과 endAngle은 그리기를 시작하고 종료하는 각도이며, 라디안에 따른 지정이 필요하다.

(라디언이란건 각도에 대한 변환공식으로 예를들어 90도 라고 가정할 경우, 90 * Math.PI / 180 으로 계산한다.)

anticlockwise는 그릴 방향을 나타내는 것으로 true로 지정하면 시계반대방향으로 원호를 그린다. 또한 이미 서브 패스가 있다면 그 서비 패스의 끝점에서 원호의 시작점까지의 직선이 자동으로 그어진다.

아놔. 설명이 역시 길다. 예제 후딱 보자.

 

 

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE> HTML5 TEST </TITLE>
</HEAD>
<BODY>
 <canvas id="canvas1" width="300" height="300"></canvas>

 <SCRIPT LANGUAGE="JavaScript">
 <!--
 var canvas = document.getElementById("canvas1");
 var context = canvas.getContext("2d");

 

 context.beginPath();

 context.arc(200, 200, 100, 0, 90 * Math.PI / 180, false);
 context.stroke();
 //-->
 </SCRIPT>

</BODY>
</HTML>

 

그려질 원의 중심은 (200, 200)으로, 반지름은 100 이다.

그리고 그려질 부분의 각도는 90도이며, 라디언 변환을 사용해야 하므로, 위와 같이 표현했다.

마지막 인자는 3시 부분부터 시작해서 시계방향으로 그려지게 하기 위함이다. 3시에서 90도 시계방향이면....

그냥 결과를 보자.

 

 

이것이 바로 3시에서 시계방향으로 90도 그려진 결과이다.

false말고 true로 하면 어떻게 되는지 궁금한 사람을 위해 아래를 보자.

 

 

사실 나도 궁금해서 실행해본것이다. 크허허허허.

시계반대방향으로 그려졌다. 90도를 지정한것이 무색할 정도의 결과가 나타났다. 두둥...

그럼 원은 어떻게 그리나?

 

 

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE> HTML5 TEST </TITLE>
</HEAD>
<BODY>
 <canvas id="canvas1" width="300" height="300"></canvas>

 <SCRIPT LANGUAGE="JavaScript">
 <!--
 var canvas = document.getElementById("canvas1");
 var context = canvas.getContext("2d");

 

 context.beginPath();

 context.arc(200, 200, 100, 0, 2 * Math.PI, true);
 context.stroke();
 //-->
 </SCRIPT>

</BODY>
</HTML>

 

 

원은 endAngle부분의 인자에 2파이를 지정하여 완전한 원을 그려낼 수 있다.

결과는 아래에...

 

 

 

부채꼴도 그리고 싶은가? 뭐 이렇게 그리고 싶은게 많은가?

적당히 그리길 바란다. 다음은 부채꼴 그리기의 예제이다.

 

 

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE> HTML5 TEST </TITLE>
</HEAD>
<BODY>
 <canvas id="canvas1" width="300" height="300"></canvas>

 <SCRIPT LANGUAGE="JavaScript">
 <!--
 var canvas = document.getElementById("canvas1");
 var context = canvas.getContext("2d");

 

 context.beginPath();

 context.moveTo(50, 50);
 context.arc(100, 100, 50, 0, 90 * Math.PI / 180, false);
 context.closePath();
 context.stroke();

 //-->
 </SCRIPT>

</BODY>
</HTML>

 

눈여겨 볼 부분은 역시 빨간부분이다.

일단 아까와 같이 원호를 그려준다. 이전에 moveTo()를 이용해 이동을 했기때문에 중앙과 원호의 시작점은 자동으로 연결된다.

그리고 closePath() 메서드를 이용하여 원호의 종료지점부터 다시 중앙점으로 연결된다.

 

결과는?? (간밤에 먹다남긴 피자가 생각나는가?)

 

 

오호. 이제 이런저런 도형은 다 그리긴 했는데.. 뭔가 아쉽다...

왜일까...

지금껏 그려온건 모두 stroke()메서드로 선만 그었기 때문일것이다. 우리가 고작 선만 그리자고 이딴짓을 하는건 아니지 않은가.

내부를 채우는 방법을 알아보자.

 

 

패스를 기준으로 그래픽을 나타내기 위한 API

 

아까 보았듯이 stroke()는 선분을 이용해서 출력하겠다는 의미이다. 선분 말고도 다른 것들이 몇개 있다.

- stroke()

패스를 선으로 표시한다. 이때 선의 스타일이나 색은 추후에 다시 살펴볼 것이다.

 

- fill()

패스 내부를 채운다. 채울 색이나 스타일은 역시 뒤에 설명할것이다. 조금만 참자.

 

- clip()

패스의 내부를 클리핑 영역으로 지정한다. (응?)

클리핑 영역이란것은 마치 '가'모양으로 구멍이나 종이를 대고선 스프레이를 뿌려주는것과 같다. 처리가 되어질 영역을 지정하는 것이 바로 클리핑영역의 지정인 것이다. 앞서 배웠던 도형을 그린뒤, 이 모양대로 클리핑 영역을 설정하여 내부에 대한 채움처리를 하는것이다.

위에 대한 설명이 이해가 되지 않는다면, 날 원망.... 하진 말자. 책을 쓴 사람을 탓하자.

원망을 하기 전에 앞서 예제를 살펴보자.

 

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE> HTML5 TEST </TITLE>
</HEAD>
<BODY>
 <canvas id="canvas1" width="300" height="300"></canvas>

 <SCRIPT LANGUAGE="JavaScript">
 <!--
 var canvas = document.getElementById("canvas1");
 var context = canvas.getContext("2d");

 

 context.beginPath();

 context.moveTo(50, 50);
 context.arc(85, 160, 50, 0, 2 * Math.PI, true);
 context.clip();

 

 var image = new Image();
 image.onload = function() {
  context.drawImage(image, 0, 0, canvas.width, canvas.height);
 };

 image.src = "0.jpg";
 //-->
 </SCRIPT>

</BODY>
</HTML>

 

예제코드가 앞서 본것과는 좀 다르다. 뭔가 어드밴스 해진 느낌이다.

그만큼 실력도 어드밴스 해지는 것이다. 아니면 말고 -_-

 

예제에서는 원을 그렸다. 그리긴 했지만 사실 출력한 적은 없다. arc()를 이용해 그리기만 했을뿐.

그리고선 클리핑 영역을 지정하였고...

 

이미지 객체를 생성하여, 이미지가 로드되면 익명메서드를 실행하도록 설정했다.

우리가 로드할 이미지는 얼마전 주차딱지가 붙은채 날라왔던 강남구청의 주차단속반의 선물(?)이다.

이것은 바로 32,000원짜리 사진의 일부분이다. ㅠㅠ

 

눈물나는 결과를 보자.

 

 

이런식으로 클리핑 영역에만 이미지의 영향이 끼치게 되었다.

실행결과를 보면 클리핑 영역이란것이 무엇인지, 코드가 어떤 결과를 가져오는지 이해할 수 있으리라 믿는다.

 

다음시간에는 선과 채우기에 대한 스따~일을 지정하는 법에 대해 배우겠다.

기대가 된다면 손번쩍 들어주길 바란다. 


덧글

  • 박병은 2012/01/16 20:26 # 삭제 답글

    좋은 정보 감사합니다 농사꾼 봉팔씨
  • 농사꾼봉팔 2012/01/17 16:02 # 삭제

    본 정보는 금품을 요구합니다.
    박병은씨는 이번주말에 저에게 현금으로 완납해 주시기 바랍니다.
    감사합니다.
  • green7nigh 2012/01/20 12:04 # 삭제 답글

    좋은 정보 감사합니다 ㅎ 회사분을 이런 곳에서 뵙긴 처음이네요.
댓글 입력 영역


통계 위젯 (화이트)

1622
132
358626

red 210