Canvas2D는 항상 여러분입니다.

아론 크라제스키
아론 크라예스키

셰이더, 메시, 필터의 세계에서 Canvas2D를 유용하게 활용하지 못할 수 있습니다. 하지만 알고 있어야 합니다. 웹페이지의 30~40% 에 <canvas> 요소가 있으며 모든 캔버스의 98% 가 Canvas2D 렌더링 컨텍스트를 사용합니다. 자동차, 냉장고, 우주 등에서 Canvas2D를 사용할 수 있습니다.

물론, API는 최첨단 2D 그리기에 비해 약간 뒤처지고 있습니다. 다행히 Google은 CSS를 따라잡고, 인체공학을 간소화하고, 성능을 개선하기 위해 Canvas2D에 새로운 기능을 구현하기 위해 노력해 왔습니다.

파트 1: CSS 따라잡기

CSS에는 Canvas2D에서 거의 누락된 몇 가지 그리기 명령어가 있습니다. 새 API에는 가장 요청이 많았던 몇 가지 기능이 추가되었습니다.

둥근 직사각형

모서리가 둥근 직사각형: 인터넷, 컴퓨팅, 문명의 초석입니다.

전체적으로 둥근 직사각형은 매우 유용합니다. 버튼, 채팅 풍선, 썸네일, 말풍선 등 이름을 지정할 수 있습니다. Canvas2D에서는 항상 둥근 직사각형을 만들 수 있었지만, 약간 지저분했습니다.

const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
ctx.fillStyle = 'magenta';

const top = 10;
const left = 10;
const width = 200;
const height = 100;
const radius = 20;

ctx.beginPath();
ctx.moveTo(left + radius, top);
ctx.lineTo(left + width - radius, top);
ctx.arcTo(left + width, top, left + width, top + radius, radius);
ctx.lineTo(left + width, top + height - radius);
ctx.arcTo(left + width, top + height, left + width - radius, top + height, radius);
ctx.lineTo(left + radius, top + height);
ctx.arcTo(left, top + height, left, top + height - radius, radius);
ctx.lineTo(left, top + radius);
ctx.arcTo(left, top, left + radius, top, radius);
ctx.stroke();

이 모든 것은 단순하고 모서리가 둥근 직사각형을 만드는 데 필요했습니다.

모서리가 둥근 직사각형.

새 API에는 roundRect() 메서드가 있습니다.

ctx.roundRect(upper, left, width, height, borderRadius);

따라서 위의 함수를 다음과 같이 완전히 대체할 수 있습니다.

ctx.roundRect(10, 10, 200, 100, 20);

또한 ctx.roundRect() 메서드는 최대 4개의 숫자인 borderRadius 인수의 배열을 취합니다. 이러한 반경은 CSS의 경우와 동일한 방식으로 모서리가 둥근 직사각형의 네 모서리를 제어합니다. 예를 들면 다음과 같습니다.

ctx.roundRect(10, 10, 200, 100, [15, 50, 30]);

데모를 통해 테스트해 보세요.

원뿔 그라데이션

지금까지 선형 그래디언트를 확인했습니다.

const gradient = ctx.createLinearGradient(0, 0, 200, 100);
gradient.addColorStop(0, 'blue');
gradient.addColorStop(0.5, 'magenta');
gradient.addColorStop(1, 'white');
ctx.fillStyle = gradient;
ctx.fillRect(10, 10, 200, 100);

선형 그라데이션.

방사형 그래디언트:

const radialGradient = ctx.createRadialGradient(150, 75, 10, 150, 75, 70);
radialGradient.addColorStop(0, 'white');
radialGradient.addColorStop(0.5, 'magenta');
radialGradient.addColorStop(1, 'lightblue');

ctx.fillStyle = radialGradient;
ctx.fillRect(0, 0, canvas.width, canvas.height);

원형 그라데이션.

하지만 멋진 원뿔 그라데이션은 어떨까요?

const grad = ctx.createConicGradient(0, 100, 100);

grad.addColorStop(0, 'red');
grad.addColorStop(0.25, 'orange');
grad.addColorStop(0.5, 'yellow');
grad.addColorStop(0.75, 'green');
grad.addColorStop(1, 'blue');

ctx.fillStyle = grad;
ctx.fillRect(0, 0, 200, 200);

원뿔 그라데이션입니다.

텍스트 수정자

Canvas2Ds의 텍스트 렌더링 기능은 이전보다 크게 뒤처졌습니다. Chrome은 Canvas2D 텍스트 렌더링에 몇 가지 새로운 속성을 추가했습니다.

이러한 속성은 모두 동일한 이름을 가진 CSS의 대응 속성과 일치합니다.

파트 2: 인체 공학적 조정

이전에는 Canvas2D를 사용할 때 가능한 몇몇 작업이 가능했지만 불필요하게 구현하기가 복잡했습니다. Canvas2D를 사용하려는 JavaScript 개발자를 위한 몇 가지 품질 개선 사항은 다음과 같습니다.

컨텍스트 재설정됨

캔버스를 지우는 방법을 설명하기 위해 작은 복고풍 패턴을 그리는 함수를 작성했습니다.

