المحتوى عن 'js canvas 101'.



مزيد من الخيارات

  • ابحث بالكلمات المفتاحية

    أضف وسومًا وافصل بينها بفواصل ","
  • ابحث باسم الكاتب

نوع المُحتوى


التصنيفات

  • التخطيط وسير العمل
  • التمويل
  • فريق العمل
  • دراسة حالات
  • نصائح وإرشادات
  • التعامل مع العملاء
  • التعهيد الخارجي
  • التجارة الإلكترونية
  • الإدارة والقيادة
  • مقالات ريادة أعمال عامة

التصنيفات

  • PHP
    • Laravel
    • ووردبريس
  • جافاسكريبت
    • Node.js
    • jQuery
    • AngularJS
    • Cordova
  • HTML
    • HTML5
  • CSS
  • SQL
  • سي شارب #C
    • منصة Xamarin
  • بايثون
    • Flask
    • Django
  • لغة روبي
    • Sass
    • إطار عمل Bootstrap
    • إطار العمل Ruby on Rails
  • لغة Go
  • لغة جافا
  • لغة Kotlin
  • برمجة أندرويد
  • لغة Swift
  • لغة R
  • لغة TypeScript
  • سير العمل
    • Git
  • صناعة الألعاب
    • Unity3D
  • مقالات برمجة عامة

التصنيفات

  • تجربة المستخدم
  • الرسوميات
    • إنكسكيب
    • أدوبي إليستريتور
    • كوريل درو
  • التصميم الجرافيكي
    • أدوبي فوتوشوب
    • أدوبي إن ديزاين
    • جيمب
  • التصميم ثلاثي الأبعاد
    • 3Ds Max
    • Blender
  • نصائح وإرشادات
  • مقالات تصميم عامة

التصنيفات

  • خواديم
    • الويب HTTP
    • قواعد البيانات
    • البريد الإلكتروني
    • DNS
    • Samba
  • الحوسبة السّحابية
    • Docker
  • إدارة الإعدادات والنّشر
    • Chef
    • Puppet
    • Ansible
  • لينكس
  • FreeBSD
  • حماية
    • الجدران النارية
    • VPN
    • SSH
  • مقالات DevOps عامة

التصنيفات

  • التسويق بالأداء
    • أدوات تحليل الزوار
  • تهيئة محركات البحث SEO
  • الشبكات الاجتماعية
  • التسويق بالبريد الالكتروني
  • التسويق الضمني
  • التسويق بالرسائل النصية القصيرة
  • استسراع النمو
  • المبيعات
  • تجارب ونصائح

التصنيفات

  • إدارة مالية
  • الإنتاجية
  • تجارب
  • مشاريع جانبية
  • التعامل مع العملاء
  • الحفاظ على الصحة
  • التسويق الذاتي
  • مقالات عمل حر عامة

التصنيفات

  • الإنتاجية وسير العمل
    • مايكروسوفت أوفيس
    • ليبر أوفيس
    • جوجل درايف
    • شيربوينت
    • Evernote
    • Trello
  • تطبيقات الويب
    • ووردبريس
    • ماجنتو
  • أندرويد
  • iOS
  • macOS
  • ويندوز

التصنيفات

  • شهادات سيسكو
    • CCNA
  • شهادات مايكروسوفت
  • شهادات Amazon Web Services
  • شهادات ريدهات
    • RHCSA
  • شهادات CompTIA
  • مقالات عامة

أسئلة وأجوبة

  • الأقسام
    • أسئلة ريادة الأعمال
    • أسئلة العمل الحر
    • أسئلة التسويق والمبيعات
    • أسئلة البرمجة
    • أسئلة التصميم
    • أسئلة DevOps
    • أسئلة البرامج والتطبيقات
    • أسئلة الشهادات المتخصصة

التصنيفات

  • ريادة الأعمال
  • العمل الحر
  • التسويق والمبيعات
  • البرمجة
  • التصميم
  • DevOps

