Advertisement
  1. Web Design
  2. HTML/CSS
  3. HTML

قماش من سكراتش: التحولات والتدرجات 

Scroll to top
Read Time: 10 min
This post is part of a series called Canvas From Scratch.
Canvas From Scratch: Advanced Drawing
Canvas From Scratch: Pixel Manipulation

() translation by (you can also view the original English article)

في هذه المقالة ، سوف أطلعك على التحولات في اللوحة ، بالإضافة إلى الظلال والتدرجات.  تعد التحويلات مجموعة قيّمة للغاية من الطرق التي تسمح لك ببدء الإبداع بطريقة رسم الأشياء على اللوحة. دعونا نبدأ بعد القفزة! 


اعداد 

ستستخدم نموذج HTML نفسه من المقالات السابقة ، لذا افتح محرر المفضلة لديك ثم الصقه بالرمز التالي: 

1
<!DOCTYPE html>
2
3
<html>
4
    <head>
5
        <title>Canvas from scratch</title>
6
        <meta charset="utf-8">
7
8
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
9
10
        <script>
11
            $(document).ready(function() {
12
                var canvas = document.getElementById("myCanvas");
13
                var ctx = canvas.getContext("2d");
14
            });
15
        </script>
16
    </head>
17
18
    <body>
19
        <canvas id="myCanvas" width="500" height="500">
20
            <!-- Insert fallback content here -->
21
        </canvas>
22
    </body>
23
</html>

لا يوجد لدينا أكثر من صفحة HTML أساسية تحتوي على عنصر لوحة رسم وبعض JavaScript يتم تشغيله بعد تحميل DOM. لا شيء مجنون. 


الترجمات في العمل 

ترجمة تحولات نظام الإحداثيات بشكل أساسي. 

واحدة من أبسط التحولات في قماش هي ترجمة . يتيح لك هذا تحريك نقطة الأصل لسياق العرض ثنائي الأبعاد ؛ موضع (0 ، 0) على اللوحة. دعني أريكم ما يعنيه هذا. 

أولا ، ضع مربع في قماش في الموضع (0 ، 0): 

1
ctx.fillRect(0, 0, 100, 100);

سوف يرسم نفسه على الحافة العلوية اليسرى من اللوحة. لا يزال - لا شيء خارج عن المألوف هنا. 

A simple squareA simple squareA simple square

الآن ، حاول ترجمة سياق العرض ثنائي الأبعاد ورسم مربع آخر في نفس الموضع: 

1
ctx.save();
2
ctx.translate(100, 100);
3
ctx.fillStyle = "rgb(0, 0, 255)";
4
ctx.fillRect(0, 0, 100, 100);
5
ctx.restore();

ماذا تعتقد سوف يحصل؟ هل لديك نجمة ذهبية إذا كنت تفكر في أن يتم رسم مربع جديد في الموقف (100 ، 100). لا وقت للعب لأولئك الذين خمنوا خطأ. آسف! 

Translating a squareTranslating a squareTranslating a square

إذن ماذا حدث هنا إذن؟ بقدر ما يتعلق الأمر برمز الرسم المربع الثاني ، قمت برسمه في نفس مكان المربع الأول.  السبب في ذلك هو أنك قمت بتحويل نظام الإحداثيات بالكامل من اللوحة بحيث يكون موضعها (0 ، 0) الآن في المكان (100 ، 100).

How translation worksHow translation worksHow translation works

هل يجعل الأمر أكثر منطقية الآن؟ أنا امل ذلك. يمكن أن يستغرق الأمر بعض الوقت للحصول على رأسك ، ولكنه مفهوم بسيط بمجرد فهمه. 

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

دعونا نلقي نظرة على التحول القادم في القائمة. 


تحجيم مرئياتك 

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

قم بإزالة التعليمة البرمجية التي عملت عليها مع مثال الترجمة ، وقم بإضافة التعليمة البرمجية التالية: 

1
ctx.fillRect(100, 100, 100, 100);

سيؤدي ذلك إلى رسم مربع قياسي في الموضع (100 ، 100) ، مع عرض وارتفاع 100 بكسل. إذن كيف نقيس هذا؟ 

A simple squareA simple squareA simple square

الخصائص في الحجم هي مضاعفات للأبعاد x و y. 

على نطاق و يستخدم التحول بطريقة مشابهة إلى ترجمة ، لأنه دعا قبل رسم الكائنات التي تريد أن يتم تطبيقها على.  من المهم الإشارة إلى أن الخصائص في الحجم هي مضاعفاتللأبعاد x و y . هذا يعني أن مقياس (1 ، 1) سيضاعف حجم سياق العرض 2d بواحد ، تاركًا له نفس الحجم الذي كان عليه من قبل.  و على نطاق و سيكون من (5، 5) مضاعفة حجم سياق تقديم 2D خمسة، مما يجعل من خمس مرات أكبر مما كانت عليه في السابق. بسيط. 