draw90sPattern();

삼각형과 사각형의 복고풍 패턴입니다.

좋습니다. 이제 패턴을 완료했으니 캔버스를 지우고 다른 것을 그리려고 합니다. 잠깐, 캔버스를 다시 지우려면 어떻게 해야 하나요? 와우! 물론 ctx.clearRect()입니다.

ctx.clearRect(0, 0, canvas.width, canvas.height);

안 되네요. 와우! 먼저 변환을 재설정해야 합니다.

ctx.resetTransform();
ctx.clearRect(0, 0, canvas.width, canvas.height);
빈 캔버스입니다.

그렇다면 빈 캔버스가 멋지네요. 이제 멋진 가로선을 그려 보겠습니다.

ctx.moveTo(10, 10);
ctx.lineTo(canvas.width, 10);
ctx.stroke();

가로선과 대각선입니다.

그르르! 오답입니다. 👀 여기서 늘어난 줄은 뭘까? 그리고 왜 분홍색일까? 그럼 StackOverflow를 확인해 보겠습니다.

canvas.width = canvas.width;

왜 이렇게 멍청한 거야? 왜 이렇게 어려운가요?

더 이상은 없어요. 새로운 API를 통해 단순하고 우아하며 아름다운 획기적인 기술을 선보입니다.

ctx.reset();

시간이 너무 오래 걸려 죄송합니다.

필터

SVG 필터는 그 자체로 하나의 세계입니다. 처음 접하는 사용자라면 놀라운 잠재력을 보여주는 The Art Of SVG Filters And Why It Is Awesome을 읽어보는 것이 좋습니다.

Canvas2D에서는 SVG 스타일 필터를 이미 사용할 수 있습니다. 페이지의 다른 SVG 필터 요소를 가리키는 URL로 필터를 전달하도록 하면 됩니다.

<svg>
  <defs>
    <filter id="svgFilter">
      <feGaussianBlur in="SourceGraphic" stdDeviation="5" />
      <feConvolveMatrix kernelMatrix="-3 0 0 0 0.5 0 0 0 3" />
      <feColorMatrix type="hueRotate" values="90" />
    </filter>
  </defs>
</svg>
const canvas = document.createElement('canvas');
canvas.width = 500;
canvas.height = 400;
const ctx = canvas.getContext('2d');
document.body.appendChild(canvas);

ctx.filter = "url('#svgFilter')";
draw90sPattern(ctx);

이 것은 패턴을 꽤 잘 해칩니다.

블러 효과가 적용된 레트로 패턴입니다.

그러나 위의 작업을 수행하면서도 JavaScript를 유지하고 문자열을 변경하지 않으려면 어떻게 해야 할까요? 새로운 API를 사용하면 이 모든 것이 가능합니다.

ctx.filter = new CanvasFilter([
  { filter: 'gaussianBlur', stdDeviation: 5 },
  {
    filter: 'convolveMatrix',
    kernelMatrix: [
      [-3, 0, 0],
      [0, 0.5, 0],
      [0, 0, 3],
    ],
  },
  { filter: 'colorMatrix', type: 'hueRotate', values: 90 },
]);

만들기 정말 쉽죠? 사용해 보고 여기의 데모에서 매개변수를 사용해 보세요.

3부: 성능 개선

우리는 새로운 Canvas2D API를 사용하여 가능한 경우 성능을 개선하고자 했습니다. 개발자가 웹사이트를 더 세밀하게 제어하고 가장 매끄러운 프레임 속도를 구현할 수 있도록 몇 가지 기능을 추가했습니다.

자주 읽을 예정임

getImageData()를 사용하여 캔버스에서 픽셀 데이터를 다시 읽습니다. 속도가 매우 느릴 수 있습니다. 새 API를 사용하면 캔버스에 다시 읽을 수 있도록 명시적으로 표시할 수 있습니다 (예: 생성 효과). 이를 통해 내부에서 항목을 최적화하고 더 다양한 사용 사례에 맞게 캔버스를 빠르게 유지할 수 있습니다. 이 기능은 한동안 Firefox에 제공되어 왔으며 드디어 캔버스 사양에 포함됩니다.

const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d', { willReadFrequently: true });

컨텍스트 손실

슬픈 탭을 다시 행복하게 만들어 보세요. 클라이언트의 GPU 메모리가 부족하거나 캔버스에 다른 재해가 발생하는 경우 이제 필요에 따라 콜백을 수신하고 다시 그릴 수 있습니다.

const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');

canvas.addEventListener('contextlost', onContextLost);
canvas.addEventListener('contextrestored', redraw);

캔버스 컨텍스트와 손실에 관해 자세히 알아보려면 WhatWG의 위키에 관한 유용한 설명을 읽어보세요.

결론

Canvas2D를 처음 사용하는 분이든, 오랫동안 사용해 왔든, 몇 년 동안 사용하지 않고 계셨던 분들도 모두 캔버스를 새롭게 디자인해 보세요. 여태까지 만들어 왔던 API-Next-도어입니다.

감사의 말씀

UnsplashSandie Clarke 히어로 이미지