تمّ العثور على 5 نتائج

  1. سنتطرّق في هذا الدّرس إلى طريقة إنشاء رسم بياني باستخدام Canvas قبل أن نتطرّق إلى بعض عمليات التّعديل على الصّور وبعض التّحولات، ثم سنختم بإنشاء معرض جميل للصّور. أنصحم بالاطّلاع على المقالات السّابقة حول Canvas هنا على أكاديمية حسوب قبل مواصلة القراءة. رسم الصور تُستخدم الدالة ()drawImage لتصيير الكائن image على العنصر canvas، تأخذ الدالة ()drawImage عدة أشكال overloaded وذلك بتغيير نوع وعدد المعاملات كما سنرى في الأمثلة المقبلة. الشكل الأول: drawImage(image, x, y) تقوم برسم CanvasImageSource محدّدة بالمعامل image في الإحداثيات (x,y). رسم خط بياني بسيط باستخدام الدالة ()drawImage سأعرض مثالًا يستخدم صورة خارجية كخلفية لرسم خط بياني بسيط. يتيح لك استخدام الخلفيات أو backdrops من أن تجعل السكربت الخاص بك أصغر بكثير وتجنب الحاجة لكتابة الشيفرات البرمجية لتوليد الخلفية. سأستخدم في هذا المثال صورة واحدة لذا يمكنني استخدام معالج حدث التحميل load event handler لتنفيذ جمل الرسم. تقوم الدالة ()drawImage بوضع صورة الخلفية عند الإحداثيات (0, 0) والمحدّدة بالزاوية اليسارية العليا للعنصر canvas. function draw() { var ctx = document.getElementById('canvas').getContext('2d'); var img = new Image(); img.onload = function(){ ctx.drawImage(img,,); ctx.beginPath(); ctx.moveTo(30,96); ctx.lineTo(70,66); ctx.lineTo(103,76); ctx.lineTo(170,15); ctx.stroke(); }; img.src = 'https://mdn.mozillademos.org/files/5395/backdrop.png'; } سيظهر الرسم البياني مع صورة الخلفية على الشكل التالي: التحجيم Scaling تتيح لك الدالة ()drawImage تحديد حجم الصور وفق ما ترغب وذلك بإضافة معاملين إضافيين هما الطول والعرض: drawImage(image, x, y, width, height) من خلال الخاصيتين width و height تستطيع إعطاء الحجم المناسب للصورة عند رسمها على الـ canvas. تبليط صورة Tiling an image في المثال التالي سأستخدم الصورة أدناه وأكررها عدّة مرات على مساحة الـ canvas بعد تحجيمها لتبدو كلوحة جدارية. سنحتاج لإنشاء حلقتي تكرار واستدعاء الدالة: drawImage(image, x, y, width, height) مع تغيير إحداثيات رسم الصورة كل مرة، ستكرر الحلقة الأولى الصورة عبر الصفوف والحلقة الثانية ستكرر الصورة عبر الأعمدة. سأقوم بتحجيم الصورة إلى ثلث حجمها الأصلي وهو 50x30 بكسل. ملاحظة: قد تبدو الصور ضبابية عند التحجيم وذلك بحسب نوع التحجيم (تكبير أو تصغير) كذلك إن كانت بعض الصور تحوي نصوصًا قد يؤدي تصغير حجمها إلى جعل النصوص غير مقروءة. function draw() { var ctx = document.getElementById('canvas').getContext('2d'); var img = new Image(); img.onload = function(){ for (var i=;i<4;i++){ for (var j=;j<3;j++){ ctx.drawImage(img,j*50,i*38,50,38); } } }; img.src = 'https://mdn.mozillademos.org/files/5397/rhino.jpg'; } ستظهر الصورة على الشكل التالي: استعرض المثال على jsfiddle. التشريح Slicing الاستخدام الثالث والأخير للدالة ()drawImage هو قص الصور حيث تأخذ الدالة ثمان معاملات: drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight) تحدد الدالة أعلاه مساحة الصورة التي يحددها المستطيل الذي زاويته اليسارية العليا محدّدة بـ (sx, sy) وطوله وعرضه محدّد بـ (sWidth ، sHeight) وتقوم برسمه على الـ canvas في الموضع (dx, dy) وتحدد قيمة التحجيم بالمعاملين (dWidth و dHeight). لتستطيع فهم عمل المعاملات بوضوح انظر للصورة التالية: كما تلاحظ أنه تم تحديد مساحة الصورة المراد قصها اعتمادًا على قيمة المعاملات في الدالة: drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight) تعتبر أداة التشريح او القص مفيدة عندما تريد عمل تراكيب حيث يمكن أن يكون لديك عدة عناصر في ملف صورة واحد وتستخدم الدالة ()drawImage لتجميعها برسم كامل على سبيل المثال يمكنك أن تقوم بإنشاء رسم بياني كصورة png وتكون كل النصوص اللازمة لوضعها على الرسم البياني موجودة في ملف واعتمادًا على البيانات يمكنك تغيير حجم الرسم البياني بكل سهولة. ميزة أخرى في عمل تركيبات الصور هي أنك لن تكون بحاجة لتحميل كل صورة على حدة والذي يمكن أن يحسن من أداء التحميل. تأطير الصورة Framing an image سأقوم بعرض مثال أستخدم فيه نفس الصورة السابقة لقصها باستخدام الدالة ()drawImage ووضعها بداخل إطار Frame: <html> <body onload="draw();"> <canvas id="canvas" width="150" height="150"></canvas> <div style="display:none;"> <img id="source" src="https://mdn.mozillademos.org/files/5397/rhino.jpg" width="300" height="227"> <img id="frame" src="https://mdn.mozillademos.org/files/242/Canvas_picture_frame.png" width="132" height="150"> </div> </body> </html> function draw() { var canvas = document.getElementById('canvas'); var ctx = canvas.getContext('2d'); // Draw slice ctx.drawImage(document.getElementById('source'), 33, 71, 104, 124, 21, 20, 87, 104); // Draw frame ctx.drawImage(document.getElementById('frame'),,); } ستظهر الصورة على الشكل التالي: استعرض المثال على jsfiddle. إنشاء معرض فني Art Gallery حان الوقت الآن لإنشاء معرض صور واستخدام الأدوات التي تعلمناها في التعامل مع الصور في canvas سيكون المعرض عبارة عن جدول يحوي مجموعة صور. عند تحميل الصفحة يقوم العنصر canvas بإدراج الصور ورسم إطار حول كل صورة. في حالتنا هذه سيكون لكل صورة طول وعرض ثابتين وكذلك الإطار. سنقوم باسترداد صورة الإطار من الرابط: https://mdn.mozillademos.org/files/242/Canvas_picture_frame.png ثم إنشاء حلقة تكرار للإنشاء رقعة canvas لكل صورة ومن ثم رسم الصورة ويتم ذلك باستخدام الدالة: parentNode.insertBefore تقوم هذه الدالة بإدراج الصورة قبل إدراج عنصر canvas في عناصر DOM: // Insert before the image document.images.parentNode.insertBefore(canvas,document.images); بعد إنشاء عنصر canvas وإدراج الصورة نقوم باستخدام سياق التصيير واستدعاء الدالة ()drawImage لرسم الصورة على الرقعة: ctx.drawImage(document.images,15,20); إضافة بعض التنسيقات CSS: body { background: -100px repeat-x url(https://mdn.mozillademos.org/files/5415/bg_gallery.png) #4F191A; margin: 10px; } img { display: none; } table { margin: auto; } td { padding: 15px; } السكربت أدناه يقوم برسم الصور مع الإطار: function draw() { // Loop through all images for (var i=;i<document.images.length;i++){ // Don't add a canvas for the frame image if (document.images[i].getAttribute('id')!='frame'){ // Create canvas element canvas = document.createElement('canvas'); canvas.setAttribute('width',132); canvas.setAttribute('height',150); // Insert before the image document.images[i].parentNode.insertBefore(canvas,document.images[i]); ctx = canvas.getContext('2d'); // Draw image to canvas ctx.drawImage(document.images[i],15,20); // Add frame ctx.drawImage(document.getElementById('frame'),,); } } } ستظهر الصورة على الشكل التالي: استعراض المثال على jsfiddle. التحكم بسلوك التحجيم Scaling Behavior كما ذكرت سابقًا أن عملية تحجيم الصورة يمكن أن تؤدي إلى تشويهها أو جعلها تبدو غير واضحة. يمكنك استخدام الخاصية imageSmoothingEnabled للتحكم باستخدام خوارزمية تنعيم أو تمهيد الصورة Smoothing وذلك بتحديد القيمة التي تأخذها إما true أو false ctx.mozImageSmoothingEnabled = false; ctx.webkitImageSmoothingEnabled = false; ctx.msImageSmoothingEnabled = false; ctx.imageSmoothingEnabled = false; التحولات Transformations يوفّر سياق التصيير Rendering Context في canvas مجموعة من الدوال لتطبيق التحولات على الأشكال في canvas كالتحريك، النقل، الدوران والتحجيم حيث يمكنك تطبيق هذه الخصائص بطرق مختلفة على الأشكال البسيطة في الرقعة canvas والحصول على أشكال معقدة أو متحركة بكل سهولة. قبل البدء بالتعرّف على دوال التحولات التي يوفرها سياق التصيير دعونا نلقي نظرة على حالتين لا غنى عنهما سنستخدمهما بمجرد البدء بتوليد أشكال معقدة باستخدام خصائص التحويل في canvas. حالتي الحفظ والاستعادة Saving and restoring state ()save: تقوم هذه الدالة بحفظ الحالة التي تكون عليها الرقعة في الوقت الحالي. ()restore: تعيد هذه الدالة أحدث حالة كانت عليها الرقعة canvas. يتم تخزين حالات الرقعة في الـ stack أو المجمع حيث أنه في كل مرة يتم فيها استدعاء الدالة ()save يتم وضع حالة الرسم الحالية في المجمع. مم تتكون حالة الرسم؟ تتكون حالة الرسم من العناصر التالية: التحولات التي يمكن تطبيقها في سياق التصيير كالنقل translate، الدوران rotate والتحجيم scale. القيم الحالية للخصائص التالية: strokeStyle, fillStyle globalAlpha lineWidth, lineCap, lineJoin miterLimit lineDashOffset shadowOffsetX, shadowOffsetY shadowBlur, shadowColor globalCompositeOperation font, textAlign, textBaseline direction imageSmoothingEnabled مسار clipping path الحالي. ملاحظة: يمكنك استدعاء الدالة ()save عدة مرات كما تريد. في كل مرة يتم فيها استدعاء الدالة ()restore يتم أخذ آخر حالة حفظ موجودة في المجمع واسترجاع جميع الإعدادات الأخيرة المحفوظة. سنكمل في الدرس المقبل شرح دوال التحولات وعرض مثال واضح عن استخدام حالتي الحفظ والاستعادة في سياق التصيير بالإضافة إلى شرح التحولات وطرق التعامل معها مع عرض مثال لكل خاصية تحول لترى كيف يمكنك عمل مجموعة من الأشكال المعقدة وتحريكها على عنصر الرقعة canvas. المصادر
  2. إن عالم الويب أصبح جزءًا لا يتجزأ من حياتنا اليومية هذا ما يجعلنا نبتكر طُرقًا وأساليبَ جديدة ليكون قريبًا منا أكثر. نحنُ كمطوري ويب بحاجة دائمًا إلى إضافةِ لمساتٍ ساحرة وتصاميمَ مبتكرة لإنعاش موقع الويب والتفرّد بعنصر الإبداع في إظهار الموقع بأبهى حلّة وأجمل تصميم. سأضع بين يديك مقدمة لأهم خيارين قد يختار منهما مطوّر الويب عند الشروع في بناء وتصميم محتوى وعناصر موقع الويب. الخيار أو الأسلوب الأوّل وهو الأكثر شهرة بحكم قدمه هو العمل مع عناصر DOM في HTML هذا النهج الذي تستخدمه أنت و 99% من المطورين في العالم الذي يعتمد على إنشاء HTML ،CSS، و JavaScript ليكون لديك عناصر ورسومات تُظهرها بإبداعك الخاص. النهج الثاني والذي ظهر بظهور HTML5 وهو استخدام عنصر <canvas>. والذي يتيح لك أن تجرب وتتخيل الرسم بطريقةٍ أخرى وأكثر متعة غير تلك التي ألِفناها. إنّ كُلًّا من هذين الخيارين له استخدامه الخاص الذي يعتمد بالدرجة الأولى على درجةِ تعقيدِ عنصر التصميم الذي تودُّ إنشاءه، سأقوم بعرض لمحة سريعة عن الفروقات بين المنهجيتين واستخدام كل منهما. إن عملية ترجمة محتوى الصفحة وإظهارها على المتصفّح تسير وفق نظامين هما نظام وضع الاحتفاظ (retained mode (Dom والنظام الحالي أو الفوري (Immediate Mode (canvas. نظام وضع الاحتفاظ (Dom) في هذا النظام تقوم بإرسال العناصر والمحتويات التي قمتَ بإنشائها إلى Graphics API والذي بدوره يقوم بإظهارها على المتصفّح. في الشكل التالي توضيح لكيفية حدوث نظام وضع الاحتفاظ retained mode: النظام الحالي أو الفوري (Canvas) النظام الفوري أو الحالي الذي يعتمد على استخدام <canvas> يتمتع بلياقة عالية تجعله أهلًا لرفع الأحمال الثقيلة heavy lifting فإنك لا تقوم بتحديد ما ستود رسمه فقط بل تقوم بإنشاء وصيانة التصميم أي أن Graphics API الذي قام بالكثير من أجلك في نظام وضع الاحتفاظ retained mode لا يقوم بالشيء الكثير هنا. في الشكل التالي توضيح لكيفية حدوث النظام الفوري أو الحالي Immediate mode: بمجمل الأحوال فإن استخدام عنصر <canvas> أسرع بكثير من استخدام نظام وضع الاحتفاظ retained mode كما أنه يوفّر مرونة كبيرة مقارنة بوضع الاحتفاظ وخاصة في التّعامل مع عناصر كثيرة. توجد سيئة واحدة في استخدام <canvas> وهي في حال العمل على مساحة واسعة سيكون هناك نوعًا من البطء في الأداء. لا يمكنك تخيل ما قد تستطيع عمله في هذه الأداة فبإمكانك القيام برسومات بيانية، إنشاء رسوم بتأثيرات حركية Animations وعمل تراكيب صور photo Compositions أو حتى القيام بمعالجة الفيديو. تدعم Canvas جميع المُتصّفحات الحديثة: فيرفكس (الإصدار 1.5 وما فوق). safari و OS X Dashboard (على نظام ماك). IE (الإصدار 9 وما فوق). Chrome و Opera. لنبدأ الآن بالتعرف على عنصر <canvas> عن قرب وتَعلُّم كيفيّة إنشاء سياق لوحة ثنائي الأبعاد وتقوم برسم أول مثال لك على متصفّحك. الرقعة Canvas يبدو لنا للوهلة الأولى أن عنصر <canvas> يشبه عنصر <img> مع فارق واضح وكبير هو أن عنصر <canvas> ليس لديه خاصيّة src و alt. عنصر <canvas> لديه خاصيتان وحيدتان فقط هما العرض width والطول height، القيم الافتراضية هي 300 بكسل للعرض و 150 بكسل للطول. ككل عناصر HTML فإن عنصر <canvas> يعرف كوسم: <canvas id="tutorial" width="150" height="150"> </canvas> لا تعتبر الخاصيّة id خاصيّة محددة بالرُّقعة <canvas> ولكنها واحدة من الخصائص العامة لـHTML global Html attribute. يمكن تصميم عنصر <canvas> كأي عنصر صورة image وتحديد الخصائص مثل (margin ،border ،background، ...) مثل هذه الخصائص لا تؤثر على عملية الرسم الفعلي هي فقط تحدد الشكل العام للوحة <canvas>. المحتوى الاحتياطي Fallback Content بالرّغم من أنه لا يتم إظهار أو تشغيل عنصر Canvas في المتصفّحات غير الداعمة للـ HTML5 إلا أنه يمكنك إنشاء محتوى احتياطي fallback content ليحل محل <canvas> في المتصفّحات ذات الإصدارات القديمة نوعًا ما والتي لا تدعم HTML5 مثل إصدارات Internet Explorer IE السابقة للإصدار 9. يجب أن توفر دائمًا محتوى احتياطي في حال استخدامك لعنصر الرُّقعة <canvas> ليتم إظهارها على جميع أنواع وإصدارات المتصفّحات التي لا تدعمها. لتوفير محتوى احتياطي ستحتاج إلى إضافة نص أو صورة داخل وسم <canvas> بحيث حين يتم تشغيل الصفحة في متصفّح لا يدعم Canvas سيقوم المتصفّح بتجاهل العنصر الحاوي على المحتوى الاحتياطي وهو عنصر canvas ومن ثم إظهار المحتوى الاحتياطي الذي بداخلها. أما في حال دعم المتصفّح لعنصر Canvas فسيقوم بتجاهل المحتوى الاحتياطي ويقوم بعمل rendering تصيير لعنصر <canvas> بشكل طبيعي. على سبيل المثال لنقم بإنشاء <canvas> وتوفير محتوى احتياطي لها، سأقوم بعمل محتوى احتياطي عبارة عن نص وكذلك مثال آخر يكون المحتوى الاحتياطي فيه عبارة عن صورة <img>: <canvas id="stockGraph" width="150" height="150"> current stock price: $3.15 +0.15 </canvas> <canvas id="clock" width="150" height="150"> <img src="images/clock.png" width="150" height="150" alt=""/> </canvas> وسم الإغلاق </canvas> لا بد أنك لاحظت أن الوسم <img> مثلًا لا يتطلب وسم إغلاق ولا تتأثر بذلك باقي العناصر، عنصر في حين أن عنصر canvas يحتاج لوضع وسم الإغلاق </canvas> هو وسم مطلوب required وذلك لأنه في حال عدم وضعه سيتم اعتبار كل شيء في الصفحة بعد الوسم <canvas> هو عبارة عن محتوى احتياطي ولن يتم إظهاره. سياق التصيير The rendering Context يقوم عنصر <canvas> بإنشاء سطح ذو قياس ثابت يتسع لأكثر من سياق تصيير rendering context التي يتم استخدامها لإنشاء والتعامل مع المحتوى المعروض. سنركز هنا على سياق التصيير ثنائي الأبعاد 2D rendering context. يوجد سياقات أخرى توفر أنواعًا مختلفة من التصيير rendering مثل السياق ثلاثي الأبعاد WebGL الذي يرتكز على OpenGL ES. بطبيعة الحال عند إنشاء <canvas> ستكون فارغة ولإظهار شيء فإن السكربت يحتاج للوصول إلى سياق التصيير Rendering Context والرسم عليه. عنصر <canvas> يحتوى على دالة method تسمى ()getContext تستَخدم لتطبيق سياق التصيير Rendering Context ودوال الرسم الخاصة به، تأخذ الدالة ()getContext معاملًا واحدًا one parameter وهو نوع السياق، للرسومات ثنائية الأبعاد 2D Graphics نقوم بتحديد “2d” لنحصل على سياق تصيير ثنائي الأبعاد Canvas RenderingContext2D. كما في المثال التالي: var canvas = document.getElementById('tutorial'); var ctx = canvas.getContext('2d'); يجلب السطر الأول من السكربت العنصر <canvas> من خلال استدعاء الدالة ()document.getElementById، ثم تحديد نوع السياق عن طريق الدالة ()getContext. التأكد من الدعم Checking for support شرحنا في البداية أن المحتوى الاحتياطي يظهر في المتصفّحات التي لا تدعم عنصر <canvas> يمكن أيضًا للسكربت أن يقوم بالتأكُّد من الدّعم برمجيًا من خلال اختبار بسيط لوجود الدالة ()getContext. لنقم بتعديل الشيفرة البرمجية أعلاه ونستخدم السكربت في التأكد من دعم المتصفّح لعنصر <canvas> ليصبح على النحو التالي: var canvas = document.getElementById('tutorial'); if (canvas.getContext){ var ctx = canvas.getContext('2d'); // drawing code here } else { // <canvas> unsupported code here } قالب الهيكل Skeleton Template سأقوم ببناء قالب أساسي لاستخدامه كنقطة انطلاق لأمثلتنا اللاحقة. ملاحظة: ليس من الأمور الجيدة تضمين السكربت في وسم HTML ولكن قمت بذلك للحفاظ على المثال موجز ومختصر. <!DOCTYPE html> <html> <head> <meta charset="utf-8"/> <title>canvas tutorial</title> <script type="text/javascript"> function draw(){ var canvas = document.getElementById('tutorial'); if (canvas.getContext){ var ctx = canvas.getContext('2d'); } } </script> <style type="text/css"> canvas { border: 1px solid black; } </style> </head> <body onload="draw();"> <canvas id="tutorial" width="150" height="150"> </canvas> </body> </html> يحتوي السكربت على دالة تدعى ()draw التي تُنّفذ في حين الانتهاء من تحميل صفحة الويب، يتم ذلك عن طريق الاستماع للحدث load في الصفحة حيث يتم استدعاءه باستخدام ()window.setTimeout و ()window.setInterval أو أي معالج حدث آخر event handler طالما أنه يتم تحميل الصفحة أولًا. عند تنفيذ السكربت أعلاه سيظهر لنا الشكل التالي في صفحة الويب: تطبيق مثال بسيط دعونا نلقي نظرة على مثال بسيط يقوم برسم مستطيلين متقاطعين أحدهما يحوي على شفافية لونية alpha transparency. <!DOCTYPE html> <html> <head> <meta charset="utf-8"/> <script type="application/javascript"> function draw() { var canvas = document.getElementById("canvas"); if (canvas.getContext) { var ctx = canvas.getContext("2d"); ctx.fillStyle = "rgb(200,0,0)"; ctx.fillRect (10, 10, 55, 50); ctx.fillStyle = "rgba(0, 0, 200, 0.5)"; ctx.fillRect (30, 30, 55, 50); } } </script> </head> <body onload="draw();"> <canvas id="canvas" width="150" height="150"> </canvas> </body> </html> اعتمادًا على القالب الأساسي الذي أنشأتُه وضعت السكربت الخاص باستخدام سياق التصيير ()Rendering Context getContext ضمن الشرط if وذلك ليتم تنفيذه في حال تحقق وجود دعم للعنصر <canvas> من قِبل المتصفّح. تقوم الدالة ()getContext بإرجاع متغير يمكن اعتباره غرض object يحوي على مجموعة دوال تقوم بعمليات الرسم وإنشاء الأشكال. الخاصيّة fillStyle تقوم بتحديد اللّون الذي سيتم به تلوين العنصر التالي، تأخذ الخاصيّة fillStyle اللّون بنظام (RGB (Red, Green, Blue والشفافية opacity. لاحظ أنه تم تلوين المستطيل الأول باللون الأحمر حيث أخذ قيمة 200 في حقل red، والمستطيل الثاني بلون أزرق مع تحديد الشفافية opacity=0.5 أي سيكون ذو شفافية لونية بنسبة 50% (تأخذ الخاصيّة opacity قيمها من 0.0 -1.0). الدالة ()FillRect ترسم مستطيل ذو مساحة لونية كاملة solid color وذلك بتحديد إحداثيات النقاط الأربع للمستطيل الذي نود رسمه ابتداءً من الزاوية اليسارية العليا التي تأخذ احداثيات المركز (0,0). كانت هذه أبرز النقاط التي تحيطك بالمفاهيم الأساسية لاستخدام عنصر canvas في الدروس المقبلة ستكون الشروحات غنية للغاية وسترى إمكانيات مذهلة لعنصر canvas تشحذ أفكارك الابداعية بامتياز. المصادر
  3. تعرَّفنا في المقال السّابق على العنصر Canvas الذي أُضيف إلى HTML5 ليوفّر أداة ومساحة لرسم الأشكال والتصاميم باستخدام جافاسكربت. سنتعلم في هذا الدّرس كيفية رسم الأشكال على Canvas باستخدام جافا سكربت مثل الدوائر، المثلَّثات والمستطيلات وسنتعرف على المنحنيات Curves لرسم أشكال أكثر تعقيدًا. الشبكة The grid إن أي عنصر يتم إضافته أو رسمه على Canvas يُحَدّد موقعه بواسطة الزَّاوية اليسارية العليا (0, 0) أي بإحداثيات (x, y) بحيث أنه يبعد عن المركز (0, 0) بمقدار (x, y). رسم المستطيلات Rectangles توفر canvas ثلاث دوال لرسم المستطيلات وجميعها تأخذ معاملات argumrnts مماثلة. الإحداثيات (x, y) تحدد موقع المستطيل بالنسبة للمركز (0, 0) والذي يحدَّد بالزَّاوية اليسارية العليا للـ Canvas، العرض width والطول height تحددان قياس المستطيل. الدَّالة ()fillRect ترسم مستطيلًا ذي مساحة لونية solid color. الدَّالة ()strokeRect ترسم مستطيلًا Storke (مُفرغًا) ذي حواف فقط outline. الدَّالة ()clearRect تقوم بمسح مستطيل محدّد بالمعاملات x, y) ،width ،height) أي تجعله شفافًا Transparent. ولا ننسى طبعا الدَّالة ()draw والتي تدير جميع عمليات الرَّسم على الـ canvas في الجافاسكربت. سنرى كيفية رسم المستطيلات باستخدام الدَّوال الثلاث أعلاه. السكربت التالي يرسم ثلاثة مستطيلات بإحداثيات وقياسات مختلفة : <script type="application/javascript"> function draw() { var canvas = document.getElementById("canvas"); if (canvas.getContext) { var ctx = canvas.getContext("2d"); ctx.fillStyle = "rgb(200,0,0)"; ctx.fillRect(10, 10, 200, 200); ctx.clearRect(30, 30, 150, 150); ctx.strokeRect(50, 50, 60, 60); } } </script> باستخدام ()fillRect تم رسم مستطيل ذو مساحة لونية حمراء بقياس 200*200 عند الإحداثيات (10,10). باستخدام ()clearRect تم رسم مستطيل بلا لون (شفاف) بقياس 150*150 عند الإحداثيات (30,30). باستخدام ()storkRect تم رسم مستطيل stroke مُفرغ ذو حواف بقياس 60*60 عند الإحداثيات (50,50). رسم المسارات Paths المسارات paths هي عبارة عن مجموعة من النقاط متصلة مع بعضها البعض بواسطة خطوط صغيرة segments لتقوم بتشكيل رسومات مختلفة كأشكال منحنية، أشكال هندسية…الخ. يمكن أن يكون المسار مفتوحًا مثل نصف دائرة او مغلقًا كالمثلَّث. هناك 4 خطوات أساسية لرسم المسارات حيث تُنفّذ مجموعة من الدَّوال بالتّرتيب للحصول على المسار بالشكل المطلوب. ()beginPath تقوم هذه الدَّالة بإنشاء المسار بحيث يتم رسم المسار وتخزين نقاطه في قائمة List. the methods هي مجموعة من الدَّوال التي تقوم بإنشاء أشكال أساسية مثل الدَّالة arc التي ترسم قوس والدّالة lineTo التي ترسم خط مستقيم. ()moveTo تقوم في كل مرة برسم نقطة انطلاق جديدة لبدء الرَّسم منها. ()closePath تقوم بإغلاق المسار ليتم الرَّسم خارج المسار بعدها أي البدء بمسار جديد. ()stroke تحول المسار المرسوم إلى شكل مُفرَّغ ذو حواف أي دون ملأ المسار. ()fill تحول المسار المرسوم إلى مسار ممتلئ بمساحة لونية solid. الخطوة الأولى لإنشاء مسار path هي استدعاء الدَّالة ()beginPath (بشكل ضمني المسارات تُخزَّن بشكل مسارات جزئية في مصفوفة أو قائمة List مثل خطوط أو منحنيات..الخ) والتي بمجملها مسؤولة عن تكوين الشكل. في كل مرة تتم فيها استدعاء الدَّالة ()beginPath يتم فيها إعادة إنشاء مصفوفة أو قائمة List جديدة ويمكننا البدء برسم شكل جديد. الخطوة الثانية هي استدعاء إحدى الدَّوال التي تقوم بتحديد المسار الذي سيُرسم مثل الدَّالة ()moveTo أو الدَّالة ()lineTo. الخطوة الثالثة هي استدعاء إحدى الدالتين ()storke أو ()fill. الخطوة الرابعة وهي خطوة اختيارية يتم فيها استدعاء الدَّالة ()closePath هذه الدَّالة تقوم بإغلاق الشكل عن طريق رسم خط مستقيم من النُّقطة الحالية التي توقف عندها الرَّسم إلى نقطة البداية التي بدأ عندها رسم المسار. ملاحظات: في حين كان الشكل قد أُغلق أثناء الرَّسم أو بقيت نقطة واحدة في القائمة List فهذه الدَّالة لن تقوم بعمل أي شيء. عند استدعاء الدَّالة ()fill فإن الأشكال المفتوحة ستُغلق تلقائيًّا أي لن يكون هناك داعي لاستدعاء الدَّالة ()closePath ولكن لا تنطبق هذه الحالة عند استدعاء الدَّالة ()storke. رسم مثلث اعتمادًا على خطوات إنشاء المسارات أعلاه سأقوم بإنشاء مسار مثلَّث كما في السكربت التالي: <script type="application/javascript"> function draw() { var canvas = document.getElementById("canvas"); if (canvas.getContext) { var ctx = canvas.getContext("2d"); ctx.beginPath(); ctx.moveTo(100, 100); ctx.lineTo(300, 200); ctx.lineTo(100, 200); ctx.fillStyle = "rgb(200,0,180)"; ctx.fill(); ctx.closePath(); ctx.beginPath(); ctx.moveTo(100, 300); ctx.lineTo(400, 300); ctx.lineTo(400, 200); ctx.fillStyle = "rgb(140,50,80)"; ctx.fill(); } } </script> قمت بإنشاء مثلَّثين الأول عند النُّقطة (100, 100)، رسم خط مستقيم بواسطة الدَّالة ()lineTo إلى النُّقطة (300, 200)، خط مستقيم إلى النُّقطة (100, 200) ثم تحديد اللّون عن طريق الدَّالة ()fillStyle وبالنهاية استدعاء الدَّالة ()fill ليتم تلوين المسار والحصول على شكل مثلَّث. كذلك الأمر بالنسبة للمثلَّث الثاني. عند تشغيل المتصفّح يظهر المثلَّثان بهذا الشكل: الرسم بتحريك القلم moving pen تخيل أنك تقوم برسم لوحة فنية كم مرة ستحتاج لترك نقطة رسم وتحريك القلم للبدء من نقطة جديدة، هذا ما تقوم به الدَّالة ()moveTo أي أنها تقوم بنقل نقطة بدء الرَّسم إلى نقطة (x, y) جديدة. عند إنشاء canvas أو عند استدعاء الدَّالة ()beginPath ستحتاج إلى استدعاء الدَّالة ()moveTo لتحديد نقطة البداية التي ستبدأ عندها الرَّسم. أو عندما تكون بحاجة لرسم مسارات متقطعة. للتوضيح أكثر سأقوم برسم وجه ضاحك smiley face وتلوينه كما في السكربت التالي: <script type="application/javascript"> function draw() { var canvas = document.getElementById('canvas'); if (canvas.getContext) { var ctx = canvas.getContext('2d'); ctx.beginPath(); ctx.fillStyle = "rgb(0, 0, 0)"; ctx.arc(75, 75, 50, 0, Math.PI * 2, true); ctx.stroke(); ctx.closePath(); ctx.beginPath(); ctx.fillStyle = "rgb(250, 250, 0)"; ctx.arc(75, 75, 50, 0, Math.PI * 2, true); ctx.fill(); ctx.closePath(); ctx.beginPath(); ctx.fillStyle = "rgb(250, 0, 0)"; ctx.moveTo(110, 75); ctx.arc(75, 75, 35, 0, Math.PI, false); ctx.fill(); ctx.closePath(); ctx.moveTo(65, 65); ctx.beginPath(); ctx.fillStyle = "rgb(0, 0, 0)"; ctx.arc(60, 65, 5, 0, Math.PI * 2, true); ctx.fill(); ctx.closePath(); ctx.beginPath(); ctx.moveTo(95, 65); ctx.fillStyle = "rgb(0, 0, 0)"; ctx.arc(90, 65, 5, 0, Math.PI * 2, true); ctx.fill(); ctx.closePath(); } } </script> يحتوى الشكل على 4 مسارات مغلقة: الإطار الخارجي للوجه، الوجه، الفم، العين اليمنى، العين اليسرى. لاحظ أنني قمت باستدعاء الدَّالة ()beginPath أربع مرات ولم أكن بحاجة لاستدعاء الدَّالة ()closePath عندما رسمت الإطار بالرغم من أنه stroke وذلك بسبب تقاطع نقطة النهاية مع البداية. أيضًا عند رسم الأشكال solid لم أحتج لاستدعاء الدَّالة ()closePath وذلك لأن الدَّالة ()fill تقوم بإغلاق المسار بشكل تلقائي لتلوينه. الخطوط Lines تُستخدم الدَّالة ()lineTo لرسم خطوط مستقيمة بحيث ترسم الخط من النُّقطة الحالية إلى نقطة محددة بـ (x, y). النقطة الحالية تتعلق بآخر مسار تم رسمه (أي أن النُّقطة الأخيرة لرسم المسار الأول هي نقطة بداية رسم المسار الثاني) يمكنك تغيير النُّقطة الحالية عبر استدعاء الدَّالة ()moveTo كما شرحنا في المثال السابق. لنقم بعمل مثال آخر لرسم مثلَّثين أحدهما solid والآخر stroke باستخدام الدالتين ()lineTo و ()moveTo واستدعاء الدَّالة ()lineTo مرتين لكل عملية رسم مثلَّث كما في السكربت التالي: <script> function draw() { var canvas = document.getElementById('canvas'); if (canvas.getContext) { var ctx = canvas.getContext('2d'); // Filled triangle ctx.beginPath(); ctx.moveTo(100, 100); ctx.lineTo(180, 100); ctx.lineTo(100, 180); ctx.fill(); // Stroked triangle ctx.beginPath(); ctx.moveTo(125, 125); ctx.lineTo(125, 45); ctx.lineTo(45, 125); ctx.closePath(); ctx.stroke(); } } </script> قمت باستدعاء الدَّالة ()beginPath عند البدء في رسم الشكل ثم استدعاء الدَّالة ()moveTo للانتقال لنقطة بداية الرَّسم. ثم بعد ذلك استدعاء الدَّالة ()LineTo مرّتين لرسم المثلَّث بالإحداثيات المناسبة. الآن استدعاء الدَّالة ()closePath عند الانتهاء من رسم المثلَّث من نوع storke لإغلاق المسار لأنه في حال عدم استدعاء هذه الدَّالة سيقوم برسم خطين فقط وليس مثلَّثا كاملًا. الأقواس Arcs يتم رسم الأقواس باستخدام الدالتين ()arc أو ()arcTo. تقوم الدالة (arc(x, y, radius, startAngle, endAngle, anticlockwise برسم قوس عند النُّقطة (x, y) بمقدار القطر radius r ببداية الزَّاوية startAngle وانتهاءً بالزَّاوية endAngle وبالاتجاه anticlockwise (القيمة الافتراضية تكون مع اتجاه عقارب الساعة clockwise). تقوم الدالة (arcTo(x1, y1, x2, y2, radius برسم قوس بمجموعة نقاط وقطر radius يتصل بالنُّقطة السابقة بواسطة خط مستقيم. إنَّ الدَّالة ()arcTo تأخذ 5 معاملات arguments: (x, y) وهما إحداثيي مركز الدائرة التي سيرسم عندها القوس القطر raduis هو قطر الدائرة المعاملان startAngle و endAngle يُحدّدان بداية ونهاية نقاط القوس بالراديان radians على طول قوس الدائرة حيث أنها تقاس من المحور x المعامل anticlockwise هو متغير منطقي Boolean عندما يأخذ القيمة true سيتم رسم القوس عكس اتجاه عقارب الساعة وإلا سيتم رسم القوس باتجاه عقارب الساعة. ملاحظة: الزَّوايا في الدَّالة ()arc تقاس بالراديان radians وليس بالدّرجات، للتحويل من الدّرجات للراديان يمكنك استخدام السكربت: radians = (Math.PI/180)*degrees سأقوم بعرض مثال يشرح طريقة رسم مجموعة من 12 قوسًا بزوايا مختلفة، حيث ستُعرض الأقواس على شكل صفوف (أسطر وأعمدة) في كل صف ثلاث أقواس. سيتم إنشاء حلقتي تكرار وتطبيقهما على أسطر وأعمدة الأقواس. لكل مسار قوس سيتم استدعاء ()beginPath في السكربت لإنشاء مسار جديد في كل مرّة لرّسم شكل جديد. قمت بتخزين كل معامل للدالة arc ضمن متغير لتسهيل استخدامها عند استدعاء الدَّالة. القطر radius وزاوية البداية startAngle هما ثوابت. أمّا زاوية النّهاية endAngle تبدأ من 180 درجة (نصف دائرة) في العمود الأول. وتزداد بمقدار 90 درجة لتصل إلى دائرة كاملة في العمود الأخير. في السّطر الأوّل والثّالث سيتم رسم الأقواس باتجاه عقارب الساعة، وفي السّطر الثّاني والرّابع سيتم رسم الأقواس عكس اتجاه عقارب الساعة. أخيرًا الشرط if سيقوم بعرض أقواس مُفرغة Stroke في الجزء العلوي من الصّفوف وأقواس ذات مساحة لونية solid في الجزء السُّفلي من الصّفوف. سنكون بحاجة إلى canvas بقياسات 150*200. function draw() { var canvas = document.getElementById(‘canvas’); if (canvas.getContext) { var ctx = canvas.getContext(‘2d’); for (var i = 0; i < 4; i++) { for (var j = 0; j < 3; j++) { ctx.beginPath(); var x = 25 + j * 50; var y = 25 + i * 50; var radius = 20; var startAngle = 0; var endAngle = Math.PI + (Math.PI * j) / 2; var anticlockwise = i % 2 == 0 ? false : true; ctx.arc(x, y, radius, startAngle, endAngle, anticlockwise); if (i > 1) { ctx.fill(); } else { ctx.stroke(); } } } } } المنحنيات التكعيبية والتربيعية Cubic and Quadratic Curves تخيّل أنّك تريد إنشاء قوس مائل أو قوس بقمة حادة أو أي نوع من الأقواس المعقدة، توفّر لك الدَّالة ()quadraticCurveTo إمكانيّة رسم أقواس ومنحنيات تربيعية Quadratic Curves والدَّالة ()bezierCurveTo تقوم برسم أقواس أو منحنيات تكعيبية cubic أو ما يعرف بـBézier Curves منحنيات بيزيير. 1- رسم منحني تربيعي تقوم الدالة (quadraticCurveTo(cp1x, cp1y, x, y برسم منحني بيزيير Bézier تربيعي من النُّقطة الحاليّة إلى نقطة معيّنة محددة بـ (x, y) باستخدام نقطة تحكم control point المحدّدة بـ cp1x و cp1y. تقوم الدَّالة (bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y برسم منحني بيزيير Bézier تكعيبي cubic باستخدام النّقاط المتحكّمة عن طريق (cp1x, cp1y) و (cp2x, cp2y). الصورة التّالية توضّح الفرق بين المنحنيين Quadratic و cubic: لاحظ أن منحني Bézier من الدّرجة الرّابعة لديه نقطة بداية ونقطة نهاية (النقاط الزرقاء) ونقطة تحكم واحدة (النُّقطة الحمراء) في حين أن منحني Bézier من الدرجة الثالثة لديه نقطتي تحكم. المعاملين x و y في كلا الدّالتين هما إحداثيات نقطة النّهاية. المعاملين cp1x و cp1y هما إحداثيات نقطة التحكم الأولى، المعاملين cp2x و cp2y هما إحداثيات نقطة التحكم الثانية. لنأخذ مثالًا عن كيفية إنشاء منحني Bézier تربيعي سيكون المثال مسلي بعض الشيء إذ أنني سأقوم بإنشاء بالون محادثة speech balloon: function draw() { var canvas = document.getElementById('canvas'); if (canvas.getContext) { var ctx = canvas.getContext('2d'); ctx.beginPath(); ctx.moveTo(75, 25); ctx.quadraticCurveTo(25, 25, 25, 62.5); ctx.quadraticCurveTo(25, 100, 50, 100); ctx.quadraticCurveTo(50, 120, 30, 125); ctx.quadraticCurveTo(60, 120, 65, 100); ctx.quadraticCurveTo(125, 100, 125, 62.5); ctx.quadraticCurveTo(125, 25, 75, 25); ctx.stroke(); } } تقوم الدَّالة ()quadraticCurveTo برسم منحني بالإحداثيات ونقطة التحكم المناسبة عند استدعائها بالقيم وبالترتيب أعلاه: 2- رسم منحي تكعيبي في المثال التالي شرح استخدام الدَّالة (bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y لرسم منحنيات من الدرجة الثالثة. تفيدنا هذه الدَّالة في رسم أشكال أكثر تعقيدًا لنأخذ مثلًا شكل القلب: function draw() { var canvas = document.getElementById(‘canvas’); if (canvas.getContext) { var ctx = canvas.getContext(‘2d’); ctx.beginPath(); ctx.fillStyle = "rgb(200,0,0)"; ctx.moveTo(75, 40); ctx.bezierCurveTo(75, 37, 70, 25, 50, 25); ctx.bezierCurveTo(20, 25, 20, 62.5, 20, 62.5); ctx.bezierCurveTo(20, 80, 40, 102, 75, 120); ctx.bezierCurveTo(110, 102, 130, 80, 130, 62.5); ctx.bezierCurveTo(130, 62.5, 130, 25, 100, 25); ctx.bezierCurveTo(85, 25, 75, 37, 75, 40); ctx.fill(); } } ينتج عن استدعاء الدَّالة (bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y بالقيم وبالترتيب أعلاه الشكل: ها قد أنهينا تفاصيل إنشاء ورسم أشكال بطرق مختلفة على عنصر اللوحة Cancas، بوصولك إلى هنا تكون قد كونت معرفة ممتازة عن كيفية رسم مستطيلات، مثلثات، خطوط، أقواس ومنحنيات وأيضًا التعامل مع المسارات في Canvas. سنقوم في الدرس المقبل بـإنشاء شكل رسومي أكثر احترافية باستخدام كل تلك الأدوات معًا. المصادر
  4. سنتعرف في هذا الدّرس على الأنماط Patterns، الظلال Shadows وقواعد الملء في Canvas بالإضافة لرسم النصوص وتطبيق التنسيقات عليها مثل أنواع الخطوط Fonts وخصائصها. كما سنتعرف على واحدة من السمات الأكثر إثارة في canvas وهي القدرة على استخدام الصور لعمل تركيبات صور ديناميكية، خلفيات أو حتى شخصيات الألعاب. الأنماط Patterns تتيح لك canvas إنشاء أنماط باستخدام الصور وتحديد أنواعها باستخدام الدالة ()createPattern. تأخذ الدالة ()createPtterns معاملين هما الصورة المراد استخدامها لتطبيق النمط والتي يمكن أن تكون عنصر HTML أو وسم <video> أو حتى عنصر canvas آخر. المعامل الآخر هو النوع Type وهو عبارة عن نص string يحدد كيفيّة استخدام الصورة لتطبيق النمط. createPattern(image, type) يأخذ المعامل type أحد القيم التالية والتي تحدد كيفية استخدام الصورة لإنشاء النمط Pattern: Repeat: تكرر الصورة في الاتجاهين الأفقي Horizontal والعمودي Vertical repeat-x: تكرر الصورة في الاتجاه الأفقي Horizontal repeat-y: تكرر الصورة في الاتجاه العمودي Vertical no-repeat: تظهر الصورة مرة واحد كما هي. تشبه الدالة ()createPattern دوال التدرج اللّوني gradient التي شرحتها في الدرس السّابق. عند إنشاء نمط يمكننا إسناده إلى الخاصية fillStyle أو strokeStyle كما في المثال التالي: var img = new Image(); img.src = 'someimage.png'; var ptrn = ctx.createPattern(img,'repeat'); ملاحظة: تأكّد من أنك قمت بإنشاء صورة وإعطائها المسار الصحيح قبل استدعاء الدالة ()createPattern. في هذا المثال سنقوم بإنشاء نمط وإسناده للخاصية fillStyle حيث سننشئ النمط ضمن الدالة onload للصورة وذلك للتأكد من تحميل الصورة قبل إسنادها للنمط. function draw() { var ctx = document.getElementById('canvas').getContext('2d'); var img = new Image(); img.src = 'https://mdn.mozillademos.org/files/222/Canvas_createpattern.png'; img.onload = function(){ var ptrn = ctx.createPattern(img,'repeat'); ctx.fillStyle = ptrn; ctx.fillRect(0,0,150,150); } } النتيجة: الظلال Shadows باستخدام الظلال في canvas يمكنك عمل تظليل للنصوص والصور. استخدام الظلال في canvas يتضمن 4 خصائص: shadowOffsetX = float تشير إلى أن الظل يمتد من الكائن بمسافة أفقية. لا تتأثر هذه القيمة بمصفوفة التحويل Transformation matrix وقيمتها الافتراضية هي 0. shadowOffsetY = float تشير إلى أن الظل يمتد من الكائن بمسافة عمودية. لا تتأثر هذه القيمة بمصفوفة التحويل Transformation matrix وقيمتها الافتراضية هي 0. shadowBlur = float تحدد حجم تأثير الضبابية blurring. لا تتعلق هذه القيمة بعدد الـ pixels ولا تتأثر بمصفوفة التحويل Transformation matrix وقيمتها الافتراضية هي 0. shadowColor = color هي قيمة ألوان CSS قياسية وتحدد لون الظل وقيمتها الافتراضية هي لون أسود بشفافية كاملة. الخاصيتان shadowOffsetX و shadowOffsetY تشيران إلى أي مدى ينبغي أن يمتد الظل من الكائن في الاتجاه X والاتجاه Y. تأخذ الخاصيتين قيمًا سالبة وذلك لتحديد اتجاه الظل إما لليسار X- أو للأعلى Y-. الخاصية shadowBlur تحدد حجم الضبابية للظل ولا تتعلق بعدد الـ pixels ولا تتأثر بمصفوفة التحويل Transformation matrix وقيمتها الافتراضية هي 0. المثال التالي يرسم نصًا بتأثيرات ظلال مختلفة باستخدام القيم أعلاه: function draw() { var ctx = document.getElementById('canvas').getContext('2d'); ctx.shadowOffsetX = 2; ctx.shadowOffsetY = 2; ctx.shadowBlur = 2; ctx.shadowColor = "rgba(0, 0, 0, 0.5)"; ctx.font = "20px Times New Roman"; ctx.fillStyle = "Black"; ctx.fillText("أهلًا بك في أكاديمية حسوب", 5, 30); } قواعد الملء Fill Rules عند استخدام الخاصية ()fill يمكنك تحديد خوارزمية الملء التي تريد تطبيقها ويمكن من خلالها تحديد فيما إذا كانت النقطة داخل أو خارج المسار وبالتالي تحديد هل سيتم ملئها أم لا. ويوجد لها قيمتان: nonzero وهي القيمة الافتراضية. evenodd مثال: function draw() { var ctx = document.getElementById('canvas').getContext('2d'); ctx.beginPath(); ctx.arc(50, 50, 30, 0, Math.PI*2, true); ctx.arc(50, 50, 15, 0, Math.PI*2, true); ctx.fill("evenodd"); } رسم النصوص كأي شكل من الأشكال التي يمكن رسمها على canvas يمكن أيضًا رسم النصوص وتطبيق خصائص مختلفة عليها. يوفّر سياق التصيير rendering context في canvas طريقتين لتصيير النصوص: 1- باستخدام الدالة fillText fillText(text, x, y [, maxWidth]) تملأ نصًا مُعيّنًا عند موضع x,y معين، المعامل maxWidth معامل اختياري يحدد أقصى عرض للرسم. 2- باستخدام الدالة strokeText strokeText(text, x, y [, maxWidth]) تملأ حواف نص معين عند موضع x,y معين، المعامل maxWidth معامل اختياري يحدد أقصى عرض للرسم. مثال: ملء نص باستخدام fillStyle function draw() { var ctx = document.getElementById('canvas').getContext('2d'); ctx.font = "48px serif"; ctx.fillText("Hello world", 10, 50); } مثال: ملء حواف نص باستخدام strokeStyle function draw() { var ctx = document.getElementById('canvas').getContext('2d'); ctx.font = "48px serif"; ctx.strokeText("Hello world", 10, 50); } تصميم وتنسيق النصوص يوفر سياق التصيير Rendering Context مجموعة من الخصائص تمكّنك من تحديد المظهر الذي تريد إظهار النص به على Canvas. ستبدو هذه الخصائص مألوفة لك إن كنت قد عملت على CSS من قبل. font = value تحدد نمط النص الحالي (نوع الخط) الذي سيظهر به النص، تستخدم هذه الخاصية نفس قواعد استخدام الخاصية CSS font. القيمة الافتراضية للخط هي 10px sans-serif. textAlign = value تُحدّد إعدادات محاذاة النص. القيم التي تأخذها هذه الخاصية هي start ،end ،left ،right أو center. القيمة الافتراضية لها هي center. textBaseline = value تُحدّد إعدادات خط الأساس .Baseline القيم التي تأخذها الخاصية text Baseline هي top ،hanging ،middle ،alphabetic ،ideographic أو bottom. القيمة الافتراضية لها هي alphabetic. direction = value تُحدّد الاتجاهية. القيم التي تأخذها الخاصية textAlign هي ltr ،rtl ،inherit. القيمة الافتراضية لها هي inherit. يوضّح الرّسم البياني التالي المأخوذ من WHATWG مختلف خطوط الأساس Baseline التي تدعمها الخاصية textBaseline. مثال: ctx.font = "48px serif"; ctx.textBaseline = "hanging"; ctx.strokeText("Hello world", 0, 100); قياسات النصوص المتقدمة في حال كنت بحاجة لتطبيق المزيد من التفاصيل على النصوص فإن الدالة ()measureText توفر لك إمكانية لقياس النصوص حيث تُرجع الدالة ()measureText كائن من نوع TextMetrics يحتوي على عرض النص الحالي بالبكسل. يظهر المثال التالي كيف يمكنك قياس الخط والحصول على عرضه: function draw() { var ctx = document.getElementById('canvas').getContext('2d'); var text = ctx.measureText("foo"); object text.width; } الصور يعتمد استيراد الصور في Canvas على خطوتين أساسيتين: الحصول على مرجع reference لكائن HTMLImage أو لعنصر Canvas آخر لاستخدامه كمصدر. يمكن استخدام الصور أيضًا عن طريق توفير رابط URL. رسم الصورة على canvas باستخدام DrawImage. يستخدم Canvas API أي من أنواع البيانات التالية باعتبارها مصدر صورة للحصول على الصور ورسمها: HTMLImageElement: يتم إنشاء الصور باستخدام المنشئ constructor كأي عنصر <img> في HTML. HTMLVideoElement: استخدام عنصر <video> كمصدر للصورة أي استخدام الاطار الحالي للفيديو كصورة. HTMLCanvasElement: يمكن استخدام عنصر <canvas> آخر كمصدر صورة. استخدام الصور في Canvas يوجد عدة طرق لاستخدام الصور في Canvas: استخدام صور من نفس الصفحة يمكننا الحصول على مرجع للصور reference من نفس الصفحة باستخدام أحد الطرق التالية: document.images collection استخدام الدالة ()document.getElementsByTagName استخدام الدالة ()document.getElementById عن طريق معرّف ID الخاص بالصورة استخدام صور من مجالات أخرى ويتم ذلك باستخدام الخاصية crossorigin للعنصر <img> يمكنك طلب إذن لتحميل الصورة من مجال Domain آخر لاستخدامها في استدعائك للدالة ()drawImage. إذا سمح مجال الاستضافة وصول cross-domain للصورة فسيتم استخدام الصورة في Canvas دون التأثير عليها أما في حال لم يتم السماح بالوصول للصورة فسيحدث تشويه للعنصر canvas. استخدام عناصر Canvas أخرى كما هو الحال مع الصور العادية يمكن الوصول لعناصر canvas أخرى باستخدام الدالة ()document.getElementsByTagName أو ()document.getElementById. يجب التأكد قبل استخدام عنصر Canvas آخر من أن العنصر الأساسي يحوي على رسم أو مسار. واحدة من أهم استخدامات هذا الأسلوب هو استخدام عنصر canvas كمعرض صور مصغرات لعنصر Canvas أكبر منه. إنشاء صورة من الصفر خيار آخر لإنشاء HTMLImageElement هي باستخدام المنشئ() Image: var img = new Image(); img.src = 'myImage.png'; في حال استدعائك للدالة ()drawImage قبل الانتهاء من تحميل الصورة قد يظهر خطأ في المتصفحات القديمة لذا عليك التأكد من استخدام الحدث load بعد الانتهاء من تحميل الصورة: var img = new Image(); img.addEventListener("load", function() { // execute drawImage statements here }, false); img.src = 'myImage.png'; استخدام إطارات الفيديو يمكنك أيضًا استخدام إطارات الفيديو <video> لإظهاره في الـ canvas. مثال: function getMyVideo() { var canvas = document.getElementById('canvas'); if (canvas.getContext) { var ctx = canvas.getContext('2d'); return document.getElementById('myvideo'); } } سنكمل في الدّرس القادم التعامل مع الصور في canvas والتعرّف على خصائصها بالإضافة لإنشاء معرض فني. المصادر
  5. قبل التعرف على التنسيقات والألوان في Canvas سنقوم بتطبيق مثال رسومي للعبة شهيرة باستخدام أنواع المسارات التي تعلّمناها في الدرس السابق لإنشاء شخصيات لعبة Pacman الشهيرة. تصميم واجهة اللعبة سنحتاج لرسم مستطيلات بحواف دائرية لتمثيل الحواجز في اللُّعبة لذا سننشئ دالة ولتكن roundRect ونعطيها المعاملات parameters المناسبة لإنشاء مستطيل بحواف دائرية. السّياق Context سنحتاج لتمرير نوع السّياق للدالة التي سيتم إنشاؤها. إحداثيات نقطة بداية الرسم (x,y). عرض المستطيل width. طول المستطيل height. القطر radius. function roundedRect(ctx, x, y, width, height, radius) في بداية كل عملية رسم سنحتاج لاستدعاء الدالة beginPath لإنشاء القائمة List التي ستحوي نقاط المسار كما شرحنا في الدرس السّابق. تتبعها الدالة moveTo لتحديد النقطة التي سيبدأ عندها الرسم. سيتم تمرير المعاملات x,y للدالة moveTo مع جمع قيمة القطر radius للقيمة y. نبدأ الآن برسم خط مستقيم باستخدام الدالة lineTo وتمرير القيمة x نفسها التي بدأنا عندها الرسم مع قيمة y المضاف إليها طول المستطيل height ليتم رسم خط مستقيم بطول المستطيل وطرح قيمة القطر radius وهكذا ينشأ الضلع الأول للمستطيل. الآن رسم حافة المستطيل باستخدام الدالة quadraticCurveTo وتحديد المعاملات: quadraticCurveTo(x, y + height, x + radius, y + height); ثم رسم الضلع الثاني للمستطيل باستدعاء الدالة lineTo: ctx.lineTo(x + width-radius, y + height); رسم الحافة الثانية للمستطيل: ctx.quadraticCurveTo(x + width, y + height, x + width, y + height-radius); رسم الضلع الثالثة للمستطيل: ctx.lineTo(x + width, y + radius); رسم الحافة الثالثة للمستطيل: ctx.quadraticCurveTo(x + width, y, x + width-radius, y); رسم الضلع الرابعة للمستطيل: ctx.lineTo(x + radius, y); رسم الحافة الرابعة للمستطيل: ctx.quadraticCurveTo(x, y, x, y + radius); أخيرًا استدعاء الدالة stroke لرسم المستطيل بشكل مفرغ: function roundedRect(ctx, x, y, width, height, radius){ ctx.beginPath(); ctx.moveTo(x, y + radius); ctx.lineTo(x, y + height-radius); ctx.quadraticCurveTo(x, y + height, x + radius, y + height); ctx.lineTo(x + width-radius, y + height); ctx.quadraticCurveTo(x + width, y + height, x + width, y + height-radius); ctx.lineTo(x + width, y + radius); ctx.quadraticCurveTo(x + width, y, x + width-radius, y); ctx.lineTo(x + radius, y); ctx.quadraticCurveTo(x, y, x, y + radius); ctx.stroke(); } حان الوقت الآن لاستدعاء الدالة roundedRect ورسم المستطيلات التي ستمثل الحواجز في لعبة pacman. في الدالة draw سيتم استدعاء الدالة roundedRect على عدد المستطيلات (الحواجز) التي ستكون في الشكل. سأقوم بإنشاء جزء من واجهة اللُّعبة (جزء من الإطار الخارجي وعدد من المستطيلات) كما في الشيفرة التالية: function draw() { var canvas = document.getElementById('tutorial'); if (canvas.getContext) { var ctx = canvas.getContext('2d'); roundedRect(ctx, 12, 12, 150, 150, 15); roundedRect(ctx, 19, 19, 150, 150, 9); roundedRect(ctx, 53, 53, 49, 33, 10); roundedRect(ctx, 53, 119, 49, 16, 6); roundedRect(ctx, 135, 53, 49, 33, 10); roundedRect(ctx, 135, 119, 25, 49, 10); } } سينتج الشكل: رسم شكل pacman سنحتاج لرسم شكل pac man إلى استدعاء الدالة arc لرسم الشكل الدائري والدالة lineTo لتحديد الفم: ctx.beginPath(); ctx.arc(37, 37, 13, Math.PI / 7, -Math.PI / 7, false); ctx.lineTo(31, 37); ctx.fill(); رسم مستطيلات صغيرة تمثل طعام pacman سنحتاج إلى حلقات تكرار لإنشاء مستطيلات صغيرة بين الحواجز كما في المثال التالي: for (var i = 0; i < 8; i++) { ctx.fillRect(51 + i * 16, 35, 4, 4); } for (i = 0; i < 6; i++) { ctx.fillRect(115, 51 + i * 16, 4, 4); } for (i = 0; i < 8; i++) { ctx.fillRect(51 + i * 16, 99, 4, 4); } رسم الشبح لرسم هيكل جسم الشبح سنستخدم الدالة bezierCurveTo لعمل الشكل العلوي من الجسم ثم استدعاء الدالة lineTo بإحداثيات مناسبة لعمل المنحنيات السّفلية للجسم: 1- رسم هيكل الشبح ctx.beginPath(); ctx.moveTo(83, 116); ctx.lineTo(83, 102); ctx.bezierCurveTo(83, 94, 89, 88, 97, 88); ctx.bezierCurveTo(105, 88, 111, 94, 111, 102); ctx.lineTo(111, 116); ctx.lineTo(106.333, 111.333); ctx.lineTo(101.666, 116); ctx.lineTo(97, 111.333); ctx.lineTo(92.333, 116); ctx.lineTo(87.666, 111.333); ctx.lineTo(83, 116); ctx.fill(); 2- العينان ctx.fillStyle = "white"; ctx.beginPath(); ctx.moveTo(91, 96); ctx.bezierCurveTo(88, 96, 87, 99, 87, 101); ctx.bezierCurveTo(87, 103, 88, 106, 91, 106); ctx.bezierCurveTo(94, 106, 95, 103, 95, 101); ctx.bezierCurveTo(95, 99, 94, 96, 91, 96); ctx.moveTo(103, 96); ctx.bezierCurveTo(100, 96, 99, 99, 99, 101); ctx.bezierCurveTo(99, 103, 100, 106, 103, 106); ctx.bezierCurveTo(106, 106, 107, 103, 107, 101); ctx.bezierCurveTo(107, 99, 106, 96, 103, 96); ctx.fill(); 3- البؤبؤ الأيمن ctx.fillStyle = "black"; ctx.beginPath(); ctx.arc(101, 102, 2, 0, Math.PI*2, true); ctx.fill(); 4- البؤبؤ الأيسر ctx.beginPath(); ctx.arc(89, 102, 2, 0, Math.PI*2, true); ctx.fill(); يمكنك استعراض المثال على JSFiddle. الكائن Path2D كما لاحظت في المثال السّابق أن كل شكل هو عبارة عن سلسلة من التعليمات التي تنفذ بالترتيب للحصول على المسار المطلوب ولا يوجد ارتباط واضح بين سلسلة التعليمات والشكل الناتج. ما رأيك أن نقوم بعملية تبسيط وتحسين وذلك بتحديد التعليمات الخاصة بكل شكل عن طريق استخدام الكائن Path2D. يقوم المنشئ Constructor عند إنشاء كائن Path2D بإرجاع كائن Path2D. new Path2D(); new Path2D(path); new Path2D(d); جميع الدوال الخاصة بإنشاء المسارات مثل moveTo ،rect ،arc، أو quadraticCurveTo..الخ يمكن استدعاؤها عن طريق الكائن Path2D. يوفّر Path2d API طريقة للجمع بين المسارات باستخدام الدالة addPath ويكون ذلك مفيدًا عندما ترغب في بناء شكل من عدة مكونات. سأقوم بإنشاء مستطيل ودائرة باستخدام الكائن Path2D. كل من المستطيل والدائرة يُخزن ككائن Path2D بحيث تكون متاحة للاستخدام في وقت لاحق. function draw() { var canvas = document.getElementById('canvas'); if (canvas.getContext){ var ctx = canvas.getContext('2d'); var rectangle = new Path2D(); rectangle.rect(10, 10, 50, 50); var circle = new Path2D(); circle.moveTo(125, 35); circle.arc(100, 35, 25, 0, 2 * Math.PI); ctx.stroke(rectangle); ctx.fill(circle); } } لاحظ أنه تم استدعاء الدالتين stroke و fill من خلال السّياق ctx وتمرير الكائنين rectangle و circle من نوع Path2D كمعاملات. وكذلك أصبح واضحًا ما الشكل الذي ترسمه كل سلسلة من التعليمات. الألوان Colors حتى الآن تعرّفنا على الخاصيّة fillStyle والتي تقوم بملأ المسار بلون معين. سنتعرّف أيضًا على الخاصيّة fillStroke والتي تقوم بتلوين المسار المفرّغ (تلوين الحواف). إذًا يوجد خاصيتين أساسيتين لتطبيق الألوان على الأشكال: fillStyle = color strokeStyle = color القيمة الافتراضية لـ color هي اللون الأسود والتي تمثل القيمة #000000، يمكن تمثيل اللون color بعدة طرق. مثلًا تطبيق اللون البرتقالي باستخدام الخاصيّة fillStyle: ctx.fillStyle = "orange"; ctx.fillStyle = "#FFA500"; ctx.fillStyle = "rgb(255, 165, 0)"; ctx.fillStyle = "rgba(255, 165, 0, 1)"; تطبيق الألوان على شكل باستخدام الخاصية FillStyle سأعرض مثالًا لكيفية ملء شكل باستخدام مجموعة مستطيلات بألوان مختلفة ليبدو شكل متعدد الألوان. سيتم إنشاء حلقتي تكرار وذلك لتوليد مجموعة ألوان RGB مختلفة بتغيير قيمة red وgreen باستخدام المتغيرين i و j وترك القيمة blue ثابتة 0 سيبدو لك الشكل وكأنه منشأ باستخدام photoshop. unction draw() { var ctx = document.getElementById('canvas').getContext('2d'); for (var i = 0; i < 6; i++){ for (var j = 0; j < 6; j++){ ctx.fillStyle = 'rgb(' + Math.floor(255-42.5*i) + ',' + Math.floor(255-42.5*j) + ',0)'; ctx.fillRect(j*25, i*25, 25, 25); } } } النتيجة: تطبيق الألوان على شكل باستخدام الخاصية StrokeStyle سيكون المثال التالي مشابهًا للمثال السّابق مع تغيير الخاصيّة fillStyle إلى strokeStyle واستخدام الدالة arc لرسم دوائر داخل مستطيل وتوليد مجموعة ألوان RGB مختلفة بتغيير قيمة green و blue باستخدام المتغيرين i و j وترك القيمة red ثابتة. function draw() { var ctx = document.getElementById('canvas').getContext('2d'); for (var i = 0; i < 6; i++){ for (var j = 0; j < 6; j++){ ctx.strokeStyle = 'rgb(0,' + Math.floor(255-42.5*i) + ',' + Math.floor(255-42.5*j) + ')'; ctx.beginPath(); ctx.arc(12.5+j*25, 12.5+i*25, 10, 0, Math.PI*2,true); ctx.stroke(); } } } النتيجة: الشفافية Transparency بالإضافة لرسم الأشكال الواضحة يمكن أيضًا رسم أشكال شبه شفافة أو شفافة ويتم ذلك إما عن طريق تعيين الخاصيّة globalAlpha أو عن طريق تحديد الشفافية في اللون RGB باستخدام الخاصيّتين StrokeStyle أو FillStyle: globalAlpha = transparencyValue تشبه الدالة ()rgba الدالة ()rgb باختلاف المعامل الأخير والذي يحدد قيمة الشفافية اللَّونية. تأخذ الشفافية قيمتها من 0.0 شفافية مطلقة إلى 1.0 شفافية معدومة. مثال لتحديد الشفافية باستخدام الدالة ()rgba: ctx.strokeStyle = "rgba(255, 0, 0, 0.5)"; ctx.fillStyle = "rgba(255, 0, 0, 0.5)"; تحديد الشفافية باستخدام GlobaAlpha سأقوم بعرض مثال لرسم 4 مربعات متلاصقة وبألوان مختلفة ليتم تشكيل مربع كبير ثم تطبيق شفافية بشكل دوائر متدرجة الأحجام مركزها هي نقطة تلاقي المربعات (مركز المربع) وذلك عن طريق إنشاء حلقة تكرار ورسم الدوائر بقطر متزايد فوق بعضها البعض. function draw() { var ctx = document.getElementById('canvas').getContext('2d'); ctx.fillStyle = '#FD0'; ctx.fillRect(0, 0, 75, 75); ctx.fillStyle = '#6C0'; ctx.fillRect(75, 0, 75, 75); ctx.fillStyle = '#09F'; ctx.fillRect(0, 75, 75, 75); ctx.fillStyle = '#F30'; ctx.fillRect(75, 75, 75, 75); ctx.fillStyle = '#FFF'; ctx.globalAlpha = 0.2; for (i = 0; i < 7; i++){ ctx.beginPath(); ctx.arc(75, 75, 10+10*i, 0, Math.PI*2, true); ctx.fill(); } } تحديد الشفافية باستخدام ()RGBA سأقوم بعرض مثالًا مشابهًا للمثال السّابق ولكن بدلًا من رسم دوائر فوق بعضها بقطر متزايد سأرسم مستطيلات بشفافية متزايدة (زيادة التعتيم) باستخدام ()rgba: function draw() { var ctx = document.getElementById('canvas').getContext('2d'); ctx.fillStyle = 'rgb(255, 221, 0)'; ctx.fillRect(0, 0, 150, 37.5); ctx.fillStyle = 'rgb(102, 204, 0)'; ctx.fillRect(0, 37.5, 150, 37.5); ctx.fillStyle = 'rgb(0, 153, 255)'; ctx.fillRect(0, 75, 150, 37.5); ctx.fillStyle = 'rgb(255, 51, 0)'; ctx.fillRect(0, 112.5, 150, 37.5); for (var i = 0; i < 10; i++){ ctx.fillStyle = 'rgba(255, 255, 255,'+(i+1)/10+')'; for (var j = 0; j < 4; j++){ ctx.fillRect(5+i*14, 5+j*37.5, 14, 27.5); } } } تصاميم وتنسيقات الخطوط يمكنك إنشاء ورسم خطوط بأشكال وتنسيقات مختلفة باستخدام مجموعة من الخصائص: lineWidth = value تحدد سمك الخط المراد رسمه: lineCap = type تحدد مظهر نهاية الخط: lineJoin = type تحدد مظهر الزوايا عند الخطوط المتلاقية: getLineDash() تُرجع مصفوفة لخط من نمط dashes تحوي على أرقام تحدد المسافات لتناوب رسم الخط والمسافة: setLineDash(segments) تحدد الخط الحالي ليأخذ نمط dash: lineDashOffset = value تحدد أين ستبدأ مصفوفة النمط dash على الخط. خاصية lineWidth هذه الخاصيّة تُحدد سمك الخط الحالي وتأخذ قيم موجبة، القيمة الافتراضية لها هي 1.0. عرض الخط هو سمك الحواف Stroke التي تتركز على مسار معين. المثال التالي يعرض 10 خطوط مسقيمة ذات سمك متزايد. function draw() { var ctx = document.getElementById('canvas').getContext('2d'); for (var i = 0; i < 10; i++){ ctx.lineWidth = 1+i; ctx.beginPath(); ctx.moveTo(5+i*14, 5); ctx.lineTo(5+i*14, 140); ctx.stroke(); } } خاصية lineCap تحدد الخاصيّة lineCap كيف ستُرسم النقاط النهائية للخط حيث تأخذ الخاصيّة lineCap ثلاث قيم butt ،round وsquare. القيمة الافتراضية هي butt. butt: تحدد نهايات الخطوط لتكون مربعة. round: تحدد نهايات الخطوط لتكون دائرية. square: تقوم بإنشاء مربع بنفس عرض الخط وارتفاع يساوي نصف سماكة الخط وتضيفه عند نهاية الخط. سأقوم بعرض مثال يرسم ثلاثة خطوط بقيم lineCap مختلفة سيتم تحديد بداية ونهاية الخطوط بواسطة دليلن (خطين أفقيين) لتمييز الفرق بين الخطوط الثلاثة: function draw() { var ctx = document.getElementById(‘canvas’).getContext(‘2d’); var lineCap = [‘butt’,’round’,’square’]; // Draw guides ctx.strokeStyle = ‘#09f’; ctx.beginPath(); ctx.moveTo(10,10); ctx.lineTo(140,10); ctx.moveTo(10,140); ctx.lineTo(140,140); ctx.stroke(); // Draw lines ctx.strokeStyle = ‘black’; for (var i=0;i } كما تلاحظ في الخط اليساري رُسم بقيمة butt. الخط في المنتصف رُسم بقيمة round الخط الأخير رسم بقيمة square والتي تقوم بإنشاء مربع بنفس عرض الخط وارتفاع يساوي نصف سماكة الخط. خاصية lineJoin تحدد الخاصيّة lineJoin كيف لمسارين (خطوط، أقواس، منحنيات) أن يرتبطا معًا أي أنها تحدد شكل نقطة الارتباط بين مسارين. تأخذ الخاصيّة lineJoin ثلاث قيم round ،bevel وmiter. القيمة الافتراضية لـ lineJoin هي miter. Round: تقوم بتدوير زوايا الشكل عن طريق ملئها بقطاعات دائرية نصف قطر هذه الزوايا الدائرية يساوي عرض الخط. Bevel: تقوم بسد المنطقة المثلثية الناتجة من تلاقي خطين بحيث تقوم بحذف المثلث الناتج من تلاقي الخطين. وملأ المساحة المتبقية. Miter: تقوم بملأ المساحة بين نهايتي الخطين المتلاقين لتشكل مثلث. المثال التالي يوضح عمل كل واحد من تلك الخصائص: function draw() { var ctx = document.getElementById('canvas').getContext('2d'); var lineJoin = ['round', 'bevel', 'miter']; ctx.lineWidth = 10; for (var i = 0; i < lineJoin.length; i++){ ctx.lineJoin = lineJoin[i]; ctx.beginPath(); ctx.moveTo(-5, 5+i*40); ctx.lineTo(35, 45+i*40); ctx.lineTo(75, 5+i*40); ctx.lineTo(115, 45+i*40); ctx.lineTo(155, 5+i*40); ctx.stroke(); } } استخدام الشرطات dashes يمكنك تحديد الخط ليأخذ نمط الشرطات dashed باستخدام الدالة setLineDash والخاصيّة lineDashOffset لتحديد نمط الشرطات للخطوط. تأخذ الدالة setLineDash قائمة list من الأرقام التي تحدد المسافات لتناوب رسم الخط والمسافة. الخاصيّة lineDashOffset تحدد القيمة التي سيبدأ عندها النمط. في المثال أدناه سأقوم بإنشاء شكل يشبه تأثير مسيرة النمل مع تأثير حركي عادةً يوجد في أداة التحديد selection tool في برامج الجرافيكس.( سيتم شرح التأثيرات الحركية بالتفصيل لاحقًا) var ctx = document.getElementById('canvas').getContext('2d'); var offset = 0; function draw() { ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.setLineDash([4, 2]); ctx.lineDashOffset = -offset; ctx.strokeRect(10, 10, 100, 100); } function march() { offset++; if (offset > 16) { offset = 0; } draw(); setTimeout(march, 20); } march(); التدرجات اللونية Gradient يوجد نوعان من التدرّجات اللَّونية في canvas: تدرجات لونية خطية Linear Gradient. وتدرجات لونية شعاعية Radial Gradient. يتم إنشاء تدرُّجات لونية عن طريق إنشاء كائن CanvasGradient باستخدام أحد الدالتين التالييتن ثم نطبق أحد الخاصيّتين fillStyle أو strokeStyle على الكائن. 1- الدالة CreateLinearGradient createLinearGradient(x1, y1, x2, y2) تنشئ كائن من نوع linear gradient حيث تمثل x1, y1 نقطة البداية و x2, y2 نقطة النهاية. 2- الدالة Create RadialGradient createRadialGradient(x1, y1, r1, x2, y2, r2) تنشئ تدرج لوني شعاعي حيث تمثل المعاملات دائرتين x1, y1 مركز الدائرة الأولى ونصف قطرها r1 و x2, y2 مركز الدائرة الثانية ونصف قطرها هو r2. مثال: var lineargradient = ctx.createLinearGradient(0, 0, 150, 150); var radialgradient = ctx.createRadialGradient(75, 75, 0, 75, 75, 100); بعد إنشاء نوع التدرّج اللَّوني يمكنك تطبيق الألوان عليه باستخدام الدالة ()addColorStop: gradient.addColorStop(position, color) المعامل position هو رقم بين 0.0 و 1.0 ويحدد الوضع النسبي للون في الإنحدار. المعامل color يحدد اللون ويجب أن يكون نص string ممثل بـ CSS. يمكن إضافة العديد من نقاط اللّون إلى التدرّج فيما يلي مثال لانحدار خطي بسيط من اللّونين الأبيض والأسود: var lineargradient = ctx.createLinearGradient(0, 0, 150, 150); lineargradient.addColorStop(0, 'white'); lineargradient.addColorStop(1, 'black'); تطبيق تدرج لوني خطي Linear Gradient مع الخاصيتين fillStyle و strokStyle كما ستلاحظ في المثال التالي أن كلا الخاصيّتين fillStyle و strokeStyle تأخذان كائنًا من نوع canvasGradient. function draw() { var ctx = document.getElementById('canvas').getContext('2d'); var lingrad = ctx.createLinearGradient(0, 0, 0, 150); lingrad.addColorStop(0, '#00ABEB'); lingrad.addColorStop(0.5, '#fff'); lingrad.addColorStop(0.5, '#26C000'); lingrad.addColorStop(1, '#fff'); var lingrad2 = ctx.createLinearGradient(0, 50, 0, 95); lingrad2.addColorStop(0.5, '#000'); lingrad2.addColorStop(1, 'rgba(0, 0, 0, 0)'); ctx.fillStyle = lingrad; ctx.strokeStyle = lingrad2; ctx.fillRect(10, 10, 130, 130); ctx.strokeRect(50, 50, 50, 50); } المثال أعلاه يشرح كيفيّة عمل تدرج لوني خطي يمثل لون السماء والأرضية عن طريق إنشاء متغير lingrad ثم استدعاء الدالة ()addColorStop لتطبيق الألوان الأزرق والأبيض ثم الأخضر والأبيض ثم إسنادها للخاصية fillStlye ثم إنشاء تدرج لوني أسود عن طريق إنشاء متغير 2lingrad وتطبيق نقاط لونية باللون الأسود ثم إسناده للخاصية strokeStyle. أخيرًا رسم الأشكال بالإحداثيات المناسبة: تطبيق تدرج لوني شعاعي Radial Gradient مع الخاصيتين fillStyle و strokStyle لفهم كيفية عمل التدرّج اللَّوني الشّعاعي لابد من عرض مثال. المثال أدناه يحدد أربعة تدرجات شعاعية مختلفة حيث سيتم إنشاء تدرّجات شعاعية أكثر تعقيدًا عن التدرّجات الشّعاعية الكلاسيكية. function draw() { var ctx = document.getElementById('canvas').getContext('2d'); var radgrad = ctx.createRadialGradient(45, 45, 10, 52, 50, 30); radgrad.addColorStop(0, '#A7D30C'); radgrad.addColorStop(0.9, '#019F62'); radgrad.addColorStop(1, 'rgba(1,159,98,0)'); var radgrad2 = ctx.createRadialGradient(105, 105, 20, 112, 120, 50); radgrad2.addColorStop(0, '#FF5F98'); radgrad2.addColorStop(0.75, '#FF0188'); radgrad2.addColorStop(1, 'rgba(255,1,136,0)'); var radgrad3 = ctx.createRadialGradient(95, 15, 15, 102, 20, 40); radgrad3.addColorStop(0, '#00C9FF'); radgrad3.addColorStop(0.8, '#00B5E2'); radgrad3.addColorStop(1, 'rgba(0,201,255,0)'); var radgrad4 = ctx.createRadialGradient(0, 150, 50, 0, 140, 90); radgrad4.addColorStop(0, '#F4F201'); radgrad4.addColorStop(0.8, '#E4C700'); radgrad4.addColorStop(1, 'rgba(228,199,0,0)'); ctx.fillStyle = radgrad4; ctx.fillRect(0, 0, 150, 150); ctx.fillStyle = radgrad3; ctx.fillRect(0, 0, 150, 150); ctx.fillStyle = radgrad2; ctx.fillRect(0, 0, 150, 150); ctx.fillStyle = radgrad; ctx.fillRect(0, 0, 150, 150); } كما تلاحظ تم إنشاء 4 تدرجات لونية شعاعية وتحديد إحداثيات ونصف قطر كل من الدائرتين اللَّونيتين لكل تدرج شعاعي. كانت هذه المعلومات بمثابة طرف الخيط الذي يقودك للبدء في تعلُّم رسم الأشكال على Canvas كالمحترفين. يحتاج الأمر منك للكثير من التجريب والتخيل لتتقن العمل على هذه الأداة واكتشاف ميزاتها. المصادر