شرح العنصر <canvas>
في HTML
مقدمة
في عالم تطوير الويب، يُمثل عنصر <canvas>
أحد أكثر الأدوات قوةً ومرونةً لإنشاء الرسومات بشكل برمجي. هذا العنصر الذي أُدخل في HTML5 قد غيّر طريقة تفاعلنا مع الرسومات على الويب، من خلال توفير سطح رسم (لوحة) يمكن التعامل معه عبر JavaScript لإنشاء كل شيء من الرسومات البسيطة إلى التطبيقات المعقدة مثل الألعاب وتطبيقات معالجة الصور.
ما هو عنصر <canvas>
<canvas>
هو عنصر HTML يُستخدم لرسم الرسومات ديناميكيًا عبر JavaScript. يمكن اعتباره كـ "لوحة فنان" رقمية تتيح لك:
- رسم الأشكال والخطوط والنصوص
- عرض ومعالجة الصور
- إنشاء الرسوم المتحركة
- تطبيق المؤثرات البصرية
- معالجة بيانات البكسل مباشرة
البنية الأساسية
<canvas id="اسم_الفنان" width="العرض" height="الارتفاع">
نص بديل يظهر إذا لم يدعم المتصفح canvas
</canvas>
السمات الأساسية:
id
: معرف فريد للوصول إلى العنصر من JavaScriptwidth
: عرض منطقة الرسم بالبكسل (الافتراضي: 300)height
: ارتفاع منطقة الرسم بالبكسل (الافتراضي: 150)
إعداد بيئة العمل
لبدء الرسم على canvas، نحتاج إلى خطوتين أساسيتين:
1 الوصول إلى عنصر canvas:
const canvas = document.getElementById('اسم_الفنان');
2 الحصول على سياق الرسم (Rendering Context):
const ctx = canvas.getContext('2d');
هناك أنواع أخرى من السياقات مثل webgl
للرسومات ثلاثية الأبعاد، لكننا سنركز على السياق ثنائي الأبعاد (2d
) في هذا المقال.
أساسيات الرسم على Canvas
1 رسم المستطيلات
هناك ثلاث طرق لرسم المستطيلات:
// مستطيل مملوء
ctx.fillStyle = 'blue'; // تحديد لون التعبئة
ctx.fillRect(x, y, width, height); // رسم مستطيل مملوء
// مستطيل حدودي (غير مملوء)
ctx.strokeStyle = 'red'; // تحديد لون الحدود
ctx.lineWidth = 3; // تحديد عرض الخط
ctx.strokeRect(x, y, width, height); // رسم مستطيل حدودي
// مسح منطقة مستطيلية
ctx.clearRect(x, y, width, height); // مسح المنطقة لجعلها شفافة
2 رسم المسارات (Paths)
المسارات هي أساس رسم الأشكال المعقدة:
ctx.beginPath(); // بدء مسار جديد
ctx.moveTo(50, 50); // نقل القلم إلى النقطة (50,50)
ctx.lineTo(200, 50); // رسم خط إلى النقطة (200,50)
ctx.lineTo(125, 125); // رسم خط إلى النقطة (125,125)
ctx.closePath(); // إغلاق المسار (اختياري)
ctx.stroke(); // رسم حدود المسار
// أو
ctx.fill(); // تعبئة المسار
3 رسم الأشكال الهندسية
الدوائر والأقواس:
ctx.beginPath();
// arc(x, y, radius, startAngle, endAngle, anticlockwise)
ctx.arc(100, 100, 50, 0, Math.PI * 2); // دائرة كاملة
ctx.stroke();
المنحنيات:
// منحنى بيزير
ctx.beginPath();
ctx.moveTo(50, 50);
ctx.quadraticCurveTo(100, 100, 150, 50); // (cp1x, cp1y, x, y)
ctx.stroke();
العمل مع النصوص
يمكنك إضافة نصوص إلى canvas بعدة طرق:
ctx.font = '30px Arial'; // تحديد الخط والحجم
ctx.fillStyle = 'black'; // لون النص
ctx.fillText('Hello Canvas', x, y); // نص مملوء
ctx.strokeStyle = 'blue'; // لون حدود النص
ctx.strokeText('Hello Canvas', x, y); // نص حدودي
محاذاة النص:
ctx.textAlign = 'center'; // left, right, center, start, end
ctx.textBaseline = 'middle'; // top, hanging, middle, alphabetic, ideographic, bottom
العمل مع الصور
يمكنك رسم الصور على canvas بعدة طرق:
const img = new Image();
img.src = 'path/to/image.jpg';
img.onload = function() {
// الطريقة الأساسية
ctx.drawImage(img, x, y);
// مع تغيير الحجم
ctx.drawImage(img, x, y, width, height);
// اقتصاص جزء من الصورة
ctx.drawImage(img, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);
};
التحويلات (Transformations)
تتيح لك التحويلات تعديل نظام الإحداثيات:
ctx.translate(x, y); // نقل نقطة الأصل
ctx.rotate(angle); // التدوير (بالراديان)
ctx.scale(scaleX, scaleY); // تغيير المقياس
ctx.transform(a, b, c, d, e, f); // تحويل مصفوفة عام
ctx.setTransform(a, b, c, d, e, f); // إعادة تعيين التحويل
ctx.resetTransform(); // إعادة التعيين إلى التحويل الأساسي
التدرجات والأنماط
التدرجات اللونية:
// التدرج الخطي
const linearGradient = ctx.createLinearGradient(x0, y0, x1, y1);
linearGradient.addColorStop(0, 'red');
linearGradient.addColorStop(1, 'blue');
ctx.fillStyle = linearGradient;
// التدرج الدائري
const radialGradient = ctx.createRadialGradient(x0, y0, r0, x1, y1, r1);
radialGradient.addColorStop(0, 'red');
radialGradient.addColorStop(1, 'blue');
ctx.fillStyle = radialGradient;
الأنماط (Patterns):
const img = new Image();
img.src = 'pattern.png';
img.onload = function() {
const pattern = ctx.createPattern(img, 'repeat'); // repeat, repeat-x, repeat-y, no-repeat
ctx.fillStyle = pattern;
ctx.fillRect(0, 0, canvas.width, canvas.height);
};
الرسوم المتحركة
لإنشاء رسوم متحركة على canvas، نستخدم requestAnimationFrame
:
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height); // مسح Canvas
// رسم العناصر المتحركة هنا
requestAnimationFrame(animate); // طلب الإطار التالي
}
animate(); // بدء الرسوم المتحركة
معالجة البكسل
يتيح لك Canvas الوصول المباشر إلى بيانات البكسل:
// الحصول على بيانات البكسل
const imageData = ctx.getImageData(x, y, width, height);
// تعديل البكسل
for (let i = 0; i < imageData.data.length; i += 4) {
imageData.data[i] = 255 - imageData.data[i]; // الأحمر
imageData.data[i+1] = 255 - imageData.data[i+1]; // الأخضر
imageData.data[i+2] = 255 - imageData.data[i+2]; // الأزرق
// imageData.data[i+3] هو قناة ألفا (الشفافية)
}
// إعادة البيانات المعدلة إلى Canvas
ctx.putImageData(imageData, x, y);
أداء Canvas
لتحسين أداء تطبيقات Canvas:
- استخدام
requestAnimationFrame
للرسوم المتحركة بدلاً منsetInterval
- تقليل عدد عمليات الرسم (مثل تجميع عمليات الرسم المتشابهة)
- استخدام طبقات متعددة من Canvas للعناصر المختلفة
- تجنب عمليات حسابية كثيرة في حلقة الرسوم المتحركة
- مسح مناطق محددة فقط عند التحديث
التطبيقات العملية لـ Canvas
- الرسوم البيانية والتخيل البيانات: مكتبات مثل Chart.js تستخدم Canvas
- الألعاب: يمكن بناء ألعاب ثنائية الأبعاد كاملة
- تعديل الصور: تطبيقات الفلاتر وتعديل الصور
- التوقيع الرقمي: إنشاء حقول توقيع رقمي
- التأثيرات البصرية: موجات، جسيمات، إلخ
- التعليم: عرض المفاهيم الرياضية والعلمية
الحدود والبدائل
حدود Canvas:
- غير متوافق مع تقنيات الوصول (مثل قارئات الشاشة)
- محتواه غير قابل للبحث أو التحديد
- قد يكون أداؤه ضعيفًا مع الرسومات المعقدة جدًا
بدائل:
SVG
: للأشكال المتجهية القابلة للتكبيرWebGL
: للرسومات ثلاثية الأبعاد المعقدةCSS
: للرسومات البسيطة والحركات
مثال شامل: لعبة Pong بسيطة
كود المثال
<!DOCTYPE html>
<html>
<head>
<title>لعبة Pong باستخدام Canvas</title>
<style>
body { margin: 0; overflow: hidden; }
canvas { display: block; background: #000; }
</style>
</head>
<body>
<canvas id="gameCanvas"></canvas>
<script>
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
// ضبط حجم Canvas ليملأ الشاشة
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
// متغيرات اللعبة
const paddleHeight = 100;
const paddleWidth = 15;
const ballSize = 10;
let playerY = (canvas.height - paddleHeight) / 2;
let computerY = (canvas.height - paddleHeight) / 2;
let ballX = canvas.width / 2;
let ballY = canvas.height / 2;
let ballSpeedX = 5;
let ballSpeedY = 5;
let playerScore = 0;
let computerScore = 0;
// التحكم بالمضرب
canvas.addEventListener('mousemove', (e) => {
playerY = e.clientY - paddleHeight / 2;
if (playerY < 0) playerY = 0;
if (playerY > canvas.height - paddleHeight) playerY = canvas.height - paddleHeight;
});
// حلقة اللعبة
function gameLoop() {
// مسح الشاشة
ctx.fillStyle = 'black';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// رسم المضارب
ctx.fillStyle = 'white';
ctx.fillRect(10, playerY, paddleWidth, paddleHeight); // لاعب
ctx.fillRect(canvas.width - paddleWidth - 10, computerY, paddleWidth, paddleHeight); // حاسوب
// رسم الكرة
ctx.fillRect(ballX - ballSize/2, ballY - ballSize/2, ballSize, ballSize);
// حركة الكرة
ballX += ballSpeedX;
ballY += ballSpeedY;
// اصطدام الكرة بالحواف العلوية والسفلية
if (ballY < ballSize/2 || ballY > canvas.height - ballSize/2) {
ballSpeedY = -ballSpeedY;
}
// اصطدام الكرة بمضرب اللاعب
if (ballX - ballSize/2 < 10 + paddleWidth &&
ballY > playerY && ballY < playerY + paddleHeight) {
ballSpeedX = -ballSpeedX * 1.1; // زيادة السرعة قليلاً
}
// اصطدام الكرة بمضرب الحاسوب (بشكل بسيط)
if (ballX + ballSize/2 > canvas.width - 10 - paddleWidth &&
ballY > computerY && ballY < computerY + paddleHeight) {
ballSpeedX = -ballSpeedX;
}
// تحريك مضرب الحاسوب (ذكاء اصطناعي بسيط)
computerY += (ballY - (computerY + paddleHeight/2)) * 0.1;
// تسجيل النقاط
if (ballX < 0) {
computerScore++;
resetBall();
}
if (ballX > canvas.width) {
playerScore++;
resetBall();
}
// عرض النتيجة
ctx.font = '30px Arial';
ctx.fillText(playerScore, 100, 50);
ctx.fillText(computerScore, canvas.width - 100, 50);
requestAnimationFrame(gameLoop);
}
function resetBall() {
ballX = canvas.width / 2;
ballY = canvas.height / 2;
ballSpeedX = -ballSpeedX;
ballSpeedY = 5 * (Math.random() - 0.5);
}
gameLoop(); // بدء اللعبة
</script>
</body>
</html>
الخلاصـــة
يُعتبر <canvas>
أداة قوية ومتعددة الاستخدامات في تطوير الويب الحديث. من خلال فهم أساسياته والممارسة المستمرة، يمكنك إنشاء تطبيقات رسومية غنية وتفاعلية تعمل مباشرة في المتصفح دون الحاجة إلى إضافات خارجية. سواء كنت تريد إنشاء تصورات بيانات ديناميكية، أو ألعاب متصفح، أو تطبيقات فنية، فإن <canvas>
يوفر الأساس اللازم لتحقيق ذلك.
تذكر أن الإبداع هو الحد الوحيد لما يمكنك تحقيقه باستخدام هذه التقنية. جرب، تعلّم من الأخطاء، واستمر في تطوير مهاراتك في رسم Canvas لإنشاء تجارب ويب مذهلة.