عرض قماشي حاد على شاشات DPI وشاشات Retina العالية
لماذا تبدو رسومات القماش ضبابية على شاشات Retina والشاشات ذات النقاط العالية لكل بوصة، وكيفية إصلاحها باستخدام DevicePixelRatio، بما في ذلك معالجة تغيير الحجم وحدود الأداء.
الوجبات الجاهزة الأساسية
تبدو اللوحة القماشية ضبابية على الشاشات عالية الكثافة عندما يتطابق حجم البكسل الخاص بها مع حجم CSS، لأن كل بكسل من اللوحة القماشية ممتد على عدة وحدات بكسل فعلية. قم بإصلاحه عن طريق ضبط عرض اللوحة القماشية وارتفاعها على حجم CSS مضروبًا في window.devicePixelRatio، مع الحفاظ على حجم CSS دون تغيير، وتغيير حجم سياق الرسم بنفس النسبة. قم بتحديثه عند تغيير الحجم والتكبير.
لماذا اللوحات طمس
يصف MDN نسبة بكسل الجهاز على أنها نسبة وحدات البكسل الفعلية إلى CSS بكسل على الشاشة الحالية: 1 على شاشة كلاسيكية 96 نقطة في البوصة و2 على شاشات HiDPI أو Retina النموذجية. تحتوي اللوحة القماشية على مخزن مؤقت للبكسل خاص بها. إذا كان هذا المخزن المؤقت هو 300 × 150 بكسل ولكنه يظهر بحجم 300 × 150 CSS بكسل على الشاشة بنسبة 2، فإن المتصفح يقوم بتمديده إلى أكثر من 600 × 300 بكسل مادي، مما يبدو ناعمًا.
الإصلاح
الأسلوب الموصى به لـ MDN هو استخدام devicesPixelRatio لإضافة كثافة البكسل الإضافية: قم بتعيين المخزن المؤقت لقماش الرسم على حجم CSS مضروبًا في النسبة، واحتفظ بحجم CSS كما هو، وقم بقياس السياق ثنائي الأبعاد حتى يتمكن كود الرسم الخاص بك من الاستمرار في استخدام وحدات البكسل 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 للتذكر
- DevicePixelRatio = وحدات البكسل الفعلية لكل CSS بكسل (2 على شاشات Retina النموذجية)
- اضبط Canvas.width/height على نسبة الحجم × CSS؛ احتفظ بحجم CSS
- قم بقياس السياق بحيث يستخدم كود الرسم وحدات بكسل CSS
- إعادة حساب على تغيير الحجم، ومراقبة التغيير والتكبير
- قم بتغطية النسبة على اللوحات الكبيرة للأداء
الأسئلة المتداولة
المصادر
- Window: devicePixelRatio property — MDN مستندات الويب