في حالتك تريد مضاعفة حجم المربع ، لذلك قمت بتطبيق مقياس (2 ، 2): 

1
ctx.save();
2
ctx.scale(2, 2);
3
ctx.fillRect(100, 100, 100, 100);
4
ctx.restore();

ما ينتج عنه مربع حجمه ضعف الحجم: 

Scaling a squareScaling a squareScaling a square

ومع ذلك، لاحظ كيف يجري الآن رسم مربع في وضع مختلف عما كان يجري رسمها قبل تطبيق على نطاق و . والسبب في ذلك هو أن المقياس يضاعف حجم كل شيء في سياق العرض ثنائي الأبعاد ، بما في ذلك الإحداثيات.  في حالتك ، يصبح الموضع (100 ، 100) الآن (200 ، 200) ؛ الإحداثيات هي ضعف الحجم الذي يمكن أن تكون بدون مقياس. 

للتغلب على هذا ، يمكننا تنفيذ ترجمة تنقل أصل سياق العرض ثنائي الأبعاد إلى الموضع الذي تريد رسم المربع. إذا قمت بعد ذلك بتطبيق المقياس ورسم المربع في الموضع (0 ، 0) ، فلن يتم نقل موضعه: 

1
ctx.save();
2
ctx.translate(100, 100);
3
ctx.scale(2, 2);
4
ctx.fillRect(0, 0, 100, 100);
5
ctx.restore();

ما ينتج عنه مربع أكبر مرتين من الحجم الأصلي ، ولكن يتم رسمه في نفس موضع النص الأصلي:

Scaling and translating squareScaling and translating squareScaling and translating square

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


عناصر دوارة 

حتى الآن ، كانت كل التحولات التي تعاملت معها غير موحية. لحسن الحظ ، فإن التحولالتدوير هنا لحفظ اليوم ، وأنه من السهل المفضل لدي من باقة. 

أنا متأكد من أن التدوير لا يحتاج إلى مقدمة ، لذا دعنا نقفز إلى اليمين وندير مربعًا بمقدار 45 درجة (تذكر أن الدرجات يجب أن تكون بالراديان): 

1
ctx.save();
2
ctx.rotate(Math.PI/4); // Rotate 45 degrees (in radians)

3
ctx.fillRect(100, 100, 100, 100);
4
ctx.restore();

التي مواقف مربع في (100 ، 100) وتدور .. woah ، تعلق! هذا لا يبدو صحيحا: 

Rotating a squareRotating a squareRotating a square

انظر ماذا حدث؟ يبدو أن الساحة تحاول الهروب من نافذة المتصفح ، بدلاً من الدوران على الفور في الموضع (100 ، 100).  هذا لأن التدوير ، مثل كل التحولات ، يؤثر على سياق العرض ثنائي الأبعاد بالكامل ، وليس الكائنات بشكل فردي. 

فيما يلي توضيح لما يحدث لنظام الإحداثي عندما تقوم بتدوير 45 درجة : 

How rotation worksHow rotation worksHow rotation works

لاحظ كيف استدار نظام الإحداثيات بأكمله 45 درجة من نقطة الأصل (0 ، 0)؟ هذا هو السبب في أن تبدو الساحة وكأنها كانت تفلت من نافذة المتصفح ، وذلك ببساطة لأن الموقف (100 ، 100) قد تم تدويره على شكل ضربة صفعة على حافة المتصفح. 

الطريقة البسيطة للتغلب على هذه المشكلة هي الجمع بين التدوير مع الترجمة ، مثل: 

1
ctx.save();
2
ctx.translate(150, 150); // Translate to centre of square

3
ctx.rotate(Math.PI/4); // Rotate 45 degrees

4
ctx.fillRect(-50, -50, 100, 100); // Centre at the rotation point

5
ctx.restore();

يؤدي تنفيذ الترجمة إلى نقل نقطة الأصل لسياق العرض ثنائي الأبعاد (0 ، 0) إلى النقطة التي يجب أن تكون النقطة المركزية للمربع (150 ، 150). وهذا يعني أن أي تناوب سيعتمد الآن على الموقف (150 ، 150).  إذا كنت ثم رسم مربع مع السلبية س و ص الموقف، أي ما يعادل نصف عرض مربع والارتفاع، فسوف ينتهي رسم مربع يشبه تم استدارة حول نقطة مركزية وهي: 

Rotating and translating a squareRotating and translating a squareRotating and translating a square

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

