تنظيم التعقيد باستخدام واجهة برمجة تطبيقات الرسوم المتحركة على الويب
نشرت: 2022-03-10لا يوجد حل وسط بين الانتقالات البسيطة والرسوم المتحركة المعقدة. إما أنك على ما يرام مع ما توفره CSS Transitions and Animations أو أنك تحتاج فجأة إلى كل القوة التي يمكنك الحصول عليها. تمنحك Web Animations API الكثير من الأدوات للعمل مع الرسوم المتحركة. لكن عليك أن تعرف كيف تتعامل معها. ستوجهك هذه المقالة إلى النقاط والتقنيات الرئيسية التي قد تساعدك في التعامل مع الرسوم المتحركة المعقدة مع الحفاظ على المرونة.
قبل الغوص في المقالة ، من الضروري أن تكون على دراية بأساسيات Web Animations API و JavaScript. لتوضيح الأمر وتجنب تشتيت الانتباه عن المشكلة المطروحة ، فإن أمثلة الشفرة المقدمة واضحة. لن يكون هناك أي شيء أكثر تعقيدًا من الوظائف والكائنات. كنقاط دخول لطيفة إلى الرسوم المتحركة نفسها ، أود أن أقترح MDN كمرجع عام ، وسلسلة Daniel C. Wilson الممتازة ، و CSS Animations vs Web Animations API بواسطة أولي ويليامز. لن نتبع طرق تحديد التأثيرات وضبطها لتحقيق النتيجة التي تريدها. تفترض هذه المقالة أنك حددت الرسوم المتحركة الخاصة بك وتحتاج إلى أفكار وتقنيات للتعامل معها.
نبدأ بنظرة عامة على الواجهات وما الغرض منها. ثم سننظر في التوقيت ومستويات التحكم لتحديد ماذا ومتى وإلى متى. بعد ذلك ، سوف نتعلم كيفية التعامل مع العديد من الرسوم المتحركة كأنها واحدة من خلال لفها في كائنات. سيكون ذلك بداية جيدة في طريقك لاستخدام Web Animations API.
واجهات
تمنحنا Web Animations API بُعدًا جديدًا للتحكم. قبل ذلك ، كانت انتقالات CSS والرسوم المتحركة توفر طريقة فعالة لتعريف التأثيرات ولا تزال تتمتع بنقطة تشغيل واحدة . مثل مفتاح الضوء ، كان إما في وضع التشغيل أو الإيقاف. يمكنك اللعب مع وظائف التأخير والتخفيف لإنشاء تأثيرات معقدة للغاية. ومع ذلك ، في مرحلة معينة ، يصبح العمل مرهقًا ويصعب العمل معه.
تعمل واجهة برمجة تطبيقات Web Animations على تحويل نقطة التشغيل الفردية هذه إلى تحكم كامل في التشغيل . يتحول مفتاح الضوء إلى مفتاح باهتة مع شريط تمرير. إذا كنت ترغب في ذلك ، يمكنك تحويله إلى شيء المنزل الذكي بالكامل ، لأنه بالإضافة إلى التحكم في التشغيل ، يمكنك الآن تحديد التأثيرات وتغييرها في وقت التشغيل. يمكنك الآن تكييف التأثيرات مع السياق أو يمكنك تنفيذ محرر رسوم متحركة بمعاينة في الوقت الفعلي.
نبدأ بواجهة الرسوم المتحركة. للحصول على كائن متحرك ، يمكننا استخدام طريقة Element.animate
. أنت تمنحه الإطارات الرئيسية والخيارات ويقوم بتشغيل الرسوم المتحركة على الفور. ما يفعله أيضًا هو إرجاع مثيل كائن Animation
. والغرض منه هو التحكم في التشغيل.
فكر في الأمر على أنه مشغل كاسيت ، إذا كنت تتذكرها. أنا أدرك أن بعض القراء قد لا يكونون على دراية بما هو عليه. من المحتم أن أي محاولة لتطبيق مفاهيم العالم الحقيقي لوصف أشياء حسابية مجردة سوف تنهار بسرعة. لكن دعها تطمئن - أي قارئ لا يعرف متعة إعادة لف شريط بقلم رصاص - أن الأشخاص الذين يعرفون ما هو مشغل الكاسيت سيشوشون أكثر بنهاية هذا المقال.
تخيل صندوق. تحتوي على فتحة حيث يذهب الكاسيت ولديها أزرار للتشغيل والإيقاف والإرجاع. هذا هو مثيل واجهة الرسوم المتحركة - مربع يحتوي على رسوم متحركة محددة ويوفر طرقًا للتفاعل مع تشغيلها. أنت تعطيها شيئًا لتلعبه وتعطيك التحكم مرة أخرى.
تتشابه عناصر التحكم التي تحصل عليها بشكل ملائم مع تلك التي تحصل عليها من عناصر الصوت والفيديو. إنها طرق التشغيل والإيقاف المؤقت ، وخاصية الوقت الحالية . باستخدام عناصر التحكم الثلاثة هذه ، يمكنك إنشاء أي شيء عندما يتعلق الأمر بالتشغيل.
الكاسيت نفسه عبارة عن حزمة تحتوي على مرجع للعنصر المتحرك ، وتعريف التأثيرات ، والخيارات التي تتضمن التوقيت من بين أشياء أخرى. وهذا ما هو KeyframeEffect
. شريط الكاسيت الخاص بنا هو شيء يحتوي على جميع التسجيلات والمعلومات المتعلقة بطول التسجيلات. سأترك الأمر لمخيلة الجمهور الأكبر سنًا لمطابقة كل تلك الخصائص مع مكونات شريط كاسيت مادي. ما سأعرضه لكم هو كيف يبدو في الكود.
عندما تنشئ رسمًا متحركًا من خلال Element.animate
، فأنت تستخدم اختصارًا يقوم بثلاثة أشياء. يقوم بإنشاء مثيل KeyframeEffect
. يضع في مثيل Animation
الجديد. يبدأ تشغيله على الفور.
const animation = element.animate(keyframes, options);
دعنا نقسمها ونرى الكود المكافئ الذي يفعل نفس الشيء.
const animation = new Animation( // (2) new KeyframeEffect(element, keyframes, options) // (1) ); animation.play(); (3)
احصل على الكاسيت (1) ، ضعه في مشغل (2) ، ثم اضغط على زر التشغيل (3).
الهدف من معرفة كيفية عملها وراء الكواليس هو التمكن من فصل تعريف الإطارات الرئيسية وتحديد وقت تشغيلها. عندما يكون لديك الكثير من الرسوم المتحركة لتنسيقها ، فقد يكون من المفيد جمعها جميعًا أولاً حتى تعرف أنها جاهزة للعب. إن توليدهم بسرعة وتأمل أن يبدأوا اللعب في الوقت المناسب ليس شيئًا تتمنى أن تأمل فيه. من السهل جدًا كسر التأثير المطلوب بسحب عدد قليل من الإطارات. في حالة التسلسل الطويل الذي يتراكم فيه السحب ينتج عنه تجربة غير مقنعة على الإطلاق.
توقيت
كما في الكوميديا ، التوقيت هو كل شيء في الرسوم المتحركة. لجعل التأثير يعمل ، لتحقيق شعور معين ، يجب أن تكون قادرًا على ضبط الطريقة التي تتغير بها الخصائص. هناك مستويان من التوقيت يمكنك التحكم فيهما في Web Animations API.
على مستوى الخصائص الفردية ، لدينا offset
. يمنحك الإزاحة التحكم في توقيت خاصية واحدة . بإعطائه قيمة من صفر إلى واحد ، فإنك تحدد متى يبدأ كل تأثير. عند حذفه يساوي صفرًا.
قد تتذكر من @keyframes
في CSS كيف يمكنك استخدام النسب المئوية بدلاً من from
/ to
. هذا ما هو offset
ولكن مقسومة على مائة. قيمة offset
هي جزء من مدة التكرار الفردي .
تتيح لك offset
ترتيب الإطارات الرئيسية داخل KeyframeEffect
. كونك رقمًا معادلاً نسبيًا ، تأكد من أنه بغض النظر عن المدة أو معدل التشغيل ، تبدأ جميع الإطارات الرئيسية في نفس اللحظة بالنسبة لبعضها البعض.
كما ذكرنا سابقًا ، فإن offset
هي جزء من المدة . الآن أريدك أن تتجنب أخطائي وتضييع الوقت في هذا الأمر. من المهم أن نفهم أن مدة الرسوم المتحركة تختلف عن المدة الإجمالية للرسوم المتحركة. عادة ، هم نفس الشيء وهذا ما يمكن أن يربكك ، وهذا ما أربكني بالتأكيد.
المدة هي مقدار الوقت بالمللي ثانية الذي يستغرقه التكرار الواحد للانتهاء. ستكون مساوية للمدة الإجمالية بشكل افتراضي. بمجرد إضافة تأخير أو زيادة عدد التكرارات في مدة الرسوم المتحركة ، تتوقف مدة إخبارك بالرقم الذي تريد معرفته. من المهم أن تفهم كيفية استخدامه لصالحك.
عندما تحتاج إلى تنسيق تشغيل إطار رئيسي ضمن سياق أكبر ، مثل تشغيل الوسائط ، فإنك تحتاج إلى استخدام خيارات التوقيت. المدة الكاملة للرسوم المتحركة من البداية إلى الحدث "المنتهي" بالمعادلة التالية:
delay + (iterations × duration) + end delay
يمكنك رؤيتها أثناء العمل في العرض التوضيحي التالي:
ما يسمح لنا هذا بالقيام به هو محاذاة العديد من الرسوم المتحركة في سياق الوسائط ذات الطول الثابت. الحفاظ على المدة المرغوبة للرسوم المتحركة كما هي ، يمكنك " delayEnd
" مع delay
في البداية والتأخير في النهاية لتضمينها في سياق ذي مدة أطول. إذا كنت تفكر في ذلك فإن delay
بهذا المعنى سيكون بمثابة الإزاحة في الإطارات الرئيسية. فقط تذكر أن التأخير محدد بالمللي ثانية ، لذا قد ترغب في تحويله إلى قيمة نسبية.
خيار توقيت آخر من شأنه أن يساعد في محاذاة الرسوم المتحركة هو iterationStart
. يحدد موضع البداية للتكرار. خذ عرض كرة البلياردو. من خلال ضبط iterationStart
، يمكنك ضبط وضع البداية للكرة والدوران ، على سبيل المثال ، يمكنك ضبطها لبدء القفز من وسط الشاشة وجعل الرقم مستقيمًا في الكاميرا في الإطار الأخير.
السيطرة على عدة كواحد
عندما عملت على محرر الرسوم المتحركة لتطبيق عرض تقديمي ، كان علي ترتيب العديد من الرسوم المتحركة لعنصر واحد في مخطط زمني. كانت محاولتي الأولى هي استخدام offset
لوضع الرسوم المتحركة الخاصة بي في نقطة البداية الصحيحة على جدول زمني.
سرعان ما ثبت أن هذه هي الطريقة الخاطئة لاستخدام offset
. فيما يتعلق بواجهة المستخدم هذه بالتحديد ، فإن الرسوم المتحركة المتحركة على المخطط الزمني تهدف إلى تغيير موضع البداية دون تغيير مدة الرسوم المتحركة. مع offset
، كان هذا يعني أنني بحاجة إلى تغيير العديد من الأشياء ، offset
نفسها وأيضًا تغيير offset
خاصية الإغلاق للتأكد من عدم تغيير المدة. ثبت أن الحل معقد للغاية بحيث لا يمكن فهمه.
المشكلة الثانية جاءت مع خاصية transform
. نظرًا لحقيقة أنه يمكن أن يمثل العديد من التغييرات المميزة لعنصر ما ، فقد يكون من الصعب جعله يفعل ما تريد. في حالة الرغبة في تغيير تلك الخصائص بشكل مستقل عن بعضها البعض ، فقد يصبح الأمر أكثر صعوبة. يؤثر تغيير وظيفة المقياس على جميع الوظائف التي تليها. إليكم سبب حدوث ذلك.
يمكن أن تأخذ خاصية التحويل عدة وظائف في تسلسل كقيمة. اعتمادًا على ترتيب الوظيفة ، تتغير النتيجة. خذ scale
translate
. في بعض الأحيان يكون من السهل تحديد translate
بالنسبة المئوية ، مما يعني نسبة إلى حجم العنصر. لنفترض أنك تريد كرة تقفز بارتفاع ثلاثة أقطار بالضبط. الآن اعتمادًا على المكان الذي تضع فيه وظيفة المقياس - قبل translate
أو بعدها - تتغير النتيجة من ثلاثة ارتفاعات للحجم الأصلي أو المقاس.
إنها سمة مهمة في خاصية transform
. أنت في حاجة إليها لتحقيق تحول معقد تمامًا. ولكن عندما تحتاج إلى أن تكون تلك التحولات متميزة ومستقلة عن التحولات الأخرى لعنصر ما ، فإنها تعترض طريقك.
هناك حالات لا يمكنك فيها وضع كل التأثيرات في خاصية transform
واحدة. يمكن أن تحصل على الكثير بسرعة كبيرة. خاصة إذا كانت الإطارات الرئيسية الخاصة بك تأتي من أماكن مختلفة ، فستحتاج إلى دمج معقد للغاية لسلسلة محولة . بالكاد يمكنك الاعتماد على آلية تلقائية لأن المنطق ليس واضحًا. أيضًا ، قد يكون من الصعب فهم ما يمكن توقعه. لتبسيط هذا والاحتفاظ بالمرونة ، نحتاج إلى فصل هذه القنوات في قنوات مختلفة.
يتمثل أحد الحلول في لف عناصرنا في div
s بحيث يمكن تحريك كل منها على حدة ، على سبيل المثال div للوضع على اللوحة القماشية ، وواحد آخر للقياس ، وثالث للتدوير. بهذه الطريقة ، لا تقوم فقط بتبسيط تعريف الرسوم المتحركة إلى حد كبير ، بل تفتح أيضًا إمكانية تحديد أصول التحويل المختلفة عند الاقتضاء.
قد يبدو أن الأمور تخرج عن نطاق السيطرة بهذه الحيلة. أننا نضرب عدد المشاكل التي واجهتنا من قبل. في الواقع ، عندما وجدت هذه الحيلة لأول مرة ، تجاهلت أنها أكثر من اللازم. اعتقدت أنه يمكنني فقط التأكد من تجميع خاصية transform
الخاصة بي من جميع القطع بالترتيب الصحيح في قطعة واحدة. لقد تطلب الأمر وظيفة transform
أخرى لجعل الأمور معقدة للغاية بحيث لا يمكن إدارتها وبعض الأشياء من المستحيل القيام بها. بدأ مترجم سلسلة خاصية transform
الخاص بي في أخذ المزيد والمزيد من الوقت للحصول على المعلومات الصحيحة لذا فقد استسلمت.
اتضح أن التحكم في تشغيل العديد من الرسوم المتحركة ليس بالأمر الصعب كما يبدو في البداية. تذكر القياس على مشغل أشرطة الكاسيت منذ البداية؟ ماذا لو كنت تستطيع استخدام المشغل الخاص بك الذي يأخذ أي عدد من أشرطة الكاسيت؟ أكثر من ذلك ، يمكنك إضافة العديد من الأزرار على هذا المشغل.
الفرق الوحيد بين استدعاء play
على رسم متحرك واحد ومجموعة من الرسوم المتحركة هو أنك تحتاج إلى التكرار. إليك الكود الذي يمكنك استخدامه لأي طريقة لمثيلات Animation
:
// To play just call play on all of them animations.forEach((animation) => animation.play());
سنستخدم هذا لإنشاء جميع أنواع الوظائف للاعبنا.
لنقم بإنشاء هذا المربع الذي سيحتوي على الرسوم المتحركة ونشغلها. يمكنك إنشاء هذه الصناديق بأي طريقة مناسبة. لتوضيح ذلك ، سأريكم مثالاً على القيام بذلك باستخدام وظيفة وكائن. تأخذ وظيفة createPlayer
مجموعة من الرسوم المتحركة التي سيتم تشغيلها بشكل متزامن. تقوم بإرجاع كائن بطريقة play
الفردي.
function createPlayer(animations) { return Object.freeze({ play: function () { animations.forEach((animation) => animation.play()); } }); }
يكفي أن تعرف أن تبدأ في توسيع الوظائف. دعونا نضيف أساليب وقفة currentTime
.
function createPlayer(animations) { return Object.freeze({ play: function () { animations.forEach((animation) => animation.play()); }, pause: function () { animations.forEach((animation) => animation.pause()); }, currentTime: function (time = 0) { animations.forEach((animation) => animation.currentTime = time); } }); }
createPlayer
بهذه الطرق الثلاث تحكمًا كافيًا لتنظيم أي عدد من الرسوم المتحركة . لكن دعنا ندفعها قليلاً. دعونا نجعلها بحيث لا يمكن للاعبنا فقط أخذ أي عدد من الكاسيت ولكن لاعبين آخرين أيضًا.
كما رأينا سابقًا ، تشبه واجهة Animation
واجهات الوسائط. باستخدام هذا التشابه ، يمكنك وضع كل أنواع الأشياء في المشغل الخاص بك. لاستيعاب ذلك ، دعنا نعدل طريقة currentTime
لجعلها تعمل مع كائنات الرسوم المتحركة والكائنات التي جاءت من createPlayer
.
function currentTime(time = 0) { animations.forEach(function (animation) { if (typeof animation.currentTime === "function") { animation.currentTime(time); } else { animation.currentTime = time; } }); }
المشغل الذي أنشأناه للتو هو ما سيسمح لك بإخفاء تعقيد العديد من عناصر div
لقنوات الرسوم المتحركة أحادية العنصر. يمكن تجميع هذه العناصر في مشهد. ويمكن أن يكون كل مشهد جزءًا من شيء أكبر. كل ما يمكن القيام به بهذه التقنية.
لإثبات عرض التوقيت ، قمت بتقسيم جميع الرسوم المتحركة إلى ثلاثة لاعبين. الأول هو التحكم في تشغيل المعاينة على اليمين. الثاني يجمع بين الرسوم المتحركة القفز لجميع الخطوط العريضة للكرات على اليسار والخطوة في المعاينة.
أخيرًا ، الثالث هو لاعب يجمع حركات الموضع للكرات في الحاوية اليسرى. يسمح هذا اللاعب للكرات بالانتشار في عرض توضيحي مستمر للرسوم المتحركة بمعدل 60 إطارًا في الثانية.
خاتمة
تعرض لنا واجهات الويب مثل Web Animations API أشياء معينة كانت تفعلها المتصفحات طوال الوقت. تعرف المتصفحات كيفية العرض السريع عن طريق تمرير العمل إلى وحدة معالجة الرسومات. مع Web Animations API ، يمكننا التحكم فيه. على الرغم من أن هذه السيطرة قد تبدو غريبة بعض الشيء أو مربكة ، إلا أن هذا لا يعني أن استخدامها يجب أن يكون مربكًا أيضًا. من خلال فهم التوقيت والتحكم في التشغيل ، لديك أدوات لترويض واجهة برمجة التطبيقات هذه وفقًا لاحتياجاتك. يجب أن تكون قادرًا على تحديد مدى تعقيدها.
قراءة متعمقة
- "تقنيات عملية في تصميم الرسوم المتحركة" سارة دراسنر
- "التصميم مع حركة مخفضة لحساسية الحركة ،" فال هيد
- "واجهة مستخدم صوتية بديلة لمساعدي الصوت" أوتوماتياس بيورا
- "تصميم تلميحات أفضل لواجهات مستخدم الهاتف المحمول" ، إريك أوليف