Yüksek DPI ve Retina Ekranlarda Keskin Kanvas İşleme
Kanvas grafiklerin Retina ve yüksek DPI ekranlarda neden bulanık göründüğü ve yeniden boyutlandırma yönetimi ve performans sınırları da dahil olmak üzere bu durumun DevicePixelRatio ile nasıl düzeltileceği.
Ana nokta
Bir tuval, piksel boyutu CSS boyutuyla eşleştiğinde yüksek yoğunluklu ekranlarda bulanık görünür çünkü her bir tuval pikseli birkaç fiziksel piksel üzerine gerilir. Kanvas genişliğini ve yüksekliğini CSS boyutu ile window.devicePixelRatio çarpımına ayarlayarak, CSS boyutunu değiştirmeden ve çizim bağlamını aynı orana göre ölçeklendirerek sorunu düzeltin. Yeniden boyutlandırma ve yakınlaştırma ile güncelleyin.
Tuvaller neden bulanıklaşıyor?
MDN, DevicePixelRatio'yu geçerli ekrandaki fiziksel piksellerin CSS piksellere oranı olarak tanımlar: klasik 96 DPI ekranda 1 ve tipik HiDPI veya Retina ekranlarda 2. Bir tuvalin kendi piksel arabelleği vardır. Bu arabellek 300 x 150 piksel ise ancak 2 oranlı bir ekranda 300 x 150 CSS piksel olarak gösteriliyorsa, tarayıcı onu 600 x 300 fiziksel pikselin üzerine uzatır ve bu da yumuşak görünür.
Düzeltme
MDN'in önerilen yaklaşımı, ekstra piksel yoğunluğunu eklemek için DevicePixelRatio'yu kullanmaktır: tuval arabelleğini CSS boyutu çarpı oran olarak ayarlayın, CSS boyutunu aynı tutun ve çizim kodunuzun CSS piksellerini kullanmaya devam edebilmesi için 2B bağlamı ölçeklendirin. Aşağıdaki koda bakın.
Yeniden boyutlandırmayı ve yakınlaştırmayı yönetin
Oran, bir pencere başka bir monitöre taşındığında veya kullanıcı sayfayı yakınlaştırdığında değişir. Yeniden boyutlandırmayı yeniden hesaplayın ve çözünürlük medya sorgusunda yapılan değişiklikleri dinleyin, böylece yeni yoğunlukta yeniden çizim yapabilirsiniz. Tuval öğesindeki ResizeObserver, boyutu düzen ile senkronize tutmanın güvenilir bir yoludur.
Performans sınırları
Oranın iki katına çıkması çizilecek piksel sayısını dört katına çıkarır. Çok büyük tuvallerde veya düşük kaliteli cihazlarda oranı örneğin 2 olarak sınırlayın ve kare sürelerini ölçün. Lottie'in tuval oluşturucusu, Rive ve ExodeUI gibi tuvale çizim yapan animasyon çalışma zamanları bu ölçeklendirmeyi sizin için gerçekleştirir, ancak aynı taviz de geçerlidir.
Üretim için uygulama örneği
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
}Hatırlanacak temel ilkeler
- DevicePixelRatio = CSS piksel başına fiziksel piksel (tipik Retina ekranlarda 2)
- Kanvas genişliğini/yüksekliğini CSS boyut × oranına ayarlayın; CSS boyutunu koruyun
- Çizim kodunun CSS piksel kullanması için bağlamı ölçeklendirin
- Yeniden boyutlandırma, izleme değişikliği ve yakınlaştırma üzerinde yeniden hesaplama
- Performans için büyük tuvallerde oranı sınırlayın
Sık sorulan sorular
Kaynaklar
- Window: devicePixelRatio property — MDN Web Belgeleri