Анимация на основе JavaScript с использованием Anime.js, часть 4: обратные вызовы, прокси и SVG

22 января 2018

После завершения первых трех учебников серии вы должны теперь быть очень довольны множеством функций Anime.js. В первом учебном пособии показано, как выбрать целевые элементы. Во втором учебном пособии вы узнали о различных типах параметров, которые могут быть использованы для точного контроля за задержкой и продолжительностью анимаций разных элементов. В третьем учебнике основное внимание уделялось изучению того, как иметь больший контроль над значениями одного свойства во время анимации.

В этом учебном пособии вы узнаете о различных обратных вызовах, которые могут быть использованы для выполнения функции на основе прогресса анимации. Почти каждый пример предыдущих руководств использовал свойства CSS, чтобы продемонстрировать, как работают разные методы и параметры. Возможно, это дало вам представление о том, что библиотека больше подходит для анимации свойств CSS. На этот раз у нас будет раздел, посвященный созданию интересных анимаций, связанных с SVG, в Anime.js.

Обратные вызовы

Как я упоминал во введении, вы можете использовать обратные вызовы для выполнения функций на основе прогресса анимации. Существует четыре разных обратных вызова: запуск, запуск, обновление и завершение. Каждая функция обратного вызова запускается в определенное время, и каждый принимает объект анимации в качестве своего аргумента.

Функция begin () вызывается, когда анимация начинается на самом деле. Это означает, что если анимация имеет задержку в 800 мс, begin () будет вызван только после того, как эта задержка закончится. Вы можете проверить, начала ли анимацию или нет использование анимацииName.begin, которая вернет true или false соответственно.

Обратный вызов запуска может использоваться для выполнения функции в каждом кадре после начала анимации. Если вы хотите выполнить функцию в каждом кадре с самого начала анимации независимо от ее задержки, вместо этого вы должны использовать обратный вызов обновления.

Полный обратный вызов аналогичен началу, за исключением того факта, что он вызывается после завершения анимации. Как и вы, вы можете использовать анимациюName.complete, чтобы проверить, закончилась ли анимация или нет.

Вы уже видели в первом учебнике, как использовать обратный вызов обновления во время анимации числовых значений объекта JavaScript. В этом уроке мы изменим этот пример и посмотрим, как использовать все эти обратные вызовы вместе, чтобы предоставить пользователю дополнительную информацию.

var filesScaed = { count: 0, infected: 0 };
var scanCount = document.querySelector(".scan-count");
var infected = document.querySelector(".infected-count");
var scaing = anime({
  targets: filesScaed,
  autoplay: false,
  count: 100,
  infected: 8,
  delay: 1000,
  duration: 2000,
  easing: "linear",
  round: 1,
  update: function(anim) {
    if (anim.currentTime < 1000) {
      document.querySelector(".update-cb").ierHTML = "Creating an Index...";
    }
  },
  begin: function() {
    document.querySelector(".begin-cb").ierHTML = "Starting the Scan...";
  },
  run: function() {
    scanCount.ierHTML = filesScaed.count;
    infected.ierHTML = filesScaed.infected;
  },
  complete: function() {
    document.querySelector(".complete-cb").ierHTML = "Scan Complete...";
  }
});

Я намеренно добавил некоторую задержку в этой анимации, чтобы мы могли заметить разницу в сроках выполнения различных обратных вызовов. Обратный вызов обновления начинает выполнять свою функцию сразу же после запуска экземпляра анимации.

Фактическая анимация начинает воспроизводиться через 1000 мс, и именно тогда, когда функция начала показывает свое сообщение «Запуск сканирования...» пользователю. Функция запуска также запускается в одно и то же время и обновляет числовые значения объекта после каждого кадра. После завершения анимации полный обратный вызов показывает пользователю сообщение «Scan Complete...».

Функции исключения

Функции Easing могут использоваться для управления тем, как значение свойства переходит из его начального значения в его окончательное значение. Эти функции ослабления могут быть заданы с помощью параметра easing, который может принимать строки, а также настраиваемые координаты кривой Bézier (в виде массива).