دعونا ننتقل إلى شيء أكثر إثارة للإعجاب بصريا قليلا. 


مضيفا الظلال 

إضافة الظلال إلى الكائنات بسيطة بشكل مبهج. 

يأتي قماش مع بعض الخصائص للتلاعب في مظهر الكائنات التي يتم رسمها عليه ، ومجموعة واحدة من هذه الخصائص تسمح لك بإضافة الظلال. 

إضافة الظلال إلى الكائنات بسيطة بشكل مبهج. فهو يتطلب ببساطة shadowColorالممتلكات التي سيتم تحديدها في سياق تقديم 2D إلى لون غير شفافة الأسود، وإما منshadowBlur ، shadowOffsetX ، أو shadowOffsetY خصائص لتعيين قيمة أخرى من 0. 

جرب الشفرة التالية: 

1
ctx.save();
2
ctx.shadowBlur = 15;
3
ctx.shadowColor = "rgb(0, 0, 0)";
4
ctx.fillRect(100, 100, 100, 100);
5
ctx.restore();

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

Adding a blurred shadowAdding a blurred shadowAdding a blurred shadow

الاشياء القياسية جدا حتى الآن. 

إذا قمت بتعيين shadowBlur على 0 ، قم بتغيير shadowColor إلى رمادي فاتح ، وإعطاء ظلًا إيجابيًا shadowOffsetX و shadowOffsetY : 

1
ctx.save();
2
ctx.shadowBlur = 0;
3
ctx.shadowOffsetX = 6;
4
ctx.shadowOffsetY = 6;
5
ctx.shadowColor = "rgba(125, 125, 125, 0.5)"; // Transparent grey

6
ctx.fillRect(300, 100, 100, 100);
7
ctx.restore();

سوف ينتهي بك الأمر بظلال صلبة تظهر قليلاً إلى اليمين وأسفل الكائن الذي تم رسمه: 

Adding a solid shadowAdding a solid shadowAdding a solid shadow

وبقدر تهدئة الظلال ، فإنها يمكن أن تكون خنزيرًا من الموارد. 

من المهم أن نتذكر أن الظلال تؤثر على كل شيء التي يتم رسمها بعد تعريفها، لذلك فمن المفيد استخدام حفظ و استعادة طرق لانقاذ لكم من الاضطرار إلى إعادة تعيين خصائص الظل مرة واحدة كنت قد استخدمت لهم. 

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


خلق التدرجات 

يمكنك إنشاء نوعين من التدرجات في القماش - الخطي والشعاعي. 

الميزات الأخيرة التي أريد أن أغطيها معك في هذا البرنامج التعليمي هي التدرجات. هناك نوعان من التدرجات اللونية في القماش ، أولهما تدرجات خطية (مستقيمة).  يمكنك إنشاء تدرج خطي باستخدام طريقة createLinearGradient (ما يكفي بشكل مدهش) ، والتي تبدو مثل هذا في رمز زائف: 

1
ctx.createLinearGradient(startX, startY, endX, endY);

أول مجموعة من الوسيطتين هي x و y في بداية التدرج ، والمجموعة الثانية من الوسيطات هي x و y في نهاية التدرج. ومن المهم أيضا أن نشير إلى أن التدرج في قماش هو في الواقع نوع من قيمة اللون، لذلك يمكنك تطبيقها على نمط ملء و strokeStyle خصائص. 

في ما يلي مثال على كيفية إنشاء تدرج خطي يتم تشغيله من أعلى اللوحة ، على طول الطريق إلى الأسفل: 

1
var gradient = ctx.createLinearGradient(0, 0, 0, canvas.height);
2
gradient.addColorStop(0, "rgb(255, 255, 255)");
3
gradient.addColorStop(1, "rgb(0, 0, 0)");
4
5
ctx.save();
6
ctx.fillStyle = gradient;
7
ctx.fillRect(0, 0, canvas.width, canvas.height);
8
ctx.restore();

لاحظ كيف تقوم بتعيين التدرج إلى متغير ، ثم استخدم هذا المتغير لاستدعاء طريقةaddColorStop . تسمح لك هذه الطريقة بتعيين اللون عند نقاط معينة على طول التدرج.  على سبيل المثال ، يمثل الموضع 0 بداية التدرج (موضع x و y الأول) ، و 1 يمثل نهاية التدرج (موضع x و y الثاني ).  يمكنك أيضًا استخدام النقاط العشرية بين 0 و 1 لتعيين لون عند نقطة مختلفة على طول التدرج ، مثل 0.5 سيكون نصف الطريق. 

من خلال تطبيق متغير التدرج على خاصية fillStyle ، ينتهي بك الأمر بتدرجلطيف ينتقل من اللون الأبيض (في الموضع 0 أعلى اللوحة) ، إلى الأسود (في الموضع 1 في أسفل اللوحة): 

