셰이더, 메시, 필터의 세계에서 Canvas2D는 그리 흥미롭지 않을 수 있습니다. 하지만 그래야 합니다.
웹페이지의 30~40% 에는 <canvas>
요소가 있고 모든 캔버스의 98% 는 Canvas2D 렌더링 컨텍스트를 사용합니다. 자동차, 냉장고, 우주 (실제로)에 Canvas2D가 있습니다.
최신 2D 그리기와 관련하여 API는 약간 뒤처져 있습니다. 다행히 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]);
Conic Gradient
선형 그라데이션을 본 적이 있을 것입니다.
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);
텍스트 수식어
Canvas2D의 텍스트 렌더링 기능은 매우 뒤떨어져 있습니다. Chrome은 Canvas2D 텍스트 렌더링에 몇 가지 새로운 속성을 추가했습니다.
- ctx.letterSpacing
- ctx.wordSpacing
- ctx.fontVariant
- ctx.fontKerning
- ctx.fontStretch
- ctx.textDecoration
- ctx.textUnderlinePosition
- ctx.textRendering
이러한 속성은 모두 이름이 동일한 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 필터는 그 자체로 하나의 세계입니다. SVG 필터를 처음 사용하는 경우 SVG 필터의 기술과 그 멋진 이유를 읽어보시기 바랍니다. 이 도움말에서는 SVG 필터의 놀라운 잠재력을 보여줍니다.
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입니다.