مقدمة إلى HTML5 Canvas ودوال JavaScript
في عالم تطوير الويب المتسارع، يمثل إتقان أدوات الرسم والتفاعل البصري مهارة أساسية. تعد HTML5 Canvas إضافة قوية تتيح للمطورين إنشاء رسومات ديناميكية وتفاعلية مباشرة في المتصفح باستخدام JavaScript. يهدف هذا المقال إلى تقديم مقدمة شاملة لـ HTML5 Canvas، بدءًا من أساسيات الدوال في JavaScript وصولاً إلى بناء أشكال معقدة ورموز تعبيرية جذابة.
للمتابعة العملية، يمكنك استخدام بيئات تطوير متكاملة عبر الإنترنت مثل repl.it أو codepen.io التي توفر لك محررًا فوريًا لتجربة الأكواد.
ما هي الدوال (Functions)؟
لفهم كيفية استخدام HTML5 Canvas، يجب أن ندرك أساسيات الدوال. الدوال (Functions) هي وحدات برمجية مستقلة مصممة لإنجاز مهمة محددة. عادةً ما تستقبل الدوال بيانات (مدخلات)، تعالجها، ثم تعيد نتيجة (مخرجات). بمجرد كتابة الدالة، يمكن إعادة استخدامها مرارًا وتكرارًا، مما يعزز كفاءة الكود وقابليته للصيانة.
الآن، دعنا نستعرض بعض الأمثلة على أنواع الدوال التي سنتعامل معها.
أنواع الدوال
الدالة الاعتيادية البسيطة
نعلن عن دالة أساسية باستخدام الكلمة المفتاحية function في JavaScript.
function sayHelloTo ( name ) {
return 'Hello ' + name;
}
sayHelloTo('Adam');
تستقبل هذه الدالة معلمة واحدة تسمى name. وهي متغير يتم تمريره إلى الدالة sayHelloTo. لذلك، عندما يتم تنفيذ البرنامج، فإنه سيمرر القيمة المقدمة. في هذا المثال، القيمة هي 'Adam'، لذا سترى في وحدة التحكم (console) Hello Adam.
نمط المُنشئ (Constructor Pattern)
يمكننا أيضًا إنشاء دالة باستخدام نمط المُنشئ.
function Person ( name ) {
this.name = name;
this.sayHello = function ( ) {
return "Hello, my name is " + this.name;
}
}
var me = new Person("Adam");
me.sayHello();
تشير الكلمة المفتاحية this في JavaScript إلى الدالة نفسها. هذا يعني أنه عندما نمرر متغيرًا مثل name، تمامًا كما فعلنا من قبل، يمكننا تعيينه للدالة ولأي نسخة (instance) من تلك الدالة. لإنشاء نسخة، نستخدم الكلمة المفتاحية new في JavaScript. عندما يتم إنشاء هذه النسخة الجديدة من الدالة، فإنها تحتوي أيضًا على خصائص مثل قيمة this.name وطريقة this.sayHello. عندما أنشأنا نسخة من الدالة، مررنا اسمًا: var me = new Person('Adam'). عندما تنظر إلى طريقة sayHello، فإنها تستخدم هذا الاسم، الذي أصبح الآن جزءًا من تلك النسخة، لإنشاء جملة. إذا قمت بتنفيذ هذا الكود في بيئة NodeJS REPL، فسترى الإخراج Hello, my name is Adam.
الرسم على Canvas
الآن بعد أن فهمنا أساسيات الدوال، دعنا ننتقل إلى الرسم على canvas. الطريقة المقترحة لتعلم هذا القسم هي استخدام بيئات تطوير مثل codepen.io. إذا كنت ترغب في المتابعة، يمكنك إنشاء حساب وإنشاء pen جديد.
إنشاء Canvas
أولاً، نحتاج إلى إنشاء عنصر canvas لتتمكن من الرسم عليه. في ملف HTML الخاص بك، أنشئ وسم <canvas>.
<canvas id="canvas"></canvas>
الآن، كل ما يلي سيكون باستخدام JavaScript! نحتاج إلى الحصول على عنصر canvas الخاص بنا من نموذج كائن المستند (DOM) وإعلانه كمتغير. سيتيح لنا ذلك تعيين سياقه (context). لسنا ماهرين بما يكفي في الرسومات ثلاثية الأبعاد ('3d') بعد، لذا سنلتزم بسياق ثنائي الأبعاد ('2d').
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
يمكننا أيضًا إعطاء canvas خصائص العرض (width) والارتفاع (height).
var canvas = document.getElementById("canvas");
canvas.width = 800;
canvas.height = 800;
var context = canvas.getContext("2d");
أود الإشارة هنا إلى أن canvas يتصرف تمامًا ككائن (object). له خصائص (properties) وطرق (methods) تمامًا كما رأينا في دالة المُنشئ أعلاه. يختلف قليلاً في كيفية إعلانه ولكنه يعمل بشكل مشابه جدًا من الناحية الوظيفية. لذا، سترى أن له خصائص height و width بالإضافة إلى طريقة getContext.
الآن، دعنا نضع كل ذلك في دالة لتتعرف على البرمجة الوظيفية.
function draw ( ) {
var canvas = document.getElementById("canvas");
canvas.width = 800;
canvas.height = 800;
var context = canvas.getContext("2d");
}
لن يظهر أي شيء على الشاشة بعد، سنستخدم طريقة fillRect لمساعدتنا في ذلك.
function draw ( ) {
var canvas = document.getElementById( "canvas" );
canvas.width = 800;
canvas.height = 800;
var context = canvas.getContext( "2d" );
context.fillRect( 10, 10, 100, 200 );
}
إذا لم تكن قد خمنت، فإن طريقة fillRect تستقبل أربع معلمات: إحداثي x، إحداثي y، العرض (width)، والارتفاع (height). على canvas، يبدأ المحور x من 0 على اليسار ويتجه إلى ما لا نهاية نحو اليمين. ويبدأ المحور y من 0 من الأعلى ويتجه إلى ما لا نهاية نحو الأسفل. لذا، عندما نبدأ من (10, 10)، فإننا نضع المؤشر الافتراضي عند النقطة (x = 10, y = 10) ونتجه 100 وحدة إلى اليمين و 200 وحدة إلى الأسفل من تلك النقطة.
كما لاحظت، لم يتم إضافة المستطيل إلى الصفحة بعد. أضف دالة window.onload بسيطة واجعلها تساوي دالة draw المكتملة.
function draw ( ) {
var canvas = document.getElementById( "canvas" );
canvas.width = 800;
canvas.height = 800;
var context = canvas.getContext( "2d" );
context.fillRect( 10, 10, 100, 200 );
}
window.onload = draw;
قد تتساءل لماذا تم تنفيذ دالة draw على الرغم من أننا لم ننفذها بأقواس (()). هذا لأن window.onload يتوقع دالة ليتم تنفيذها عند تحميل النافذة. عندما تُسند دالة (مثل draw) إليه بدون أقواس، فإنه يقوم بتنفيذها تلقائيًا عند وقوع حدث التحميل، مماثلًا لاستدعائها بالأقواس. هذا يعني أن window.onload ينفذ دالة عندما يتم تحميل النافذة.
دعنا نضيف بعض الألوان للمتعة! هنا نستخدم طريقة fillStyle لذلك. يجب أن تأتي قبل fillRect وإلا فلن تظهر.
function draw ( ) {
var canvas = document.getElementById( "canvas" );
canvas.width = 800;
canvas.height = 800;
var context = canvas.getContext( "2d" );
context.fillStyle = "blue";
context.fillRect( 10, 10, 100, 200 );
}
window.onload = draw;
رسم أشكال أخرى
كان ذلك بسيطًا جدًا. دعنا نرسم بعض الأشكال الأخرى الآن. تمامًا كما فعلنا من قبل، سنقوم بإنشاء دالة وتهيئة canvas الخاص بنا بـ width و height و context.
function triangle ( ) {
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
canvas.width = 400;
canvas.height = 400;
}
حتى لا ننسى، قم بتغيير دالة onload لتأخذ دالة triangle الآن.
window.onload = triangle;
الآن بعد أن أصبح لدينا canvas، دعنا نبدأ في رسم الخطوط على canvas لإنشاء مثلثنا.
function triangle ( ) {
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
canvas.width = 400;
canvas.height = 400;
context.beginPath();
context.moveTo( 75, 50 );
}
هنا نبدأ مسارنا (path) وننقل المؤشر إلى النقطة (x = 75, y = 50). الآن دعنا نرسم بعض الخطوط.
function triangle ( ) {
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
canvas.width = 400;
canvas.height = 400;
context.beginPath();
context.moveTo( 75, 50 );
context.lineTo( 100, 75 );
context.lineTo( 100, 25 );
context.stroke();
}
هذا أنشأ الخطين الأولين اللذين احتجناهما. لإنهائه، نعود إلى حيث بدأنا.
function triangle ( ) {
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
canvas.width = 400;
canvas.height = 400;
context.beginPath();
context.moveTo( 75, 50 );
context.lineTo( 100, 75 );
context.lineTo( 100, 25 );
context.lineTo( 75, 50 ); // العودة إلى نقطة البداية
context.stroke();
}
لملء المثلث، يمكننا استخدام طريقة fill.
function triangle ( ) {
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
canvas.width = 400;
canvas.height = 400;
context.beginPath();
context.moveTo( 75, 50 );
context.lineTo( 100, 75 );
context.lineTo( 100, 25 );
context.lineTo( 75, 50 );
context.stroke();
context.fill();
}
يمكننا الآن فعل الشيء نفسه بسهولة لإنشاء هرم ضخم.
function pyramid ( ) {
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
canvas.width = 400;
canvas.height = 400;
}
تذكر تغيير دالة onload إلى pyramid.
window.onload = pyramid;
الآن دعنا ننقل المؤشر إلى حيث نريده أن يكون.
function pyramid ( ) {
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
canvas.width = 400;
canvas.height = 400;
context.beginPath();
context.moveTo( 200, 0 );
}
نريد أن يشغل الهرم أكبر قدر ممكن من المساحة، لذلك نبدأ من أعلى canvas تمامًا وفي منتصف المحور x. الآن يمكننا البدء في رسم شكلنا وملئه.
context.lineTo( 0, 400 );
context.lineTo( 400, 400 );
context.lineTo( 200, 0 );
context.stroke();
context.fillStyle = "orange";
context.fill();
لقد انتهينا! يجب أن يكون لديك الآن هرم برتقالي جميل على شاشتك.
الرموز التعبيرية (Emojis)!
الآن نصل إلى ما جئت من أجله: الرموز التعبيرية! تمامًا كما فعلنا من قبل، نقوم بإعداد canvas الخاص بنا.
function smileyFaceEmoji ( ) {
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
canvas.width = 500;
canvas.height = 500;
}
تذكر تغيير onload إلى هذه الدالة.
window.onload = smileyFaceEmoji;
الآن دعنا نرسم وجهنا.
context.beginPath();
context.arc( 250, 250, 100, 0, Math.PI*2, true );
context.stroke();
لقد غيرت الأمور قليلاً هنا باستخدام دالة arc. تستقبل دالة arc عددًا لا بأس به من المعاملات: إحداثي x، إحداثي y، نصف القطر (radius)، نقطة البداية بالراديان (radians)، نقطة النهاية بالراديان، وما إذا كانت مرسومة باتجاه عقارب الساعة (قلنا true). على عكس كيفية إنشاء المستطيل الذي يبدأ من نقطة وينتقل إلى التالية، فإن النقطة (x = 250, y = 250) هي في الواقع منتصف الدائرة ثم تمتد 100 بكسل. رائع أليس كذلك؟!
بعد ذلك تأتي العيون.
context.moveTo( 235, 225 );
context.arc( 225, 225, 10, 0, Math.PI*2, true );
context.moveTo( 285, 225 );
context.arc( 275, 225, 10, 0, Math.PI*2, true );
context.stroke();
ثم الفم.
context.moveTo( 250, 275 );
context.arc( 250, 275, 50, 0, Math.PI, false );
context.moveTo(250, 275);
context.lineTo(200, 275);
context.stroke();
لقد قمت بذلك، لقد صنعت للتو رمزًا تعبيريًا لوجه مبتسم!
تمارين
إذا كنت ترغب في الارتقاء بمهاراتك في canvas إلى المستوى التالي، جرب أحد التمارين أدناه:
- ارسم رمزًا تعبيريًا للبراز (poop emoji).
- ارسم أحرف اسمك الأولى بخط متصل (cursive).
ملخص
في هذا الدرس، تعلمت عن الدوال (functions): كيفية إنشاء الدوال، تنفيذ الدوال، واستخدام الدوال لبناء برامج صغيرة ترسم الخطوط على canvas. لقد تعلمنا أن الدوال تتخذ أشكالًا عديدة ويمكن إعطاؤها خصائص (properties) وطرقًا (methods). كان الهدف من هذا الدرس هو إظهار قوة الدوال دون إغراقك بالمصطلحات المعقدة، وبدلاً من ذلك، استخدام المحفزات البصرية لإضفاء الحياة عليها!
💡 الخلاصة التقنية
تُعد HTML5 Canvas أداة أساسية للمطورين لإنشاء رسومات ديناميكية في المتصفح، مدعومة بقوة JavaScript. من خلال فهم الدوال (functions) وأنماطها المختلفة مثل الدوال الاعتيادية والمُنشئات (constructors)، يمكننا التفاعل مع Canvas ككائن ذي خصائص وطرق. تتيح لنا واجهة برمجة تطبيقات Canvas API التحكم الدقيق في الرسم عبر سياق ثنائي الأبعاد ('2d' context)، باستخدام طرق مثل fillRect()، beginPath()، moveTo()، lineTo()، arc()، بالإضافة إلى stroke() و fill() لإنشاء أشكال معقدة وتلوينها. كما أن فهم كيفية عمل window.onload ضروري لتشغيل الكود عند تحميل الصفحة، مما يضمن ظهور الرسومات بشكل صحيح.