Creating a linear gradientCreating a linear gradientCreating a linear gradient

ولكنك لا تحتاج دائمًا إلى استخدام التدرجات الخطية ؛ يمكنك أيضا إنشاء التدرجات شعاعي! 

يتم إنشاء التدرجات النصفية باستخدام طريقة createRadialGradient ، والتي تبدو مثل هذا في رمز زائف: 

1
ctx.createRadialGradient(startX, startY, startRadius, endX, endY, endRadius);

المجموعة الأولى من ثلاث حجج هي موضع x و y بالإضافة إلى نصف قطر الدائرة عند بداية التدرج ، مع الوسيطات الثلاثة الأخيرة التي تمثل x و y بالإضافة إلى نصف قطر الدائرة في نهاية التدرج. 

صوت محير ، أليس كذلك؟ الأمر قليل ، لذا دعنا نقفز وننشئ تدرجًا نصف قطريًا لرؤية ما يحدث: 

1
var gradient = ctx.createRadialGradient(350, 350, 0, 50, 50, 100);
2
gradient.addColorStop(0, "rgb(0, 0, 0)");
3
gradient.addColorStop(1, "rgb(125, 125, 125)");
4
5
ctx.save();
6
ctx.fillStyle = gradient;
7
ctx.fillRect(0, 0, canvas.width, canvas.height);
8
ctx.restore();

لقد قمت بإنشاء تدرج شعاعي يحتوي على نقطة بداية عند (350 ، 350) مع نصف قطر من 0 ، ونقطة نهاية عند (50 ، 50) مع نصف قطر 100. هل يمكنك تخمين كيف سيبدو هذا؟20 نقطة إذا خمنت أنها ستبدو هكذا: 

Creating a radial gradientCreating a radial gradientCreating a radial gradient

إذا كنت مثلي ، فهذا ليس ما توقعت رؤيته. لقد استخدمت التدرجات شعاعي من قبل في تطبيقات مثل أدوبي فوتوشوب ، وأنها تبدو شيئا من هذا القبيل!  فلماذا تبدو هكذا بعد ذلك؟ حسناً ، هذا ما يعنيه أن تبدو مثل الغرابة 

تحقق من هذا الرسم البياني الذي يوضح بدقة كيفية عمل التدرج الشعاعي في اللوحة: 

How radial gradients workHow radial gradients workHow radial gradients work

مثيرة للاهتمام ، أليس كذلك؟ يسمح لك أساسا بإنشاء شكل مخروطي ، ولكن ماذا لو كنت تريد إنشاء تدرج شعاعي مناسب مثل الذي في Photoshop؟ لحسن الحظ ، الأمر بسيط. 

يتطلب إنشاء تدرج شعاعي مناسب فقط وضع دائرتي التدرج في نفس موضع x و y بالضبط ، مع التأكد من أن إحدى دوائر التدرج أكبر من الأخرى: 

1
var canvasCentreX = canvas.width/2;
2
var canvasCentreY = canvas.height/2;
3
4
var gradient = ctx.createRadialGradient(canvasCentreX, canvasCentreY, 250, canvasCentreX, canvasCentreY, 0);
5
gradient.addColorStop(0, "rgb(0, 0, 0)");
6
gradient.addColorStop(1, "rgb(125, 125, 125)");
7
8
ctx.save();
9
ctx.fillStyle = gradient;
10
ctx.fillRect(0, 0, canvas.width, canvas.height);
11
ctx.restore();

ينشئ الرمز أعلاه تدرجًا نصف قطري يقع في منتصف اللوحة. تحتوي إحدى الدوائر في التدرج على نصف قطر ، بينما تحتوي الأخرى على دائرة نصف قطرها 250.  تكون النتيجة تدرجًا نصف قطريًا تقليديًا ينتقل من مركز اللوحة الخارجية إلى الخارج ، مثل: 

Creating a radial gradientCreating a radial gradientCreating a radial gradient

هذا يبدو أفضل! لقد دهشت بصدق عندما رأيت كيف تم تنفيذ التدرجات شعاعي في قماش.أراهن أنه تعثر الكثير من الناس عندما يرون هذا الشكل المخروط. حسناً ، على الأقل أنت تعرف كيف تصنع منها السليم الآن. 

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


تغليف 

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

في الإدخال التالي في "Canvas from Scratch" ، سننطلق من الكائنات الرسومية ونلقي نظرة على كيفية التعامل مع الصور ومقاطع الفيديو في اللوحة. هذا هو المكان الذي تبدأ الأمور في الحصول على مثيرة للاهتمام حقا! ترقب! 

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Web Design tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.