높은 DPI 및 Retina 화면에서 선명한 캔버스 렌더링
Retina 및 높은 DPI 화면에서 캔버스 그래픽이 흐릿하게 보이는 이유와 크기 조정 처리 및 성능 제한을 포함하여 devicePixelRatio를 사용하여 문제를 해결하는 방법입니다.
핵심 포인트
캔버스의 픽셀 크기가 CSS 크기와 일치하면 고밀도 화면에서 캔버스가 흐릿하게 보입니다. 각 캔버스 픽셀이 여러 물리적 픽셀에 걸쳐 늘어나기 때문입니다. 캔버스 너비와 높이를 CSS 크기에 window.devicePixelRatio를 곱한 값으로 설정하고, CSS 크기를 변경하지 않은 채 유지하고, 그리기 컨텍스트의 크기를 동일한 비율로 조정하여 문제를 해결하세요. 크기 조정 및 확대/축소 시 업데이트하세요.
캔버스가 흐려지는 이유
MDN는 devicePixelRatio를 현재 디스플레이의 물리적 픽셀 대 CSS 픽셀의 비율로 설명합니다. 클래식 96 DPI 화면에서는 1이고 일반적인 HiDPI 또는 Retina 화면에서는 2입니다. 캔버스에는 자체 픽셀 버퍼가 있습니다. 해당 버퍼가 300 x 150 픽셀이지만 비율이 2인 화면에서 300 x 150 CSS 픽셀로 표시되는 경우 브라우저는 버퍼를 600 x 300 실제 픽셀 이상으로 늘려 부드러워 보입니다.
수정 사항
MDN에서 권장하는 접근 방식은 devicePixelRatio를 사용하여 추가 픽셀 밀도를 추가하는 것입니다. 캔버스 버퍼를 CSS 크기와 비율의 곱으로 설정하고, CSS 크기를 동일하게 유지하고, 그리기 코드가 CSS 픽셀을 계속 사용할 수 있도록 2D 컨텍스트의 크기를 조정합니다. 아래 코드를 참조하세요.
크기 조정 및 확대/축소 처리
창이 다른 모니터로 이동하거나 사용자가 페이지를 확대/축소하면 비율이 변경됩니다. 크기 조정 시 다시 계산하고 해상도 미디어 쿼리의 변경 사항을 수신하여 새 밀도로 다시 그릴 수 있습니다. 캔버스 요소의 ResizeObserver는 크기를 레이아웃과 동기화하는 안정적인 방법입니다.
성능 제한
비율을 두 배로 늘리면 그릴 픽셀 수가 네 배로 늘어납니다. 매우 큰 캔버스나 저가형 장치에서는 비율을 2로 제한하고 프레임 시간을 측정합니다. Lottie의 캔버스 렌더러, Rive 및 ExodeUI와 같이 캔버스에 그리는 애니메이션 런타임은 이러한 크기 조정을 처리하지만 동일한 절충안이 적용됩니다.
프로덕션 구현 예시
function setupCanvas(canvas) {
const ctx = canvas.getContext('2d');
function resize() {
const ratio = Math.min(window.devicePixelRatio || 1, 2); // cap for performance
const { width, height } = canvas.getBoundingClientRect(); // CSS size
canvas.width = Math.round(width * ratio); // backing store in device pixels
canvas.height = Math.round(height * ratio);
ctx.setTransform(ratio, 0, 0, ratio, 0, 0); // draw in CSS pixels
draw(ctx, width, height);
}
new ResizeObserver(resize).observe(canvas);
resize();
}
function draw(ctx, width, height) {
ctx.clearRect(0, 0, width, height);
ctx.lineWidth = 1;
ctx.strokeRect(0.5, 0.5, width - 1, height - 1); // crisp 1px border
}기억할 핵심 원칙
- devicePixelRatio = CSS 픽셀당 물리적 픽셀(일반적인 Retina 화면에서는 2)
- canvas.width/height를 CSS 크기 × 비율로 설정합니다. CSS 크기를 유지하세요
- 그리기 코드에서 CSS 픽셀을 사용하도록 컨텍스트 크기 조정
- 크기 조정 시 다시 계산, 변경 사항 모니터링 및 확대/축소
- 성능을 위해 대형 캔버스에서 비율 제한
자주 묻는 질문
출처
- Window: devicePixelRatio property — MDN 웹 문서