مقدمة
إنّ شاشات HiDPI رائعة، فهي تجعل كل شيء يبدو أكثر سلاسة ووضوحًا. ولكنّها تطرح أيضًا مجموعة جديدة من التحديات للمطوّرين. في هذه المقالة، سنلقي نظرة على التحديات الفريدة لرسم الصور في اللوحة في سياق شاشات HiDPI.
سمة devicePixelRatio
لنبدأ من البداية. في السابق، قبل أن نحصل على شاشات بدرجة دقة عالية (HiDPI)، كان كل بكسل بكسلًا (إذا تجاهلنا التكبير والتصغير لبعض الوقت)، ولم يكن عليك تغيير أي شيء. إذا قمتَ بتعيين شيء ما ليكون بعرض 100 بكسل، فهذا كل ما في الأمر. بعد ذلك، بدأت تظهر أوّل هواتف محمولة قليلة ذات كثافة عالية للبكسل مع سمة devicePixelRatio الغامضة قليلاً في عنصر النافذة، وكانت متاحة للاستخدام في طلبات البحث عن الوسائط. ما سمحت لنا به هذه السمة هو فهم نسبة كيفية تحويل قيم البكسل (التي نسميها قيمة البكسل المنطقي) في CSS إلى العدد الحقيقي للبكسل الذي سيستخدمه الجهاز عند العرض. في حالة هاتف iPhone 4S، الذي يحتوي على نسبة PixelRatio لجهاز Pixel 2، ستلاحظ أن القيمة المنطقية 100 بكسل تساوي قيمة الجهاز 200 بكسل.
هذا مثير للاهتمام، ولكن ماذا يعني ذلك بالنسبة لنا كمطورين؟ في الأيام الأولى، بدأنا جميعًا نلاحظ أنّ هذه الأجهزة كانت تكبّر صورنا. كنا ننشئ صورًا بعرض البكسل المنطقي لعناصرنا، وعندما يتم رسمها، سيتم ترقيتها بواسطة جهاز PixelRatio وستكون ضبابية.
كان الحلّ الفعلي لهذه المشكلة هو إنشاء صور يتم تكبيرها باستخدام devicePixelRatio ثم استخدام CSS لتصغيرها بالقدر نفسه، وينطبق ذلك أيضًا على مساحة العرض.
function setupCanvas(canvas) {
// Get the device pixel ratio, falling back to 1.
var dpr = window.devicePixelRatio || 1;
// Get the size of the canvas in CSS pixels.
var rect = canvas.getBoundingClientRect();
// Give the canvas pixel dimensions of their CSS
// size * the device pixel ratio.
canvas.width = rect.width * dpr;
canvas.height = rect.height * dpr;
var ctx = canvas.getContext('2d');
// Scale all drawing operations by the dpr, so you
// don't have to worry about the difference.
ctx.scale(dpr, dpr);
return ctx;
}
// Now this line will be the same size on the page
// but will look sharper on high-DPI devices!
var ctx = setupCanvas(document.querySelector('.my-canvas'));
ctx.lineWidth = 5;
ctx.beginPath();
ctx.moveTo(100, 100);
ctx.lineTo(200, 200);
ctx.stroke();