البحث في الموقع
المحتوى عن 'التحريك'.
-
إنّ هدف الوحدات عمومًا هو توزيع المهام عن طريق تعريف توابع الواجهة البرمجية (API) والحدّ من رؤية السلوك (أجسام التوابع) والبيانات (العناصر والمتغيّرات). معظم المنصّات البرمجيّة تتضمّن دعمًا داخليًّا للوحدات، حتّى أصبح استخدامها أمرًا مسلّمًا به. ولكنّ JavaScript المستخدمة من طرف العميل لا تستخدم الوحدات حاليًّا، وتؤدي إلى احتدام النقاشات المليئة بين مؤيّد ومعارض للحلّ المشهور (الإضافات add-ons) مثل CommonJS و تعريف الوحدة غير المتزامن (AMD). أبقِ في ذهنك عندما تقوم بمقارنة الحلول المطروحة، أنّ نظام الوحدات في Angular لا يقوم بتحميل الوحدة. فهو لا يقوم بتحميل الشيفرة المصدرية من ملفّاتٍ أو من الإنترنت. فالحلّ الذي تقدّمه Angular هو نظام الوحدات المدمج فيها، والذي يرتبط ارتباطًا وثيقًا بنظام حقن التابعية المدمج أيضًا في Angular. معًا، يكوّن هذان النّظامان جزءًا كبيرًا من البنية التّحتيّة لـAngular. ولكن هل نحن بحاجةٍ إليها حقًّا؟ صحيحٌ أنّ بإمكان أيّ مطوّر تعلّمها، ولكن لمَ نحتاجها؟ تُشكّل الوحدات وحقن التّابعيّة كلّ بنية Angular، ولكن كما رأينا فإنّ Angular تسمح لنا بالبدء دون استخدام نظام الوحدات. حتّى الآن، كان بإمكاننا إنجاز الكثير ببساطة عن طريق تعريف المتحكمات كتوابع معرّفة في المجال العامّ. ولكنّ ذلك لم يكن ليعمل لولا القليل من الإعدادات، وهذه الإعدادات سمحت للتّوجيه ng-controller بالبحث عن توابع التّحكّم في المجال العام وأيضًا في نظام الوحدات. هذه الطريقة السهلة في استخدام المجال العام مسموحةٌ في Angular، ولكن فقط إلى هذه النقطة. لماذا نستخدم وحدات Angular؟ لابدّ لك من فهم وإتقان نظام الوحدات في Angular لتتمكّن من تجاوز الأساسيّات فيها والغوص في المفاهيم العميقة. لا تسعى هذه السلسلة لإقناعك بالأهمّيّة الكامنة في الوحدات وفي حقن التّابعيّة في Angular، فعندما تواجهك مشكلة إدارة التّعقيد في تطبيقك فالأمر يعود إلى تجربتك الشّخصيّة في أفضل الممارسات البرمجيّة، والحلّ الأبسط سيكون الأفضل. سيغطّي هذا الكتاب الوحدات في Angular ومبدأ حقن التّابعيّة بما يشمل الجزء الأهمّ منها في Angular. لنبدأ بنظرةٍ عامّة إلى المزايا الهامّة التي تدفعنا لاستخدام نظام الوحدات: مكوّنات مخصّصة - لتعريف المتحكّمات الخاص بك، التّوجيهات، المرشّحات، والمؤثّرات الخاصّة، لا بدّ من استخدام نظام الوحدات.(يمكننا استثناء المتحكّمات كما أشرنا سابقًا.) حقن التّابعيّة - الخدمات ليست إلّا كائنات وتوابع JavaScript عاديّة، إلّا أنّ الخدمات التي يتمّ إنشاؤها في نظام الوحدات يمكن أن تُحقن بسهولة مع التّبعيّات الخاصّة بها، وذلك إن كانت تتيح حقن التّابعيّة فيها. الوحدات الخارجيّة - هناك نظامٌ بيئيّ مثيرٌ للاهتمام، مجّانيٌّ ومفتوح المصدر من الإضافات لـAngular، وقد قام بكتابة بعض هذه الإضافات فريق تطوير قلب Angular وكذلك المطوّرون كطرفٍ ثالث. لاستخدام أيٍّ من هذه المكاتب في تطبيقك لا بُدّ من استخدام نظام الوحدات. إعدادات وقت-التّحميل - يسمح نظام الوحدات في Angular بالوصول إلى تعلّقات دورة الحياة (lifecycle hooks) المتعلّقة بالإعدادات الدّاخليّة لـAngular، وكذلك المتعلّقة بإعدادات الوحدات المضافة، وسنتطرّق لها في نهاية الفصل الأخير، حيث سنقوم بإعداد رأس HTML مخصص. الاختبار - إنّ البنية التّحتيّة الخاصّة بالاختبار في Angular تبيّن فاعليّة نظام حقن التّابعيّة والّذي يعتمد بدوره على نظام الوحدات. سيبيّن فصلٌ لاحقٌ، فصل الخدمات، كيف نقوم بتعريف مقدم لمكوّنات JavaScript المخصّصة. سنرى في هذا الفصل كيف نعرّف متحكّمًا، وسنقوم أيضًا بتحميل وحدةٍ خارجيّةٍ، وأثناء تنفيذ ذلك سنتعلّم أساسيّات نظام الوحدات في Angular. إنشاء وحدة التطبيق يمكن تهيئة تطبيق Angular باستخدام وحدةٍ جذريّة واحدة فقط. سنقوم بتسمية الوحدة في أمثلة هذا الفصل بالاسم app ويمكنك اختيار أيّ اسمٍ آخر إن أردت، إلّا أنّ هذا الاسم شائع الاستخدام في مرجع Angular. angular.module('app', []); أرجو أن تركّز على الوسيط الثاني للتابع module في مثالنا السابق، ورغم أنّه يبدو فارغًا، وله مظهر مصفوفة بريئة خالية ([]) إلّا أنّ وجود هذا الوسيط الثاني شديد الأهمّيّة، فبدونه سيتغيّر سلوك التّابع angular.module كليا، وسأشرح لك سلوك هذا التابع كما يلي: عند استدعاء التابع angular.module مع وجود الوسيط الثاني، سيعمل التّابع في نمط الإنشاء (create)، وسيقوم بإنشاء وحدةٍ ويسمّيها app إن لم يكن هناك وحدة بنفس الاسم سابقًا، أمّا عند استدعائه دون الوسيط الثّاني فسيعمل في نمط البحث (lookup)، فإن عثر على وحدةٍ بالاسم المعطى سيقوم بإعادتها، أمّا إن لم يجدها فسيقوم برمي خطأٍ يطلب تمرير الوسيط الثاني. قمنا في المثال السابق بالاستخدام الصحيح للتابع، ولكن كن حذرًا دومًا من الفرق بين الطريقتين في استدعاء هذا التّابع, أمّا بالنّسبة لهذه المصفوفة التي تمرر كوسيط، فهي تُستخدم لجلب الوحدات الخارجية التي سنناقشها في هذا الفصل، باستخدام وحدة animation في أمثلتنا. تحميل وحدة التطبيق في مستند HTML الذي يستضيف التّطبيق، يمكننا أن نأمر Angular بتحميل وحدة هذا التّطبيق عن طريق تمرير اسمه إلى التّوجيه ng-app. <body ng-app="app"> <!-- الأمثلة توضع هنا --> </body> ستكون جميع المكوّنات التي نضيفها إلى وحدة التّطبيق متاحةً للاستخدام. لنرى الآن كيف نقوم بتعريف متحكّم داخل وحدةً بدلًا من تعريفه في المجال العام. تعريف متحكم تتضمّن الواجهة البرمجية للعنصر module توابع لتعريف مكوّنات Angular المخصّصة. والمكوّن الوحيد الذي تعرفنا عليه سابقًا هو المتحكّم، لذا لنقم باستخدام التابع controller لإنشاء متحكّم. سنحتاج أوّلًا إلى جلب مرجعٍ لوحدة التّطبيق، وكما ذكرنا سابقًا، يجب أن نقوم باستدعاء التابع angular.module بدون تمرير الوسيط الثاني، وذلك كي يعمل في نمط البحث lookup. var app = angular.module('app'); app.controller('MessageController', function($scope) { $scope.message = "This is a model."; }); والآن، في مكان ما ضمن العنصر الذي قمنا فيه باستدعاء الوحدة عن طريق "ng-app="app، يمكننا استخدام التّوجيه ng-controller لتحميل المتحكّم. <p ng-controller="MessageController"> {{message}} </p> الناتج This is a model. وكما يمكنك أن ترى، فتعريف المتحكّم داخل الوحدة يحتاج إلى عمل أكثر بقليل من تعريفه في المجال العام، ولكنّه ليس بهذه الصعوبة أبدًا. سلسلة التعريفات لنفترض بأننا نريد تعريف متحكّمين للقالب التالي. <p ng-controller="MessageController"> {{message}} </p> <p ng-controller="AnotherMessageController"> {{message}} </p> إنّ توابع التعريف ضمن العنصر Module قابلةٌ للسَّلسَلة، حيث يمكننا إنشاء متحكّمين باستخدام عبارةٍ واحدة. angular.module('app') .controller('MessageController', function($scope) { $scope.message = "This is a model."; }) .controller('AnotherMessageController', function($scope) { $scope.message = "This is another model."; }); الناتج This is a model. This is another model. لاحظ أن الاستدعاء الأول للتابع controller لم تتبعه فاصلةٌ منقوطة. إن لم تعجبك هذه الطريقة في سَلسَلة الاستدعاءات، يمكنك استدعاء التابع module كلّما أردت الحصول على مرجعٍ للوحدة، أو يمكنك تخزين هذا المرجع في متغيّر، كما يبيّن المثال التالي. عند استخدامك لمتغيّر، سيكون من الجيّد أن تضعه ضمن تابعٍ يُستدعى آنيًّا (IIFE) أو أيّ مجالٍ مغلقٍ آخر، لمنع ذلك المتغيّر من أن يُنشأ في المجال العام. var app = angular.module('app'); app.controller('MessageController', function($scope) { $scope.message = "This is a model."; }); app.controller('AnotherMessageController', function($scope) { $scope.message = "This is another model."; }); يمكنك اختيار أيٍّ من الطريقتين، ولكنّ طريقة السَّلسلة هي الأكثر شيوعًا. تحميل الوحدات يُعدّ التحريك (animations) ميزةً جديدةً في Angular تمّت إضافتها إلى حزمة منفصلة اسمها ngAnimate. الخطوة الأولى لاستخدام التحريك هي تضمين ملف JavaScript المحتوي على الوحدة. الشيفرة المصدريّة للوحدة جزءٌ من قلب Angular، ولكنّها موجودةٌ في ملفٍّ منفصل، كما نرى أدناه. <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.4.2/angular.js"></script> <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.4.2/angular-animate.js"></script> حان الوقت لنستخدم الوسيط الثّاني للتابع module كما يجب، فبدلًا من تمرير مصفوفةٍ خاليةٍ فيه سنقوم الآن بالتصريح عن الوحدات المتعلّقة بوحدتنا. angular.module('app', ['ngAnimate']); لقد قمنا الآن بتحميل ngAnimate إلى داخل وحدة التّطبيق، والآن ستقوم التّوجيهات ng-show و ng-hide و ng-class و العديد من التّوجيهات الأخرى بالتّحقّق من التحريك الخاصّ بـCSS وJavaScript أيضًا الذي يمكن تطبيقه على أحداث المستند مثل add و enter و leave و move و remove، وتطبيق هذا التّحريك شفّاف فهو لا يتطلّب أيّ تغيير على شيفرة القالب المكتوبة، وإن لم نكن قد طبّقنا هذا التّحريك سواء على شكل CSS أو كـJavaScript عن طريق تسجيل الحركة عبر module.animation، فإنّ الشيفرة ستسلك السّلوك الافتراضيّ لها بشكل طبيعيّ. <input type="checkbox" ng-model="showMessage"> Check the box to show the message <h2 ng-show="showMessage"> The secret message. </h2> بالنّقر على الـcheckbox ستقوم ng-show بعملها كالمعتاد، وسيتمّ التّبديل بين إظهار وإخفاء العنصر بشكلٍ فوريّ دون تدرّج أو تأثير اختفاءٍ بسيط، إلى أن نكتب شيفرة التّحريك في CSS أو JavaScript. في المثال التّالي سنستخدم CSS، وهي عمومًا الخيار الأفضل للتحريك بسبب الأسلوب التصريحي في كتابتها. يمكنك على أيّ حالٍ استخدام التابع animate في jQuery ليقوم بالمهمّة إن وجدت ذلك أسهل، أما Angular فتقوم بذلك عن طريق الوحدة module.animation. يتطلّب التّحكّم بتأثير الاختفاء التّدريجيّ استخدام أربع فئات CSS تقوم بالتّعلّق (hook)، وذلك حسب توثيق الواجهة البرمجية الخاصّ بالتّوجيه ng-show. هذه الفئات الأربعة هي ng-hide-add و ng-hide-add-active و ng-hide-remove و ng-hide-remove-active. .ng-hide-add, .ng-hide-remove { transition: all linear 1s; display: block !important; } .ng-hide-add.ng-hide-add-active, .ng-hide-remove { opacity: 0; } .ng-hide-add, .ng-hide-remove.ng-hide-remove-active { opacity: 1; } قد تحتاج إلى إضافة خصائص محدّدة من قبل المصنّع لبعض المتصفّحات حسب زوّار موقعك، مثل webkit-transition- الخاص بمتصفّح سفاري 6 لأنظمة iOS. (يُعدّ موقع caniuse.com مرجعًا جيّدًا لتوافق المتصفّحات مع HTML5 و CSS3.) أرجو أن تنتبه أيضًا إلى أنّ هذا التّحريك سيتمّ تطبيقه في كلّ الأماكن التي ستستخدم فيها ng-show و ng-hide في تطبيقك. يمكنك إضافة فئة CSS مخصّصة لتزيد قدرتك على التّحكّم، وذلك للعنصر ولمحدّد CSS الذي تتعامل معه، مثلًا يمكنك كتابة my-class.ng-hide-add. و my-class.ng-hide-remove. وهكذا. خاتمة أتمنى أن تكون سهولة إضافة ngAnimate قد أقنعتك بأهمّية فهم نظام الوحدات في Angular. ومن المفرح أن تعلم بأنّ ngAnimate ليست إلّا البداية ضمن الكثير من الوحدات المُضافة إلى Angular. يمكنك أن تختار وحداتٍ أخرى متاحةّ بشكلٍ مجّانيّ من هذا النّظام البيئيّ سريع النموّ الذي يعتمد على إبداعات المطوّرين من مواقع مثل GitHub، وذلك إضافةً إلى الوحدات التي تتيحها Angular أصلًا مثل ngResource وngRoute. أحد أكثر المشاريع شُهرةً هو AngularUI، الذي يحوي وحداتٍ عظيمة الأهمّيّة مثل UI Router وUI Bootstrap، ومعظم هذه الوحدات يمكن تحميله بسهولة في مشروعك باستخدام Bower، مدير حزم الويب، ولربّما ستبدأ بنشر وحدات Angular الخاصّة بك مفتوحة المصدر على GitHub وBower عندما تملك زمام Angular، وهذا ما أتمنّاه. تقدّم الوحدة ngAnimate إثباتًا واضحًا للقوّة المتاحة في الوحدات المضافة، ولكنّها لا تتضمّن استخدام البنية التّحتيّة لحقن التّابعيّة في Angular بسبب أسلوبها الجزئيّ في التكامل. سنغطّي حقن التّابعيّة في الفصل القادم، وذلك لأنّه يعمل يدًا بيد مع الوحدات. ترجمة وبتصرّف للفصل السادس من كتاب: Angular Basics لصاحبه: Chris Smith.
-
حظيت مواصفات لغة التكامل المتزامن للوسائط المتعدّدة (Synchronized Multimedia Integration Language، أو SMIL اختصارا)، وهي معيار مختص بترميز رسوميات SVG ، بشهرة كبيرة لتوفيرها إمكانيات عديدة للتعامل مع رسوميات SVG المتحركة. للأسف دعم SMIL يتناقص بمرور الزمن على محركات WebKit القياسية ولم تكن مدعومة أساسًا على متصفحات Microsoft (وغالبًا لن تدعمها أبدًا في المستقبل). لكن لا تقلق، يمكن علاج ذلك. هنا سنكتشف بدائل للميزات الخاصة في SMIL، ونبيِّن طرقًا بديلة لأداء تلك المهام وجعلها تحظى بدعم لفترة أطول. ميزة SMIL: التحريك وفقًا لمسار أحد أهم مميزات SMIL المتعلقة بالحركة الواقعية هي القدرة على التحريك وفقًا لمسار محدد. القليل فقط من الأشياء تتحرك في خط مستقيم على أرض الواقع، لذلك القدرة على التحكم بالرسوميات على مسار محدد مسبقًا يساعد على محاكاة الحركة الواقعية. باستعمال الخاصية animateMotion، كان يمكنك تمرير مسار SVG وتحديد بيانات الحركة والاتجاه ثم تحديد العنصر المراد تحريكه بإسناد معرّفه للرابط xlink:href="#thingtoanimate" كما في المثال التالي: <animateMotion xlink:href="#lil-guy" dur="3s" repeatCount="indefinite" fill="freeze" path="M 25,50 C 37.5,25 37.5,25 50,0 75,50 75,50 100,100 50,100 50,100 0,100 12.5,75 12.5,75 25,50 Z" /> البديل باستخدام CSS لحسن الحظ، القدرة على التحريك وفقًا لمسار مدمجة في لغة CSS. رغم ذلك مجال الدعم المتوفر لها لا يزال محدودًا (متصفحات كروم، وأوبرا، وفيرفكس على سطح المكتب، وبعض متصفح أندرويد). بالنسبة لمتصفح سفاري، فالأمر تطلب الإبلاغ عن الأعطال لطلب ميزة التحريك وفقًا لمسار كخاصية CSS. يتطلب استخدام التحريك وفقًا لمسار على CSS تحديد مسار الحركة باستعمال نقاط مرور كالتالي: .move-me { offset-path: path('M3.9,74.8c0,0,0-106.4,75.5-42.6S271.8,184,252.9,106.9s-47.4-130.9-58.2-92s59.8,111.2-32.9,126.1 S5.9,138.6,3.9,74.8z'); } نتيجة المثال أعلاه يمكن الحصول على بيانات المسار ونقاط المرور من نتائج مخرجات تصميم SVG على Illustrator ثم تحسينها عن طريق أداةSVGOMG. سنتأكد في هذا المثال أن العنصر سيتبع المسار من نقطة البداية وصولًا لنهايته ويمكنك ملاحظة أنه مسار مغلق، أي أن العنصر سينتهي به المطاف عائدًا لنقطة البداية مكررًا مساره. حدّدت هنا قيم الإطارات المفتاحية وخُصّصت القيمة 100% فقط لأن القيمة الافتراضية محددة عند 0: @keyframes motionpathguy { 100% { motion-offset: 100%; } } ثم نحدد خيارات تحريك العنصر: .move-me { animation: motionpathguy 10s linear infinite both; } بديل: أسلوب GreenSock للتحريك إذا كنت تسعى لخيارات الدعم الأوسع والأكثر مرونة في التطبيق، فعليك باستخدام مكتبة GreenSock المكتوبة بجافاسكريبت. يوفّر ملحق Bezier-Plugin دعمًا يمتد حتى الإصدار السابع من متصفح مايكروسوفت بدون استعمال عناصر SVG، وحتى الإصدار التاسع في حال أردت استعمال عناصر SVG (وهو أشمل دعم متوفّر لتحريكات SVG). يجدر بنا ذكر أنك ستحتاج إلى إدراج مصفوفة لإحداثيات المسار: bezier: { type: "soft", values:[{x:10, y:30}, {x:-30, y:20}, {x:-40, y:10}, {x:30, y:20}, {x:10, y:30}], autoRotate: true } يمكنك استعمال خيار التدوير التلقائي على غرار SMIL. وإذا كنت تفتقد قدرات SMIL على التحكم بالانعكاس التلقائي أو تحديد موضع الدوران التلقائي وزاويته، تتيح لك المكتبة التحكم بالدوران حتى 90 درجة من الميلان أو أي درجة من التحكم قد تحتاجها. autorotate: [ قيمة الموضع الأول "x", قيمة الموضع الثاني "y", "rotationY" أو "rotation" قيمة الحركة الدائرية، عادةً , قيمة رقمية تمثل زاوية بداية الدوران، مثلًا "10", false أو true قيمة منطقية (radians/degree) لاختيار وحدة قياس الزاوية ] يمكنك التحكم بدوران العنصر على SMIL أثناء حركته بالتلاعب بالمسار أو المسار، أما في مكتبة GreenSock فيمكنك أداء ذلك بسهولة بإيقاف التدوير التلقائي وبرمجة الدوران بسلسلة تعليمات، أيضًا يمكنك التلاعب بخصائص عناصر SVG كما كنت تفعل على SMIL برغم أنه أقل أناقة وأصعب في التتبع أثناء تحضيره. TweenMax.set("#foo" { rotation: 90 // أو أي قيمة مناسبة }); يمكنك الاختيار بين القيم thru، أو soft، أو quadratic، أو cubic لتحديد نوع المسار. تعليمات الشرح لكل منها موجودة على مكتبة GreenSock البرمجية. نقطة قوة thru هي القدرة على التأثير على مدى انحناء عنصر. إذا عدَدْنا أن نقاط المرور هي إحداثيات للتنقل منها وإليها، مدى الانحناء سيحدد اتجاه المسار عند الانتقال بين تلك النقاط. مدى الانحناء 0 سيكون اتجاهًا مباشرًا، 1 سيكون مائلًا قليلًا، 2 سينتج مسارًا منحنيًا، 3 وأكثر سيجعل المسار ينغلق على نفسه. إليك مثال حي. مؤخرًا، أثبت GreenSock قدرته على تمرير بيانات المسار مثل CSS و SMIL. جاء ذلك في صيغة تمديد (Extension) لملحق MorphSVG الخاص بها. يُضاف الملحق ويُستعمَل كالتالي: TweenMax.to("#lil-guy", 3, { bezier: { MorphSVGPlugin.pathDataToBezier("#path", {align: "#lil-guy" }), type: "cubic" }, ease: Linear.easeNone, repeat: -1 }); <path id="path" d="M 25,50 C 37.5,25 37.5,25 50,0 75,50 75,50 100,100 50,100 50,100 0,100 12.5,75 12.5,75 25,50 Z" fill="none" /> إليك النتيجة حية. سيعيّن الوضع الافتراضي أعلى مجموعة العناصر المُراد تحريكها، أي العنصر المسمى lil-guy#، إلى المسار، أي أنّ الركن العلوي الأيسر هو ما سيمرّ على المسار. بصريًا ستبدو الحركة غير متناسقة لذا قمنا بجعل العنصر lil-guy# يستخدم نقطة مركزية باستعمال تعليمات TweenLite.set: TweenLite.set("#lil-guy", {xPercent:-50, yPercent:-50}); يمكنك موازنة تلك المسارات بتمرير كائن إلى الوسيط الثاني في التابع TweenLite.set، وتعيين قيم offsetX و offsetY في التابع pathDataToBezier. كن حذرًا هنا فقد تحتاج لتوسيع صندوق العرض (viewBox) في SVG حتى لاتتداخل العناصر قيد التحريك ببعضها، أو تفقد بعض أجزائها خارج الصندوق. // أزح إحداثيات المسار بمقدار 125 بكسلًا أفقيًا و 50 بكسلًا رأسيًا TweenMax.to("#lil-guy", 3, { bezier: { values: MorphSVGPlugin.pathDataToBezier("#path", { offsetX: 125, offsetY: 50, align: "#lil-guy" }), type: "cubic" }, ease: Linear.easeNone, repeat: -1 }); إليك النتيجة حية. يمكنك حتى تعريف مصفوفة إحداثيات لهذا التموضع: // ضاعف إحداثيات المسار بمقدار 1.25 // أزحه بمقدار 120 بكسل على المحور الأفقي // ارفعه بمقدار 30 بكسل على المحور الرأسي TweenMax.to("#lil-guy", 3, { bezier: { values: MorphSVGPlugin.pathDataToBezier("#path", { matrix:[1.5,0,0,1.5,120,-30], align:"lil-guy"}), type: "cubic" }, ease: Linear.easeNone, repeat: -1 }); إليك النتيجة حية. يوجد خيار آخر يتمثّل في تحديد قيمة المحاذاة إلى relative، وهو ما سيمنع العنصر من القفز خارج مساره بتثبيت الموضع لكل الإحداثيات المرتبطة إلى القيم x:0, y:0. في الأمثلة السابقة استعملنا المحاذاة بالتزامن مع مجموعة عناصر lil-guy#. لمعلومات محدثة عن هذه الميزة لملحق Bezier، تفقَّد التوثيق على مكتبة GreenSockالبرمجية. ميزة SMIL: تحوير الشكل سابقًا كان باستطاعتك تمرير بيانات المسار كقيم داخل خصائص الرسوميات بهدف تحوير الشكل. البديل: مكتبة Snap.svg أو SVG Morpheus توفر بعض المكتبات البرمجية مثل Snap.svg و SVG Morpheus القدرة على تحوير الشكل أو المسار. لكن يجب مطابقة عدد نقاط الشكل الأساسي والمحوَّر وإلا تشوَّه الشكل الناتج. بسبب ذلك، عليك مراقبة الشكل الناتج من التحوير باستمرار أثناء التصميم أو نسِّق مع مصممك لتحصل على بيانات تلك النقاط مع تلافي إضافة نقاط غير ضرورية حتى لا تتسبب بإبطاء الرسوميات الناتجة. بديل: ملحق MorphSVG من GreenSock ينبغي التأكيد على بهذا الملحق، إذ يمكنه تحوير الأشكال والمسارات بسلاسة باستعمال مقادير مختلفة من النقاط، كما في هذا المثال. لمَّا كان ملحق MorphSVG يُعدل على بيانات المسار، فستحتاج إلى استعمال خيار convertToPath إذا احتجت لتعديل الشكل: MorphSVGPlugin.convertToPath("ellipse"); // or circle, rect, etc هذا سيسمح لك بإجراء تعديلات معقدة على الأشكال وهي طفرة حقيقية على مستوى التحريك على الويب. يقدّم الملحق ميزات إضافية جديرة بالذكر. الأولى هي ميزة findShapeIndex متعددة الاستخدامات. لنقل إن الشكل الحالي المحَّر لا يعجبك (برغم أن إعادة الضبط التلقائي عادةً ما تفي بالغرض). ستُحمِّل الملحق الخاص (ليس عليك القلق بشأن زيادة حجم مشروعك، فلا داعي للملحق بعد مرحلة التطوير)، ثم تمرر قيمتين: معرَّف الشكل الأول، ومعرّف الشكل الثاني. ستظهر لديك واجهة رسومية يمكنك بها الانتقال بين القيم، وأيضًا ستستعمل التكرار على نحو افتراضي (repeat: -1) لتستمر إعادة الحركة بين الأشكال. findShapeIndex("#hex", "#star"); // findShapeIndex() يمكنك تعليق السطر البرمجي أعلاه لإلغاء تفعيل واجهة إليك النتيجة حية. بمجرد حصولك على تلك القيم الإضافية، يمكنك تحديد قيمة shapeIndex داخل مصفوفة morphSVG: TweenLite.to("#hex", 1, {morphSVG: { shape: "#star", shapeIndex: 1 }}); الميزة الثانية لهذا الملحق هي قدرته على تحليل المسارات، لا يوجد ملحق آخر يمكّنك من ذلك. أخيرًا يمكن إعادة استعمال قيمة المعرّف الخاصة ببداية الحركة بدون الحاجة لتخزينها. من الجدير بالذكر أنه عند الإطلاق الأول لهذا الملحق لم تكن هذه الميزات موجودة، لكن GreenSock ظلّت تدعمه بالميزات بلستمرار وبما أننا لم نعد ملزمين بعدد معين للنقاط يمكننا توسيع آفاقنا لمزيد من التأثيرات. هنا مثال على دخان. ميزة SMIL: أحداث التفاعل مع الصفحة وفَّر SMIL تأثيرات مثل التحويم على العناصر والضغط عليها وعند الرغبة باستعمال أي منها يمكنك تحديد الحدث باستعلام مثل begin="click" أو begin="hover": <animate xlink:href="#rectblue" attributeName="x" from="0" to="300" dur="1s" begin="click" values="20; 50" keyTimes="0; 1" fill="freeze" /> بديل: لغة JavaScript هنالك أحداث مدمجة ضمن اللغة مثل onmouseenter و onmouseleave لتأثيرات الحومان والضغط. يمكنك استعمالها لتفعيل رسوميات JavaScript. البديل: التعاون بين JavaScript و CSS يمكنك استعمال JavaScript لتغيير صنف عنصر ما أو تغيير تنسيقات CSS الخاصة به مباشرة. كمثال سنغير حالة الرسوميات لتتفعل بناءً على حدث ما: .st0 { animation: moveAcross 1s linear both; animation-play-state: paused; } @keyframes moveAcross { to { transform: translateX(100px); } } document.getElementById("rectblue").addEventListener("click", function() { event.target.style.animationPlayState = "running"; }); إما إذا اعتدت على استعمال jQuery فالاستعلام كالتالي: $(".st0").on("click", function() { $(this).css("animation-play-state", "running"); }); إليك النتيجة حية. تنفيذ هذا الاستعلام لن يعيد الرسوميات إلى نقطة البداية مباشرة كما فعل SMIL في المثال السابق. إذا أردت إنجاز ذلك فستحتاج إلى استعمال عدَّة خدع CSS مختصة بذلك. البديل: Greensock إعادة الحركة باستخدام مكتبة GreenSock أكثر بساطة. يمكننا إضافة الرسوميات إلى جدول زمني للتحكم بإيقاف واستئناف الرسوميات بالضغط على العنصر. طريقة التنفيذ هذه شبيهة بما اعتدته من SMIL حيث لا نحتاج للتعامل مع نسخ أو إعادة إدخال أي نقاط شجرية للصفحة أو تغيير خصائص العناصر: // TimelineLite إنشاء نسخة من var tl = new TimelineLite(); // إضافة رسوميات إلى جدول زمني tl.to(foo, 0.5, { left: 100 }); $(".st0").on("click", function() { tl.restart(); }); ميزة SMIL: تشغيل X بعد اكتمال Y يستطيع SMIL إنشاء أحداث بتوقيت أكثر تعقيدًا مثل begin="circ-anim.begin + 1s" (بدء حركة عنصر بعد ثانية من بدء حركة عنصر آخر). وهذا مفيد بالأخص عند إنشاء رسوميات متسلسلة. بديل: CSS على CSS يمكنك إنشاء تسلسل للرسوميات بتحديد تأخير على الرسوميات اللاحقة: .foo { animation: foo-move 2s ease both; } .bar { animation: bar-move 4s 2s ease both; /* تتطابق القيمة 2s مع مدة التكرار في العنصر الأول أعلاه */ } طريقة العمل قد تصبح مسببة للإزعاج إذ عليك تذكر تغيير الفجوة الزمنية الأولى وكذلك التأخير لكل عنصر. بديل آخر: برمجة CSS مسبقة (SASS) إعداد وإدارة تلك الفجوات الزمنية يمكن تسهيله إذا استعملت متغيرات Sass مثلًا: $secs: 2s; .foo { animation: foo-move $secs ease both; } .bar { animation: bar-move 4s $secs ease both; } هكذا ستتأكد أن تحديث قيمة واحدة لن يؤثر على التزامن. لكن إذا أردت تتبع الرسوميات عند اكتمالها، فجافاسكريبتيقدم دعمًا وظيفيًا أصليًّا باستعمال animationEnd: $("#rectblue").on("animationend", function() { $(this).closest("svg").find("#rectblue2").css("animation-play-state", "running"); }); #rectblue2 { animation: moveAcross 2s 1s ease both; animation-play-state: paused; } إليك النتيجة حية (قد تحتاج للنقرعلى زر إعادة التشغيل لرؤية الحركة). لتنفيذ التأخير يمكننا جدولة توقيت ظهور العناصر عبر خاصيات تأخير رسوميات CSS للعناصر أو باستعمال setTimeout: setTimeout(function timeoutHandler() { // أدرج الرسوميات هنا، بغض النظر عن لغة البرمجة المستخدمة }, 1000); // انتظر لثانية واحدة بديل آخر: Greensock هذا هو الخيار المفضل لديّ للحصول على تحكم دقيق بالمسار الزمني الخاص بالرسوميات، إذ يمكنك أداء ذلك بعدة طرق مختلفة. خط زمني بسيط: // TimelineLite أنشئ var tl = new TimelineLite(); // أضف الرسوميات لبداية الخط الزمني tl.to(foo, 0.5, { left: 100 }); // استعمل قيمة الموضع (+=1) لبدء الرسوميات التالية بعد ثانية واحدة من انتهاء الحالية tl.to(foo, 0.5, { left: 200 }, "+=1"); خط زمني بوصف نسبي: // أضف علامة متأخرة 0.5 ثانية لتحديد موضع الإطار التالي tl.add("العلامة") // استخدم العلامة لتحديد ظهور الرسوميات بعد الثانية التالية tl.to(foo, 0.5, { scale: 0 }, "العلامة+=1"); // أو استعمل العلامة لإنشاء واجهة للتفاعل tl.play("العلامة"); من الأفضل استعمال الوصف النسبي حيث تختار نقطة زمنية ما لتقوم بتفعيل العديد من الثأثيرات أو تأخيرها. حتى لو كانت خاضعة لتعديل زمني، وليس عليك القيام بأي إعادة لحسابات CSS. الفائدة من استعمال المسار الزمني هي القدرة على التحكم الدقيق بعدة عناصر من مكان واحد كما يمكنك استعمال خاصيّات مثل تأخير التكرارات. يقدم SMIL أيضًا خاصية repeatDur التي تمكنك من تحديد مدة التكرار المحدد، إذا لم ترغب بالقيمة الافتراضية "repeatDur="01:30 يمكنك التحكم بالسرعة بمساعدة GreenSock وبالتالي تعدي مدة التكرار باستعمال timeScale (n) أو repeat: -1. خلاف ذلك، يمكنك تحديد التكرار بالخاصية "repeatDur="indefinite. جدول بياني للبدائل بعدما انتهينا من استكشاف أفضل مميزات SMIL يجدر بنا الإشارة إلى مزيد من البدائل لخصائص SMIL والتي ربما استعملتها مسبقا. في ما يلي جدول للرجوع إليه للحصول بسرعة على بدائل الوظائف الأكثر سهولة. table { width: 100%; } thead { vertical-align: middle; text-align: center; } td, th { border: 1px solid #dddddd; text-align: right; padding: 8px; text-align: inherit; } tr:nth-child(even) { background-color: #dddddd; } SMIL الشفرة البديلة التقنية البديلة keyTimes @keyframes CSS keySplines cubic-bezier CSS restart restart() GSAP calcMode="discrete" steps() CSS remove kill(); clear(); clearProps: "all" GSAP freeze animation-play-state: paused CSS freeze pause() GSAP fill animation-fill-mode CSS repeatCount="indefinite" animation-iteration-count: infinite; CSS repeatCount="indefinite" repeat: -1 GSAP whenNotActive detect animation-play-state in JS CSS, vanilla JavaScript or jQuery animateMotion path motion-path CSS animateMotion path bezier GSAP animate values (path morphing) MorphSVG GSAP begin="hover" mouseover, mouseenter, mouseout, mouseleave jQuery, vanilla JS begin="circ-anim.begin + 1s" animation-delay: $vars; SASS begin="circ-anim.begin + 1s" timeline, position parameter ex "+=1" GSAP ترجمة - وبتصرف - للمقال SMIL is dead! Long live SMIL! A Guide to Alternatives to SMIL Features لصاحبته Sarah Drasner.
-
في الوقت الذي ستُلقي فيه نظرة على هذا المقال قد تكون معايير SMIL أصبحت شيئًا من الماضي، لكن مهلًا! في هذا المقال ستجد دليلًا لاستبدال بعض الميزات وتطويرها. لمحة عامة يمكن تحريك الرسوم المتجهة (SVG graphics) باستخدام عناصر التحريك المعرفة في مواصفات لغة التكامل المتزامن للوسائط المتعدّدة SMIL، تشمل تلك العناصر ما يلي: <animate>: يسمح لك هذا العنصر بتحريك خاصيات HTML وخاصيات الكائنات على مدى فترة زمنية محددة. <set>: وهو اختزال مناسب للتحريك، فهو يفيد في تعيين قيم التحريك لخاصيات HTML وخاصيات الكائنات مثل خاصية الظهور والرؤية. <animateMotion>: يعمل على تحريك العنصر على امتداد مسار الحركة. <animationColor>: تستطيع من خلال هذا العنصر تعديل القيم اللونية لخاصيات HTML وخاصيات الكائنات مع مرور الوقت. لاحظ إهمال العنصر <animateColor> لمجرد استخدام عنصر التحريك لاستهداف خصائص من الممكن أن تمتلك قيم لونية. بالرغم من ذلك لا يزال ذلك العنصر متاحًا في مواصفات SVG1.1، على العكس من SVG2 فهو مهمل ومحذوف بالكامل. بالإضافة إلى عناصر التحريك المعرفة في مواصفات SMIL تحتوي الرسوم المتجهة SVG ملحقات متوافقة مع مواصفات SMIL والتي تحتوي على خاصيات توسع نطاق عمل العنصر <animateMotion> وعناصر إضافية أخرى. تشمل ملحقات الرسوم المتجهة SVG ما يلي: <animateTransform>: يتيح لك تحريك إحدى خاصيات الرسوم المتجهة مع مرور الوقت، مثل خاصية transform. path (خاصية HTML): تسمح بتحديد أي خاصية من صيغ بيانات مسار الرسوم المتجهة SVG في خاصية المسار لعنصر animateMotion، (التحريك اعتمادًا على SMIL فقط يسمح بتفرع صيغ بيانات الرسوم المتجهة خلال مسار). سنتطرق بالحديث أكثر عن animateMotion في الفقرات القادمة. <mpath>: يستخدم بالاقتران مع عنصر animateMotion للإشارة إلى مسار حركة الذي سيستخدم كمسار لتحريك العناصر. مع العلم أن عنصر mpath مضمن داخل عنصر animationMotion قبل علامة الإغلاق. <keypoints> (خاصية HTML): تستخدم كخاصية لـ animateMotion لتوفير تحكم دقيق في سرعة حركة العناصر في مساراتها. <rotate> (خاصية HTML): تستخدم أيضًا كخاصية لـ animateMotion للتحكم في ما إذا كان الكائن يستجيب للدوران تلقائيًا بحيث يشير المحور السيني له في نفس الاتجاه (أو الاتجاه المعاكس) مثل متجه الظل الاتجاهي لمسار الحركة. هذه الخاصية هي مفتاح نجاح تحريك العناصر على امتداد مسار ما كما تتوقع للحركة أن تكون. مزيدًا من التوضيح في الجزئية الخاصة بشرح animationMotion. حركة رسوم SVG من الممكن أن تكون مشابهة لرسوم CSS والانتقالات عبرها حسب طبيعتيهما. مفاتيح الحركة تُضبط وبالتالي تتحرك العناصر وتتغير الألوان …إلخ. مع ذلك بإمكان رسوم SVG القيام بأمور لا تستطيع رسوم CSS القيام بها وهذا ما سنتطرق له لاحقًا. لماذا قد تستخدم الرسوم المُتجهة (SVG Animation)؟ من الممكن تصميم وتحريك الرسوم المتجهة (SVG) باستخدام CSS. بشكل أساسي التأثيرات الحركية التي تطبق على عناصر HTML من الممكن أيضًا تطبيقها على عناصر SVG. ولكن هناك بعض الخصائص التي يمكن تطبيقها على SVG ليست فعالة على CSS. مسار SVG على سبيل المثال يأتي مع مجموعة من البيانات (d="" خاصية HTML) التي تعطي للمسار شكلًا. تلك البيانات يمكن تعريفها وتحريكها خلال SMIL ولكن الأمر لا ينطبق على CSS. ذلك لأن عناصر SVG تتصف بمجموعة من خاصيات HTML تُعرف بخاصيات للعرض. بعض تلك الخاصيات من الممكن معايرتها والتحكم فيها وتحريكها باستخدام CSS وهذا لا ينطبق على الخاصيات جميعها. وهكذا ترى أن العديد من تأثيرات الحركة يمكن تطبيقها حاليًا باستخدام CSS. وأما الفجوات في استخدام SVG CSS من الممكن تجاوزها عند استخدام JavaScript أو SVG المستمدة من SMIL. إذا كنت تفضل استخدام JavaScript فيستحسن أن تجرب snap.svg بواسطة Dmitry Baranovsky الذي يعد كمكتبة حافلة بالكثير من النصوص البرمجية الخاصة بـ SVG. ويمكنك الاطلاع على العديد من الأمثلة على ذلك. أما إذا كنت تفضل الخوض في مسار تعريفي أكثر بإمكانك استخدام عناصر التحريك التي سيتطرق لها هذا الدليل. ميزة أخرى تميز SMIL عن JS هي أن رسوم JS لا تعمل عند تضمين رسوم SVG كصور img أو استعمالها كصورة خلفية (background-image) في CSS. رسوم SMIL تعمل في كلا الحالتين أو هكذا ينبغي. وهذه ميزة عظيمة. لربما ستجد نفسك قد اخترت SMIL عن غيرها من الخيارات بسبب تلك الميزة. ومن هنا فهذا الدليل سيؤدي دور المساعد لتتعلم كيف تستخدم SMIL بدءًا من اليوم. دعم المتصفح والنسخ الاحتياطية دعم المتصفح لرسوم SMIL لائق للغاية. حيث أنه يعمل في جميع المتصفحات باستثناء Internet Explorer و Opera Mini. للحصول على نظرة شاملة حول دعم المتصفح، يمكنك الرجوع إلى جدول التوافق. إذا كنت بحاجة إلى توفير نسخة احتياطية لحركة الرسوم لـ SMIL، يمكنك اختبار دعم المتصفح أثناء التنقل باستخدام Modernizr. إذا لم يكن SMIL مدعومًا ، فيمكنك تقديم نوع من الاستعاضة (رسوم JavaScript متحركة، تجربة بديلة، …إلخ). تحديد الهدف من الحركة باستخدام xlink: href بغض النظر عن أي من عناصر التحريك الأربعة التي تختارها، فأنت بحاجة إلى تحديد هدف الحركة المحدد بواسطة هذا العنصر. لتحديد الهدف يمكنك استخدام خاصية xlink: href. تعطي خاصية HTML هذه مرجع URI للعنصر المستهدف في التحريك والذي سيجري تعديله بمرور الوقت. يجب أن يكون العنصر المستهدف جزءًا من مستند SVG الحالي. <rect id="cool_shape" ... /> <animate xlink:href="#cool_shape" ... /> إذا واجهت عناصر التحريك في SVG من قبل، فمن المحتمل أنك رأيتها متداخلة مع العنصر المفترض تحريكه. هذا ممكن تبعًا لمحددات: إذا لم تتوفر خاصية xlink: hrefHTML، فسيكون العنصر المستهدف هو العنصر الأصل المباشر لعنصر الحركة الحالي. <rect id="cool_shape" ... > <animate ... /> </rect> لذلك إذا كنت تريد "تضمين" الرسم المتحرك في العنصر الذي ينطبق عليه، فبإمكانك القيام بذلك. وإذا كنت تريد أن تبقي الرسم المتحرك منفصل في مكان آخر في المستند، فيمكنك القيام بذلك أيضًا، وحدّد الهدف من كل حركة باستخدام xlink: href. كلا الطريقتين تعملان بشكل جيد. تحديد الخاصية المستهدفة للحركة باستخدام attributeName وattributeType تشترك جميع عناصر التحريك أيضًا في خاصية HTML أخرى وهي attributeName. تُستخدم attributeName لتحديد اسم خاصية HTML التي تقوم بتحريكها. على سبيل المثال، إذا كنت ترغب في تحريك موضع مركز الدائرة <circle> على المحور السيني (x-axis)، حدد cx كقيمة لخاصية attributeName. تأخذ attributeName قيمة واحدة فقط، ولا تقبل قيم متعددة، لذلك يمكنك تنشيط خاصية HTML واحدة فقط في كل مرة. إذا كنت ترغب في تحريك أكثر من خاصية HTML واحدة فأنت بحاجة إلى تعريف أكثر من تحريك واحد للعنصر. لربما لا توجد طريقة أخرى ولهذا لـ CSS أفضلية عن SMIL. ولكن مرة أخرى، نظرًا للقيم المحتملة لخاصيات الحركة الأخرى (والتي سنتطرق لها بعد ذلك)، فمن المنطقي تحديد اسم خاصية HTML واحد فقط في المرة الواحدة، وإلا فقد تصبح قيم الخاصيات الأخرى معقدة للغاية بحيث لا يمكن التعامل معها. عند تحديد اسم خاصية HTML، يمكنك إضافة البادئة XMLNS (اختصار namespace XML) للإشارة إلى مجال اسم خاصية HTML. يمكن أيضًا تحديد مجال الاسم باستخدام الخاصية attributeType. على سبيل المثال، تعد بعض الخاصيات جزءًا من مساحة اسم CSS (مما يعني أنه يمكن العثور عليها كخاصية CSS أيضًا) والبعض الآخر XML فقط. يمكن العثور على جدول يوضح هذه الخاصيات هنا. خاصيات HTML في الجدول ليست كلها من خاصيات SVG إنها فقط تلك التي يمكن ضبطها باستخدام CSS. بعضها متاح بالفعل كخصائص CSS. إذا لم تُعيّن قيمة attributeType بشكل صريح أو عُيّنت على "تلقائي"auto، يجب أن يبحث المتصفح أولاً من خلال قائمة خصائص CSS عن اسم خاصية مطابق، وإذا لم يُعثر على أي منهما سيبحث في مجال اسم XML الافتراضية للعنصر. على سبيل المثال، يوضح المقتطف التالي التحكم في تحريك شفافية مستطيل SVG. نظرًا لأن خاصية HTML للشفافية opacity متوفرة أيضًا كخاصية CSS، تُعين attributeType على مجال اسم CSS: <rect> <animate attributeType="CSS" attributeName="opacity" from="1" to="0" dur="5s" repeatCount="indefinite" /> </rect> سنتجاوز خاصيات الحركة الأخرى في الأمثلة التالية أدناه. جميع خاصيات التحريك متعارف عليها ما بين جميع عناصر التحريك ما لم يذكر خلاف ذلك. تحريك خاصية HTML لعنصر من قيمة لأخرى على مدار فترة زمنية وتحديد الحالة النهائية: from وby وto وdur وfill ابدأ بتحريك دائرة من موقع إلى آخر عن طريق تغيير قيمة الخاصية cx الخاصة بها (والتي تحدد قيمة x لمركزها). عنصر <animate> سيتيح لك القيام بذلك حيث يستخدم لتحريك خاصية واحدة في كل مرة. عادةً ما تتحرك الخاصيات التي تأخذ قيم رقمية ولونية باستخدام هذا العنصر. تفقد الجدول للتعرف على الخاصيات التي يمكن تحريكها. للتغيير من قيمة إلى أخرى خلال فترة زمنية يمكنك استخدام الخاصيات From وto وdur. ستحتاج أيضًأ إلى تحديد بداية الحركة عن طريق خاصية begin. <circle id="my-circle" r="30" cx="50" cy="50" fill="orange" /> <animate xlink:href="#my-circle" attributeName="cx" from="50" to="450" dur="1s" begin="click" fill="freeze" /> يوضح المثال السابق طريقة تعريف دائرة وتحريكها من مركزها من الموضع الأولي عند 50 وحدة ثم إلى الموضع الجديد 450 وحدة على امتداد محور السينات (x-axis). تتحدد قيمة البداية begin بالنقر click أي أن الدائرة سوف تتحرك عند النقر عليها. ويمكنك أيضًا قيمة البداية كقيمة زمنية. على سبيل المثال، تعيين القيمة "begin="0s يعني أن حركة العنصر ستبدأ بمجرد تحميل الصفحة. بإمكانك تأخير حركة العنصر عند تحديد قيمة موجبة، مثلًا "begin="2s تعني أن حركة العنصر ستبدأ بعد ثانيتين من تحميل الصفحة. الأكثر إثارةً هو أنه بإمكانك تعيين قيمة البداية begin مثل s1+click لتبدأ حركة العنصر خلال ثانية واحدة بعد النقر عليه! علاوةً على ذلك بإمكانك استخدام قيم أخرى تسمح لك بمزامنة العنصر بدون حساب المدة الزمنية وزمن التأخير للعناصر المتحركة الأخرى. ستعرف المزيد لاحقًا. خاصية dur تكافئ animation-duration في CSS. الخاصيتان from وto تشبهان الإطارين المفتاحيين (keyframes) from وto في قاعدة @keyframe الخاصة بـ CSS: @keyframes moveCircle { from { /* start value */ } to { /* end value */ } } أما خاصية HTML التعبئة fill (والتي تحمل نفس اسم خاصية HTML "التعبئة" التي تحدد لون العنصر لسوء الحظ) فهي تشبه خاصية وضع ملء الرسوم fill-mode property والتي تحدد ما إذا كان على العنصر أن يعود لحالته الأولية بعد انتهاء عملية التحريك. تتشابه قيم SVG مع تلك الموجودة في CSS، باستثناء اختلاف التسميات: freeze: يُعني هذا التأثير بتجميد قيمة التأثير لآخر قيمة في الفترة النشطة. يبقى التأثير مجمدًا للفترة الزمنية المتبقية في المستند أو حتى إعادة تشغيل الحركة. remove: يقوم هذا التأثير بإزالة تأثير الحركة (أي أنه لم يعُد مُطبقًا) عند انتهاء المدة النشطة للحركة. بعد انتهاء زمن الحركة لم يعد الهدف متأثرًا بالحركة ما لم يُعاد تشغيل الحركة من جديد. حاول تغيير القيم في العرض الحي المباشر لترى كيف تتأثر الحركة: تستخدم خاصية by لتعيين إزاحة نسبية للحركة. كما يوحي الاسم فبإمكانك استخدام الخاصية HTML لتحديد مقدار الإزاحة التي تريد للحركة أن تتقدم بها. يكون تأثير الخاصية by مرئيًا عند تقدمك خلال مدة الحركة في خطوات منفصلة، على غرار الطريقة المعمول بها في CSS عبر steps(). المكافئ لدالة steps() في CSS هو "calcMode="discrete في SVG، وسنتطرق لخاصية calcMode لاحقًا في المقالة. الحالة الأخرى عندما يكون تأثير by أكثر وضوحًا عند تحديد خاصية to. سيأتي مثال على ذلك لاحقًا. وأخيرًا وليس آخرًا، تأتي by بفائدة أخرى عند العمل مع الحركة المضافة والتراكمية. إعادة تشغيل الحركة باستخدام restart قد يكون من المفيد وقف إعادة تشغيل الحركة أثناء نشاطها. للقيام بذلك تمنح SVG خاصية restart المزودة بخيارات ثلاثة: always: تمكنك من إعادة تشغيل الحركة في أي وقت حيث أنها القيمة الافتراضية. whenNotActive: يمكن إعادة تشغيل الحركة فقط عندما لا تكون نشطة (أي بعد النهاية النشطة). أما محاولات إعادة تشغيل الحركة خلال المدة النشطة فيتم تجاهلها. never: لا يمكن إعادة تشغيل العنصر لما تبقى من المدة البسيطة الحالية لحاوية الزمن. (في حالة SVG نظرًا لأن حاوية الوقت الأصلية هي جزء من مستند SVG، فلا يمكن إعادة تشغيل الحركة للفترة المتبقية من مدة المستند). تسمية الحركة ومزامنتها افترض أننا نريد تحريك موضع ولون دائرة، بحيث يتغير اللون في نهاية الحركة. بإمكانك القيام بذلك عن طريق تحديد قيمة begin لحركة تغيير اللون لتكون مساوية لمدة الحركة dur، هذه هي الطريقة التي نفعلها عادة في CSS. SMIL مع ذلك، لديها ميزة لطيفة التعامل مع الأحداث. لقد ذكرنا قبل ذلك أن الخاصية begin تقبل قيمًا مثل click + 5s. تسمى هذه القيمة "قيمة الحدث (event value)، وتتكون في هذه الحالة من مرجع حدث متبوعًا بـ "قيمة الساعة". الجزء المثير للاهتمام هنا هو تسمية الجزء الثاني: "قيمة الساعة". لماذا ليست مجرد "قيمة زمنية"؟ حسنًا، الجواب هو أنه يمكنك استخدام قيمة الساعة حرفيًا مثل "10min" أو "01:33" أي ما يعادل "دقيقة و 33 ثانية"، أو حتى "02:30:03" (ساعتان، 30 دقيقة، و 3 ثوان). في وقت كتابة هذا التقرير، لم تُطبق قيم الساعة بالكامل في أي متصفح. لذا، إذا أردنا العودة إلى العرض الحي السابق واستخدمت click + 01:30، إذا بدأ متصفح يدعمه، ستبدأ الحركة خلال دقيقة و 30 ثانية بعد النقر فوق الدائرة. نوع آخر من القيم التي يمكن أن يقبلها هو معرف رسوم متحركة أخرى يتبعها مرجع حدث. إذا كان لديك حركتان (أو أكثر) (سواء طبقت على نفس العنصر أم لا!) وتريد مزامنتهما بحيث تبدأ إحداهما نسبة إلى الأخرى، يمكنك القيام بذلك دون الحاجة إلى معرفة مدة الحركة المتبقية. على سبيل المثال، في العرض الحي التالي، يبدأ المستطيل الأزرق في التحرك لمدة ثانية واحدة بعد بدء حركة الدائرة. و ذلك عن طريق إعطاء معرف كل حركة ID، ثم استخدام هذا المعرف مع الحدث begin كما هو موضح في التعليمات البرمجية التالية: <circle id="orange-circle" r="30" cx="50" cy="50" fill="orange" /> <rect id="blue-rectangle" width="50" height="50" x="25" y="200" fill="#0099cc"></rect> <animate xlink:href="#orange-circle" attributeName="cx" from="50" to="450" dur="5s" begin="click" fill="freeze" d="circ-anim" /> <animate xlink:href="#blue-rectangle" attributeName="x" from="50" to="425" dur="5s" begin="circ-anim.begin + 1s" fill="freeze" id="rect-anim" /> البداية "begin="circ-anim.begin + 1s هي الجزء الذي يخبر المتصفح ببدء الحركة للمستطيل بعد ثانية واحدة من بداية الدائرة. تفقد العرض التوضيحي التالي: يمكنك أيضًا بدء الحركة للمستطيل بعد انتهاء حركة الدائرة باستخدام حدث النهاية end بتتبع الشيفرة التالية: <animate xlink:href="#blue-rectangle" attributeName="x" from="50" to="425" dur="5s" begin="circ-anim.end" fill="freeze" id="rect-anim"/> يمكنك حتى بدء تشغيله قبل نهاية حركة الدائرة باستخدام الشيفرة التالية: <animate xlink:href="#blue-rectangle" attributeName="x" from="50" to="425" dur="5s" begin="circ-anim.end - 3s" fill="freeze" id="rect-anim"/> تكرار الحركة باستخدام repeatCount إذا كنت ترغب في تشغيل الحركة أكثر من مرة، فيمكنك القيام بذلك باستخدام خاصية repeatCount. يمكنك تحديد عدد المرات التي ترغب في تكرارها، أو استخدام الكلمة المفتاحية الأساسية غير المحددة لجعلها تتكرر إلى ما لا نهاية infinite. لذلك، إذا أردنا تكرار الحركة للدائرة مرتين، ستكون الشيفرة كما يلي: <animate xlink:href="#orange-circle" attributeName="cx" from="50" to="450" dur="5s" begin="click" repeatCount="2" fill="freeze" id="circ-anim" /> يمكنك التحقق من العرض الحي هنا. في المثال الحي، عين عدد التكرار ليكون 2 على الدائرة، وبشكل غير نهائي في المربع infinite. لاحظ طريقة إعادة تشغيل الحركة من القيمة الأولية from من القيمة بدلاً من القيمة التي وصلت إليها في نهاية الحركة. لسوء الحظ، لا تتضمن SMIL طريقة للرجوع إليها بين قيم البداية والنهاية مثل CSS التي تتيح لنا القيام بذلك. في CSS، تحدد خاصية اتجاه الحركة animation-direction ما إذا كانت الحركة يجب أن تنفذ بشكل معاكس على بعض أو كل الدورات أو التكرارات. Animation-direction: alternate: تعني القيمة البديلة أن عمليات تكرار دورة الحركة ذات القيم الفردية يتم تشغيلها في الاتجاه الطبيعي، وأما القيم الزوجية فتكون في اتجاه عكسي. هذا يعني أن الدورة الأولى ستكون من البداية إلى النهاية، ثم ستليها الدورة الثانية من النهاية إلى البداية، ثم الدورة الثالثة من البداية إلى النهاية، وهكذا. في SMIL للقيام بذلك، يجب عليك استخدام JavaScript لتغيير قيم الخاصيات from وto بشكل صريح. كتب جون مكبارتلاند من Big Bite Creative منشورًا لفترة من الوقت يشرح فيه كيف فعل ذلك من أجل تحريك رمز القائمة الذي عمل عليه. حل آخر هو تحديد القيمة النهائية كقيمة متوسطة ومن ثم تكون القيمة النهائية هي نفسها القيمة الأولية. على سبيل المثال، يمكنك تعيين الحركة لتبدأ من from قيمة وتنتهي بنفس القيمة مع to وكذلك باستثناء أنك تحدد ما كنت قد حددته ليكون قيمة نهائية كقيمة وسيطة بين from وto. في CSS، سنفعل ذلك باستخدام شيء مثل هذا: @keyframes example { from, to { left: 0; } 50% { left: 300px; } } المكافئ في SMIL هو استخدام خاصية values، والتي سنشرحها قريبًا. ومع ذلك، فإن الحل المذكور أعلاه قد يعمل أو لا يعمل وفقًا لنوع الحركة التي تتبعها، وما إذا كنت تقوم بسلسلة الحركة أم لا، أو تكرارها، أو القيام برسوم متحركة إضافية. إليكم رسمًا جميلًا بسيطًا من قِبل Miles Elam يستخدم فيه بعض أوقات البدء المتأخرة: تقييد وقت التكرار باستخدام repeatDur قد تصبح حركة العنصر المستمرة مزعجة أو غير متآلفة مع الاستخدام في حالة استمرار الحركة لفترة طويلة. لذلك، قد يكون من الجيد ضبط وقت التكرار على فترة زمنية معينة، وإيقاف التكرار بعد مرور بعض الوقت بالنسبة لبداية المستند. هذا هو المعروف باسم وقت العرض. يشير وقت العرض التقديمي إلى أن الموضع في الخط الزمني بالنسبة للمستند يبدأ من جزء معين. يُحدد باستخدام خاصية repeatDur. يشبه بناء الجملة الخاص بقيمة الساعة، ولكن بدلاً من أن يكون متصلاً بحدث حركة آخر أو حدث تفاعلي، فهو يتعلق ببداية المستند. على سبيل المثال، ستؤدي الشيفرة التالية إلى إيقاف تكرار الحركة لمدة دقيقة و 30 ثانية بعد بدء المستند: <animate xlink:href="#orange-circle" attributeName="cx" from="50" to="450" dur="2s" begin="0s" repeatCount="indefinite" repeatDur="01:30" fill="freeze" id="circ-anim" /> وهنا تستطيع مشاهدة العرض الحي: مزامنة الحركة على أساس عدد التكرارات الآن لنرجع خطوة إلى المزامنة بين موضوعين في التحريك. في الواقع، في SMIL يمكنك مزامنة الحركة بحيث تبدأ حركة إحداهما بناء على عدد تكرار حركة الأخرى. على سبيل المثال، يمكنك بدء رسم متحرك بعد تكرار رقم آخر، بإضافة أو طرح مقدار الوقت الذي قد ترغب في إضافته. المثال التالي يبدأ في تحريك للمستطيل في التكرار الثاني لحركة الدائرة: <animate xlink:href="#blue-rectangle" attributeName="x" from="50" to="425" dur="5s" begin="circ-anim.repeat(2)" fill="freeze" id="rect-anim" /> يوضح العرض التالي بداية حركة المستطيل بعد ثانيتين من ثاني تكرار لحركة الدائرة: يمكنك الاطلاع على نموذج لأساسيات SVG بإصدارها الثاني من إعداد David Eisenberg. التحكم في قيم الإطارات المفتاحية للحركة: keyTimes وvalues في CSS يمكننا تحديد القيم التي نريد أن تأخذها حركة الرسوم الخاصة بنا في إطار معين أثناء التحريك. على سبيل المثال، إذا كنت تحرك العنصر بإزاحة لليساربدلًا من تنشيطه من 0 إلى 300 مثلاً، يمكنك تحريكه بحيث يأخذ قيمًا معينة مثل هذا: @keyframes example { 0% { left: 0; } 50% { left: 320px; } 80% { left: 270px; } 100% { left: 300px; } } الإطارات 0٪ و 20٪ و 80٪ و 100٪ هي إطارات الحركة، والقيم الموجودة في كل إطار تحدد قيمته. التأثير الموصوف أعلاه هو أحد العناصر التي ترتد عن الحائط، ثم تعود إلى الموضع النهائي. في SMIL، يمكنك التحكم في القيم لكل إطار بطريقة مماثلة، لكن بناء الشيفرة مختلف تمامًا. لتحديد إطارات مفتاحية، يمكنك استخدام خاصية keyTimes ثم لتحديد قيمة الخاصية المتحركة لكل إطار، يمكنك استخدام خاصية values. اصطلاحات التسمية في SMIL مريحة للغاية. إذا أردنا العودة إلى الدائرة المتحركة التي رافقتنا في الأمثلة السابقة، واستخدمنا قيمًا مماثلة لتلك الموجودة في إطارات CSS الأساسية أعلاه، فإن الشيفرة سيبدو كما يلي: <animate xlink:href="#orange-circle" attributeName="cx" from="50" to="450" dur="2s" begin="click" values="50; 490; 350; 450" keyTimes="0; 0.5; 0.8; 1" fill="freeze" id="circ-anim" /> إذن ماذا فعلنا هناك؟ أول ما يجب ملاحظته هنا هو تحديد أوقات الإطار الرئيسي والقيم الوسيطة كقوائم. خاصية keyTimes هي قائمة مفصولة بفواصل منقوطة لقيم الوقت المستخدمة للتحكم في سرعة الحركة. في كل مرة في القائمة يتوافق مع قيمة في قائمة خاصية values، ويحدد متى تُستخدم القيمة في وظيفة التحريك. تُحدد كل قيمة زمنية في قائمة keyTimes كقيمة نقطة عائمة بين 0 و 1 (ضمنًا)، مما يمثل إزاحة متناسبة في المدة البسيطة لعنصر الحركة. لذا تشبه أوقات المفاتيح تلك الموجودة في CSS، إلا أنه بدلًا من تحديدها كنسب مئوية، فإنك تحددها ككسر. ما يلي هو العرض الحي للشيفرة أعلاه. انقر على الدائرة لبدء الحركة. لاحظ أنه إذا استخدمت قائمةvalues، فإن الحركة ستطبق القيم بالترتيب على مدار فترة الحركة. إذا حددت قائمة values، فسيتم تجاهل أي من الخاصيات from وto وby. في هذه المرحلة، تجدر الإشارة أيضًا إلى أنه يمكنك استخدام خاصية values بدون خاصية keyTimes - تنتشر القيم تلقائيًا بالتساوي خلال الوقت لكل قيمة calcMode بخلاف paced (راجع القسم التالي). التحكم في سرعة الحركة باستخدام التخفيف المخصص: calcMode و keySplines سنتطرق إلى موازنة CSS-SMIL مرة أخرى لأن بناء SMIL ومفاهيمه سيكون أسهل بكثير لفهم ما إذا كنت ستعتاد بالفعل على التحريك بواسطة CSS. في CSS، يمكنك اختيار تغيير سرعة الحركة الافتراضية الموحدة وتحديد وظيفة تخفيف مخصصة تتحكم في الحركة، باستخدام خاصية animation-timing-function. يمكن أن تكون وظيفة التوقيت واحدة من الكلمات المفتاحية المحددة مسبقًا، أو وظيفة مكعب cubic bezier. يمكن إنشاء ذلك باستخدام أداة مثل هذه المعدة بواسطة Lea Verou. في SMIL، تُحدد سرعة الحركة باستخدام خاصية calcMode. سرعة الحركة الافتراضية هي linear لجميع عناصر الحركة باستثناء animateMotion (سنصل إليها لاحقًا في المقالة). بالإضافة إلى قيمة linear، يمكنك تعيين القيمة إلى: discrete أوpaced أوspline. discrete: تحدد أن وظيفة الحركة ستقفز من قيمة إلى أخرى دون أي تقاطع. هذا مشابه للدالة steps() في CSS. paced: يشبه linear، إلا أنه سيتجاهل أي أوقات تقدم وسطية تحددها keyTimes. ويحسب المسافة بين القيم اللاحقة ويقسم الوقت وفقًا لذلك. إذا كانت قيمك كلها بترتيب خطي linear، فلن تلاحظ الفرق. ولكن إذا كانت ذهابًا وإيابًا، أو إذا كانت ألوانًا (والتي يعامل معها كقيم متجه ثلاثي الأبعاد)، فسترى بالتأكيد القيم الوسيطة. فيما يلي عرض حي من Amelia Bellamy-Royds، يُظهر الفرق بين قيم calcMode الثلاث المذكورة حتى الآن: spline: وهي القيمة الرابعة المقبولة بواسطة calcMode. يتشابك من قيمة واحدة في قائمة values إلى القيمة التالية وفقًا لوظيفة الوقت المحددة بواسطة cubic Bezier spline. تعرف نقاط الشريحة في خاصية keyTimes، وتحددد نقاط التحكم لكل فاصل زمني في خاصية keySplines. ربما لاحظت الخاصية HTML الجديدة في الجملة الأخيرة: خاصية keySplines. لذا، ماذا تفعل خاصية keySplines؟ مرة أخرى، إلى ما يعادلها في CSS. في CSS، يمكنك تحديد سرعة الحركة داخل كل إطار رئيسي، بدلاً من تحديد سرعة حركة واحدة للحركة بأكملها. يمنحك هذا تحكمًا أفضل في كيفية متابعة كل حركة للإطار الرئيسي. مثال باستخدام هذه الميزة هو إنشاء تأثير ارتداد الكرة. قد تبدو الإطارات المفتاحية لذلك كما يلي: @keyframes bounce { 0% { top: 0; animation-timing-function: ease-in; } 15% { top: 200px; animation-timing-function: ease-out; } 30% { top: 70px; animation-timing-function: ease-in; } 45% { top: 200px; animation-timing-function: ease-out; } 60% { top: 120px; animation-timing-function: ease-in; } 75% { top: 200px; animation-timing-function: ease-out; } 90% { top: 170px; animation-timing-function: ease-in; } 100% { top: 200px; animation-timing-function: ease-out; } } بدلاً من تسهيل الكلمات المفتاحية، كان بإمكاننا استخدام الدالة ()cubic-bezier ذات الصلة: ease-in = cubic-bezier(0.47, 0, 0.745, 0.715) ease-out = cubic-bezier(0.39, 0.575, 0.565, 1) لنبدأ بتحديد الأوقات الرئيسية وقائمة القيم للدائرة البرتقالية لتخضع لنفس تأثير الارتداد: <animate xlink:href="#orange-circle" attributeName="cy" from="50" to="250" dur="3s" begin="click" values="50; 250; 120;250; 170; 250; 210; 250" keyTimes="0; 0.15; 0.3; 0.45; 0.6; 0.75; 0.9; 1" fill="freeze" id="circ-anim" /> ستبدأ الحركة عند النقر، وستتوقف بمجرد وصولها إلى القيمة النهائية. بعد ذلك، من أجل تحديد وتيرة كل إطار رئيسي، سنضيف خاصية keySplines. تأخذ خاصية keySplines مجموعة من نقاط التحكم bezier المرتبطة بقائمة keyTimes، وتحديد وظيفة bezier المكعبة التي تتحكم في سرعة الفاصل الزمني. قيمة الخاصية HTML هي قائمة مفصولة بفواصل منقوطة لوصف نقطة التحكم. كل وصف لنقطة التحكم عبارة عن مجموعة من أربع قيم: y1 x1 x2 y2، تصف نقاط التحكم bezier لشريحة وقت واحدة. يجب أن تكون جميع القيم في النطاق من 0 إلى 1، وتستبعد الخاصية HTML ما لم تُعين calcMode على شكل spline. بدلاً من أخذ دوال cubic-bezier كقيم، تأخذ keySplines إحداثيات نقطتي التحكم المستخدمة لرسم المنحنى. يمكن رؤية نقاط التحكم في لقطة الشاشة التالية المأخوذة من أداة Lea. تعرض لقطة الشاشة أيضًا إحداثيات كل نقطة، كل لون بنفس لون النقطة نفسها. بالنسبة لخاصية keySplines، هذه هي القيم التي سنستخدمها لتحديد سرعة الحركة الموجودة في keyframe. يسمح SMIL بفصل هذه القيم إما بفواصل بمسافة بيضاء اختيارية أو بمسافة بيضاء فقط. قيم keyTimes التي تحدد الجزء المرتبط هي "نقاط الربط" bezier، وقيم keySplines هي نقاط التحكم. وبالتالي، يجب أن يكون هناك مجموعة واحدة أقل من نقاط التحكم من keyTimes. إذا عدنا إلى مثال الكرة المرتدة، تُعرض إحداثيات نقطة التحكم للدالتين ease-in و ease-out كما هو موضح في الصور التالية: لترجمة ذلك إلى عنصر متحرك في SVG، نحصل على الشيفرة التالي: <animate xlink:href="#orange-circle" attributeName="cy" from="50" to="250" dur="3s" begin="click" values="50; 250; 120;250; 170; 250; 210; 250" keyTimes="0; 0.15; 0.3; 0.45; 0.6; 0.75; 0.9; 1" keySplines=".42 0 1 1; 0 0 .59 1; .42 0 1 1; 0 0 .59 1; .42 0 1 1; 0 0 .59 1; .42 0 1 1; 0 0 .59 1;" fill="freeze" id="circ-anim"/> وهنا تتابع العرض الحي: إذا كنت ترغب فقط في تحديد دوال التسارع (easing function) بأكملها دون أي قيم وسيطة، فلا يزال يتعين عليك تحديد الإطارات المفتاحية باستخدام خاصية keyTimes، ولكن عليك فقط تحديد إطارات المفاتيح للبداية والنهاية، وهي1 ؛ 0، وليس القيم المتوسطة values. الحركات المضافة والتراكمية: addictive وaccumulate في بعض الأحيان، من المفيد تحديد رسم متحرك يبدأ من حيث انتهت الحركة السابقة؛ أو آخر يستخدم المجموع التراكمي للحركات السابقة كقيمة للمتابعة. لذلك، يحتوي SVG على خاصيتين مناسبتين: addictive وaccumulate. افترض أن لديك عنصرًا تريد أن "يزداد" عرضه، أو خطًا تريد زيادة طوله، أو عنصرًا تريد نقله خطوة بخطوة من موضع إلى آخر، عبر خطوات منفصلة. هذه الميزة مفيدة بشكل خاص للحركة المتكررة. تمامًا مثل أي حركة أخرى، ستحدد قيم from وto. ومع ذلك، عند تعيين additive إلىsum، ستكون قيمتهما متناسبة مع القيمة الأصلية للخاصية HTML المتحركة. لذا، بالعودة إلى دائرتنا، يكون الموضع الأولي لـ cx هو 50. عندما تقوم بتعيين from = "0" وto = "100"، فإن الصفر إذا كان في الواقع هو 50 الأصلي، و 100 هو في الواقع 50 + 100؛ بمعنى آخر، من الناحية العملية يشبه from = "50" to = "150". من خلال القيام بذلك، نحصل على النتيجة التالية: هذا هو كل ما تفعله خاصية additive. إنه تحدد فقط ما إذا كان يجب أن تكون القيم from وto متناسبة مع القيمة الحالية أم لا. تأخذ الخاصية HTML واحدة من قيمتين فقط: sum وreplace. الأخير هو القيمة الافتراضية، وهذا يعني بشكل أساسي أن القيم from وtoسوف تحل محل القيم الحالية /الأصلية، والتي قد تؤدي في النهاية إلى قفزة غريبة قبل بدء الحركة. (حاول استبدال sum بـreplace في المثال أعلاه للحصول على مقارنة أفضل). ومع ذلك، ماذا لو أردنا إضافة القيم بحيث يبدأ التكرار الثاني من قيمة نهاية القيمة السابقة؟ هذا هو المكان الذي تأتي فيه خاصية accumulate. تتحكم خاصية accumulate فيما إذا كانت الحركة تراكمية أم لا. القيمة الافتراضية هي none، مما يعني أنه عند تكرار الحركة على سبيل المثال، ستبدأ من البداية. ومع ذلك، يمكنك تعيينها علىsum، والتي تحدد أن كل إعادة للتكرار بعد الأول يبني على القيمة الأخيرة للتكرار السابق. لذلك، إذا أردنا العودة إلى الحركة السابقة وتحديد accumulate = "sum"، فسنحصل على النتيجة المفضلة التالية: لاحظ أنه يتم تجاهل خاصية accumulate إذا كانت قيمة الخاصية HTML الهدف لا تدعم الإضافة، أو إذا كان العنصر المتحرك لا يتكرر. سيتم تجاهله أيضًا إذا عُينت وظيفة الحركة مع خاصية to فقط. تحديد نهاية الحركة باستخدام end كما أنه بإمكانك تحديد بداية حركة الرسوم فبإمكانك أيضًا تحديد نهايتها باستخدام خاصية end. على سبيل المثال، يمكنك تعيين حركة عنصر ما لتتكرر بشكل دائم ومن ثم إيقاف الحركة عند بداية حركة عنصر آخر. تأخذ خاصية end قيم شبيهة للقيم التي تأخذها begin. بإمكانك تحديد قيم مطلقة أو نسبية للوقت أو تطبيق إزاحة أو تكرار أو غيرها. فمثلًا في العرض الحي التالي تتحرك الدائرة ذات اللون البرتقالي ببطء في دورة تستمر 30 ثانية بالاتجاه الآخر لمسطح العمل. الدائرة ذات اللون الأخضر ستتحرك فقط عند النقر عليها. حركة الدائرة البرتقالية ستنتهي عند بدء حركة الدائرة الخضراء. انقر على الدائرة الخضراء وانظر كيف ستتوقف حركة الدائرة البرتقالية: يمكن تحقيق نفس التزامن للحركة عند تطبيق حركتين على نفس العنصر. على سبيل المثال، افترض تعيين حركة تغيير لون عنصر ما من قيمة لأخرى بشكل لانهائي. بعدها عند النقر على العنصر فإنه يتحرك للناحية الأخرى من مسطح العمل. والآن أوقف حركة تغيير اللون عند النقر على العنصر ومن بعدها تتوقف الحركة كليًا. تعيين فترات الحركة باستخدام قيم كلًا من begin وend في الواقع، تقبل كل من الخاصية begin وend قائمة القيم شبه المفصولة. ستتوافق كل قيمة في خاصية begin مع قيمة في خاصية end، وبالتالي تتشكل فواصل متحركة نشطة وغير نشطة. يمكنك أن تفكر في هذا على أنه يشبه سيارة متحركة، حيث تكون إطارات السيارة نشطة ومن ثم غير نشطة لفترات زمنية، اعتمادًا على ما إذا كانت السيارة تتحرك أم لا. يمكنك أيضًا إنشاء تأثير سيارة متحركة من خلال تطبيق الحركة على السيارة: أحدها يترجم السيارة أو يحركها على طول مسار يمثل أيضًا حركة مضافة وتراكمية، والأخرى تدور إطارات السيارة في فواصل يمكن مزامنتها مع عملية التحويل. مثال يوضح أوقات البدء والانتهاء المتعددة (أي الفواصل الزمنية) هو العرض الحي التالي، حيث يدور المستطيل استنادًا إلى الفواصل الزمنية المحددة، ويتغير من نشط إلى غير نشط وفقًا لذلك. (أعد تشغيل العرض الحي إذا فاتتك الحركة). لاحظ أنه في المثال أعلاه، استخدمت عنصر<animateTransform> لتدوير المستطيل حول مركزه. سنتحدث عن هذا العنصر بمزيد من التفصيل في القسم التالي أدناه. لاحظ أيضًا أنه، حتى إذا قمت بتعيين تكرار repeatCount بشكل غير نهائي indefinite، سيتجاوز من خلال قيم end ولن يتكرر بتلك الصورة النهائية. تقييد المدة النشطة لعنصر باستخدام min وmax مثلما يمكنك تقييد وقت تكرار الحركة، يمكنك أيضًا تقييد المدة النشطة الخاصة بها. تحدد خاصيات min وmax الحد الأدنى والحد الأقصى لقيمة المدة النشطة على التوالي. حيث أنها توفر لنا وسيلة للسيطرة على الحد السفلي والعلوي من فترة العنصر النشط. تأخذ كلا الخاصيتين قيمة الساعة كقيمة. بالنسبة لـ min، يحدد طول الحد الأدنى لقيمة المدة النشطة، ويقاس بالوقت الفعلي للعنصر. يجب أن تكون القيمة أكبر من أو تساوي 0، وهي القيمة الافتراضية ولا تقيد المدة النشطة على الإطلاق. بالنسبة إلىmax، تحدد قيمة الساعة طول الحد الأقصى لقيمة المدة النشطة، وتُقاس في وقت العنصر النشط. يجب أن تكون القيمة أكبر من 0. القيمة الافتراضية لـ max هي indefinite. وهذا لا يقيد المدة النشطة على الإطلاق. إذا حددت كل من الخاصيتين min وmax، فيجب أن تكون قيمة max أكبر من أو تساوي قيمة min. وإلا فسيتم تجاهل كلا الخاصيتين. ولكن ما الذي يحدد المدة النشطة لعنصر ما؟ ذكرنا مدة التكرار من قبل، بالإضافة إلى "المدة البسيطة"، وهي مدة الحركة دون أي تكرار (محدد باستخدام dur)، فكيف تعمل كل هذه الأشياء معًا؟ من الذي يتجاوز ماذا؟ ثم ماذا عن الخاصية end التي سيتم تجاوزها ومن ثم ببساطة تنتهي الحركة؟ الطريقة التي يحدث بها ذلك هي أن المتصفح سيقوم أولاً بحساب المدة النشطة بناءً على قيم dur و repeatCount وrepeatDur وend. بعد ذلك، تعمل المدة المحسوبة مقابل قيم min وmax المحددة. إذا كانت النتيجة ضمن الحدود، تكون قيمة المدة المحسوبة الأولى صحيحة ولن تتغير. وإلا قد تحدث حالتان: إذا كانت المدة الزمنية المحسوبة الأولى أكبر من قيمة max، تعرف المدة النشطة للعنصر بأنها تساوي قيمة max. إذا كانت المدة المحسوبة الأولى أقل من قيمة min، تصبح المدة النشطة للعنصر مساوية للقيمة min ويكون سلوك العنصر كما يلي: إذا كانت مدة التكرار (أو المدة البسيطة إذا لم يتكرر العنصر) للعنصر أكبر من min، يُشغل العنصر بشكل طبيعي لمدة نشطة (min مقيدة). بخلاف ذلك، يعمل العنصر بشكل طبيعي خلال مدة التكرار (أو المدة البسيطة إذا لم يتكرر العنصر) ثم يُجمد أو يختفي عتمادًا على قيمة خاصية fill. هذا يتركنا مع تساؤل عن طريقة قيام المتصفح بحساب المدة النشطة فعليًا. من أجل الإيجاز، لن نخوض في التفاصيل هنا. ولكن هناك جدول شامل للغاية في المواصفات التي تعرض التكوينات المختلفة لخصائص dur، وrepeatCount، وrepeatDor وend، ثم توضح المدة الفعلية التي ستستند إليها كل مجموعة. يمكنك التحقق من الجدول وقراءة المزيد حول هذا الموضوع في هذا القسم من المواصفات أخيرًا، إذا حدد عنصر للبدء في الحركة قبل العنصر الآخر (على سبيل المثال مع قيمة إزاحة سالبة بسيطة)، يُقاس الحد الأدنى للمدة من وقت البدء المحسوب وليس بداية الملاحظة. هذا يعني أن قيمة min قد لا يكون لها أي تأثير ملحوظ. أمثلة على <animate>: تحوير المسارات إحدى الخاصيات التي يمكن تحريكها في SMIL (ولكن ليس في CSS)هي الخاصية d (اختصار لـ data) الخاصة بـ SVG <path>. تحتوي الخاصية d على البيانات التي تحدد الخطوط العريضة للشكل الذي ترسمه. تتكون بيانات المسار من مجموعة من الأوامر والإحداثيات التي تخبر المتصفح عن مكان وكيفية رسم النقاط والأقواس والخطوط التي تشكل المسار النهائي. يسمح لنا تنشيط هذه الخاصية HTML بتحويل مسارات SVG وإنشاء تأثيرات ربط الأشكال. ولكن لكي تتمكن من تحوير الأشكال، يجب أن يكون لأشكال المسار البداية والنهاية وأي مسار وسطي نفس عدد الرؤوس /النقاط بالضبط، ويجب أن تظهر بنفس الترتيب. إذا لم يتطابق عدد النقاط، فلن تعمل الحركة. والسبب في ذلك هو أن تغيير الشكل يحدث فعليًا عن طريق تحريك الرؤوس، وتحريف مواقعها، لذلك إذا كانت نقطة واحدة مفقودة أو غير متطابقة، فلن تُقرب المسارات. لتحريك مسارSVG، يمكنك تحديد attributeName لتكون d، ثم اضبط قيم from وto التي تحدد أشكال البداية والنهاية، ويمكنك استخدام خاصية values لتحديد أي قيم وسيطة تريد أن يمر الشكل فيما بينها. من أجل الإيجاز، لن نخوض في تفاصيل كيفية القيام بذلك هنا. بدلًا من ذلك، يمكنك قراءة هذا المقال الممتاز من تأليف Noah Blon، إذ يشرح كيف قام بتحوير الأشكال لإنشاء حركة التحميل باستخدام <animate>. بإمكانك الاطلاع على العرض الحي للمقال: وهنا مثال آخر لتحوير الأشكال من إعداد Felix Hornoiu: يمكنك حتى تحوير قيم المسار المستخدم كـ clipping mask مثال على ذلك من إعداد Heather Buchel: الحركة على طول المسارات الافتراضية: العنصر <animateMotion> يعد عنصر<animateMotion> عنصر الحركة المفضل في SMIL. يمكنك استخدامه لنقل عنصر على طول المسار. عن طريق تحديد مسار الحركة باستخدام إحدى الطريقتين اللتين سنتطرق لهما بعد ذلك، ثم لإعداد العنصر بحيث يتحرك على طول هذا المسار. يقبل عنصر<animateMotion> نفس الخاصيات المذكورة سابقًا، بالإضافة إلى ثلاث خاصيات أخرى: keyPoints، و rotate، وpath. أيضًا، هناك اختلاف واحد فيما يتعلق بخاصية calcMode، حيث تكون القيمة الافتراضية لـ <animateMotion> هي paced، وليست linear. تحديد مسار الحركة باستخدام خاصية path تستخدم خاصية path لتحديد مسار الحركة. حيث يُعبر عنها بنفس التنسيق وتُفسر بنفس طريقة الخاصية d في العنصر path. يتمثل تأثير الحركة لمسار الحركة في إضافة مصفوفة تحويل تكميلية إلى مصفوفة التحويل الحالية للكائن المشار إليه والتي تتسبب في ترجمة على طول المحورين x و y لنظام إحداثيات المستخدم الحالي بواسطة قيم X و Y المحسوبة على زمن. بمعنى آخر، يُحسب المسار المحدد بالنسبة إلى الموضع الحالي للعنصر، باستخدام بيانات المسار لتحويل العنصر إلى موضع المسار. بالعودة إلى دائرتنا، سنقوم بتحريكها على طريق يشبه ما يلي: بإمكانك تطبيق تلك الحركة على الدائرة باستخدام الشيفرة التالي: <animateMotion xlink:href="#circle" dur="1s" begin="click" fill="freeze" path="M0,0c3.2-3.4,18.4-0.6,23.4-0.6c5.7,0.1,10.8,0.9,16.3,2.3 c13.5,3.5,26.1,9.6,38.5,16.2c12.3,6.5,21.3,16.8,31.9,25.4c10.8,8.7,21,18.3,31.7,26.9c9.3,7.4,20.9,11.5,31.4,16.7 c13.7,6.8,26.8,9.7,41.8,9c21.4-1,40.8-3.7,61.3-10.4c10.9-3.5,18.9-11.3,28.5-17.8c5.4-3.7,10.4-6.7,14.8-11.5 c1.9-2.1,3.7-5.5,6.5-6.5" /> هناك أمر واحد ركزنا عليه هنا: الإحداثيات في بيانات المسار. يبدأ المسار عن طريق تحريك (M) إلى النقطة مع الإحداثيات (0، 0)، قبل أن يبدأ في رسم منحنى (c) إلى نقطة أخرى. من المهم أن نلاحظ أن النقطة (0، 0) هي في الواقع موضع الدائرة، بغض النظر عن مكانها - ليست الزاوية العليا اليسرى من نظام الإحداثيات. كما ذكرنا أعلاه، فإن الإحداثيات في خاصية path تتعلق بالموضع الحالي للعنصر! نتيجة الشيفرة أعلاه هي: إذا كنت ترغب في تحديد المسار الذي يبدأ من نقطة أخرى غير (0، 0)، ستقفز الدائرة فجأة بالمقدار المحدد في نقطة البداية. على سبيل المثال، افترض أنك رسمت مسارًا في Illustrator ثم قمت بتصدير بيانات المسار لاستخدامها كمسار حركة (هذا ما فعلته في المرة الأولى التي قمت فيها بهذا)؛ قد يبدو المسار المُصدّر كالتالي: <path fill="none" stroke="#000000" stroke-miterlimit="10" d="M100.4,102.2c3.2-3.4,18.4-0.6,23.4-0.6c5.7,0.1,10.8,0.9,16.3,2.3 c13.5,3.5,26.1,9.6,38.5,16.2c12.3,6.5,21.3,16.8,31.9,25.4c10.8,8.7,21,18.3,31.7,26.9c9.3,7.4,20.9,11.5,31.4,16.7 c13.7,6.8,26.8,9.7,41.8,9c21.4-1,40.8-3.7,61.3-10.4c10.9-3.5,18.9-11.3,28.5-17.8c5.4-3.7,10.4-6.7,14.8-11.5 c1.9-2.1,3.7-5.5,6.5-6.5"/> نقطة بداية المسار في هذه الحالة هي (100.4، 102.2). إذا أردنا استخدام هذه البيانات كمسار للحركة، ستقفز الدائرة بمقدار 100 وحدة تقريبًا إلى اليمين و102 وحدة تقريبًا لأسفل، ثم تبدأ الحركة على طول المسار بالنسبة للموضع الجديد. لذلك، تأكد من وضع ذلك في الاعتبار عند إعداد مسار الحركة للحركة الخاصة بك. في حالة استخدامها، تحدد الخاصيات from وby وto وvalues شكلًا على مساحة العمل الحالية التي تمثل مسار الحركة. تحديد مسار الحركة باستخدام عنصر <mpath> هناك أيضًا طريقة أخرى يمكنك من خلالها تحديد مسار الحركة. بدلًا من استخدام خاصية HTML المسار النسبي path، يمكنك الرجوع إلى مسار خارجي باستخدام عنصر <mpath> التابع لعنصر <animateMotion>، والذي يشير إلى المسار الخارجي باستخدام الخاصية xlink: href. <animateMotion xlink:href="#circle" dur="1s" begin="click" fill="freeze"> <mpath xlink:href="#motionPath" /> </animateMotion> يمكن تحديد مسار الحركة <path> في أي مكان في المستند؛ يمكن تعريفه حرفيًا فقط داخل عنصر <defs> ولا يُعرض على سطح العمل على الإطلاق. في المثال التالي، المسار ظاهر وواضح لأنه في معظم الحالات قد ترغب في إظهار المسار الذي يتحرك فيه العنصر. لاحظ أنه، وفقا للمواصفات: مرة أخرى، "يتضاعف" موضع الدائرة أو "يتحول" بواسطة الإحداثيات في بيانات المسار. في المثال التالي، لدينا مسار في منتصف اللوحة. تُوضع الدائرة في بداية المسار. ومع ذلك، عند تطبيق مسار الحركة، لا تبدأ الدائرة حركتها من موضعها الحالي. تفقد العرض الحي للحصول على شرح أفضل. انقر على الدائرة لتحريكها. انظر كيف تتبع الدائرة نفس شكل المسار، ولكن على موضع مختلف؟ هذا يرجع إلى حقيقة أن موضع الدائرة يُحول بواسطة قيم بيانات المسار. تتمثل إحدى طرق الالتفاف حول ذلك في البدء بوضع الدائرة في (0، 0)، بحيث عند استخدام بيانات المسار لتحويلها، ستبدأ وتستمر كما هو متوقع. هناك طريقة أخرى تتمثل في تطبيق تحويل "يعيد تعيين" إحداثيات الدائرة بحيث تُحسب على الصفر قبل تطبيق المسار. فيما يلي نسخة معدلة من العرض الحي أعلاه، وذلك باستخدام مسار مغلق وتكرار الحركة بشكل غير نهائي. تجاوز القواعد لـ <animateMotion> نظرًا لوجود أكثر من طريقة واحدة لفعل نفس الشيء مع animateMotion، فمن المنطقي أن يكون هناك قواعد تجاوز لتحديد القيم التي تتجاوز القيم الأخرى. قواعد التجاوز لـ animateMotion كالتالي: فيما يتعلق بتعريف مسار الحركة، يتجاوز عنصر mpath خاصية path، التي تتجاوز values، والتي بدورها تتجاوز from وby وto. فيما يتعلق بتحديد النقاط التي تتوافق مع خاصيات keyTimes، فإن مسارkeyPoints يتخطى path، والذي يتجاوز values، والذي بدوره يتخطى from وby وto. تحديد اتجاه عنصر على طول مسار الحركة باستخدام rotate في المثال السابق، حدث أن العنصر الذي كنا نتحرك فيه على طول المسار هو دائرة. ولكن ماذا لو كنا نحرك عنصرًا له اتجاه معين، على سبيل المثال، رمز سيارة؟ رمز السيارة في المثال التالي من إعداد Freepik. في هذا المثال، استبدلت الدائرة بمعرف "السيارة"، الذي يحتوي على العنصر الذي يُكون المجموعة. بعد ذلك، من أجل تجنب مشكلة الحركة على طول المسار المذكور أعلاه، ثم تطبيق تحويل على السيارة بحيث يترجمها بمقدار معين، بحيث ينتهي الموضع الأولي عند (0، 0). القيم الموجودة داخل التحويلات هي في الواقع إحداثيات النقطة التي يبدأ فيها رسم المسار الأول للسيارة (مباشرة بعد أمر النقل M). ثم تبدأ السيارة تتحرك على طول مسار الحركة. لكن… هكذا تبدو الحركة: اتجاه السيارة ثابت، ولا يتغير لمطابقة مسار الحركة. لتغيير ذلك، سنستخدم خاصية rotate. تأخذ خاصية rotate إحدى القيم الثلاث: auto: تشير إلى أن الكائن يدور بمرور الوقت بزاوية الاتجاه (أي متجه الظل الاتجاهي) لمسار الحركة. auto-reverse: تشير إلى أن الكائن يدور بمرور الوقت بزاوية الاتجاه (أي متجه الظل الاتجاهي) لمسار الحركة بإضافة 180 درجة. رقم: يشير إلى أن العنصر الهدف يحتوي على تحويل دوران ثابت مطبق عليه، حيث تكون زاوية الدوران هي العدد المحدد من الدرجات. لإصلاح اتجاه السيارة في المثال أعلاه، سنبدأ بتعيين قيمة الدوران على auto. سننتهي بالنتيجة التالية: أما في حال أردت تدوير السيارة خارج المسار، قيمة auto-revesre ستتكفل بذلك. يبدو هذا أفضل، لكن لا تزال لدينا مشكلة واحدة وهي أن السيارة تبدو وكأنها تتحرك للخلف على طول المسار! لتغيير ذلك، نحتاج إلى قلب السيارة على طول محورها y. يمكن القيام بذلك عن طريق تحجيمه بعامل "-1" على طول هذا المحور. لذلك، إذا طبقنا التحويل على g باستخدام معرف السيارة car، فستتحرك السيارة للأمام كما هو متوقع. سيرتبط التحجيم مع الترجمة السابقة التي طبقناها سابقًا. <g id="car" transform="scale (-1, 1) translate(-234.4, -182.8)"> وبالتالي، ستكون النتيجة كما هي موضحة في العرض: التحكم في مسافة الحركة على طول مسار الحركة باستخدام keyPoints توفر خاصية keyPoints القدرة على تحديد التقدم على طول مسار الحركة لكل من قيم keyTimes المحددة. إذا حددت ذلك، فإن keyPoints تؤدي إلى تطبيق keyTimes على القيم الموجودة في keyPoints بدلاً من النقاط المحددة في خاصية values أو النقاط الموجودة في خاصية path. تأخذ keyPoints قائمة مفصولة بفواصل منقوطة لقيم الفاصلة العائمة بين 0 و 1 وتشير إلى مدى طول مسار الحركة التي يجب أن يتحرك فيها الكائن في الوقت المحدد بواسطة قيمة keyTimes المقابلة. تُحدد الحسابات عن بعد من خلال خوارزميات المتصفح. تقابل كل قيمة تقدم في القائمة قيمة في قائمة خاصية keyTimes. عند تحديد قائمة نقاط KeyPoints، يجب أن يكون هناك بالضبط العديد من القيم في قائمة keyPoints كما هو الحال في قائمة keyTimes. أحد الأشياء المهمة التي يجب ملاحظتها هنا هو ضبط قيمة calcMode على linear لكي تعمل KeyPoints. يبدو أيضًا أنه يجب أن يعمل بشكل منطقي مع الحركة، إذا كانت النقاط الرئيسية تتحرك ذهابًا وإيابًا، لكنها لا تعمل. فيما يلي مثال من إعداد Amelia Bellamy-Royds (تفقد صفحتها الشخصية) توضح فيه استخدام keyPoints لتقليد السلوك فتبدأ الحركة على مسار من إزاحة محددة مسبقًا، لأننا لا نملك هذه القدرة حاليًا بشكل افتراضي في SMIL. تحريك النص على طول مسار افتراضي يختلف نقل النص عبر مسار افتراضي عن نقل عناصر SVG الأخرى عبر المسارات. لتحريك النص، سيتعين عليك استخدام عنصر <animation>، وليس عنصر <animateMotion>. أولاً، لنبدأ بوضع النص على طول المسار. يمكن القيام بذلك عن طريق تداخل عنصر<textPath> داخل عنصر <text>. سيتحدد النص الذي سيوضع على طول مسار داخل عنصر<textPath>، وليس كتابع لعنصر<text>. ستقوم textPath بعد ذلك بالإشارة إلى المسار الفعلي المراد استخدامه، تمامًا كما فعلنا في الأمثلة السابقة. يمكن أيضًا تقديم المسار المشار إليه على مسطح العمل أو تعريفه داخل <defs>. تحقق من الشيفرة في العرض الحي التالي: لتحريك النص على طول هذا المسار، سنستخدم العنصر <animate> لتحريك خاصية startOffset. تمثل startOffset إزاحة النص على المسار. 0٪ هي بداية المسار؛ 100 ٪ تمثل نهايته. لذلك، على سبيل المثال، إذا ضبطت الإزاحة على 50٪، فسيبدأ النص في منتصف المسار. ومن هنا ستتضح الأمور للذهاب قدمًا. عن طريق تنشيط startOffset، سنقوم بإنشاء تأثير نقل النص على طول المسار. تحقق من الشيفرة في العرض الحي التالي. تحولات الحركة: عنصر <animateTransform> ينقل عنصر <animateTransform> خاصية HTML تحويل على عنصر مستهدف، مما يسمح للحركة بالتحكم في التحوير والتحجيم و/أو التدوير و/أو الربط. يستغرق نفس الخصائص المذكورة للعنصر <animation>، بالإضافة إلى خاصية HTML إضافية: type. تستخدم خاصية type لتحديد نوع التحويل الذي تُطبق الحركة عليه. وتأخذ أحد القيم الخمسة: translate وscale وrotate وskewX وskewY. تأخذ الخاصيات from وby وto قيم يعبّرعنها باستخدام تركيب الجملة نفسه المتاح لنوع التحويل المحدد: بالنسبة لـ"type="translate، يُعبر عن كل قيمة فردية كـ [<tx> [,<ty> بالنسبة لـ "type="scale، يُعبر عن كل قيمة فردية كـ [<sx> [,<sy> بالنسبة لـ "type="rotate، يُعبر عن كل قيمة فردية كـ[<rotate-angle> [<cx> <cy> بالنسبة لـ "type="skewX و"type="skewY، يُعبر عن كل قيمة فردية كـ <skew-angle> إذا لم تكن معتادًا على بناء جملة SVG لخاصية transform، ومن أجل إيجاز هذه المقالة، ولأن تفاصيل بناء الجملة وكيفية التعامل معها خارج نطاقها، بإمكانك قراءة مقال فهم أنظمة تنسيق SVG والتحولات (الجزء 2): خاصية HTML التحويل، قبل الانتقال إلى هذا الدليل. بالعودة إلى العرض الحي السابق، حيث قمنا بتدوير المستطيل الوردي باستخدام عنصر <animateTransform>. تبدو شيفرة الدوران كما يلي: <rect id="deepPink-rectangle" width="50" height="50" x="50" y="50" fill="deepPink" /> <animateTransform xlink:href="#deepPink-rectangle" attributeName="transform" attributeType="XML" type="rotate" from="0 75 75" to="360 75 75" dur="2s" begin="0s" repeatCount="indefinite" fill="freeze" /> تحدد خاصيات from وto زاوية الدوران (البداية والنهاية) ومركز الدوران. في كليهما، يبقى مركز الدوران كما هو بالطبع. إذا لم تُحدد المركز، فسيكون ذلك هو الركن العلوي الأيسر من سطح العمل SVG. العرض الحي للرمز أعلاه هو ما يلي: هنا مثال آخر ممتع لـ animateTransform من إعداد Gabriel: إن تنشيط عملية تحويل واحدة أمر بسيط، ومع ذلك، يمكن أن تصبح الأمور فوضوية ومعقدة حقًا عند تضمين تحويلات متعددة، خاصة لأن أحد تحويلات الحركة animateTransform يمكنه تجاوز الآخر، لذلك بدلاً من إضافة التأثيرات وتسلسلها، قد ينتهي بك الأمر على العكس تمامًا. هذا بالإضافة إلى طريقة تنسيق SVG للأنظمة والتحولات في الواقع (راجع المقالة المذكورة سابقًا حول الموضوع). الأمثلة واسعة، وخارج نطاق هذه المقالة. لتحويل SVGs، يوصى باستخدام تحويلات CSS. تعمل التطبيقات على جعل هذا الأخير يعمل بشكل مثالي مع SVG، لذلك قد لا تضطر أبدًا إلى استخدام SMIL لتنشيط التحويلات في SVG على الإطلاق. عنصر <set> يوفر عنصر set وسيلة بسيطة لتعيين قيمة الخاصية HTML لمدة محددة. يدعم جميع أنواع الخاصيات، بما في ذلك الأنواع التي لا يمكن تحريفها بشكل معقول، مثل قيم السلسلة والقيمة المنطقية. عنصر set غير مضاف ولا يُسمح بالخاصيات المضافة والإجمالية، وسيتم تجاهلها عند تحديدها. نظرًا لاستخدام <set> لتعيين عنصر إلى قيمة محددة في وقت معين، فإنه لا يقبل جميع الخاصيات المذكورة لعناصر التحريك السابقة. على سبيل المثال، لا يحتوي على خاصية from أو by، لأن القيمة التي تتغير لا تتغير تدريجيًا خلال الفترة الزمنية. بالنسبة لـ set، يمكنك تحديد العنصر الذي تستهدفه، واسم الخاصية HTML ونوعها، وقيمة to، ويمكن التحكم في توقيت الحركة: begin وdur وend وmin وmax وrestart وrepeatCount وrepeatDur وfill. فيما يلي مثال يضبط لون المستطيل الدوّار إلى اللون الأزرق عند النقر فوقه. يظل اللون أزرق لمدة 3 ثوانٍ، ثم يعود إلى اللون الأصلي. في كل مرة ينفر فوق المستطيل، تعمل حركة set، ويتغير اللون لمدة ثلاث ثوانٍ. العناصر وخاصيات HTML وخاصيات الكائنات التي يمكن تحريكها لا يمكن تحريك كل خاصيات SVG، ولا يمكن تحريك كل الخاصيات التي يمكن تحريكها باستخدام جميع عناصر التحريك. للحصول على قائمة كاملة بجميع الخاصيات المتحركة، وجدول يربط الخاصيات بالعناصر التي تحركها، يرجى الرجوع إلى هذا القسم من مواصفات SVG Animation. أخيرًا لدى SMIL الكثير من الإمكانيات، وبالكاد تعرض المقال لمعلومات سطحية جدًا ولم يتطرق إلا إلى الأساسيات والتقنيات الخاصة بكيفية عملها فيSVG. يمكن إنشاء الكثير من التأثيرات المؤثرة للغاية، خاصة تلك التي تنطوي على تحوير الأشكال وتحويلها. لتكن حدودك هي السماء؛ عليك أن تكمل أنت الآن فامض بشغف! ولا تنس مشاركة ما تصنعه مع الآخرين. شكرًا لقراءتك! ترجمة وبتصرف للمقال A Guide to SVG Animations (SMIL) لصاحبته Sara Soueidan
-
أفضل طريقة لتعلّم بلندر هي بالمباشرة في العمل على مشروع. في هذه السلسلة من دروس بلندر للمبتدئين، سنقوم بتصميم وتحريك روبوت، إنشاء مشهد بسيط وإخراج فيديو نهائي. وهذا هو الروبوت، المشهد والتّحريك الذي ستقوم بإنشائه في هذه السلسلة: ولِنبدأ. كيف تصمم وتحرّك روبوت لتستخدم بلندر، ستحتاج إلى لوحة مفاتيح بها لوحة رقمية Numeric Pad وفأرة بها ثلاثة أزرار مع عجلة التمرير. إذا لم يكن لديك بالفعل، حمّل https://www.blender.org/. هذا الدرس تمّ إعداده باستخدام نسخة 2.77، لكن ستكون بخير مع أحدث إصدار. بعد أن تقوم بتشغيل بلندر، سترى الإعدادات الافتراضية بالأسفل. قد تخيفك الواجهة قليلًا في البداية، لكن لا تقلق، سيبدو لكل شيء معنى في النهاية. اللوحة الرئيسية هي لوحة العرض ثلاثي الأبعاد 3D View. في الأسفل الشريط الزمني Timeline. على اليمين يوجد Outliner (قائمة تُنّظم البيانات) والخصائص Properties. بقدر الإمكان، سأعلمك اختصارات لوحة المفاتيح، بدلًا من اختيار الأوامر من القوائم. لتصبح أفضل وأسرع على بلندر، ستحتاج إلى معرفة كافة الاختصارات، لذلك لماذا لا نبدأ الآن؟ في هذا الدرس، أوامر الفأرة ولوحة المفاتيح ستظهر بالخط العريض. الاختصارات NUM1، NUM2، NUM3، إلى آخره. تشير إلى المفاتيح في اللوحة الرقمية Numeric Pad. LMB وRMB تشير إلى زريّ الفأرة الأيمن والأيسر. بإيجاز LMB(الأيسر) يستخدم للضغط على الأزرار وRMB(الأيمن) يستخدم لتحديد العناصر. سيبدو ذلك واضحًا لاحقًا. بوجود مؤشرك على لوحة العرض 3D، اضغط على N لفتح تبويب Transform. هذا يوفّر لك المعلومات ويسمح لك بإدخال القيم لــ الموضعPosition ، الدوران Rotation والمقياس Scale للعناصر في مشهدك. سوف نستخدمه كثيرًا لاحقًا. الآن اضغط NUM1 للتحويل إلى الرّؤية الأمامية front view وNUM5 للتحويل إلى المنظورOrthographic Perspective. هل ترى كيف تم تمييز المكعب بإطار برتقالي؟ هذا يعني بأن ذلك العنصر محّدد حاليًا. اضغط X لحذف المكعب. قائمة منبثقة سوف تسألك للتأكيد. انقر علىLMB أو اضغط ENTER. فلنبدأ ببناء روبوتنا. اضغط SHIFT+A للوصول إلى قائمة الإضافة Add menu. من خلال Mesh، اختر Cylinder. استخدم عجلة الفأرة لعمل تكبير واضغط Tab للدخول إلى Edit Mode. في Edit Mode يمكنك مشاهدة النقاط والخطوط التي تشكّل الأسطوانة Cylinder مميّزة بالبرتقالي. هذه النقاط والخطوط تسمى vertices و edges، والعناصر ثلاثية الأبعاد المشكّلة من vertices و edgesتسمى meshes. بينما تضع المؤشر على الأسطوانة، اضغط CTRL+R للوصول إلى Loop Cut و Slide tool. سترى خط بنفسجي يظهر حول منتصف الأسطوانة اضغط 2 لإنشاء حلقتين loops، ثم اضغط ENTER مرتين، أولى لتأكيد الحلقتين وثانية لتأكيد الموضع (المكان) اضغط CTRL + TAB لفتح قائمة Mesh Select Mode. اختر Edge. ALT + SHIFT + RMB لاختيار الحلقة السفلية. اضغط S لتعديل المقياس Scale واكتب 1.1، ثم اضغط ENTER. اختر حافة edge على الحلقة العلويّة واضغط ALT + SHIFT + RMB لتحديد كافة حواف الحلقة. مع الاحتفاظ بحافة الحلقة محددة، اضغط G (Grab) للإمساك بها (التقاطها)، وZ لتحريكها على محور Z فقط واكتب .5، اضغط ENTER. CTRL + TAB واختر Face. ALT + SHIFT + RMB لتحديد الحلقة العلوية للأسطح faces. اضغط S لـ Scale وادخل .9، ثم اضغط ENTER للتّأكيد. اضغط NUM7 للتحويل إلى الرّؤية العلويّة top view و RMBلاختيار السطح الدائري. اضغط E لعمل “بثق” أو “استخراج” Extrude، ثم ENTER. ذلك سينشئ أسطح (أوجه) جديدة في أعلى السطح القديم. اضغط S لـ Scale وادخل .5، ثم اضغط ENTER للتّأكيد. اضغط NUM1 للتحويل إلى الرّؤية الأمامية. بعدها اضغط E لبثق extrude سطح جديد، وENTERللتأكيد. اضغط G للإمساك Grab، وZ لتقييد الحركة إلى محور Z وادخل .2، ثم اضغط ENTER. حوّل إلى الرّؤية العلويّة من خلال NUM7. اضغط K للوصول إلى أداة السكين Knife tool. اقطع الدائرة في المنتصف بوضع المؤشر على “النقطة العلوية”. اضغط LMB لبدء القطع، ثم حرك المؤشر إلى “النقطة السّفلية”. اضغط LMB لضبط موضع نقطة أخرى، ثم اضغط ENTER لإنهاء عملية القطع. اضغط NUM1 لعرض الرّؤية الأمامية، ثم اضغط NUM2 ست مرّات لتدوير العرض إلى القاع the bottom. حدّد السطح السّفلي. باستخدام أداة السكين Knife tool مرة أخرى، (بضغط K)، اقطع الدائرة من المنتصف (كما سبق)، اضغط ENTER لإنهاء عملية القطع. ذلك كان الجسم، الآن لنضيف الرأس. اضغط NUM1 للرجوع إلى الرّؤية الأمامية، ثم اضغط Z للعرض بالإطارات الشبكية wireframe. أضف مكعّب بواسطة SHIFT + A. قم بتصغير المقياس Scale بقيمة .8، من خلال S. اضغط ENTER للتأكيد. اضغط G للإمساك Grab (تقريبًا كتبت Grace بالخطأ في المقال الأصلي)، وZ لتقييد الحركة إلى محور Z وادخل 2، لتحريكه “وحدتيّ بلندر”. ثم اضغط ENTER للتأكيد. عدّل مقياس Scale المكعب على محور Z بالضغط على S، ثم Z وادخل .6، متبوعًا بـ ENTER. اضغط Z للعودة إلى العرض المصمت solid view. ثم حدّد السطح الأمامي للمكعّب. اضغط E لبثق Extrude سطح جديد وصغّر مقياسه scale بـ S وادخل .8، متبوعًا بـ ENTER. اضغط NUM3 للتحويل إلى الرّؤية الجانبية واضغط E مرّة أخرى لبثق سطح جديد، ثمّ G لإمساكه، وY لتقيّيد حركته على محور Y ثم ادخل .1، متبوعًا بـ ENTER للتأكيد. سنتابع في الدرس القادم تصميم ونمذجة العين والرقبة والذراع... ترجمة – وبتصرّف – للمقال Beginner Blender Tutorial: How to Model & Animate a Robot لصاحبه Jared
- 1 تعليق
-
- 1
-
- تصميم ثلاثي الأبعاد
- بلندر
-
(و 2 أكثر)
موسوم في:
-
في هذا الجزء، سوف تتعلّم كيف تستخدم مفاتيح التأطير في تحريك المجسمات على بلندر بإضافة ملف صوتي للمشروع الخاص بك ومزامنة حركات الروبوت مع الملف الصوتي. من لوحة الخصائص Properties أسفل Render، اضبط Frame Rate إلى 29.97. من قائمة Timeline، اختر وحوّل إلى Video Sequence Editor. من قائمة Video Sequence Editor، اضغط Add وأضف الملف الصوتي. هذا سيقودك لفتح ملف صوتي. اضغط (الملف الصوتي). ضع المؤشر عند نهاية الشريط الصوتي. ثمّ حوّل مرة أخرى من Video Sequence Editor إلى Timeline. غيّر طول التحريك ليتناسب مع موضع المؤشر عند رقم Frame (66). اضغط Shift + LEFT لتحريك المؤشر إلى بداية الخط الزمني Timeline. من Timeline اذهب إلى قائمة Playback وضع علامة على Audio Scrubbing وAV Sync. اضغط ALT + A للتشغيل. مرحبًا بالعالم (Hello World). مفتاح التأطير key frame للتحريك في بلندر اضغط RMB لتحديد جسم الروبوت robot mesh. في لوحة الخصائص Properties، اختر Object Data. اضغط RIGHT حتى تسمع البداية الأولى للصوت (11). ثمّ عُد للخلف فريم واحد (10). تحت Shape Keys، اختر Mouth. ضع مؤشر الماوس فوق شريط Value واضغط I لإدراج (مفتاح تأطير) key frame. اضغط RIGHT حتى تجد نهاية أول مقطع لفظي (“hell” 17) و ضع مؤشر الماوس فوق حقل Value واضغط I، ثمّ انتقل للخلف لإيجاد ذروة المقطع اللفظي لـ ( hell" (13". اضبط قيمة Value إلى 1، واضغط I لإدراج key frame. اضغط UP للانتقال إلى آخر مفتاح التأطير key frame، ثمّ اضغط RIGHT حتى إيجاد نهاية لفظ " hello" (39). اضغط I لإدراج key frame. اضغط LEFT لإيجاد لفْظَة الحرف “o” (30)، اضبط قيمة Value إلى 1 واضغط I لإدراج key frame. اضغط UP للانتقال إلى آخر مفتاح التأطير key frame، ثمّ اضغط RIGHT حتى إيجاد نهاية لفظ " World" (52). اضغط I لإدراج key frame. اضغط LEFT لإيجاد ذروة المقطع اللفظي “World” (45)، اضبط قيمة Value إلى 1 واضغط I لإدراج key frame. اضغط Shift + LEFT لتحريك المؤشر إلى بداية الخط الزمني Timeline. اضغط ALT + A للتشغيل. (HelloWorld)!. اضغط ALT + A لعمل توقف. حوّل العرض إلى الرّؤية الرباعية Quad View باستخدام CTRL + ALT + Q. إذا لم تكن عند بداية الشريط الزمني Timeline، اضغط SHIFT + LEFT للوصول هناك. أذرع الروبوت متيبسة قليلًا. لبدأ عملية التحريك (animation)، نحتاج لضبط الأذرع في وضع استرخاء. اضغط RMB على " HandIK.L"، ثمّ اضغط G لالتقاطه وتحريكه قليلا. استخدم أوضاع رؤية مختلفة كما تحتاج لضبطها كما هي بالأعلى. ثمّ اضغط I واختر Location. بدلًا من ذلك، يمكنك وضع المؤشر على الموقع في لوحة Transform، وضغط I. اضغط RMB على "HandIK.R" واضغط G لالتقاطه وقم بتحريك مكانه. اضغط I واختر Location. حرّك الشريط الزمني إلى 30. واضغط G لالتقاطه وقم بتحريك الذراع للأعلى. اضغط I واختر Location. اضغط RMB على " HandIK.L". اضغط I واختر Location، ثمّ قم بالتحرك إلى فريم frame رقم 50 في الشريط الزمني. اضغط G للالتقاط وقم بتحريك الذراع للأعلى. اضغط I واختر Location. اضغط Shift + LEFT لتحريك المؤشر إلى بداية الخط الزمني Timeline. اضغط ALT + A للتشغيل. مرحبًا بالعالم (Hello World)!. ترجمة -وبتصرّف- للمقال How to Model and Animate a Robot: Key Frame a Blender Animation لصاحبه Jared
-
- 1
-
- ثلاثي الأبعاد
- بلندر
- (و 7 أكثر)
-
لنبدأ بتحريك الروبوت الخاص بنا. سنقوم بذلك عن طريق العظام. نعم، العظام. والعظام هي التي تشكل المحرّكات Armatures. في بلندر، Rigging هي عمليّة ربط المحركات Armatures بعنصر(جسم) mesh لتمكين حركته. في هذا الدرس، سوف تقوم بعمل Rigging لمحركات بلندر لتحريك الروبوت الخاص بك. عمل Rigging لمحركات بلندر Blender Armatures قبل أن ننشئ العظمة الأولى، تأكد من وجود المؤشر ثلاثي الأبعاد في منتصف العرض ثلاثي الأبعاد 3D View. اضغط SHIFT + S واختر Cursor to Center. الآن اضغط Z للعرض wireframe وأضف عظمة باستخدام SHIFT + A واختر Armature، Single Bone. اضغط TAB واختر تبويب bone من قائمة الخصائص Properties. اعد تسمية Bone إلى “Spine”. اضغط TAB لتعديل الوضع. استخدم RMB لتحديد قاع " Spine". اضغط G للالتقاط وZ لتحريكه على محور Z فقط، ثمّ ادخل -1، واضغط ENTER. الآن حدّد أعلى، أو رأس “Spine”. التقط بـ G، وقيد الحركة بـ Z، وحرّك للأسفل بمقدار -.35، ثمّ ENTER. بالاحتفاظ بأعلى " Spine" محددًا، اضغط E لاستخراج عظمة جديدة، وZ لتقييدها على محور Z، ثمّ ادخل 1.35 واضغط ENTER. أعد تسمية العظمة الجديدة إلى “Neck”. حدّد أعلى “Spine” مرة أخرى. اضغط E لاستخراج عظمة جديدة وX لتقييدها على محور X. ادخل .9، واضغط ENTER. اعد تسمية هذه العظمة إلى “Shoulder.L”. حدّد رأس " Shoulder.L" واضغط E، X ثمّ ادخل 2 متبوعةً بـ ENTER، لعمل استخراج بوحدتيّ بلندر على محورX. أعد تسمية هذه العظمة إلى “Arm”. حدد عظمة “Arm” واضغط على Subdivide ثلاث مرّات من قائمة Tools. هذا سيقسّم “Arm” إلى ثمانية عظام. لا تلقى بالًا لتسميتهم. اختر العظمة الأخيرة، وأعد تسميتها إلى “Hand.L”. قرّب المشهد باستخدام عجلة الفأرة إن احتجت واختر رأس “Hand.L”. استخرج عظمة جديدة بضغط E، X وادخل .5، ثمّ ENTER. أعد تسمية العظمة الجديدة إلى “HandIK.L”. حدّد “HandIK.L” واذهب إلى لوحة الخصائص Properties، تحت تبويب Bone، تحت Relations، اضغط على علامة “X” بجانب اسمها في حقل Parent. إلتقط " HandIK.L" بضغط G وحرّكه على محور X بضغط X وإدخال .25، ثمّ اضغط ENTER. اضغط Tab لتعديل الوضع ومن Object Interaction Toggle، اختر Pose Mode. حدّد “Hand.L” ومن قائمة الخصائص Properties، اختر تبويب Bone Constraints. اضغط على زر Add Bone Constraint واختر Add Tracking : Inverse Kinematics. من لوحة IK، في حقل Target، اختر Armature وفي حقل Bone اختر HandIK.L. اضبط Chain Length إلى 8 (لأننا صنعنا ثمانية عظام عندما قسمنا “Arm” ونحن نحتاج سلسلة لربطهم مرة أخرى بالجسد). اختر HandIK.L وقم بالتقاطه بضغط G لتحريكه وترى كيف يعمل ذلك غالبًا. اضغط ALT + G لإعادة ضبط موضعه. في قائمة الخصائص، اختر تبويب Armature Object Data. تحت Display اختر B-Bone. اضغط A حتى يُحدد المحرك Armature بالكامل، ثمّ اضغط CTRL + ALT +S، لتغيير مقياس العظام وادخل .5، ثمّ اضغط ENTER. حدّد " HandIK.L" وقم بتكبير مقياسها باستخدام CTRL + ALT + S وادخل 4، ثمّ اضغط ENTER. اضغط Tab لضبط الوضع. اضغط SHIFT + S واختر Cursor to Center. تأكد من أن خيار Pivot Point مضبوط على 3D Cursor. بضغط SHIFT مع الاستمرار، حدّد Shoulder، Arms، Hand وIK bone. لا تحدّد Spine أو Neck. اضغط SHIFT + D لعمل نسخة طبق الأصل، ثمّ اضغط ENTER. الآن سنقوم باستدعاء النسخة طبق الأصل arm بتعديل مقياسها إلى الخلف 100% على محور X، اضغط S، X وادخل -1 واضغط ENTER. تحت Armature، اختر Flip Names. ومن Object Mode، اختر عنصر Robot mesh. وبالضغط مع الاستمرار على SHIFT، اختر أي عظمة. اضغط CTRL + P واختر Armature Deform مع Automatic Weights. إلتقط " HandIKs" وقم بتحريكهم لترى كيف يعمل كل شيء تقريبًا. ثمّ اضغط ALT + G لإعادتهم إلى أوضاعهم السابقة. ترجمة -وبتصرّف- للمقال How to Model and Animate a Robot: Rigging Blender Armatures لصاحبه Jared
-
- 1
-
- ثلاثي الأبعاد
- روبوت
-
(و 2 أكثر)
موسوم في:
-
سنتابع في هذا الدرس عملية تصميم جسم الروبوت عبر تنسيق التناظر في الجسم كاملًا ومن ثم تصميم الفم.... الآن سنقوم بقطع العنصر من المنتصف، اضغط B للوصول إلى the Box tool. اضغط مع الاستمرار على LMB لرسم مكعّب حول النصف الأيسر من الروبوت. اضغط X واحذف الأسطح. هدفنا هو الحصول على سطح ناعم أسفل منتصف العنصر the mesh. ربما تحتاج إلى تنظيف الأسطح المتبقية. استخدم B (Box tool) لتحديدهم وX لحذفهم. اضغط Tab للوصول إلى Object mode. في تبويب Properties، اختر Modifier. اضغط على زر Add Modifier واختر Mirror من القائمة. ثمّ اضغط Apply. اضغط Tab لتعديل الوضع edit mode. اضغط SHIFT + S واختر Cursor to Center. الآن لنضيف فم. اضغط Z للعرض wireframe. ثمّ أضف مكعّب باستخدام SHIFT + A. اضغط S لتعديل مقياس المكعّب، وادخل .6، متبوعًا بـ ENTER. اضغط S لتعديل المقياس مرة أخرى، هذه المرّة على محور Z، اضغط Z وادخل .1، ثمّ اضغط ENTER. قم بتحريك المكعّب بضغط G، Z وكتابة 1.5، ثمّ اضغط ENTER. اضغط NUM3 للتحويل إلى الرّؤية الجانبية، ثمّ اضغط S، Y واكتب .5 ثمّ ENTER، لتعديل مقياس المكعّب على محور Y. اضغط G لإمساك العنصر، وY لتقييد الحركة، وادخل -.25 متبوعًا بـ ENTER. اضغط SHIFT + H لإخفاء أي شيء آخر. اضغط Z للتحويل إلى العرض المصمت و NUM7 للتحويل إلى الرّؤية العلوية. حدّد السطح العلوي. اضغط E لبثق سطح جديد، ثمّ ENTER. صغّر مقياس السطح بضغط S، وكتابة .9، ثمّ اضغط ENTER. وقم بتصغيره مرة أخرى على محور Y بضغط S وY وكتابة .9، ثمّ ENTER. قم بالتحويل إلى الرؤية الجانبية بضغط NUM3. وعد إلى العرض wireframe بـ Z. قم ببثق سطح جديد بضغط E ثمّ ENTER. قم بإمساك السطح الجديد وحرّكه للأسفل على محور Z من خلال ضغط G، Z وكتابة -.07. اضغط ALT + H لإظهار الأسطح المخفية واضغط A لإلغاء تحديد أي شيء. اضغط NUM1 للتحويل إلى الرّؤية الأمامية. الآن، باستخدام L، حدّد الرأس، العينين والفم، لكن لا تحدد الرقبة. اضغط NUM3 للعودة إلى الرّؤية الجانبية. حرّك الرأس إلى الأمام قليلًا بإمساكه بـ G، وتقييد حركته بـ Y، وادخل -.25، ثمّ اضغط ENTER. اضغط Tab لتعديل وضع العنصر Object mode وأعد كتابة اسم العنصر the mesh من Cylinder إلى Robot. اضغط Z. مرحبًا بالعالم! تأّكد من حفظ ملف العمل الذي قمت به باستخدام CTRL + S. في الدرس التالي، سوف نضيف الألوان وبعض الحركة إلى الروبوت الخاص بنا. ترجمة – وبتصرّف – للمقال Beginner Blender Tutorial: How to Model & Animate a Robot لصاحبه Jared
-
- 1
-
- ثلاثي الأبعاد
- روبوت
-
(و 2 أكثر)
موسوم في:
-
سنتابع في هذا الدرس ما بدأناه في الدرس الماضي من تصميم ونمذجة أجزاء جسم الروبوت وسنبدأ بالعين... أضف أسطوانة باستخدام SHIFT + A. اضغط R ثم X لعمل تدوير على محور X وادخل 90 للتدوير بمقدار 90 درجة. ادخل ENTER للتأكيد. اضغط S لتصغير المقياس Scale وادخل .25، ثم اضغط ENTER. اضغط G للإمساك Grab وZ تقييد الحركة على محور Z وادخل 2، ثم اضغط ENTER. اضغط G للإمساك Grab وY لتقييد الحركة على محور Y وادخل -.7، ثم اضغط ENTER. اضغط NUM1 للتحويل إلى الرّؤية الأمامية، ثم G، X، .325 واضغط ENTER. اضغط Z للعودة إلى العرض المصمت solid view، وحدّد السطح الأمامي للأسطوانة. قرّب المشهد إن احتجت، بواسطة عجلة الفأرة. ثم اضغط E لعمل بثق ثمّ ENTER. صغّر مقياس السطح الجديد بضغط S وادخل .75، واضغط ENTER للتأكيد. اضغط Z للعرض بالإطارات الشبكية wireframe و NUM3 للتحويل إلى العرض المصمت solid view. اضغط E لبثق سطح جديد، ثم G للإمساك به، وY لتقييد الحركة على محور Y وادخل .02، ثم اضغط ENTER. حوّل العرض إلى الرّؤية الأمامية بضغط NUM1، وعُد إلى العرض المصمت من Z. أنشئ قَطع حلقي loop cut عموديًا حول الرأس باستخدام CTRL + R. انقر LMB أو اضغط ENTER للتأكيد. هذا الرأس. الآن لنقُم بربطه في الجسم. اضغط Z للعودة إلى العرض wireframe، ثمّ أضف أسطوانة جديدة باستخدام SHIFT + A. صغّر مقياس الأسطوانة على محوريّ X وY بضغط S و * SHIFT + Z*لاستبعاد محور Z. ادخل .15،ثمّ اضغط ENTER. حرّك الأسطوانة للأعلى بمسكها من G، اضغط Z وأدخل 1. ثمّ اضغط ENTER. بعدها أنشئ سلسلة من القَطع الحلقي loop cut باستخدام CTRL + R. تأكّد من وجود مؤشرك فوق جزء الرقبة والخط البنفسجي أفقي، ثمّ ادخل 32 واضغط ENTER مرتين. اضغط Z للعرض المصمت. بينما تضغط على ALT + SHIFT، حدّد حافة عمودية باستخدام RMB. تحت قائمة الاختيار Select menu في لوحة العرض 3D View، اختر Checker Deselect. بينما تضغط على ALT + SHIFT، حدّد حافة أفقية باستخدام RMB. تحت قائمة الاختيار Select menu مرة أخرى، اخترEdge Ring . اضغط CTRL + TAB واختر أيّ سطح. قم ببثق جميع الأسطح بـ E واضغط ENTER. اضغط S لتغيير مقياس الأسطح المحدّدة واضغط SHIFT + Z لتقييد ذلك على محوريّ X وY فقط، ثمّ ادخل 1.1 متبوعًا بـ ENTER. بوضع مؤشرك على جزء الرقبة، اضغط L لتحديد الأسطوانة بالكامل. واضغط SHIFT + H لإخفاء كل شيء آخر. اضغط مع الاستمرار على عجلة الفأرة وقم بالتحرك في لوحة العرض 3D View لتغيير منظور الرّؤية. حدّد السطح العلوي والسفلي للرقبة (اضغط مع الاستمرار على SHIFT لتحديد أكثر من سطح). واضغط X لحذف الأسطح المختارة. اضغط NUM1 للعودة إلى الرّؤية الأمامية و ALT + H لإظهار الأسطح المخفية. الآن لننتقل إلى الذراعين. حدّد سطح على الرقبة، واضغط L لتحديد الرقبة كلها مرة أخرى. قم بالتبديل إلى wireframe view بضغط Z. واصنع نسخة مكرّرة من الرقبة باستخدام SHIFT + D. اضغط ENTER أو LMB للتأكيد. قم بتدوير الأسطوانة الجديدة على محور Y بضغط R ثمّ Y وكتابة 90، بعدها اضغط ENTER. اضغط S لتغيير مقياس الأسطوانة الجديدة و SHIFT + X لاستبعاد محور X من العملية، ثمّ اكتب .75، واضغط ENTER للتأكيد. أمسك (التقط) الذراع بضغط G، وحرّكه على محور X، بضغط X وكتابة 1.75، ثمّ ENTER. حرّك الذراع للأسفل بضغط G، Z وادخل -.35، ثمّ ENTER. اضغط SHIFT + S للوصول إلى Cursor menu واختر Cursor to selected. أضف أسطوانة أخرى بضغط SHIFT + A. قم بتدويرها 90 درجة على محور Y، بضغط R، Y، 90 ثمّ ENTER. بعدها قم بتصغير مقياسها، بضغط S، .15 ثمّ ENTER. قم بتحريكها إلى نهاية الذراع، بضغط G، X، .1، ثمّ ENTER. اضغط A لإلغاء تحديد الأسطوانة. سنتابع في الدرس القادم عملية تنسيق التناظر في جسم الروبوت ومن ثم سنصمم الفم... ترجمة – وبتصرّف – للمقال Beginner Blender Tutorial: How to Model & Animate a Robot لصاحبه Jared
-
شاهدت مؤخرًا العديد من التصاميم ثلاثية الأبعاد للافتات نيون إعلانية تم تصميمها باستخدام برامج التصميم ثلاثي الأبعاد. أميل أكثر للتّصاميم ثنائية الأبعاد لذلك أريد أن أنتج تأثير نيون مشابه باستخدام الإليستريتور وفوتوشوب ولكن مع إضافة الحركة بواسطة صيغة GIF المتحركة. اتبع هذا الدرس لتتعلم عملية تصميم لافتة إعلانية لكوكب البيتزا مُستخدمًا أدوات فكتور الإليستريتور لإنشاء التصميم الأوّلي للافتة ثم فوتوشوب لإضفاء الحيوية على التصميم عبر أنماط الطبقات المتنوعة وتشكيل الحركة للملف. تأثير لافتة النيون سيتم إنشاؤه في الفوتوشوب باستخدام أنماط الطبقات عبر إنشاء توهجات نيون ملوّنة كما سيكون هناك طبقة قاتمة تكون عند إطفاء الأنوار والتي ستُضاف في إطار أثناء سير الحركة للملف لإضفاء الشعور بالواقعية على التأثير. لافتات النيون تعتمد على الأنابيب المنحنية لتشكيل أشكال التصميم لذلك سنستخدم الإليستريتور لصياغة مسارات فكتور بحيث لا تتقاطع الخطوط مع بعضها. افتح برنامج الإليستريتور وابدأ ملفًّا جديدًا. ارسم دائرة على لوح الرسم باستخدام أداة القطع الناقص Ellipse tool، ثم ألغِ لون التعبئة واترك فقط الحدود السوداء ظاهرة. غيّر إعدادات الحدود إلى 5pt مع نهايات مستديرة وزوايا مستديرة أيضًا. استخدم أداة النص Type tool لإضافة أي نص إلى لافتة النيون. أنا استخدمت خطًّا اسمه Darwin لكتابة Pizza Planet. اضبط حجم النص ليتوسط الدائرة ويتقاطع مع حدودها الخارجية ثم أمِلهُ بزاوية -10 درجة عموديًّا من القائمة: Object > Transform > Shear option ألغِ لون التعبئة للنص وأضف حدودًا سوداء مستخدمًا ذات الحجم 5pt مع النهايات المستديرة والزوايا المستديرة أيضًا. بالزر الأيمن اختر Convert to Outlines. ارسم دائرة صغيرة وقصّ المسار باستخدام أداة المقص Scissors tool في الجزء العلوي الأيسر. استخدم أداة التحديد المباشر Direct Selection tool لحذف المسار من النقطة السفلية إلى هذا القطع الجديد. اصنع نسخًا عديدة من هذا الشكل الأخير مع تعديل أحجامها وذلك لتعبئة المساحات الفارغة داخل الدائرة لتكوين فوهات وفتحات الكوكب. حدّد الدائرة الرئيسية للكوكب وانسخها CMD+C ثم ألصقها في المقدمة CMD+F. استمر بالضغط على ALT أثناء تمديد وضغط الشكل لتشكيل الحلقة حول الكوكب. ضاعف هذا الشكل الأخير وصغّر حجمه قليلًا بشكل يوازي الأصلي. ارسم شكلًا بيضويًّا في مكان ما على لوح الرسم ثم اسحب النقطة العلوية للأعلى باستخدام أداة التحديد المباشر Direct Selection tool لتمديد الشكل. استخدم أداة Convert Anchor Point tool الموجودة ضمن أدوات القلم لإزالة مقابض البيزير وترك النقطة حادة. أضف دوائر أخرى إلى الشكل لبناء شكل صاروخ بسيط. استخدم لوحة المحاذاة Align panel لتوسيط جميع العناصر مع جعل شكل جسم الصاروخ العنصر المفتاح عبر منحه نقرة إضافية. اصنع نسختين من الصاروخ وعدّل حجمها ودوّر كل صاروخ وضعهُ في موقعه في مدارٍ حول الكوكب مع جعلها أكبر في كل مرّة. التصميم يحوي العديد من المسارات المتداخلة فوق بعضها لذلك دعونا ننشئ المزيد من نماذج أنماط لافتة النيون. حدّد دائرة الكوكب الرئيسية ثم اذهب للقائمة: Object > Path > Offset Path ثم أدخل القيمة 3mm. انقر بالزر الأيمن على المسار الإضافي الجديد واختر Make Guides. تأكد من ظهور الأدلة عبر الضغط على CMD+; ومقفلة عبر الضغط على CMD+Alt+; استخدم أداة المقص Scissors tool لقص مسارات حلقات الكوكب في موقع تقاطعها مع الأدلة الجديدة. استخدم الأدلة الذكية Smart Guides عبر الضغط على CMD+U لتُسهّل عملية مطابقة هذه المنطقة. على الجانب الآخر فإن حرف P يتقاطع مع حدود الكوكب أيضًا لذلك ألغِ تجميع النص Ungroup من أجل تحديد هذا الحرف فرديًّا ثم أضف مسار إضافي بقيمة 3mm. الحرف P بشكل خاص بحاجة لخطوة إضافية من أجل إنشاء الأدلّة. انقر بالزر الأيمن ثم اختر Release Compound Path ثم احذف الجزء الداخلي قبل تحويل الخطوط الرئيسية إلى أدلّة. قص حلقات الكوكب عند تقاطعها مع المسار الإضافي لحرف P ثم احذف الأجزاء غير المرغوبة من المسارات. سنستخدم ذات التقنية في كل التصميم لإزالة جميع المسارات المتقاطعة ولكن بالنسبة للجزء السفلي من الحلقة فإن النص هو من يحتاج للتعديل للسماح للحلقة بالالتفاف حول الكوكب. ألغِ تجميع Ungroup عناصر النص الأخرى وأضف مسار إضافي للحرف الأول والأخير ثم أنشئ أدلّة من النتائج. تذكّر أن تحرر المسار المركب لحرف P ليصبح قابلًا للتحول إلى دليل. استخدم هذه الأدلة الجديدة لقص أي مسارات متداخلة مع بعضها وأزِل التداخلات في كل أنحاء التصميم. بالنسبة للمنطقة التي يتداخل فيها النص مع الحلقة سنحتاج إلى أدلة إضافية من مسارات الحلقة نفسها. استخدم أداة المقص Scissors tool لقص وحذف مناطق تواجد الحروف تحت الحلقة عبر خطوط الأدلة. من الضروري في بعض الأحيان تحرير المسارات المركبة للحروف من أجل تحديد وحذف الأجزاء غير المرغوبة من المسار. بعد إزالة جميع المسارات المتداخلة سيكون التصميم قد أخذ شكلًا أكثر واقعية كلافتة نيون. حدّد المسارات التي تُشكّل جزءًا محددًا وامنحها ألوانًا برّاقة للحدود كالأزرق، الأحمر، الأصفر والأبيض. افصل الألوان المختلفة داخل طبقاتها الخاصة عبر استخدام القائمة: Select > Same > Stroke Color ثم انسخ التحديد وألصقه في المقدمة. وضع الأجزاء التي ستكون متحركة في طبقات خاصة بها كالعناصر التي تُكَوِّن الصواريخ الثلاثة. اذهب إلى القائمة: File > Export وضع نوعية الملف PSD Photoshop وتأكّد من تفعيل خيار Write Layers. افتح الملف الذي تم تصديره من برنامج الإليستريتور في برنامج الفوتوشوب ووسِّع حجم العمل قليلًا. لوِّن الخلفية بالأسود وأضف خامة جدار الطوب. حدّد كل طبقات عناصر لافتة النيون ثم اضغط CMD+J لمضاعفتها ثم اضغط CMD+E لدمجها في طبقة واحدة. أعِد تسمية هذه الطبقة 'Off'. أضف سلسلة من أنماط الطبقة لجعل هذه الطبقة تبدو كالأنابيب بدون إضاءة، أي (تراكب لوني) Color Overlay، (توهج داخلي) Inner Glow و (الظلال) Drop Shadow. ضع هذه الطبقة أسفل جميع الطبقات بحيث لن تكون ظاهرة أثناء إضاءة العناصر وستظهر أكثر في العناصر المتحركة حيث ستنطفئ هذه العناصر عدة مرات. شَغِّل طبقة النيون الأولى عبر سلسلة من أنماط الطبقة. أضِف التوهُّج الداخلي لإضافة الأبيض البرّاق إلى المركز، والتوهُّج الخارجي لإطلاق الهالة الملونة، تليها المزيد من الظلال لتراكب التوهُّجات بأحجام مختلفة. كل هذه الأنماط للطبقات تُنتِج تأثيرًا واقعيًّا إلى حد كبير مشابهًا لإضاءة النيون وتأثيرات التوهُّج والتفاعل مع خلفية جدار الطوب. انسخ وألصق نمط الطبقة إلى الطبقة التالية ثم عدّل إعدادات التوهُّج حتى تناسب لون العنصر. وفّر الوقت عبر نسخ نمط الطبقة إلى باقي الطبقات التي تحمل ذات اللون. لافتة النيون ستبدو رائعة عند الانتهاء من وضع كافة أنماط الطبقات ولكننا سنضيف بعض الحركة على التصميم. اجمع عناصر كل صاروخ معًا بحيث سيكون من السهل تشغيل وإيقاف أي صاروخ أثناء الحركة. أظهر لوحة Timeline من قائمة Window ثم أنشئ إطار جديد New Frame Animation. في هذا الإطار الأول ستكون اللافتة متوقفة عن العمل لذلك سنُظهر فقط الطبقة الداكنة مع خلفية جدار الطوب. عدّل المدة الزمنية لهذا الإطار الأول إلى ثانية واحدة. أضف إطار جديد تظهر فيه أول طبقة نيون. لا تضف أي زمن لظهور هذا الإطار وبذلك سيظهر هذا الضوء على الفور. أضف إطارين بعدها بدون مدة زمنية لإضافة الأضواء الحمراء والزرقاء بحيث ستضيئ اللافتة تباعًا بسرعة. في الإطار التالي أظهر طبقة الصاروخ الأول مع جعل المدة الزمنية لعرض هذا الإطار ثانية واحدة. في الإطار التالي أخفِ الصاروخ الأول وأظهر الثاني لإعطاء الانطباع عن حركة الصاروخ. أضف إطار جديد للصاروخ الثالث من أجل إظهاره وإخفاء الصاروخ الثاني. ضاعف هذه الإطارات الثلاثة الأخيرة لتُطيل مدة الحركة. أو بدلًا من ذلك يمكن جعل هذه الطبقات الثلاثة تضيء باستمرار إلى ما لا نهاية بدون وجود الطبقة الأولى للافتة المتوقفة عن العمل. قم بتصدير العمل كملف GIF من خلال Save for Web أو أرسله إلى برنامج تعديل فيديو لتصنع حركة مستمرة أفضل. ترجمة -وبتصرّف- للمقال: How To Create an Animated Neon Sign Effect لصاحبه: Chris Spooner.