Why should you care about half pixel?
Author: ZeroX-DG
・Date: 12-10-2022
Tưởng tượng vào một ngày đẹp trời và bạn vẽ một đường thẳng lên canvas:
context.moveTo(1, 0);
context.lineTo(1, 375);
Nhưng ôi không, cái đường thẳng của bạn nó lại bị mở mịt như cái tương lai của bạn vậy.

Bạn kẹp đầu giữa gối khóc như chị tiếp viên máy bay hướng dẫn nhưng bạn biết nó cũng chẳng thể cứu được bạn.
Bạn zoom trình duyệt to ra, nhỏ lại, và ô kìa, sao nó lại ra thế này? Sao ở một vài cấp độ zoom nó lại rõ mà ở những cấp khác nó mờ?
Hiện tượng này diễn ra do 2 lý do chính:
- Độ lớn của line trong canvas phụ thuộc vào thuộc tính
lineWidth. lineWidththì to ra từ giữa line. Ví dụ toạ độ line là(10, 10),lineWidthlà5và độ dài line là20thì thay vì có hình dạng làRect(x=10, y=10, width=5, height=20)thì line sẽ được render theo hình dạngRect(x=5, y=10, width=5, height=20)tức là có sự dịch chuyển toạ độxvì cáiwidthcủa line luôn lớn lên từ ở giữa. (x_line = specified_x - line_width / 2)
Nên nếu vẽ line ở toạ độ (1, 0) và với lineWidth=1 thì toạ độ thực sự của nó là x = 1 - 1 / 2 = 0.5 tức là line sẽ nằm giữa 2 pixel và chiếm một nửa của mỗi pixel. Điều này khiến trình duyệt phải approximate phần nửa chưa bị chiếm còn lại của 2 pixel đó và render bằng một màu đậm bằng một nửa so với phần bị chiếm gây nên hiệu ứng line bị mờ.
![]()
Để tránh trường hợp này xảy ra thì nếu lineWidth của bạn là số chẵn thì toạ độ của bạn nên là số nguyên, ngược lại thì bạn nên thêm 0.5 để tránh render giữa 2 pixel như trên. Ví dụ lineWidth = 10 thì bạn có thể dùng toạ độ số nguyên (10, 20) còn lineWidth = 5 thì nên dùng (10.5, 20) .
![]()
Đọc thêm ở đây: