اذهب إلى المحتوى

العمل مع الرسوميات في جافا سكريبت: الرسومات ثنائية البعد ضمن العنصر Canvas


ابراهيم الخضور

يتضمن المتصفح مجموعة أدوات برمجية فعّالة للتعامل الرسوميات ابتداءً من لغة إنشاء الرسوميات الشعاعية SVG، إلى الواجهات التي تسمح لك بالرسم ضمن العنصر <canvas>. لهذا سنقدم في هذا المقال مدخلًا إلى الوجهة البرمجية Canvas، إضافة إلى بعض الموارد اﻷخرى لتزيد من معارفك في هذا المجال.

ننصحك قبل المتابعة في قراءة هذه المقالات أن:

الرسوميات في الويب

ذكرنا في مقالات سابقة أن الويب كان بداية نصيًا -أي يعرض محتوى نصي فقط- بشكل كامل مما جعله ضعيف الجاذبية، لذلك ظهرت الصور بداية من خلال العنصر <img> ولاحقًا من خلال خاصيات لغة التنسيق CSS مثل الخاصية background-image و من ثم بدأ استخدام الصور الشعاعية أو المتجهة SVG.

مع ذلك لم يكن كل هذا كافيًا. وعلى الرغم من إمكانية استخدام CSS وجافا سكريبت لتحريك الصور الشعاعية SVG vector images والتعامل معها كونها تُكتب باستخدام تعليمات ترميز markup ولم تكن هناك طريقة لعمل المثل على الصور النقطية bitmap images وكانت الأدوات المتوفرة محدودة. ولم توجد طريقة أصيلة في الويب ﻹنشاء الرسوميات المتحركة أو اﻷلعاب أو المشاهد ثلاثية الأبعاد والتي تحتاج متطلبات خاصة تتعامل معها لغات برمجة منخفضة المستوى مثل ++C وجافا.

بدأ الوضع بالتحسن عندما دعمت المتصفحات العنصر والواجهة البرمجية المتعلقة به في عام 2004. وكما سنرى تاليًا، تقدم عناصر canvas بعض اﻷدوات المفيدة التي تساعد في إنشاء رسوميات متحركة ثنائية البعد وألعاب، وعرض البيانات وغيرها من اﻹمكانات وخاصة عندما تتكامل مع واجهات برمجية أخرى تقدمها منصة الويب. لكن كان من الصعب إعدادها للوصول السهل accessibility.

سترى في المثال التالي الكرات القافزة المرتدة التي عملنا عليها في مقال سابق وهي مشهد ثنائي البعد مبني على أساس العنصر canvas.

وفي الفترة الممتدة بين 2006 إلى 2007 عملت موزيللا على إنجاز عناصر لوحات رسومية canvas ثلاثية اﻷبعاد، وتحولت فيما بعد إلى WebGL التي حظيت باهتمام مطوري المتصفحات وقد جرى توصيفها لتكون معيارًا بين عامي 2009-2010. وتتيح لك الواجهة WebGL إنشاء رسوميات ثلاثية اﻷبعاد ضمن المتصفح. بقدم المثال التالي مكعبًا يدور باستخدام هذه الواجهة:

نركز في مقالنا على لوحات الرسم ثنائية البعد، وبما أن شيفرة WebGL الخام شديدة التعقيد، سنعرض طريقة استخدام المكتبة WebGL ﻹنشاء مشهد ثلاثي اﻷيعاد بسهولة أكبر.

تطبيق عملي: ابدأ العمل مع لوحة الرسم canvas

إن أردت إنشاء رسوميات ثنائية وثلاثية البعد على صفحة ويب عليك أن تنطلق من عنصر HTML الذي يُمثّل لوحة الرسم <canvas>. ويُستخدم هذا العنصر في تحديد منطقة من الصفحة للرسم فيها. واﻷمر بسيط ويتم بإضافة عنصر <canvas> إلى الصفحة كما يلي:

<canvas width="320" height="240"></canvas>

تنشئ الشيفرة السابقة لوحة رسم أبعادها 230 و 240 بكسل. ولا بد أن تضع شيئًا ما ضمن وسمي البداية والنهاية للعنصر كي يصف محتوى اللوحة لمستخدمي المتصفحات التي لا تدعم العنصر أو لمستخدمي قارئات الشاشة:

<canvas width="320" height="240">
 <p>اكتب هنا وصف اللوحة للمستخدمين الذين لا يمكنهم رؤيتها </p>
</canvas>

و لابد أن يعتبر ما تضعه ضمن وسمي العنصر بديلًا مفيدًا عن محتوى اللوحة، فإن كنت تصيّر أو تعرض رسمًا يتغير بشكل مستمر ليعبر عن أسعار البورصة مثلًا ، ينبغي أن يكون المحتوى البديل صورة تتضمن آخر تحديث للرسم مع نص بديل عنها alt يتحدث عن اﻷسعار أو قائمة من الروابط المستقلة لكل صفحة من صفحات هذه البورصة.

ملاحظة: لا يمكن الوصول إلى محتوى لوحة الرسم من خلال قارئات الشاشات، لهذا عليك وضع نص يصف محتواها على شكل قيمة
للسمة arial-label ضمن العنصر <canvas> نفسه أو استخدام محتوى مستقل ضمن وسمي البداية والنهاية للعنصر. وتذكر أن محتوى <canvas> ليس جزءًا من شجرة DOM لكن العنصر الذي تضعه ضمنه كذلك.

إنشاء لوحة رسم وتحديد أبعادها

لنبدأ بإنشاء لوحة رسم خاصة بتطبيقنا، لهذا اتبع الخطوات التالية:

  1. انسخ مجلد المشروع الذي يتضمن الملفات التالية:
  • index.html
  • script.js
  • style.css
  1. افتح الملف index.html ثم أضف الشيفرة التالية ضمنه تحت الوسم <body>:
<canvas class="myCanvas">
 <p>Add suitable fallback here.</p>
</canvas>

أضفنا في الكود أعلاه صنفًا إلى العنصر <canvas> حتى يسهل الوصول إليه عن طريق جافا سكريبت في حال كان هناك أكثر من لوحة نريد العمل معها، لكننا أزلنا السمتين width و height حاليًا (بإمكانك إعادتهما إن أردت، لكننا سنضبطهما لاحقًا باستخدام جافا سكريبت). وستأخذ اللوحات افتراضيًا ارتفاعًا مقداره 150 بكسل واتساعًا مقداره 300 بكسل.

  1. افتح الملف scripts.js ثم أضف شيفرة جافا سكريبت التالية:
const canvas = document.querySelector(".myCanvas");
const width = (canvas.width = window.innerWidth);
const height = (canvas.height = window.innerHeight);

خزّنا هنا مرجعًا إلى لوحة الرسم ضمن الثابت canvas ومن ثم أنشأنا ثابتًا آخر width وضبطنا قيمته وقيمة اتساع اللوحة لتكون مساوية لاتساع نافذة المتصفح Window.innerWidth، وكررنا ما فعلناه في السطر الثالث لكن مع ارتفاع اللوحة.

وهكذا ستملأ لوحة الرسم نافذة المتصفح (تذكر أن الارتفاع هنا هو ارتفاع نافذة العرض viewport). لاحظ أيضًا كيف نفذنا سلسلة من اﻹسنادات باستخدام عدة عوامل مساواة =، وهذا أمر مسموح في جافا سكريبت ويُعد مفيدًا إن أردت إسناد القيمة ذاتها إلى عدة متغيرات. كما حرصنا على تأمين طريقة للوصول إلى أبعاد اللوحة بإسنادها إلى متغيرات، وتأتي فائدة هذه الفكرة إن احتجنا لاحقًا على سبيل المثال إلى رسم شيء ما في وسط اللوحة تمامًا.

ملاحظة: علينا غالبًا ضبط أبعاد الصور باستخدام سمات HTML أو خاصيات شجرة DOM كما شرحنا في اﻷعلى. كما يمكنك استخدام CSS لكن تطبيق اﻷبعاد الجديدة سيكون بعد تصيير لوحة الرسم وهكذا قد تتعرض لوحة الرسم كغيرها من الصورة إلى التشوه.

ضبط مسار العمل على اللوحة وإنهاء اﻹعداد

نحتاج إلى مرجع خاص إلى منطقة العمل حتى نستطيع الرسم على اللوحة يُعرف بمسار العمل context. وننفذ هذا اﻷمر باستخدام التابع ()HTMLCanvasElement.getContext الذي يأخذ معاملًا واحدًا بأبسط حالات استخدامه تمثل نوع مسار العمل الذي نريده. وما نحتاجه في تطبيقنا لوحة ثنائية البعد، لهذا سنضيف شيفرة جافا سكريبت التالية في آخر الشيفرة الموجودة في الملف script.js:

const ctx = canvas.getContext("2d");

ملاحظة: بإمكانك اختيار مسارات عمل أخرى مثل webgl من أجل WebGL و webgl2 من أجل 2 WebGL لكننا لن تحتاج هذه المسارات في مقالنا.

وهكذا تصبح لوحة الرسم جاهزة في تطبيقنا، وسيحمل المتغير ctx الكائن CanvasRenderingContext2D وسيكون الرسم على اللوحة من خلال التعامل مع هذا الكائن.

دعونا قبل إكمال العمل ننفذ شيئًا أخيرًا وهو تلوين خلفية الصفحة لتأخذ فكرة بسيطة عن الواجهة البرمجية Canvas. أضف الشيفرة التالية إلى شيفرة الملف script.js:

ctx.fillStyle = "rgb(0 0 0)";
ctx.fillRect(0, 0, width, height);

نضبط في هذه الشيفرة لون الخلفية باستخدام الخاصية fillStyle التي تأخذ قيمًا لونية كما هو حال خاصيات CSS المشابهة، ثم نرسم مربعًا يغطي كامل لوحة الرسم باستخدام التابع fillRect، ويمثل أول معاملين له الزاوية العليا اليسارية والمعاملين الباقين اتساع وارتفاع المربع الذي نريد رسمه (أخبرناك أن للمتغيرين width و height فوائد لاحقة).

أساسيات الرسوميات ثنائية البعد ضمن العنصر <canvas>

ذكرنا سابقًا أن جميع عمليات الرسم تجري من خلال التعامل مع الكائن CanvasRenderingContext2D (وهو ctx في تطبيقنا). وتحتاج الكثير من العمليات إلى إحداثيات لتحديد المكان الذي نرسم فيه بدقة، وتكون الزاوية العليا اليسارية بمثابة مبدأ الجملة اﻹحداثية وتمثل النقطة (0,0)، بينما يتجه المحور الأفقي (x) من اليسار نحو اليمين والعمودي (y) من اﻷعلى إلى اﻷسفل.

01_canvas_default_grid.png

تميل معظم الرسوميات إلى استخدام المربع البدائي primitive rectangle (الذي يمثل شكل أساسي يستخدم لبناء رسوميات أكثر تعقيدًا) أو تتبع خط عبر مسار محدد ومن ثم ملء الشكل الناتج. وسنشرح تاليًا كيف يجري اﻷمر.

مربعات بسيطة

سنبدأ برسم بعض المربعات البسيطة، لهذا:

  1. انسخ شيفرة قالب لوحة الرسم الذي حضرناه سابقًا (كما يمكنك إنشاء نسخة عن مجلد التطبيق إن لم تتابع معنا الخطوات السابقة).
  2. أضف الأسطر التالية من الشيفرة في أسفل شيفرة جافا سكريبت الموجودة:
ctx.fillStyle = "rgb(255 0 0)";
ctx.fillRect(50, 50, 100, 150);

إن حفظت التغيرات وأعدت تحميل الصفحة سترى مربعًا أحمر اللون ضمن اللوحة، تبعد زاويته العليا اليسارية مقدار 50 بكسل عن الحافتين العليا واليسارية للوحة (كما حددهما أول معاملين) وله اتساع مقداره 100 بكسل وارتفاع 150 بكسل (كما حددهما المعاملان اﻷخيران).

لنضف اﻵن مربعًا آخر أخضر هذه المرة:

ctx.fillStyle = "rgb(0 255 0)";
ctx.fillRect(75, 75, 100, 100);

احفظ التغييرات وأعد تحميل الصفحة لترى النتيجة.

تطرح الشيفرة السابقة نقطة هامة وهي أن جميع عمليات الرسم مثل رسم مربع أو خط وغيرها تُنفّذ وفق تسلسل ورودها في الشيفرة. فكّر بالأمر وكأنك ترسم على جدار، حيث تغطي كل طبقة ما تحتها. وبالطبع لا يمكن أن نغيّر هذا اﻷمر، لهذا عليك أن تفكّر مليًا بترتيب ما ترسمه على اللوحة.

كما يمكنك إنشاء رسومات شبه شفافة عند اختيارك لونًا شبه شفاف باستخدام التابع ()rgb مثلًا. إذ تُعرّف القناة ألفا alpha channel مقدار الشفافية في اللون، وكلما كانت قيمتها أكبر كلما زادت قتامة اللون وغطّى ما تحته. أضف السطرين التاليين إلى الشيفرة:

ctx.fillStyle = "rgb(255 0 255 / 75%)";
ctx.fillRect(25, 100, 175, 50);

جرب أن ترسم مربعات لتختبر قدرتك!

الإطارات وسماكة الخطوط

رسمنا حتى اللحظة مربعات ممتلئة، لكنك تستطيع أيضًا رسم إطارات مربعة strokes. ولضبط لون اﻹطار نستخدم الخاصية strokeStyle ونرسمه باستخدام التابع strokeRect.

أضف السطرين التاليين إلى الشيفرة:

ctx.strokeStyle = "rgb(255 255 255)";
ctx.strokeRect(25, 25, 175, 200);

للإطارات سماكة افتراضية قيمتها 1 بكسل، لكنك تستطيع تعديل السماكة باستخدام الخاصية lineWidth التي تأخذ قيمة تمثل سماكة اﻹطار مقدرة بالبكسل. أضف اﻵن السطر التالي إلى الشيفرة:

ctx.lineWidth = 5;

لاحظ كيف سيبدو اﻹطار أكثر سماكة. وسيبدو مثالنا حتى اللحظة كالتالي:

ملاحظة: ستجد الشيفرة الكاملة لهذا المثال على جت-هب.

رسم المسارات

لو أردت رسم ما هو أعقد من مربع، لا بد حينها من رسم مسار. ويقتضي اﻷمر بأبسط أشكاله كتابة شيفرة تحدد تمامًا المسار الذي تريد أن يتحرك قلم الرسم عليه ضمن اللوحة حتى يرسم الشكل المطلوب. وتضم الواجهة Canvas دوال لرسم خطوط مستقيمة ودوائر ومنحنيات بيزيه وغيرها الكثير.

لنبدأ اﻵن هذا القسم بنسخة جديدة من قالب المثال الذي أعددناه سابقًا، وسنستخدم بعض التوابع والخاصيات الشائعة خلال الأقسام التالية:

  • ()beginPath: يبدأ رسم مسار من النقطة التي يكون عندها القلم حاليًا في اللوحة وستكون هذه النقطة مبدأ اﻹحداثيات إن كانت اللوحة جديدة.
  • ()moveTo: ينقل القم إلى نقطة أخرى من اللوحة دون رسم أو تسجيل المسار بل يقفز القلم إلى النقطة المختارة.
  • ()fill: يرسم شكلًا يملأ المسار الذي رسمه القلم.
  • ()stroke: يرسم إطارًا مبنيًا على المسار الذي يرسمه القلم.
  • باﻹمكان استخدام الخاصيات lineWidth و fillStyle أو strokeStyle مع المسارات أيضًا.

تبدو شيفرة رسم مسار نمطي قريبة من التالي:

ctx.fillStyle = "rgb(255 0 0)";
ctx.beginPath();
ctx.moveTo(50, 50);
// ارسم مسارك
ctx.fill();

رسم الخطوط

لنرسم اﻵن مثلث متساوي الأضلاع ضمن اللوحة:

  1. أضف بداية الدالة المساعدة التالية في أسفل الشيفرة، مهمة هذه الدالة تحويل قيم الزوايا من درجات إلى راديان. تكمن فائدة هذه الدالة في أن جافا سكريبت تفهم قيم الزوايا بالراديان لكننا كبشر نفكر طبيعيًا بالدرجات.
function degToRad(degrees) {
 return (degrees * Math.PI) / 180;
}
  1. ابدأ المسار بإضافة الشيفرة التالية تحت الشيفرة السابقة، وفيها نضبط لون المثلث ونبدأ رسم المسار ثم ننتقل مباشرة إلى النقطة (0,0) دون رسم أي شيء ومن هذه النقطة نبدأ رسم المثلث:
ctx.fillStyle = "rgb(255 0 0)";
ctx.beginPath();
ctx.moveTo(50, 50);
  1. أضف اﻷسطر التالية في نهاية الشيفرة السابقة:
ctx.lineTo(150, 50);
const triHeight = 50 * Math.tan(degToRad(60));
ctx.lineTo(100, 50 + triHeight);
ctx.lineTo(50, 50);
ctx.fill();

نرسم بداية خطًا من نقطة البداية إلى النقطة (150,50) وسيتجه مسارنا 100 بكسل إلى اليمين وفق المحور x. نحسب بعد ذلك ارتفاع المثلث متساوي اﻷضلاع باستخدام قواعد مثلثية بسيطة إذ نعلم أن زوايا المثلث هي 60 درجة. لهذا نستطيع تقسيم المثلث المتساوي اﻷضلاع الذي نوجهه للأسفل إلى مثلثين قائمين لكل منهما زاويتين حادتين قياسهما 30 و60 درجة. ونعرّف في المثلث القائم:

  • الوتر hypotenuse: وهو أطول أضلاع المثلث القائم.
  • المجاور adjacent: وهو هنا الضلع المجاور للزاوية 60 وطوله 50 بكسل لأنه يمثل نصف طول المسار الذي رسمناه سابقًا.
  • المقابل opposite: وهو هنا الضلع المقابل للزاوية 60 ويمثل ارتفاع المثلث المتساوي اﻷضلاع الذي ننوي رسمه.

يُعطى طول المجاور رياضيًا من خلال جداء المقابل بظل الزاوية tan:

50 * Math.tan(degToRad(60))

نستخدم هنا الدالة ()degToRad التي بنيناها سابقًا لتحويل الزاوية 60 درجة إلى راديان وهي القيمة التي يتوقعها التابع ()Math.tan الذي يحسب ظل الزاوية.

  1. بعد حساب اﻹرتفاع، نرسم خطًا آخر إلى النقطة (100, 50+triHeight) إلى نقطة أخرى لها إحداثي X يعادل نصف طول المسار المستقيمة السابق وإحداثي Y قيمته تعادل 50 زائدًا طول اﻹرتفاع، ذلك أن قاعدة المثلث تنزاح إلى داخل اللوحة مقدار 50 بكسل عن الحافة العليا لها.
  2. أما الخطوة التالية فهي رسم خط من آخر نقطة إلى نقطة البداية ليتكون المثلث.
  3. نستدعي في النهاية التابع ()ctx.fill ﻹنهاء المسار وملئ الشكل الناتج.

رسم الدوائر

لنلق نظرة على طريقة رسم الدوائر في اللوحة. تُنفّذ هذه العملية من خلال التابع ()arc الذي يرسم جزءًا من قوس الدائرة أو قوس الدائرة بأكمله ابتداءًا من نقطة محددة:

  1. ﻹضافة دائرة إلى لوحتنا ضع الشيفرة التالية في نهاية الشيفرة السابقة:
ctx.fillStyle = "rgb(0 0 255)";
ctx.beginPath();
ctx.arc(150, 106, 50, degToRad(0), degToRad(360), false);
ctx.fill();

يأخذ التابع ()arc ست معاملات، يحدد اﻷول والثاني اﻹحداثيين x و y لمركز الدائرة والثالث هو نصف قطر الدائرة، بينما يحدد المعاملين الخامس والسادس زاويتي البداية والنهاية لقوس الدائرة (0 و 360 يرسمان دائرة كاملة) ويحدد المعامل اﻷخير إذا ما كانت الدائرة سترسم باتجاه عقارب الساعة أو عكسها (تعني القيمة false أن الرسم باتجاه عقارب الساعة)

