Canvas - 03

이강민·2022년 1월 3일
0

[혼공]Canvas

목록 보기
3/12
post-thumbnail

캔버스(canvas)를 이용한 도형 그리기 - 02

베지어(Bezier) 곡선과 이차(Quadratic )곡선

이 경로타입은 베지어 곡선으로 삼차와 이차 변수가 모두 가능하다.
이 타입은 대게 복잡한 유기체적 형태를 그리는데 사용된다.

아래의 함수에서 당연히 시작점은 moveTo나 마지막으로 설정된 값이다.

  • quadraticCurveTo(cp1x, cp1y, x, y)
    • cp1x 및 cp1y로 지정된 제어점을 사용하여 현재 펜의 위치에서 x와 y로 지정된 끝점까지 이차 베지어 곡선을 그린다.
  • bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
    • (cp1x, cp1y) 및 (cp2x, cp2y)로 지정된 제어점을 사용하여 현재 펜 위치에서 x 및 y로 지정된 끝점까지 삼차 베지어 곡선을 그린다.

위 사진은 두 곡선의 차이를 설명한다.
이차 베지에 곡선은 시작점과 끝점(파란점) 그리고 하나의 제어점(빨간점)을 가지고 있지만 삼차 베지에는 곡선은 두개의 제어점을 가지고 있다.

두 메소드에 모두 사용되는 x와 y의 변수는 모두 '끝점'의 좌표를 나타낸다. 첫번째 제어점은 cp1x, cp2y좌표, 두번째 제어점은 cp2x, cp2y 좌표로 표시되어있다.

이차 베지어 곡선 그리기

 function draw(){
        let canvas = document.getElementById('canvas');
        if(canvas.getContext){
            let ctx = canvas.getContext('2d');

            //베지에 곡선도 beginPath로 열어준다.
            ctx.beginPath();
            //최초 위치를 잡고
            ctx.moveTo(75,25);
            //제어점 x,y 위치와 끝점 x,y를 잡는다.
            ctx.quadraticCurveTo(25,25, 25, 62.5);
            ctx.quadraticCurveTo(25,100,50,100);
            ctx.quadraticCurveTo(50,120,30,125);
            ctx.quadraticCurveTo(60,120,65,100);
            ctx.quadraticCurveTo(125,100,125,62.5);
            ctx.quadraticCurveTo(125,25,75,25);

            ctx.stroke();
        }
    }
    draw();

삼차 베지어 곡선(Cubic Bezier curves) 그리기

function draw(){
        let canvas = document.getElementById('canvas');
        if(canvas.getContext){
            let ctx = canvas.getContext('2d');

            //경로 열어주고 
            ctx.beginPath();
            //최초위치 잡고
            ctx.moveTo(75,40);
            //첫번째 제어, 두번째 제어, x,y를 이용하여 그린다.
            ctx.bezierCurveTo(75,37,70,25,50,25);
            ctx.bezierCurveTo(20,25,20,62.5,20,62.5);
            ctx.bezierCurveTo(20,80,40,102,75,120);
            ctx.bezierCurveTo(110,102,130,80,130,62.5);
            ctx.bezierCurveTo(130,62.5,130,25,100,25);
            ctx.bezierCurveTo(85,25,75,37,75,40);
            ctx.fill();
        }
    }

직사각형

직사각형을 캔버스에 직접 그리는 직사각형 그리기에서 본 세 가지 메소드(fillRect, strokeRect, clearRect) 외에 rect() 메소드도 있다. 이 메소드는 현재 열린 패스에 직사각형 경로를 추가한다.

  • rect(x,y, width, height)
    • 좌측상단이 x,y이고 폭과 너비가 width와 height인 직사각형을 그린다.

이 메소드가 실행되기 전에 x,y매개변수를 가진 moveTo() 메소드가 자동 호출된다.

조합하기