Существует 31 функция встроенных функций ослабления. Один из них линейный, а другой 30 состоит из десяти различных вариантов easeIn, easeOut и easeInOut. Существуют три упругих уравнения ослабления, называемые easeInElastic, easeOutElastic и easeInOutElastic. Вы можете контролировать их эластичность с использованием параметра эластичности. Значение эластичности может быть где угодно между 0 и 1000.

Уравнения EaseIn ускоряют изменение значения свойства, начиная с нуля. Это означает, что изменение стоимости будет медленным в начале и очень быстро в конце. Скорость изменения равна нулю в начале и максимуме в конце. Уравнения EaseOut замедляют изменение значения свойства, начиная с максимального изменения скорости.

Это означает, что изменение стоимости будет очень быстрым в начале и очень медленным в конце. Уравнения EaseInOut ускоряют изменение скорости в начале и замедляют ее в конце. Это означает, что скорость изменения будет медленной как в начале, так и в конце, и она будет самой быстрой в середине анимации. Следующая демонстрация показывает разницу в скорости изменения для каждой из этих функций ослабления.

Вы также можете добавить свои собственные функции облегчения во встроенный список с помощью anime.easings. Вот пример создания пользовательских функций ослабления.

anime.easings['tanCube'] = function(t) {
  return Math.pow(Math.tan(t*Math.PI/4), 3);
}
anime.easings['tanSqr'] = function(t) {
  return Math.pow(Math.tan(t*Math.PI/4), 2);
}
var tanCubeSequence = anime({
  targets: '.tan-cube',
  translateX: '75vw',
  duration: 2000,
  easing: 'tanCube',
  autoplay: false
});
var tanSqrSequence = anime({
  targets: '.tan-sqr',
  translateX: '75vw',
  duration: 2000,
  easing: 'tanSqr',
  autoplay: false
});

анимации на основе SVG

Все анимации, связанные с движением, которые мы создали до сих пор, перемещали целевые элементы по прямым линиям. В Anime.js также возможно перемещение элемента по сложному пути SVG с большим количеством кривых. Вы можете контролировать положение и угол анимационных элементов на пути. Чтобы переместить элемент в координату x пути, вы можете использовать path (x). Аналогично, элемент можно перемещать в соответствии с координатой y пути, используя путь (y).

Если путь не является прямой линией, он почти всегда будет составлять угол относительно горизонтальной базовой линии. Если вы вращаете любой некруглый элемент, он будет более естественным, если элемент следует за углом пути. Вы можете сделать это, установив свойство rotate равным path ('angle'). Вот код, который анимирует четыре элемента с разными значениями ослабления вдоль пути SVG.

var path = anime.path('path');
var easings = ['linear', 'easeInCubic', 'easeOutCubic', 'easeInOutCubic'];
var motionPath = anime({
  targets: '.square',
  translateX: path('x'),
  translateY: path('y'),
  rotate: path('angle'),
  easing: function (el, i) {
    return easings[i];
  },
  duration: 10000,
  loop: true
});

Вы можете увидеть в следующей демонстрации, что красный квадрат с легкостью. Ускорение InCubic является самым медленным в начале и самым быстрым в конце. Точно так же оранжевый квадрат с easeOutCubic является самым быстрым в начале и самым медленным в конце.

Вы также можете анимировать морфинг различных SVG-фигур друг с другом с помощью Anime.js. Единственное условие состоит в том, что обе формы должны иметь одинаковое количество точек. Это означает, что вы можете только преобразовывать треугольники в другие треугольники и четырехугольники в другие четырехугольники. Попытка изменить между неравным числом точек полигона приведет к резкому изменению формы. Вот пример морфинга треугольной формы.

