Последовательные анимации

Paper.js предоставляет мощный механизм работы с анимациями через view.onFrame и объекты Item, такие как Path, Shape и Group. Последовательные анимации строятся на основе пошагового изменения свойств объектов с учётом времени, состояний и событий.


Использование view.onFrame для анимации

Ключевым элементом создания последовательных анимаций является обработчик кадра:

view.onFr ame = function(event) {
    // event.delta — время с предыдущего кадра
    // event.count — номер текущего кадра
};
  • event.delta позволяет масштабировать движение по времени, делая анимацию независимой от частоты кадров.
  • event.count удобно использовать для запуска действий через определённое количество кадров.

Пример плавного перемещения объекта:

var circle = new Path.Circle(new Point(50, 50), 30);
circle.fillColor = 'red';

view.onFr ame = function(event) {
    circle.position.x += 2 * event.delta;
};

Последовательные шаги анимации

Последовательные анимации строятся через состояния объектов. Один из подходов — хранить массив функций или состояний и выполнять их по очереди:

var states = [
    function() { circle.position.x += 2; },
    function() { circle.position.y += 2; },
    function() { circle.scale(1.05); }
];

var currentState = 0;

view.onFr ame = function(event) {
    if(currentState < states.length) {
        states[currentState]();
        if(states[currentState].done) {
            currentState++;
        }
    }
};

Каждое состояние может содержать собственную логику завершения, например, проверку позиции объекта или размера.


Tween-анимации

Paper.js не имеет встроенного tween-движка, но последовательные анимации можно реализовать через интерполяцию свойств. Простейший пример:

function animateProperty(item, property, to, duration) {
    var start = item[property];
    var delta = to - start;
    var time = 0;

    return function(event) {
        time += event.delta;
        var t = Math.min(time / duration, 1);
        item[property] = start + delta * t;
        if(t >= 1) this.done = true;
    };
}

var moveRight = animateProperty(circle.position, 'x', 300, 2); // 2 секунды
var grow = animateProperty(circle, 'scaling', 2, 1); // увеличение в 2 раза за 1 секунду

var animations = [moveRight, grow];
var current = 0;

view.onFr ame = function(event) {
    if(current < animations.length) {
        animations[current](event);
        if(animations[current].done) current++;
    }
};
  • Интерполяция позволяет плавно изменять позицию, масштаб, поворот, цвет.
  • Использование функции-фабрики animateProperty упрощает создание повторяющихся последовательностей.

Анимации с группами объектов

Для сложных сцен удобно объединять объекты в Group:

var group = new Group([circle, new Path.Rectangle(new Point(100, 100), new Size(50, 50))]);
group.position = new Point(0, 0);

var moveGroup = animateProperty(group.position, 'x', 400, 3);
  • Группы позволяют анимировать несколько элементов одновременно.
  • Внутренние объекты сохраняют относительные позиции.

Использование событий и задержек

Для точной последовательности можно добавлять задержки между шагами:

var timeline = [
    { action: moveRight, delay: 0 },
    { action: grow, delay: 1 } // задержка 1 секунда после предыдущей
];

var timer = 0;
var step = 0;

view.onFr ame = function(event) {
    if(step < timeline.length) {
        timer += event.delta;
        if(timer >= timeline[step].delay) {
            timeline[step].action(event);
            if(timeline[step].action.done) {
                step++;
                timer = 0;
            }
        }
    }
};
  • Задержки позволяют синхронизировать несколько анимаций.
  • Можно комбинировать с циклическими анимациями или событиями мыши/клавиатуры.

Плавное управление скоростью анимации

Для более естественных движений используют easing-функции:

function easeInOut(t) {
    return t < 0.5 ? 2*t*t : -1 + (4 - 2*t)*t;
}

function animateWithEase(item, property, to, duration) {
    var start = item[property];
    var delta = to - start;
    var time = 0;

    return function(event) {
        time += event.delta;
        var t = Math.min(time / duration, 1);
        item[property] = start + delta * easeInOut(t);
        if(t >= 1) this.done = true;
    };
}
  • Использование easing делает последовательные анимации более естественными и привлекательными.
  • Можно комбинировать несколько easing для разных свойств одновременно.

Комбинирование анимаций и взаимодействия

Последовательные анимации легко объединять с интерактивностью:

circle.onMouseD own = function(event) {
    animations.push(animateProperty(circle.position, 'y', circle.position.y + 100, 1));
};
  • Каждое событие может запускать новую последовательность анимаций.
  • Поддержка onMouseMove, onMouseUp, onKeyDown позволяет создавать динамичные и отзывчивые сцены.

Рекомендации по структуре кода

  1. Разделять анимации на отдельные функции для читаемости.
  2. Использовать массивы шагов или timeline, чтобы легко добавлять новые эффекты.
  3. Применять группы объектов, когда несколько элементов должны двигаться синхронно.
  4. Контролировать завершение анимации через done флаг или проверку состояния.
  5. Использовать easing-функции для плавности и натуральности движения.

Эти техники позволяют создавать сложные последовательные анимации, управлять временем, синхронизацией и интерактивностью в Paper.js, сохраняя код структурированным и масштабируемым.