בעולם של שיבושים, רשתות ומסננים, יכול להיות ש-Canvas2D לא יעניין אתכם. אבל זה צריך!
ב-30-40% מדפי האינטרנט יש אלמנט <canvas>
, וב-98% מכל משטחי הקנבס נעשה שימוש בהקשר של עיבוד Canvas2D. יש תמונות Canvas2D גם במכוניות, במקררים ובחלל (באמת).
אומנם ה-API נמצא בשלב קצת מוקדם יותר כשמדובר בשרטוט דו-ממדי חדשני. למרבה המזל, עבדנו קשה כדי להטמיע תכונות חדשות ב-Canvas2D כדי להתעדכן ב-CSS, לשפר את הארגונומיה ולשפר את הביצועים.
חלק 1: עדכון לגבי CSS
ב-CSS יש כמה פקודות שרטוט שחסרות מאוד ב-Canvas2D. עם ה-API החדש, הוספנו כמה מהתכונות הכי מבוקשות:
מלבן מעוגל
מלבנים מעוגלים: אבן הפינה של האינטרנט, של מחשוב, עצמות של ציוויליזציה.
ברצינות, ריבועים מעוגלים הם מאוד שימושיים: כלחצנים, כבועות צ'אט, כתמונות ממוזערות, כבועות דיבור ועוד. תמיד אפשר ליצור מלבן מעוגל ב-Canvas2D, אבל זה היה קצת מבולגן:
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
ctx.fillStyle = 'magenta';
const top = 10;
const left = 10;
const width = 200;
const height = 100;
const radius = 20;
ctx.beginPath();
ctx.moveTo(left + radius, top);
ctx.lineTo(left + width - radius, top);
ctx.arcTo(left + width, top, left + width, top + radius, radius);
ctx.lineTo(left + width, top + height - radius);
ctx.arcTo(left + width, top + height, left + width - radius, top + height, radius);
ctx.lineTo(left + radius, top + height);
ctx.arcTo(left, top + height, left, top + height - radius, radius);
ctx.lineTo(left, top + radius);
ctx.arcTo(left, top, left + radius, top, radius);
ctx.stroke();
כל זה היה נחוץ כדי ליצור מלבן מעוגל פשוט וצנוע:
ב-API החדש יש שיטה roundRect()
.
ctx.roundRect(upper, left, width, height, borderRadius);
אפשר להחליף את מה שמוצג למעלה ב:
ctx.roundRect(10, 10, 200, 100, 20);
השיטה ctx.roundRect()
מקבלת גם מערך לארגומנט borderRadius
של עד ארבעה מספרים. הרדיוס קובע את ארבע הפינות של המלבן המעוגל באותו אופן כמו ב-CSS. לדוגמה:
ctx.roundRect(10, 10, 200, 100, [15, 50, 30]);
כדאי לבדוק את הדמו כדי להתנסות.
מפל צבעים חרוט
ראית צבעים עם פסלי צבעים לינארי:
const gradient = ctx.createLinearGradient(0, 0, 200, 100);
gradient.addColorStop(0, 'blue');
gradient.addColorStop(0.5, 'magenta');
gradient.addColorStop(1, 'white');
ctx.fillStyle = gradient;
ctx.fillRect(10, 10, 200, 100);
מעברי צבע רדיאליים:
const radialGradient = ctx.createRadialGradient(150, 75, 10, 150, 75, 70);
radialGradient.addColorStop(0, 'white');
radialGradient.addColorStop(0.5, 'magenta');
radialGradient.addColorStop(1, 'lightblue');
ctx.fillStyle = radialGradient;
ctx.fillRect(0, 0, canvas.width, canvas.height);
אבל מה דעתכם על שימוש בצבעים מדורגים בקונוס?
const grad = ctx.createConicGradient(0, 100, 100);
grad.addColorStop(0, 'red');
grad.addColorStop(0.25, 'orange');
grad.addColorStop(0.5, 'yellow');
grad.addColorStop(0.75, 'green');
grad.addColorStop(1, 'blue');
ctx.fillStyle = grad;
ctx.fillRect(0, 0, 200, 200);
מגבילי טקסט
יכולות הרינדור של טקסט ב-Canvas2D היו מאחור. ל-Chrome נוספו מספר מאפיינים חדשים לרינדור טקסט Canvas2D:
- regex.letterSpacing
- ctx.wordSpacing
- ctx.fontVariant
- ctx.fontKerning
- legal.fontStretch
- ctx.textDecoration
- regex.textUnderlinePosition
- ctx.textRendering
כל המאפיינים האלה תואמים למאפיינים המקבילים ב-CSS שלהם, עם אותם שמות.
חלק 2: שינויים ארגונומיים
בעבר, חלק מהדברים בעזרת Canvas2D היו אפשריים, אבל היו יותר מסובכים ליישום. ריכזנו כאן כמה שיפורים באיכות החיים של מפתחי JavaScript שרוצים להשתמש ב-Canvas2D:
איפוס הקשר
כדי להסביר את הניקוי של אזור העריכה, כתבתי פונקציה קטנה ומטופשת לשרטוט של תבנית רטרו:
draw90sPattern();
נהדר! עכשיו, לאחר שסיימתי עם התבנית, אני רוצה לנקות את אזור העריכה ולצייר משהו אחר.
רגע, איך מוחקים קנבס שוב? כן! ctx.clearRect()
, כמובן.
ctx.clearRect(0, 0, canvas.width, canvas.height);
אופס, זה לא עבד. כן! צריך לאפס קודם את הטרנספורמציה:
ctx.resetTransform();
ctx.clearRect(0, 0, canvas.width, canvas.height);
יופי! על קנבס ריק ויפה. עכשיו נתחיל לצייר קו אופקי נחמד:
ctx.moveTo(10, 10);
ctx.lineTo(canvas.width, 10);
ctx.stroke();
גררר! זה לא נכון. 😡 מה עושה השורה הנוספת הזו כאן? בנוסף, למה הוא ורוד? בסדר, נבדוק ב-StackOverflow.
canvas.width = canvas.width;
למה זה כל כך טיפשי? למה זה כל כך קשה?
טוב, זה כבר לא המצב. ה-API החדש מאפשר לנו להציע לכם את הפתרון הפשוט, האלגנטי והחדשני:
ctx.reset();
סליחה על הזמן הארוך.
מסננים
פילטרים של SVG הם עולם בפני עצמו. אם אתם לא מכירים את המסננים האלה, מומלץ מאוד לקרוא את המאמר The Art Of SVG Filters And Why It Is Awesome, שבו מוסבר חלק מהפוטנציאל המדהים שלהם.
מסנני סגנון SVG כבר זמינים ל-Canvas2D! אתם רק צריכים להיות מוכנים להעביר את הפילטר ככתובת URL שמצביעה לרכיב מסנן אחר מסוג SVG בדף:
<svg>
<defs>
<filter id="svgFilter">
<feGaussianBlur in="SourceGraphic" stdDeviation="5" />
<feConvolveMatrix kernelMatrix="-3 0 0 0 0.5 0 0 0 3" />
<feColorMatrix type="hueRotate" values="90" />
</filter>
</defs>
</svg>
const canvas = document.createElement('canvas');
canvas.width = 500;
canvas.height = 400;
const ctx = canvas.getContext('2d');
document.body.appendChild(canvas);
ctx.filter = "url('#svgFilter')";
draw90sPattern(ctx);
מה מבולגן למדי את הדפוס:
אבל מה אם תרצו לבצע את הפעולות שלמעלה בלי לצאת מ-JavaScript ולא להתעסק עם מחרוזות? עם ממשק ה-API החדש, זה אפשרי לחלוטין.
ctx.filter = new CanvasFilter([
{ filter: 'gaussianBlur', stdDeviation: 5 },
{
filter: 'convolveMatrix',
kernelMatrix: [
[-3, 0, 0],
[0, 0.5, 0],
[0, 0, 3],
],
},
{ filter: 'colorMatrix', type: 'hueRotate', values: 90 },
]);
קל כמו שתי וערב! אפשר לנסות את האפשרות הזו ולשחק עם הפרמטרים בדמו כאן.
חלק 3: שיפורי ביצועים
רצינו גם לשפר את הביצועים ככל האפשר באמצעות ממשק ה-API החדש של Canvas2D. הוספנו כמה תכונות כדי לתת למפתחים שליטה מדויקת יותר באתרים שלהם ולאפשר להם להציג את התמונות במהירות גבוהה ככל האפשר:
יקרא לעיתים קרובות
כדי לקרוא נתוני פיקסלים באזור העריכה, משתמשים ב-getImageData()
. התהליך יכול להיות איטי מאוד. ה-API החדש מאפשר לסמן באופן מפורש לוח קנבס לקריאה חוזרת (לדוגמה, לאפקטים גנרטיביים).
כך תוכלו לבצע אופטימיזציה ברקע ולשמור על מהירות התצוגה של הקנבס במגוון רחב יותר של תרחישים לדוגמה. התכונה הזו קיימת ב-Firefox כבר זמן מה, ועכשיו אנחנו סוף סוף מוסיפים אותה למפרט של הקנבס.
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d', { willReadFrequently: true });
אובדן הקשר
נשמח שוב לשמחה של כרטיסיות עצובות! במקרה שנגמר הזיכרון של ה-GPU או שמתרחש אסון אחר באזור העריכה, אתם יכולים לקבל קריאה חוזרת (callback) ולצייר מחדש לפי הצורך:
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.addEventListener('contextlost', onContextLost);
canvas.addEventListener('contextrestored', redraw);
למידע נוסף על הקשר ואובדן של קנבס ב-whatWG, יש הסבר טוב ב-wiki.
סיכום
בין אם אתם משתמשים חדשים ב-Canvas2D, משתמשים בו כבר שנים או נמנעים משימוש בו כבר שנים, אני כאן כדי להמליץ לכם לבדוק שוב את Canvas. זהו ממשק ה-API של השכן, שהיה שם כל הזמן.