שליטה בהפעלה של אנימציות באינטרנט ב-Chrome 39

מוקדם יותר השנה, הוסיפה ל-Chrome 36 את השיטה element.animate כחלק מהמפרט הרחב יותר של Web Animations. כך אפשר ליצור אנימציות יעילות ונפוצות שנכתבות באופן אימפרטיבי – ומאפשר למפתחים ליצור את האנימציות והמעברים שלהם בשיטה המתאימה להם ביותר.

תזכורת מהירה: כך אפשר ליצור אנימציה של ענן במסך, עם קריאה חוזרת בסיום:

var player = cloud.animate([
    {transform: 'translateX(' + start + 'px)'},
    {transform: 'translateX(' + end + 'px)'}
], 5000);
player.onfinish = function() {
    console.info('Cloud moved across the screen!');
    startRaining(cloud);
};

הפעולה הזו פשוטה מאוד, ומומלץ להשתמש בה כחלק מכלי העבודה שלכם כשאתם יוצרים אנימציות או מעברים באופן גורף. עם זאת, ב-Chrome 39 נוספו תכונות של בקרת הפעלה לאובייקט AnimationPlayer שמוחזר על ידי element.animate. בעבר, אחרי שיצרתם אנימציה, הייתם יכולים רק להפעיל את cancel() או להאזין לאירוע הסיום.

התוספות האלה להפעלה פותחות את האפשרויות של Web Animations – הופכות את האנימציות לכלי למטרות כלליות, במקום לכלי שמוגדר מראש לגבי מעברים, כלומר: אנימציות 'קבועות' או מוגדרות מראש.

השהיה, חזרה אחורה או שינוי מהירות ההפעלה

נתחיל בעדכון הדוגמה שלמעלה כדי להשהות את האנימציה אם לוחצים על הענן:

cloud.addEventListener('mousedown', function() {
    player.pause();
});

אפשר גם לשנות את המאפיין playbackRate:

function changeWindSpeed() {
    player.playbackRate *= (Math.random() * 2.0);
}

אפשר גם להפעיל את השיטה reverse(), שבערך זהה להפיכת הערך הנוכחי של playbackRate (כפל ב-1-). עם זאת, יש כמה מקרים מיוחדים:

  • אם השינוי שנגרם על ידי השיטה reverse() יגרום לכך שהאנימציה שפועלת תסתיים בפועל, גם ה-currentTime יופיע הפוך – לדוגמה, אם הופכים אנימציה חדשה לגמרי, כל האנימציה תופעל לאחור.

  • אם הנגן מושהה, האנימציה תתחיל לפעול.

בחירת מיקום בנגן

עכשיו אפשר לשנות את currentTime של AnimationPlayer בזמן ההפעלה של אנימציה. בדרך כלל, הערך הזה יגדל עם הזמן (או יקטן, אם הערך של playbackRate הוא שלילי). כך יכול להיות שיהיה אפשר לשלוט במיקום של אנימציה באופן חיצוני, אולי באמצעות אינטראקציה של משתמש. התהליך הזה נקרא בדרך כלל ניקוי.

לדוגמה, אם דף ה-HTML מייצג את השמיים, ואתם רוצים שתנועת גרירה תשנה את המיקום של ענן שפועל כרגע, תוכלו להוסיף למסמך כמה פונקציות טיפול באירועים:

var startEvent, startEventTime;
document.addEventListener('touchstart', function(event) {
    startEvent = event;
    startEventTime = players.currentTime;
    player.pause();
});
document.addEventListener('touchmove', function(event) {
    if (!startEvent) return;
    var delta = startEvent.touches[0].screenX -
        event.changedTouches[0].screenX;
    player.currentTime = startEventTime + delta;
});

כשתגררו את הסמן מעל המסמך, הערך של currentTime ישתנה בהתאם למרחק מהאירוע המקורי. אפשר גם להמשיך את הפעלת האנימציה כשהמחווה מסתיימת:

document.addEventListener('touchend', function(event) {
    startEvent = null;
    player.play();
});