var morphing = anime({
  targets: 'polygon',
  points: [
    { value: '143 31 21 196 286 223' },
    { value: '243 31 21 196 286 223' },
    { value: '243 31 121 196 286 223' },
    { value: '243 31 121 196 386 223' },
    { value: '543 31 121 196 386 223' }
  ],
  easing: 'linear',
  duration: 4000,
  direction: 'alternate',
  loop: true
});

Еще один интересный эффект, который вы можете создать с помощью SVG, - это рисование линии. Все, что вам нужно сделать, это предоставить Anime.js путь, который вы хотите использовать для рисования линии, и другие параметры, которые контролируют его продолжительность, задержку или ослабление. В следующей демонстрации я использовал полный обратный вызов, чтобы заполнить линейный рисунок значка привязки шрифта Awesome с желтым цветом.

var lineDrawing = anime({
  targets: 'path',
  strokeDashoffset: [anime.setDashoffset, 0],
  easing: 'easeInOutCubic',
  duration: 4000,
  complete: function(anim) {
    document.querySelector('path').setAttribute("fill", "yellow");
  }
});

Сочетая знания всех понятий, которые вы изучили до сих пор, вы можете создавать более сложные чертежи линий с гораздо лучшим контролем над тем, как они рисуются. Вот пример, в котором я написал свое собственное имя с помощью SVG.

var letterTime = 2000;
var lineDrawing = anime({
  targets: "path",
  strokeDashoffset: [anime.setDashoffset, 0],
  easing: "easeInOutCubic",
  duration: letterTime,
  delay: function(el, i) {
    return letterTime * i;
  },
  begin: function(anim) {
    var letters = document.querySelectorAll("path"), i;
    for (i = 0; i < letters.length; ++i) {
      letters[i].setAttribute("stroke", "black");
      letters[i].setAttribute("fill", "none");
    }
  },
  update: function(anim) {
    if (anim.currentTime >= letterTime) {
      document.querySelector(".letter-m").setAttribute("fill", "#e91e63");
    }
    if (anim.currentTime >= 2 * letterTime) {
      document.querySelector(".letter-o").setAttribute("fill", "#3F51B5");
    }
    if (anim.currentTime >= 3 * letterTime) {
      document.querySelector(".letter-n").setAttribute("fill", "#8BC34A");
    }
    if (anim.currentTime >= 4 * letterTime) {
      document.querySelector(".letter-t").setAttribute("fill", "#FF5722");
    }
    if (anim.currentTime >= 5 * letterTime) {
      document.querySelector(".letter-y").setAttribute("fill", "#795548");
    }
  },
  autoplay: false
});

Я начинаю с назначения значения 2000 переменной letterTime. Это время, когда я хочу, чтобы Anime.js принимал, когда он рисует каждую букву моего имени. Свойство delay использует параметр индекса на основе функций для установки соответствующего значения задержки с помощью переменной letterTime.

Индекс первой буквы «M» равен нулю, поэтому Anime.js начинает рисовать его немедленно. Письмо «O» имеет задержку в 2000 мс, потому что это количество времени, которое требуется, чтобы полностью нарисовать букву «М».

Внутри начального обратного вызова я установил значение штриха всех букв в черный, а их значения заполнения равны ни одному. Таким образом, мы можем очистить все значения цвета, применяемые в обратном вызове обновления, чтобы буквы могли вернуться в исходное состояние при запуске в нескольких циклах. Попробуйте нажать кнопку «Написать имя» в следующей демонстрации, чтобы увидеть код в действии.

Заключительные мысли

В этом уроке вы узнали о различных функциях обратного вызова, которые можно использовать для выполнения таких задач, как обновление DOM или изменение значения атрибута на основе хода анимации. Вы также узнали о различных функциях ослабления и о том, как создать свой собственный. В заключительном разделе учебника основное внимание уделялось созданию анимаций на основе SVG.

После завершения всех четырех уроков серии вы должны обладать достаточными знаниями о Anime.js, чтобы создать интересные эффекты для вашего следующего проекта. Если у вас есть какие-либо вопросы, связанные с этим учебным курсом, пожалуйста, дайте мне знать в комментариях.