function draw(){
        let canvas = document.getElementById('canvas');
        if(canvas.getContext){
            let ctx = canvas.getContext('2d');

            //모서리가 둥근 사각형은 반복이 되니 함수를 만들어 관리한다.
            roundedRect(ctx, 12, 12, 150, 150, 15);
            roundedRect(ctx, 19, 19, 150, 150, 9);
            roundedRect(ctx, 53, 53, 49, 33, 10);
            roundedRect(ctx, 53, 119, 49, 16, 6);
            roundedRect(ctx, 135, 53, 49, 33, 10);
            roundedRect(ctx, 135, 119, 25, 49, 10);

            //주인공
            ctx.beginPath();
            ctx.arc(37,37, 13, Math.PI / 7, -Math.PI / 7, false)
            ctx.lineTo(31,37)
            ctx.fill();

            //가로 먹이
            for(let i = 0; i < 8; i++){
                ctx.fillRect(51+i*16, 35, 4, 4)
            }
            //세로 먹이
            for(let i = 0; i < 6; i++){
                ctx.fillRect(115, 51+i*16, 4,4 )
            }
            //가로 먹이2
            for(let i = 0; i < 8; i++){
                ctx. fillRect(51+i*16, 99, 4, 4)
            }

            //유령의 겉모습
            ctx.beginPath();
            ctx.moveTo(83,116);
            ctx.lineTo(83,102);
            ctx.bezierCurveTo(83,94,89,88,97,88);
            ctx.bezierCurveTo(105,88,111,94,111,102);
            ctx.lineTo(111,116)
            ctx.lineTo(106.333, 111.333);
            ctx.lineTo(101.666, 116);
            ctx.lineTo(97, 111.333);
            ctx.lineTo(92.333, 116);
            ctx.lineTo(87.666, 111.333);
            ctx.lineTo(83, 116);
            ctx.fill();

            //유령의 눈 흰자
            ctx.fillStyle = 'white';
            ctx.beginPath();
            ctx.moveTo(91,96);
            ctx.bezierCurveTo(88,96,87,99,87,101);
            ctx.bezierCurveTo(87, 103, 88, 106, 91, 106);
            ctx.bezierCurveTo(94, 106, 95, 103, 95, 101);
            ctx.bezierCurveTo(95, 99, 94, 96, 91, 96);
            ctx.moveTo(103,96);
            ctx.bezierCurveTo(100, 96, 99, 99, 99, 101);
            ctx.bezierCurveTo(99, 103, 100, 106, 103, 106);
            ctx.bezierCurveTo(106, 106, 107, 103, 107, 101);
            ctx.bezierCurveTo(107, 99, 106, 96, 103, 96);
            ctx.fill();

            //유령의 눈동자
            ctx.fillStyle = "black";
            ctx.beginPath();
            ctx.arc(101, 102, 2, 0, Math.PI * 2, true);
            ctx.fill();
            ctx.beginPath();
            ctx.arc(89, 102, 2, 0, Math.PI * 2, true);
            ctx.fill();
        }
    }

    function roundedRect(ctx, x, y, width, height, radius){
        ctx.beginPath();
        
        ctx.moveTo(x,y+radius)
        ctx.lineTo(x,y+height - radius)
        ctx.arcTo(x,y+height, x+radius, y+height, radius)
        ctx.lineTo(x+width-radius, y+height)
        ctx.arcTo(x + width, y + height, x + width, y + height-radius, radius)
        ctx.lineTo(x + width, y + radius);
        ctx.arcTo(x + width, y, x + width - radius, y, radius);
        ctx.lineTo(x + radius, y);
        ctx.arcTo(x, y, x, y + radius, radius);
        ctx.stroke()
    }
    draw();

위와 같이 유틸리티 함수를 만들어 사용하면 반복되는 모양을 찍어낼 수 있기 때문에 활용하는 것이 좋다.

Path2D 오브젝트 (Path2D objects)

캔버스에 객체를 그리는 일련의 경로와 그리기 명령이 있을 수 있다. 코드를 단순화하고 성능을 향상키기기 위해 최근 버전 브라우저에서 사용 할 수 있는 Path2D객체를 사용하여 이러한 드로잉명령을 캐시하거나 기록 할 수 있다.

  • Path()
    • Path2D() 생성자는 새로운 Path2D 객체를 반환한다. 선택적으로 다른 경로를 인수로 받거나(복사본을 생성), SVG 경로 데이터로 구성된 문자열을 받아서 객체로 반환한다.
new Path2D();     // empty path object
new Path2D(path); // copy from another Path2D object
new Path2D(d);    // path from SVG path data

moveTo, rect, arc 혹은 quadraticCurveTo 등과 같은 모든 경로 메소드 (path methods)들은 Path2D 객체에서 사용 가능합니다.

Path2D API는 또한 addPath 메소드를 사용하여 경로를 결합하는 방법을 추가합니다. 예를 들자면, 여러 요소를 사용하는 오브젝트를 만들 때 유용하게 사용 될 수 있습니다.

  • Path2D.addPath(path [, transform])
    • 옵션으로 변환 행렬(transformation matrix)을 사용하여 현재 경로에 경로를 추가한다.

클래스화처럼 new Path2D()생성자를 통해 변수를 저장하고 객체를 생성한다음 stroke나 fill의 인자로 넘겨주면 마치 찍어내듯 만들 수 있구나!

function draw(){
        let canvas = document.getElementById('canvas');
        if(canvas.getContext){
            let ctx = canvas.getContext('2d');

            //마치 클래스화 처럼 찍어낼 수 있다
            // 객체로 저장을 하는구나!
            let rectangle = new Path2D();
            rectangle.rect(10,10,50,50);

            let circle = new Path2D();
            circle.arc(100,35,25,0,Math.PI * 2, true)

            ctx.stroke(rectangle);
            ctx.fill(circle)
        }
    }
    draw();
profile
배움은 끝없이

0개의 댓글