Анимации в D3.js строятся на механизме переходов — transitions. Именно переходы позволяют плавно изменять атрибуты, стили, размеры, координаты и другие свойства SVG-элементов.
Два ключевых метода управления временем анимации:
.duration() — задаёт продолжительность анимации;.delay() — задаёт задержку перед её запуском.Эти методы используются внутри объекта transition и определяют временное поведение визуализации.
.duration()Метод .duration() задаёт длительность выполнения
анимации в миллисекундах.
selection
.transition()
.duration(1000)
В данном примере анимация будет длиться одну секунду.
<svg width="500" height="120"></svg>
<script>
const svg = d3.select("svg");
svg.append("circle")
.attr("cx", 50)
.attr("cy", 60)
.attr("r", 25)
.attr("fill", "steelblue")
.transition()
.duration(2000)
.attr("cx", 450);
</script>
Что происходит:
cx = 50.D3.js вычисляет промежуточные значения между начальным и конечным состоянием.
Например:
.attr("cx", 450)
При duration 2000 библиотека:
.duration(0)
Изменение произойдёт практически мгновенно.
Однако transition всё равно создаётся, поэтому:
rect.transition()
.duration(1500)
.attr("width", 300)
.attr("height", 120)
.style("fill", "orange");
Все свойства будут изменяться одновременно.
.duration() может принимать функцию.
selection.transition()
.duration((d, i) => i * 500);
Аргументы:
| Аргумент | Значение |
|---|---|
d |
данные элемента |
i |
индекс элемента |
svg.selectAll("circle")
.transition()
.duration((d, i) => 1000 + i * 300)
.attr("cy", 150);
Каждый следующий круг будет двигаться дольше предыдущего.
.delay().delay() задаёт паузу перед стартом анимации.
.transition()
.delay(1000)
Анимация начнётся через одну секунду.
rect.transition()
.delay(2000)
.duration(1000)
.attr("x", 300);
Поведение:
.delay() и .duration()| Метод | Назначение |
|---|---|
.delay() |
ожидание перед запуском |
.duration() |
время выполнения анимации |
.transition()
.delay(1000)
.duration(2000)
Структура времени:
0ms ----- 1000ms ----- 3000ms
старт завершение
D3.js позволяет выстраивать transition-цепочки.
circle.transition()
.duration(1000)
.attr("cx", 200)
.transition()
.duration(1000)
.attr("cy", 150);
Сначала выполнится первое движение, затем второе.
.delay() для каскадных эффектовОдин из самых популярных приёмов в D3.js — последовательное появление элементов.
svg.selectAll("rect")
.transition()
.delay((d, i) => i * 200)
.duration(800)
.attr("height", d => d);
Каждый следующий прямоугольник начнёт анимацию позже предыдущего.
<svg width="600" height="300"></svg>
<script>
const data = [40, 80, 120, 160, 100];
const svg = d3.select("svg");
svg.selectAll("rect")
.data(data)
.enter()
.append("rect")
.attr("x", (d, i) => i * 100 + 30)
.attr("y", 250)
.attr("width", 60)
.attr("height", 0)
.attr("fill", "teal")
.transition()
.delay((d, i) => i * 300)
.duration(1200)
.attr("y", d => 250 - d)
.attr("height", d => d);
</script>
Особенности:
.delay().delay() также поддерживает функцию.
.delay((d, i) => i * 100)
Это особенно полезно при:
.transition()
.delay(500)
.duration(1500)
Часто используется структура:
.delay((d, i) => i * 100)
.duration(1000)
Так создаётся:
selection.transition()
.duration(1000)
.attr("opacity", 1);
Все элементы начинают одновременно.
selection.transition()
.delay((d, i) => i * 150)
.duration(1000)
.attr("opacity", 1);
Элементы запускаются по очереди.
.duration() особенно важен при использовании easing.
.transition()
.duration(2000)
.ease(d3.easeBounce)
Чем длиннее duration:
circle.transition()
.duration(3000)
.ease(d3.easeElastic)
.attr("cx", 400);
Круг будет двигаться с эффектом упругости.
text
.style("opacity", 0)
.transition()
.duration(1000)
.style("opacity", 1);
Элемент плавно появляется.
text.transition()
.duration(800)
.style("opacity", 0);
circle.transition()
.duration(1000)
.attr("cx", 200)
.transition()
.duration(1000)
.attr("cy", 200)
.transition()
.duration(1000)
.attr("r", 50);
Получается трёхэтапная анимация:
Если transitions запускаются отдельно:
circle.transition()
.duration(1000)
.attr("cx", 300);
circle.transition()
.duration(1000)
.attr("cy", 200);
Второй transition может прервать первый.
В D3.js один элемент может иметь ограниченное количество активных переходов с одинаковым именем.
Новый transition:
const t = d3.transition()
.duration(1000);
circle.transition(t)
.attr("cx", 200);
rect.transition(t)
.attr("x", 300);
Оба элемента используют один transition.
Время можно вычислять программно.
.duration(d => d * 100)
Например:
.transition()
.duration(d => Math.abs(d) * 20)
Чем больше изменение, тем длиннее анимация.
.delay(() => Math.random() * 2000)
Подходит для:
Слишком длинные анимации:
Слишком короткие:
150–400 ms
600–1500 ms
2000+ ms
.delay(10000)
Пользователь может решить, что интерфейс завис.
.duration(15000)
Анимация становится утомительной.
Когда десятки элементов запускаются одновременно:
Очень распространённый паттерн:
selection.enter()
.append("circle")
.attr("r", 0)
.transition()
.delay((d, i) => i * 50)
.duration(500)
.attr("r", 20);
Элементы появляются постепенно.
selection
.data(newData)
.transition()
.duration(1000)
.attr("height", d => d.value);
При изменении данных диаграмма плавно перестраивается.
.end()Transition возвращает Promise.
await rect.transition()
.duration(1000)
.attr("x", 300)
.end();
После завершения можно запускать следующий код.
transition.on("start", () => {
console.log("Старт");
});
transition.on("end", () => {
console.log("Завершение");
});
const bars = svg.selectAll("rect");
bars.transition()
.delay((d, i) => i * 200)
.duration(1000)
.attr("height", d => d.value)
.transition()
.duration(500)
.style("fill", "orange");
Этапы:
const t = d3.transition()
.duration(1500)
.delay(500);
svg.selectAll("circle")
.transition(t)
.attr("r", 40);
svg.selectAll("rect")
.transition(t)
.attr("width", 120);
Полезно для синхронизации нескольких групп элементов.
D3.js использует requestAnimationFrame.
Обычно браузер стремится поддерживать:
60 FPS
При длинных и тяжёлых анимациях:
Transition может изменять:
.transition()
.duration(1000)
.attr("transform", "translate(200, 0)");
.transition()
.delay((d, i) => i * 100)
.duration(800)
.attr("transform", (d, i) => {
return `translate(${i * 80}, 0)`;
});
D3.js использует:
Методы .duration() и .delay() управляют
этими таймерами напрямую.
Каждый transition проходит стадии:
Грамотная настройка времени позволяет:
Именно .duration() и .delay() формируют
ритм всей анимационной системы D3.js.