ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Canvas(3)_스타일과 색 적용
    Canvas 2022. 10. 13. 11:10

    해당 게시글은 2022.03.10에 깃허브로 작성되었습니다.

     


     

    1. 색상

    아래에서의 color는 CSS의 <color>, 그라디언트 객체, 패턴 객체를 뜻한다.

    윤곽선과 채움 색의 초기 설정값은 검은 색이다.

    strokeStyle 또는 fillStyle 속성을 설정하면, 새로 설정된 값이 앞으로 그려질 도형의 기본 값이 된다.
    각 도형에 다른 색을 적용하려면 strokeStyle 또는 fillStyle 속성을 다시 적용해야 한다.

     

    (1) fillStyle = color

    도형을 채우는 색을 설정한다.

    function draw() {
      var ctx = document.getElementById('canvas').getContext('2d');
      for (var i = 0; i < 6; i++){
        for (var j = 0; j < 6; j++){
          ctx.fillStyle = 'rgb(' + Math.floor(255 - 42.5 * i) + ', ' +
                           Math.floor(255 - 42.5 * j) + ', 0)';
          ctx.fillRect(j*25,i*25,25,25);
        }
      }
    }

     

    (2) strokeStyle = color

    도형의 윤곽선 색을 설정한다.

    function draw() {
      var ctx = document.getElementById('canvas').getContext('2d');
      for (var i = 0; i < 6; i++) {
        for (var j = 0; j < 6; j++) {
          ctx.strokeStyle = 'rgb(0, ' + Math.floor(255 - 42.5 * i) + ', ' +
                           Math.floor(255 - 42.5 * j) + ')';
          ctx.beginPath();
          ctx.arc(12.5 + j * 25, 12.5 + i * 25, 10, 0, Math.PI * 2, true);
          ctx.stroke();
        }
      }
    }

     


     

    2. 투명도

    canvas에는 불투명한 도형도, 반투명한 도형도 그릴 수 있다.

     

    (1) globalAlpha = transparencyValue

    투명도값이 설정되면 이후 canvas에 그려지는 모든 도형들의 투명도가 바뀐다.

    설정하는 값은 0.0(완전히 투명)과 1.0(완전히 불투명) 사이에 있어야 하며, 초기 설정값은 1.0(완전히 불투명)이다.

    function draw() {
      var ctx = document.getElementById('canvas').getContext('2d');
      // 배경을 그린다
      ctx.fillStyle = '#FD0';
      ctx.fillRect(0, 0, 75, 75);
      ctx.fillStyle = '#6C0';
      ctx.fillRect(75, 0, 75, 75);
      ctx.fillStyle = '#09F';
      ctx.fillRect(0, 75, 75, 75);
      ctx.fillStyle = '#F30';
      ctx.fillRect(75, 75, 75, 75);
      ctx.fillStyle = '#FFF';
    
      // 투명값을 설정한다
      ctx.globalAlpha = 0.2;
    
      // 반투명한 원을 그린다
      for (var i = 0; i < 7; i++){
        ctx.beginPath();
        ctx.arc(75, 75, 10 + 10 * i, 0, Math.PI * 2, true);
        ctx.fill();
      }
    }

     


     

    3. 선 모양

    (1) lineWidth = value

    이후 그려질 선의 두께를 정한다. 설정값은 반드시 양수여야 하며, 초기 설정값은 1.0 단위이다.

     

    선의 두께는 지정된 경로의 가운데에 있는 획의 두께이다.

    즉, 경로의 좌우로 설정된 두께 반만큼의 폭 영역이 그려진다는 것이다.

    function draw() {
      var ctx = document.getElementById('canvas').getContext('2d');
      for (var i = 0; i < 10; i++){
        ctx.lineWidth = 1 + i;
        ctx.beginPath();
        ctx.moveTo(5 + i * 14, 5);
        ctx.lineTo(5 + i * 14, 140);
        ctx.stroke();
      }
    }

    그러나 위 예제처럼 경로의 위치 때문에 가장 왼쪽과 다른 모든 홀수 폭 두께 선선명하게 보이지 않을 수 있으므로 아래의 과정과 논리를 이해해야 한다.

     

    아래의 이미지를 보면 격자는 canvas의 좌표를 나타낸다. 격자선 사이에 있는 사각형은 실제 픽셀과 딱 맞아 떨어진다.

    (1) 위에 있는 첫번째 이미지를 보면 (2, 1)에서 (5, 5)로 사각형이 채워져 있고  이 사각형은 픽셀 경계선 사이에 딱 맞아 떨어지기에 채워진 사각형이 선명한 가장자리를 가진다.

    (2) 만일 (3, 1)에서 (3, 5)로 그리는 직선의 두께가 1.0이라면, 두번째 이미지와 같은 상황이 된다.
    채워진 실제 영역(진한 파란색)은 패스의 양쪽에 있는 픽셀의 절반까지만 확장된다.
    이건 1px을 채우는 것이 아니므로 근사값으로 화면에 그려지게 되기에 양옆의 영역으로 실제 설정한 색과는 다른 흐릿한 색으로 채워지는 것이다.

    (3) 이렇게 되는 것을 막으려면 경로를 아주 정밀하게 생성해야 하는데, 선의 두께가 1.0 이라면 경로의 양쪽으로 0.5 단위 만큼이라는 것을 알고 있으니 (3.5, 1) 에서 (3.5, 5)로 그리는 경로를 생성하면 세번째 이미지와 같이 완벽히 정밀하게 1px 두께의 수직선이 된다.

    + 짝수 두께의 선들은 반으로 나누어도 각각의 반은 정수의 양만큼이기 때문에 픽셀을 조정할 필요가 없다.

     

    (2) lineCap = type

    선의 끝모양을 설정한다. 초기 설정값은 butt이다.

     

    function draw() {
      var ctx = document.getElementById('canvas').getContext('2d');
      var lineCap = ['butt','round','square'];
    
      // 안내선을 그린다
      ctx.strokeStyle = '#09f';
      ctx.beginPath();
      ctx.moveTo(10, 10);
      ctx.lineTo(140, 10);
      ctx.moveTo(10, 140);
      ctx.lineTo(140, 140);
      ctx.stroke();
    
      // 선을 그린다
      ctx.strokeStyle = 'black';
      for (var i=0;i<lineCap.length;i++){
        ctx.lineWidth = 15;
        ctx.lineCap = lineCap[i];
        ctx.beginPath();
        ctx.moveTo(25 + i * 50, 10);
        ctx.lineTo(25 + i * 50,140);
        ctx.stroke();
      }
    }

    - butt
    선의 끝이 좌표에 딱맞게 잘린다.

    - round
    선의 끝이 동그랗다.

    - square
    선 끝에 선 두께 반만큼의 사각형 영역이 더해진다.

     

    (3) lineJoin = type

    선들이 만나는 '모서리'의 모양을 설정한다. (끝점과 제어점이 정확히 같은 위치인, 길이가 0인 부분들은 제외된다.)

    초기 설정값은 miter이며 두 부분들이 같은 방향으로 연결되어 있는 경우에는, lineJoin을 설정해도 아무런 효과가 나타나지 않는다.

    function draw() {
      var ctx = document.getElementById('canvas').getContext('2d');
      var lineJoin = ['round', 'bevel', 'miter'];
      ctx.lineWidth = 10;
      for (var i=0;i<lineJoin.length;i++){
        ctx.lineJoin = lineJoin[i];
        ctx.beginPath();
        ctx.moveTo(-5, 5 + i * 40);
        ctx.lineTo(35, 45 + i * 40);
        ctx.lineTo(75, 5 + i * 40);
        ctx.lineTo(115, 45 + i * 40);
        ctx.lineTo(155, 5 + i * 40);
        ctx.stroke();
      }
    }

    - round
    도형의 모서리를, 연결되는 부분들의 공통 끝점을 중심으로 하는 원 모양으로 만든다. 이 때 원의 반지름은 선의 두께와 같다.

    - bavel
    도형의 모서리를, 연결되는 부분들의 공통 끝점에서 세모 모양으로 만든다.

    - miter
    도형의 모서리를, 두 부분의 바깥쪽 테두리 선을 각각 연장하여 교차된 점으로 생긴 마음모꼴 모양으로 만든다. miterLimit 속성값에 따라 모양이 달라진다.

     

    + miterLimit(초기 설정값 10.0)

    끝점이 만나는 지점과 테두리 연장선이 만나는 지점이 얼마나 떨어져 있을지를 결정한다.

    두 선이 이 값을 넘게 되면, lineJoin 속성의 bavel값 모양이 적용된다.

     

    즉, 현재 좌표 방식 안에서 선의 두께에 따라 어느 정도까지 뾰족해질 수 있을지가 계산된다.

     

    (4) miterLimit = value

    두 선이 예각으로 만날 때 접합점의 두께를 제어할 수 있도록 연결부위의 크기를 제한하는 값을 설정한다.

    miterLimit = max miterLength / lineWidth = 1 / sin ( min θ / 2 )

     

    (5) getLineDash()

    음수가 아닌 짝수를 포함하는 현재 선의 대시 패턴 배열을 반환한다.

     

    (6) setLineDash(segments)

    현재 선의 대시 패턴을 설정한다.

     

    (7) lineDashOffset = value

    선의 대시 배열이 어디서 시작될지 지정한다.

    var ctx = document.getElementById('canvas').getContext('2d');
    var offset = 0;
    
    function draw() {
      ctx.clearRect(0, 0, canvas.width, canvas.height);
      ctx.setLineDash([4, 2]);
      ctx.lineDashOffset = -offset;
      ctx.strokeRect(10, 10, 100, 100);
    }
    
    function march() {
      offset++;
      if (offset > 16) {
        offset = 0;
      }
      draw();
      setTimeout(march, 20);
    }
    
    march();

     


     

    4. 그라디언트(Gradient)

    포토샵, 일러스트 등과 같이 선형 및 원형 그라디언트를 사용할 수 있다.

     

    (1) createLinearGradient(x1, y1, x2, y2)

    시작점 좌표를 (x1, y1)로 하고, 종료점 좌표를 (x2, y2)로 하는 선형 그라디언트 오브젝트를 생성한다.

    function draw() {
      var ctx = document.getElementById('canvas').getContext('2d');
    
      // 그라디언트를 생성한다
      var lingrad = ctx.createLinearGradient(0, 0, 0, 150);
      lingrad.addColorStop(0, '#00ABEB');
      lingrad.addColorStop(0.5, '#fff');
      lingrad.addColorStop(0.5, '#26C000');
      lingrad.addColorStop(1, '#fff');
    
      var lingrad2 = ctx.createLinearGradient(0, 50, 0, 95);
      lingrad2.addColorStop(0.5, '#000');
      lingrad2.addColorStop(1, 'rgba(0, 0, 0, 0)');
    
      // 외곽선과 채움 스타일에 그라디언트를 적용한다
      ctx.fillStyle = lingrad;
      ctx.strokeStyle = lingrad2;
    
      // 도형을 그린다
      ctx.fillRect(10, 10, 130, 130);
      ctx.strokeRect(50, 50, 50, 50);
    
    }

     

    (2) createRadialGradient(x1, y1, r1, x2, y2, r2)

    반지름이 r1이고 좌표 (x1, y1)을 중심으로 하는 원과, 반지름이 r2이고 좌표 (x2, y2)를 중심으로 하는 원을 사용하여 그라디언트가 생성된다.

    function draw() {
      var ctx = document.getElementById('canvas').getContext('2d');
    
      // 그라디언트를 생성한다
      var radgrad = ctx.createRadialGradient(45,45,10,52,50,30);
      radgrad.addColorStop(0, '#A7D30C');
      radgrad.addColorStop(0.9, '#019F62');
      radgrad.addColorStop(1, 'rgba(1,159,98,0)');
    
      var radgrad2 = ctx.createRadialGradient(105,105,20,112,120,50);
      radgrad2.addColorStop(0, '#FF5F98');
      radgrad2.addColorStop(0.75, '#FF0188');
      radgrad2.addColorStop(1, 'rgba(255,1,136,0)');
    
      var radgrad3 = ctx.createRadialGradient(95,15,15,102,20,40);
      radgrad3.addColorStop(0, '#00C9FF');
      radgrad3.addColorStop(0.8, '#00B5E2');
      radgrad3.addColorStop(1, 'rgba(0,201,255,0)');
    
      var radgrad4 = ctx.createRadialGradient(0,150,50,0,140,90);
      radgrad4.addColorStop(0, '#F4F201');
      radgrad4.addColorStop(0.8, '#E4C700');
      radgrad4.addColorStop(1, 'rgba(228,199,0,0)');
    
      // 도형을 그린다
      ctx.fillStyle = radgrad4;
      ctx.fillRect(0,0,150,150);
      ctx.fillStyle = radgrad3;
      ctx.fillRect(0,0,150,150);
      ctx.fillStyle = radgrad2;
      ctx.fillRect(0,0,150,150);
      ctx.fillStyle = radgrad;
      ctx.fillRect(0,0,150,150);
    }

    안쪽 원과 바깥쪽 원은 겹치지 않게 하는 편이 좋다고 한다.
    투명도가 적용된 지점에서 이전 지점까지의 색 변화를 보기 좋게 만드려면, 두 지점에 똑같은 색을 적용하면 된다.

      CanvasGradient 객체를 만들었다면, addColorStop() 메서드를 사용하여, 오브젝트에 색을 적용할 수 있다.

     

    (3) gradient.addColorStop(position, color)

    gradient 오브젝트에 새로운 색 중단점(color stop)을 생성한다.

    position0.0에서 1.0 사이의 숫자이고 gradient에서 색상의 상대적인 위치를 정의하며

    color 인자는 gradient가 진행되면서 도달한 지점의 색상을 의미한다.

     

    색 중단점은 원하는만큼 마음대로 추가할 수 있다.

     


     

    5. 패턴(Patterns) -  createPattern(image, type)

    새 canvas 패턴 객체를 만들어 반환한다.

     

    image는 CanvasImageSource(HTMLImageElement, 다른 canvas, <video> 요소 등등)이다.

    type이미지 사용방법을 나타내는 문자열이다. 문자열값은 아래 중 하나여야 한다.

    - repeat
    수직 및 수평 방향으로 이미지를 이어 붙인다.

    - repeat-x
    수평 방향으로만 이미지를 이어 붙인다.

    - repeat-y
    수직 방향으로만 이미지를 이어 붙인다.

    - no-repeat
    이미지를 이어 붙이지 않는다. 즉, 이미지는 한번만 사용된다.

     

    패턴을 생성하면 fillStyle 또는 strokeStyle 속성에 패턴을 할당할 수 있다.

    function draw() {
      var ctx = document.getElementById('canvas').getContext('2d');
    
      // 패턴으로 사용할 이미지 오브젝트를 생성한다
      var img = new Image();
      img.src = 'https://mdn.mozillademos.org/files/222/Canvas_createpattern.png';
      img.onload = function() {
    
        // 패턴을 생성한다
        var ptrn = ctx.createPattern(img,'repeat');
        ctx.fillStyle = ptrn;
        ctx.fillRect(0,0,150,150);
    
      }
    }

     


     

    6. 그림자

    (1) shadowOffsetX = float

    그림자가 객체에서 연장되어야 하는 수평 거리를 나타낸다. 이 값은 변환 행렬의 영향을 받지 않으며 기본값은 0이다.

     

    (2) shadowOffsetY = float

    그림자가 객체에서 연장되어야 하는 수직 거리 를 나타내며 기본값은 0이다.

     

    위 두 속성은 음수값을 사용하면 그림자가 위로 또는 왼쪽으로 확장되고

    양수값을 사용하면 그림자가 아래로 또는 오른쪽으로 확장된다.

     

    (3) shadowBlur = float

    흐림(blur) 효과의 크기를 나타낸다. 기본값은 0이다.

     

    (4) shadowColor = color

    그림자 효과의 색상을 나타내는 표준 CSS 색상 값. 기본적으로 검은색이다.

    function draw() {
      var ctx = document.getElementById('canvas').getContext('2d');
    
      ctx.shadowOffsetX = 2;
      ctx.shadowOffsetY = 2;
      ctx.shadowBlur = 2;
      ctx.shadowColor = "rgba(0, 0, 0, 0.5)";
    
      ctx.font = "20px Times New Roman";
      ctx.fillStyle = "Black";
      ctx.fillText("Sample String", 5, 30);
    }

     


     

    7. CANVAS 채우기 규칙

    경로가 교차하거나 중첩된 경우에 어떤 방식으로 채울지를 결정하는 규칙이며

    다음 두가지 값을 사용할 수 있다.

     

    아래 두가지 값에 대한 설명을 찾아보아도 명확히 이해가 안 가 애먹었다.

    - nonzero
    해당 점에서 임의의 방향으로 무한대로 선을 그린 다음 세그먼트가 광선과 교차하는 위치를 검사하여 모양의 한 점의 "내부"를 결정합니다.

    0부터 시작하여 경로 세그먼트가 왼쪽에서 오른쪽으로 광선을 교차할 때마다 1을 더하고
    경로 세그먼트가 오른쪽에서 왼쪽으로 광선을 교차할 때마다 1을 뺀다. 교차점을 계산한 후 결과 가 0이면 점은 경로 밖에 있는 것이고 그렇지 않으면 내부에 있는 것이다. 

    - evenodd

    해당 점에서 임의의 방향으로 무한대로 광선을 그리고 광선이 교차하는 지정된 모양의 경로 세그먼트 수를 계산하여 모양에 있는 점의 "내부"를 결정한다.
    이 숫자가 홀수이면 점은 내부에 있고 짝수이면 포인트가 외부에 있다.

    외곽선을 홀수번째에 만나면 내부, 짝수번째에 만나면 외부

     

    function draw() {
      var ctx = document.getElementById('canvas').getContext('2d');
      ctx.beginPath();
      ctx.arc(50, 50, 30, 0, Math.PI * 2, true);
      ctx.arc(50, 50, 15, 0, Math.PI * 2, true);
      ctx.fill('evenodd');
    }

     

    evenodd로 설정하면 외부를 기준으로 색이 채워지고

    nonzero로 설정하면 내부가 다 채워지는 것이다.

     


     

    갈수록 어려워진다.

    다음 시간에는 텍스트를 그리는 방법에 대해 배워보자.

    'Canvas' 카테고리의 다른 글

    Canvas(6)_변형  (0) 2022.10.13
    Canvas(5)_이미지 사용하기  (1) 2022.10.13
    Canvas(4)_텍스트 그리기  (0) 2022.10.13
    Canvas(2)_도형 그리기  (0) 2022.10.13
    Canvas(1)_Canvas에 대하여  (0) 2022.10.12
Designed by Tistory.