บทนำ
หน้าจอ HiDPI นั้นยอดเยี่ยมมาก เพราะทำให้ทุกอย่างดูราบรื่นและสะอาดตา แต่ก็มีความท้าทายใหม่ๆ เกิดขึ้นกับนักพัฒนาซอฟต์แวร์ด้วยเช่นกัน ในบทความนี้ เราจะมาพิจารณาความท้าทายเฉพาะของการวาดภาพในผืนผ้าใบในบริบทของหน้าจอ HiDPI
พร็อพเพอร์ตี้ devicePixelRatio
มาเริ่มกันตั้งแต่ต้น สมัยก่อนที่เรายังไม่มีหน้าจอ HiDPI พิกเซลก็คือพิกเซล (หากไม่สนใจการซูมและการปรับขนาดสักพัก) และคุณก็ไม่จำเป็นต้องเปลี่ยนแปลงอะไรเลย ถ้าคุณตั้งค่าความกว้าง 100 พิกเซล เท่ากับขนาดนั้นได้เลย จากนั้นโทรศัพท์มือถือ HiDPI รุ่นแรกๆ ก็เริ่มปรากฏขึ้นพร้อมพร็อพเพอร์ตี้ devicePixelRatio ที่อึมครึมเล็กน้อยบนออบเจ็กต์ window และพร้อมใช้งานใน Media Query พร็อพเพอร์ตี้นี้ช่วยให้เราเข้าใจอัตราส่วนของค่าพิกเซล (ซึ่งเราเรียกว่าค่าพิกเซลเชิงตรรกะ) ใน CSS ที่แปลงเป็นจำนวนพิกเซลจริงที่อุปกรณ์จะใช้เมื่อแสดงผล ในกรณีของ iPhone 4S ซึ่งมี devicePixelRatio เท่ากับ 2 คุณจะเห็นค่าตรรกะ 100 พิกเซลเท่ากับค่าอุปกรณ์ 200 พิกเซล
น่าสนใจ แต่การเปลี่ยนแปลงนี้ส่งผลต่อนักพัฒนาแอปอย่างไร ในช่วงแรก เราทุกคนเริ่มสังเกตเห็นว่าอุปกรณ์เหล่านี้ปรับขนาดรูปภาพของเรา เราสร้างรูปภาพด้วยขนาดพิกเซลเชิงตรรกะขององค์ประกอบ และเมื่อวาดรูปภาพออกมา ระบบจะปรับขนาดรูปภาพด้วย devicePixelRatio และรูปภาพจะเบลอ
วิธีแก้ไขโดยเบื้องต้นก็คือการสร้างรูปภาพที่ขยายขนาดขึ้นโดย devicePixelRatio จากนั้นใช้ CSS เพื่อลดขนาดลงเท่าๆ กัน ซึ่งสำหรับ Canvas ก็เช่นเดียวกัน
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();