हाई-डीपीआई और रेटिना स्क्रीन पर शार्प कैनवास रेंडरिंग
कैनवास ग्राफ़िक्स रेटिना और उच्च-डीपीआई स्क्रीन पर धुंधले क्यों दिखते हैं, और आकार बदलने की हैंडलिंग और प्रदर्शन सीमाओं सहित डिवाइसपिक्सेलरेशियो के साथ इसे कैसे ठीक करें।
कोर टेकअवे
एक कैनवास उच्च-घनत्व स्क्रीन पर धुंधला दिखता है जब उसका पिक्सेल आकार उसके CSS आकार से मेल खाता है, क्योंकि प्रत्येक कैनवास पिक्सेल कई भौतिक पिक्सेल पर फैला हुआ होता है। कैनवास की चौड़ाई और ऊंचाई को window.devicePixelRatio से गुणा किए गए CSS आकार पर सेट करके, CSS आकार को अपरिवर्तित रखते हुए और उसी अनुपात से ड्राइंग संदर्भ को स्केल करके इसे ठीक करें। आकार बदलने और ज़ूम करने पर इसे अपडेट करें।
कैनवस धुंधला क्यों हो जाता है?
MDN वर्तमान डिस्प्ले पर भौतिक पिक्सल और CSS पिक्सल के अनुपात के रूप में डिवाइस पिक्सेल अनुपात का वर्णन करता है: क्लासिक 96 डीपीआई स्क्रीन पर 1 और विशिष्ट हाईडीपीआई या रेटिना स्क्रीन पर 2। कैनवास का अपना पिक्सेल बफ़र होता है। यदि वह बफ़र 300 गुणा 150 पिक्सेल है, लेकिन 2 के अनुपात वाली स्क्रीन पर 300 गुणा 150 CSS पिक्सेल पर दिखाया जाता है, तो ब्राउज़र इसे 600 गुणा 300 भौतिक पिक्सेल तक फैला देता है, जो नरम दिखता है।
समाधान
MDN का अनुशंसित दृष्टिकोण अतिरिक्त पिक्सेल घनत्व जोड़ने के लिए डिवाइसपिक्सेल अनुपात का उपयोग करना है: कैनवास बफर को CSS आकार के अनुपात से गुणा पर सेट करें, CSS आकार को समान रखें, और 2D संदर्भ को स्केल करें ताकि आपका ड्राइंग कोड CSS पिक्सेल का उपयोग जारी रख सके। नीचे दिया गया कोड देखें.
हैंडल आकार बदलता है और ज़ूम करता है
जब कोई विंडो किसी अन्य मॉनिटर पर जाती है या उपयोगकर्ता पृष्ठ को ज़ूम करता है तो अनुपात बदल जाता है। आकार बदलने पर पुनर्गणना करें, और रिज़ॉल्यूशन मीडिया क्वेरी में परिवर्तनों को सुनें ताकि आप नए घनत्व पर फिर से निर्माण कर सकें। कैनवास तत्व पर एक 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
}याद रखने योग्य कुंजी Principle
- डिवाइस पिक्सेल अनुपात = भौतिक पिक्सेल प्रति CSS पिक्सेल (सामान्य रेटिना स्क्रीन पर 2)
- कैनवास.चौड़ाई/ऊंचाई को CSS आकार × अनुपात पर सेट करें; CSS आकार रखें
- संदर्भ को स्केल करें ताकि ड्राइंग कोड CSS पिक्सेल का उपयोग करे
- आकार बदलने, मॉनिटर परिवर्तन और ज़ूम पर पुनर्गणना करें
- प्रदर्शन के लिए बड़े कैनवस पर अनुपात कैप करें
अक्सर पूछे जाने वाले प्रश्नों
स्रोत
- Window: devicePixelRatio property — MDN वेब डॉक्स