Ответ 1
В описанной проблеме есть неявное понятие состояния системы. Анимации с состоянием, и поэтому любая их композиция является такой же с состоянием, и, возможно, даже больше.
Один из способов думать о состояниях и действиях - это конечные автоматы.
Прочтите эту статью, объясняющую, как применить FSM для реализации настраиваемой подсказки в JavaScript:
Этот пример может показаться немного запутанным, но он иллюстрирует мысль: конечный автомат заставляет вас думать , какие состояния возможны, какие переходы между ними действительны, когда они должны запускаться и какой код должен выполняться, когда они являются.
Поскольку статья IBM запрещает использование ее примера кода, я рекомендую вам также прочитать статью Бена Наделя, в которой для реализации виджета раскрывающегося меню используется FSM.
Бен пишет:
Я видел, как конечные автоматы могут выполнять большие сложные задачи и разбивать их на более мелкие, гораздо более управляемые состояния. Я даже пытался применить такой подход к привязке и отмене привязки обработчиков событий в JavaScript. Но теперь, когда мне стало удобнее работать с конечными автоматами и, в частности, с переходами между состояниями, я хотел попробовать применить этот подход к виджету связного пользовательского интерфейса.
Вот немного урезанная версия его кода:
var inDefault = {
description: "I am the state in which only the menu header appears.",
setup: function() {
dom.menu.mouseenter(inHover.gotoState);
},
teardown: function() {
dom.menu.unbind("mouseenter");
}
};
var inHover = {
description: "I am the state in which the user has moused-over the header of the menu, but the menu has now shown yet.",
setup: function() {
dom.menu.addClass("menuInHover");
dom.menu.mouseleave(inDefault.gotoState);
dom.header.click(
function(event) {
event.preventDefault();
gotoState(inActive);
}
);
},
teardown: function() {
dom.menu.removeClass("menuInHover");
dom.menu.unbind("mouseleave");
dom.header.unbind("click");
}
};
var inActive = {
description: "I am the state in which the user has clicked on the menu and the menu items have been shown. At this point, menu items can be clicked for fun and profit.",
setup: function() {
dom.menu.addClass("menuInActive");
dom.stage.mousedown(
function(event) {
var target = $(event.target);
if (!target.closest("div.menu").length) {
gotoState(inDefault);
}
}
);
dom.header.click(
function(event) {
event.preventDefault();
gotoState(inHover);
}
);
dom.items.delegate(
"li.item",
"click",
function(event) {
console.log(
"Clicked:",
$.trim($(this).text())
);
}
);
},
teardown: function() {
dom.menu.removeClass("menuInActive");
dom.stage.unbind("mousedown", inDefault.gotoState);
dom.header.unbind("click");
dom.items.undelegate("li.item", "click");
}
};
Обратите внимание, что обработчики событий связаны при входе в состояние и не связаны при выходе из этого состояния.
Самое большое преимущество, которое дают ФСМ в решении этой проблемы, - они делают состояние явным.
Хотя каждая анимация может вносить вклад в состояние охватывающей системы, ваша система никогда не может находиться в двух состояниях одновременно или вообще не находиться в состоянии, а отладка становится почти тривиальной, потому что вы всегда видите, в каком состоянии находится система (или каждая подсистема), учитывая ваш государственный дизайн имеет смысл.
Кроме того, если вы заставляете вас проектировать состояния в явном виде, использование FSM исключает возможность того, что вы не думаете о конкретной комбинации состояний/действий. Не существует "неопределенного поведения", поскольку каждый переход является явным и является частью вашего проекта FSM.
Если вы читали это далеко, вас могут заинтересовать дополнительные анимации (другое введение). Теперь они используются по умолчанию в iOS 8 и защищаются Кевином Даути уже несколько лет.
Это другой подход, при котором, сохраняя состояние системы в состоянии, вы позволяете нескольким (даже противоположным) анимациям быть активными одновременно. Это может дать вам сумасшедшие результаты, но это интересная концепция.
Основная идея состоит в том, чтобы не определять анимацию как нечто, переходящее от абсолютного значения A к абсолютному значению B, и вместо этого определять анимации относительно их окончательного значения (каждая анимация идет от -Delta до 0). Это позволяет легко объединять несколько анимаций, суммируя их относительные значения в каждый момент времени, и избегать всплесков, вызванных сторнированием или отменой:
(источник: ronnqvi.st)
Чтобы увидеть пример аддитивных анимаций, не зависящих от фреймворка, ознакомьтесь с модулем аддитивной анимации alexkuz (demo).
Если вы читали это далеко, вы должны быть действительно заинтересованы в анимации! В настоящее время я заинтригован подходом response-state-stream. Он предлагает выражать анимации как ленивые последовательности состояний. Это открывает множество возможностей, таких как выражение бесконечной анимации, постепенное добавление и удаление преобразований из анимации и т.д.
Если вы хотите прочитать одну статью об анимации, я предлагаю это Мысли об анимации Ченг Лу.