אפשר גם לשלב את התכונה הזו עם התנהגות היפוך, בהתאם למיקום שבו העכבר הרים מהדף (דגמה משולבת).

במקום לנקות את AnimationPlayer בתגובה לאינטראקציה של משתמש, אפשר להשתמש ב-currentTime שלו גם כדי להציג התקדמות או סטטוס: לדוגמה, כדי להציג את סטטוס ההורדה.

היתרון של AnimationPlayer הוא שאפשר להגדיר ערך ולאפשר להטמעה המקורית הבסיסית לדאוג לתצוגה החזותית של ההתקדמות. במקרה של הורדה, ניתן להגדיר את משך האנימציה לפי גודל ההורדה הכולל, ואת currentTime לפי הגודל שהורדתם כרגע (דוגמה).

תנועות ומעברים בממשק המשתמש

פלטפורמות לנייד הן כבר זמן רב תחום של תנועות נפוצות: גרירה, החלקה, זריקה וכו'. בדרך כלל יש לתנועות האלה נושא משותף: רכיב בממשק המשתמש שאפשר לגרור, כמו 'משיכה לרענון' בתצוגת רשימה או סרגל צד שנשלף מהצד ימין של המסך.

בעזרת אנימציות אינטרנט, קל מאוד ליצור אפקט דומה כאן באינטרנט – במחשב או בנייד. לדוגמה, כשתנועה שמפעילה את currentTime מסתיימת:

var steps = [ /* animation steps */ ];
var duration = 1000;
var player = target.animate(steps, duration);
player.pause();
configureStartMoveListeners(player);

var setpoints = [0, 500, 1000];
document.addEventListener('touchend', function(event) {
    var srcTime = player.currentTime;
    var dstTime = findNearest(setpoints, srcTime);
    var driftDuration = dstTime - srcTime;

    if (!driftDuration) {
    runCallback(dstTime);
    return;
    }

    var driftPlayer = target.animate(steps, {
    duration: duration,
    iterationStart: Math.min(srcTime, dstTime) / duration,
    iterations: Math.abs(driftDuration) / duration,
    playbackRate: Math.sign(driftDuration)
    });
    driftPlayer.onfinish = function() { runCallback(dstTime); };
    player.currentTime = dstTime;
});

כך נוצרת אנימציה נוספת שמבצעת 'הזזה'. האנימציה הזו פועלת מהמקום שבו התנועה הושלמה ועד ליעד הידוע והתקין שלנו.

הסיבה לכך היא שלאנימציות יש עדיפות על סמך סדר היצירה שלהן: במקרה הזה, driftPlayer תקבל עדיפות על פני player. כשהפעולה driftPlayer תסתיים, היא וההשפעות שלה ייעלמו. עם זאת, השעה הסופית שלו תהיה זהה ל-currentTime של הנגן הבסיסי, כך שממשק המשתמש יישאר עקבי.

לסיום, אם אתם אוהבים גורים, יש אפליקציית אינטרנט לדוגמה שבה אפשר לראות את התנועות האלה. הקוד מתאים לניידים ומשתמש ב-polyfill לצורך תאימות לאחור, אז כדאי לנסות לטעון אותו בנייד.

קדימה, element.animate

השיטה element.animate נהדרת כרגע – בין אם אתם משתמשים בה ליצירת אנימציות פשוטות או מנצלים את הערך המוחזר AnimationPlayer בדרכים אחרות.

שתי התכונות האלה נתמכות באופן מלא גם בדפדפנים מודרניים אחרים באמצעות polyfill קל. ה-polyfill הזה מבצע גם זיהוי תכונות, כך שככל שספקי הדפדפנים יטמיעו את המפרט, התכונה הזו רק תהיה מהירה ויעילה יותר עם הזמן.

גם המפרט של Web Animations ימשיך להתפתח. אם אתם רוצים להתנסות בתכונות העתידיות, הן זמינות עכשיו גם בpolyfill מפורט יותר: web-animations-next.