ملاحظة: الزاوية 0 هي الزاوية الأفقية إلى اليمين.

لنجرب إضافة قوس آخر:

ctx.fillStyle = "yellow";
ctx.beginPath();
ctx.arc(200, 106, 50, degToRad(-45), degToRad(45), true);
ctx.lineTo(200, 106);
ctx.fill();

هناك اختلافان بسيطان عن النمط السابق:

  • ضبطنا قيمة المعامل الأخير للتابع ()arc على القيمة true أي سيرسم القوس بعكس اتجاه عقارب الساعة، فحتى لو كانت زاوية البداية هي 45- وزاوية النهاية 45 درجة فإن القوس يغطي زاوية 270 درجة وليس 90 درجة والتي يمكن أن تحصل عليها إن كانت قيمة المعامل false.
  • رسمنا خطًا إلى مركز الدائرة قبل استدعاء ()fill كي نحصل على دائرة اقتطع منها مثلث. وإن لم نرسم هذا الخط سيصل المتصفح نقطة البداية ونقطة النهاية ويملأ الشكل الناتج وهو دائرة اقتطع منها طرف.

ستبدو نتيجة المثال السابق قريبة من التالي:

ملاحظة: بإمكانك الاطلاع على الشيفرة كاملة لهذا المثال على جت-هب.

رسم النصوص

يتيح لك العنصر <canvas> رسم عبارات نصية، وهذا ما سنتعلمه بإيجاز تاليًا. لنبدأ بإنشاء نسخة جديدة عن قالب التطبيق كي نرسم المثال الجديد. ونستخدم في هذا المثال التابعين:

  • ()fillText: الذي يملأ النص.
  • ()strokeText: الذي يرسم الحواف الخارجية للنص.

يأخذ كل تابع منهما ثلاثة خاصيات بشكله البسيط: النص الذي سيُرسم واﻹحداثيين x و y للنقطة التي يبدأ الرسم عندها. هذه النقطة هي عمليًا الزاوية السفلى اليسارية لصندوق النص الذي نرسمه (الصندوق الذي يحيط بالنص). قد يسبب اﻷمر إرباكًا أحيانًا بالنظر إلى أن عمليات الرسم اﻷخرى تميل إلى البدء من الزاويا العليا اليسارية، تذكر ذلك جيدًا.

وهنالك أيضًا عدد من الخاصيات التي تساعد في إدارة تصيير النص مثل font التي تسمح بتخصيص عائلة الخط وحجمه وغيرها، وتأخذ قيمها وفق الصيغة نفسها التي نستخدمها مع خاصية CSS التي تحمل نفس الاسم.

ولا يمكن لقارئات الشاشة الوصول إلى محتوى العنصر <canvas> لأن النص الذي يُرسم في اللوحة لا يُعد جزءًا من شجرة DOM، لهذا لا بد من جعله متاحًا لذوي الاحتياجات الخاصة. وفي مثالنا جعلنا النص المكتوب ضمن اللوحة قيمة للسمة aria-label.

أضف اﻵن الشيفرة التالية إلى نهاية شيفرة جافا سكريبت:

ctx.strokeStyle = "white";
ctx.lineWidth = 1;
ctx.font = "36px arial";
ctx.strokeText("Canvas text", 50, 50);

ctx.fillStyle = "red";
ctx.font = "48px georgia";
ctx.fillText("Canvas text", 50, 150);

canvas.setAttribute("aria-label", "Canvas text");

رسمنا باستخدام الشيفرة السابقة سطرين أولهما مفرّغ واﻵخر ممتلئ، ويبدو الشكل النهائي للوحة شبيهًا بالتالي:

ملاحظة: بإمكانك الاطلاع على الشيفرة كاملة لهذا المثال على جت-هب.

رسم صور ضمن اللوحة

