Hiển thị Canvas sắc nét trên màn hình Retina và Pixel cao
Tại sao đồ họa canvas trông mờ trên màn hình Retina và màn hình có độ phân giải cao, cũng như cách khắc phục bằng devicePixelRatio, bao gồm cả việc xử lý thay đổi kích thước và giới hạn hiệu suất.
Điểm chính
Canvas trông mờ trên màn hình mật độ cao khi kích thước pixel của nó khớp với kích thước CSS vì mỗi pixel canvas được kéo dài trên một số pixel vật lý. Hãy khắc phục bằng cách đặt chiều rộng và chiều cao của khung vẽ thành kích thước CSS nhân với window.devicePixelRatio, giữ nguyên kích thước CSS và chia tỷ lệ bối cảnh bản vẽ theo cùng một tỷ lệ. Cập nhật nó về thay đổi kích thước và thu phóng.
Tại sao canvas bị mờ
MDN mô tả devicePixelRatio là tỷ lệ pixel vật lý với pixel CSS trên màn hình hiện tại: 1 trên màn hình 96 dpi cổ điển và 2 trên màn hình HiDPI hoặc Retina thông thường. Canvas có bộ đệm pixel riêng. Nếu bộ đệm đó có kích thước 300 x 150 pixel nhưng hiển thị ở mức 300 x 150 pixel CSS trên màn hình với tỷ lệ 2, thì trình duyệt sẽ kéo dài nó ra trên 600 x 300 pixel vật lý, trông mềm mại.
Cách khắc phục
Phương pháp được đề xuất của MDN là sử dụng devicePixelRatio để thêm mật độ pixel bổ sung: đặt bộ đệm canvas thành kích thước CSS nhân với tỷ lệ, giữ nguyên kích thước CSS và chia tỷ lệ bối cảnh 2D để mã bản vẽ của bạn có thể tiếp tục sử dụng pixel CSS. Xem mã bên dưới.
Xử lý thay đổi kích thước và thu phóng
Tỷ lệ thay đổi khi cửa sổ di chuyển sang màn hình khác hoặc người dùng phóng to trang. Tính toán lại kích thước và lắng nghe các thay đổi đối với truy vấn phương tiện có độ phân giải để bạn có thể vẽ lại ở mật độ mới. ResizeObserver trên phần tử canvas là cách đáng tin cậy để giữ kích thước đồng bộ với bố cục.
Giới hạn hiệu suất
Nhân đôi tỷ lệ sẽ tăng gấp bốn lần số pixel cần vẽ. Trên các khung vẽ rất lớn hoặc các thiết bị cấp thấp, hãy giới hạn tỷ lệ, chẳng hạn như ở mức 2 và đo thời gian khung hình. Thời gian chạy hoạt ảnh vẽ vào canvas, chẳng hạn như trình kết xuất canvas của Lottie, Rive và ExodeUI, xử lý việc chia tỷ lệ này cho bạn, nhưng cũng áp dụng sự đánh đổi tương tự.
Đoạn mã triển khai thực tế
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
}Nguyên tắc chính cần nhớ
- devicePixelRatio = pixel vật lý trên mỗi pixel CSS (2 trên màn hình Retina thông thường)
- Đặt canvas.width/height thành tỷ lệ × kích thước CSS; giữ kích thước CSS
- Chia tỷ lệ bối cảnh để mã vẽ sử dụng pixel CSS
- Tính toán lại kích thước, theo dõi thay đổi và thu phóng
- Giới hạn tỷ lệ trên các khung vẽ lớn để đạt hiệu suất
Câu hỏi thường gặp
Nguồn
- Window: devicePixelRatio property — Tài liệu web MDN