Ostré vykresľovanie plátna na obrazovkách s vysokým rozlíšením DPI a sietnici
Prečo grafika plátna vyzerá na Retina a obrazovkách s vysokým DPI rozmazaná a ako to opraviť pomocou devicePixelRatio vrátane manipulácie so zmenami veľkosti a limitov výkonu.
Core Takeaway
Plátno vyzerá na obrazovkách s vysokou hustotou rozmazané, keď sa jeho veľkosť pixelov zhoduje s veľkosťou CSS, pretože každý pixel plátna je roztiahnutý cez niekoľko fyzických pixelov. Opravte to nastavením šírky a výšky plátna na veľkosť CSS vynásobenú hodnotou window.devicePixelRatio, pričom veľkosť CSS ponecháte nezmenenú a zmeníte mierku kontextu kreslenia o rovnaký pomer. Aktualizujte ho pri zmene veľkosti a priblížení.
Prečo sa plátna rozmazávajú
MDN popisuje devicePixelRatio ako pomer fyzických pixelov k CSS pixelom na aktuálnom displeji: 1 na klasickej obrazovke s rozlíšením 96 DPI a 2 na typických obrazovkách HiDPI alebo Retina. Plátno má vlastnú vyrovnávaciu pamäť pixelov. Ak je táto vyrovnávacia pamäť 300 x 150 pixelov, ale zobrazuje sa na obrazovke s rozmermi 300 x 150 pixelov CSS na obrazovke s pomerom 2, prehliadač ju roztiahne na viac ako 600 x 300 fyzických pixelov, čo vyzerá jemne.
Oprava
Odporúčaný prístup MDN je použiť devicePixelRatio na pridanie extra hustoty pixelov: nastavte vyrovnávaciu pamäť plátna na veľkosť CSS krát pomer, ponechajte veľkosť CSS rovnakú a škálujte 2D kontext, aby váš kresliaci kód mohol naďalej používať pixely CSS. Pozrite si kód nižšie.
Rukoväť zmeny veľkosti a priblíženia
Pomer sa zmení, keď sa okno presunie na iný monitor alebo používateľ priblíži stránku. Prepočítajte pri zmene veľkosti a počúvajte zmeny v dotaze na médium s rozlíšením, aby ste mohli prekresliť s novou hustotou. ResizeObserver na prvku canvas je spoľahlivý spôsob, ako udržať veľkosť v synchronizácii s rozložením.
Výkonnostné limity
Zdvojnásobenie pomeru zoštvornásobí počet pixelov na kreslenie. Na veľmi veľkých plátnach alebo zariadeniach nižšej kategórie obmedzte pomer, napríklad na 2, a zmerajte časy snímok. Spustenia animácií, ktoré sa kreslia na plátno, ako napríklad vykresľovanie plátna Lottie, Rive a ExodeUI, spravia toto škálovanie za vás, ale platí rovnaký kompromis.
Snippet implementácie výroby
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
}Kľúč Principle na zapamätanie
- devicePixelRatio = fyzické pixely na CSS pixel (2 na typických Retina obrazovkách)
- Nastavte canvas.width/height na CSS veľkosť × pomer; zachovať veľkosť CSS
- Prispôsobte kontext tak, aby kód kreslenia používal pixely CSS
- Prepočítajte zmenu veľkosti, sledujte zmeny a približujte
- Uzáver pomeru na veľkých plátnach pre výkon
Často kladené otázky
Zdroje
- Window: devicePixelRatio property — Webové dokumenty MDN