بإمكانك أيضًا تصيّر صور خارجية كي تُرسم ضمن العنصر <canvas>، ويمكن أن تكون الصور بسيطةً أو إطارات من فيديو أو غير ذلك. وسنلقي نظرة على رسم صور بسيطة ضمن اللوحة.

  1. أنشئ نسخة جديدة من قالب التطبيق الذي نستخدمه لتنفيذ الرسوميات. إذ ترسم الصور ضمن اللوحة باستخدام التابع ()drawImage. ويأخذ التابع بأبسط أشكاله ثلاث معاملات هي مرجع إلى الصورة واﻹحداثيين x و y للزاوية العليا اليسارية من الصورة.
  2. لنبدأ بتحديد مصدر للصورة التي نريد رسمها، لهذا أضف الشيفرة التالية إلى ملف جافا سكريبت:
const image = new Image();
image.src = "firefox.png";

أنشأنا في الشيفرة السابقة كائن HTMLImageElement جديد باستخدام الدالة البانية ()Image. وللكائن المعاد النوع ذاته الذي يُعاد عندما ننشئ مرجعًا إلى العنصر <img>، لهذا يمكن ضبط السمة src له كي تكون عنوان URL لصورة شعار فايرفوكس، وفي هذه المرحلة يبدأ المتصفح تحميل الصورة.

يمكن اﻵن رسم الصورة ضمن اللوحة باستخدام ()drawImage، لكن علينا أولًا التأكد من اكتمال تحميل الصورة وإلا ستخفق العملية. نتحقق من ذلك عن طريق الحدث load الذي يقع فقط عند إنتهاء تحميل الصورة، لهذا أضف الشيفرة التالية:

image.addEventListener("load", () => ctx.drawImage(image, 20, 20));

سترى إن أعدت تحميل اللوحة كيف رُسمت الصورة ضمن اللوحة. لكن بالطبع هناك المزيد. فماذا لو أردت رسم جزء من الصورة فقط أو أردت تغيير أبعادها؟ يمكننا بالطبع تنفيذ كلا اﻷمرين باستخدام صيغة أعقد للتابع ()drawImage. لهذا عدّل استدعاء التابع ()ctx.drawImage ليصبح كالتالي:

ctx.drawImage(image, 20, 20, 185, 175, 50, 50, 185, 175);
  • المعامل اﻷول هو مرجع إلى الصورة.
  • يحدد المعاملان 2 و 3 إحداثيات الزاوية العليا اليسارية من المنطقة التي تريد اقتطاعها من الصورة المحمّلة، ولن يُرسم أي شئ أعلى أو إلى يسار قيمتي المعاملين السابقين.
  • يحدد المعاملان 4 و 5 اتساع وارتفاع المنطقة التي تريد اقتطاعها من الصورة التي حملتها.
  • يحدد المعاملان 6 و 7 إحداثيا النقطة التي نريد أن نبدأ فيها رسم الصورة المقتطعة انطلاقًا من الزاوية العليا اليسارية لها نسبة إلى الزاوية العليا اليسارية للوحة.
  • يحدد المعاملان 8 و 9 اتساع وارتفاع المنطقة التي نريد أن نرسم فيها الصورة المقتطعة. وقد حددنا في مثالنا نفس أبعاد الصورة المقتطعة، لكن باﻹمكان إعادة تحجيم الصورة باستخدام قيم مختلفة للمعاملين.

في حال غيّرت في الصورة تغييرًا واضحًا لابد من تحديث توصيف الصورة الخاص بسهولة الوصول accessibility.

canvas.setAttribute("aria-label", "Firefox Logo");

ستبدو نتيجة المثال قريبة من التالي:

ملاحظة: بإمكانك الاطلاع على الشيفرة كاملة لهذا المثال على جت-هب.

الخلاصة

تعرفنا في هذا المقال على أساسيات الرسم ضمن العنصر <canvas> من حيث إعداد العنصر وضبط معاملاته. ثم تدربنا على رسم الخطوط والمسارات والدوائر والنصوص والصور في بيئة ثنائية البعد. وسنتابع في الجزء الثاني من هذا المقال العمل مع الرسومات المتحركة ثنائية وثلاثية البعد.

ترجمة -وبتصرف- للقسم اﻷول من مقال: Drawing graphics

اقرأ أيضًا


تفاعل الأعضاء

أفضل التعليقات

لا توجد أية تعليقات بعد



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...