Анимация в D3.js строится вокруг механизма переходов — transitions. Переход представляет собой плавное изменение атрибутов, стилей, текста или других свойств DOM-элемента во времени.
Главная особенность D3.js заключается в том, что библиотека не создаёт отдельную систему рендеринга. Все изменения происходят напрямую в SVG, HTML или Canvas через изменение свойств элементов.
Базовый синтаксис анимации:
selection.transition()
После вызова transition() все последующие изменения
становятся анимируемыми.
Пример:
d3.select("rect")
.transition()
.attr("x", 300);
Прямоугольник плавно переместится по оси X к координате
300.
SVG-элементы содержат множество атрибутов:
xycxcyrwidthheightopacitytransformD3.js умеет автоматически интерполировать значения между начальным и конечным состоянием.
svg.select("circle")
.transition()
.duration(1000)
.attr("cx", 500);
Здесь:
duration(1000) задаёт длительность анимации в
миллисекундах;cx плавно изменяется от текущего значения до
500.D3.js способен синхронно изменять множество свойств.
svg.select("rect")
.transition()
.duration(1500)
.attr("x", 400)
.attr("y", 200)
.attr("width", 300)
.attr("height", 120);
Все атрибуты изменяются параллельно.
Изменение размеров особенно важно для визуализаций данных:
svg.selectAll("rect")
.data(data)
.transition()
.duration(800)
.attr("height", d => d.value * 10);
Так строятся анимированные столбчатые диаграммы.
svg.select("circle")
.transition()
.duration(1200)
.attr("r", 80);
D3 автоматически интерполирует числовые значения.
Прозрачность регулируется через атрибут opacity.
svg.select("text")
.transition()
.duration(600)
.attr("opacity", 0);
Элемент плавно исчезнет.
Кроме SVG-атрибутов D3.js умеет анимировать CSS-свойства.
Для этого используется метод style().
svg.select("circle")
.transition()
.duration(1000)
.style("fill", "red");
D3 интерполирует цвета автоматически.
Библиотека поддерживает:
Пример:
svg.select("rect")
.transition()
.style("fill", "#00ff00");
Если начальный цвет был #ff0000, произойдёт плавный
переход между оттенками.
d3.select("div")
.transition()
.style("width", "400px")
.style("background-color", "steelblue");
D3 может анимировать HTML-элементы так же эффективно, как SVG.
.transition()
.duration(2000)
Указывает длительность анимации.
.duration(300)
Используется для интерфейсных эффектов.
.duration(5000)
Подходит для демонстрационных визуализаций.
.transition()
.delay(1000)
Анимация начнётся через одну секунду.
Часто применяется при отображении списков или диаграмм.
svg.selectAll("circle")
.data(data)
.transition()
.delay((d, i) => i * 100)
.attr("cy", 200);
Каждый следующий элемент начинает движение позже предыдущего.
По умолчанию используется easing-функция cubic.
D3 предоставляет большой набор алгоритмов плавности.
Равномерная скорость.
.transition()
.ease(d3.easeLinear)
Эффект отскока.
.transition()
.ease(d3.easeBounce)
Эффект пружины.
.transition()
.ease(d3.easeElastic)
Плавное ускорение и замедление.
.transition()
.ease(d3.easeCircle)
Переходы можно объединять в цепочки.
svg.select("circle")
.transition()
.duration(1000)
.attr("cx", 400)
.transition()
.duration(1000)
.attr("cy", 300);
Сначала выполняется движение по X, затем по Y.
Если требуется одновременное выполнение нескольких переходов:
const t = d3.transition()
.duration(1000);
svg.select("circle")
.transition(t)
.attr("cx", 300);
svg.select("rect")
.transition(t)
.attr("x", 500);
Обе анимации синхронизированы.
SVG-трансформации часто используются вместо изменения координат.
svg.select("rect")
.transition()
.attr("transform", "translate(300, 100)");
svg.select("circle")
.transition()
.attr("transform", "scale(2)");
svg.select("rect")
.transition()
.attr("transform", "rotate(45)");
D3 умеет корректно интерполировать:
Пример:
svg.select("g")
.transition()
.attr("transform", "translate(300,100) rotate(90)");
Библиотека автоматически вычислит промежуточные состояния.
Иногда стандартной интерполяции недостаточно.
svg.select("circle")
.transition()
.attrTween("cx", function() {
return d3.interpolateNumber(0, 500);
});
d3.select("div")
.transition()
.styleTween("background-color", function() {
return d3.interpolateRgb("blue", "orange");
});
D3 предоставляет множество встроенных интерполяторов.
d3.interpolateNumber(0, 100)
d3.interpolateRgb("red", "green")
d3.interpolateString("10px", "100px")
d3.interpolateDate(
new Date(2020, 0, 1),
new Date(2025, 0, 1)
)
svg.select("text")
.transition()
.style("opacity", 0.2);
svg.select("text")
.transition()
.style("font-size", "40px");
Одно из ключевых преимуществ D3 — анимированное обновление визуализации.
svg.selectAll("rect")
.data(newData)
.transition()
.duration(1000)
.attr("height", d => d * 5);
Столбцы плавно изменят размеры при изменении массива данных.
При добавлении новых элементов:
svg.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("r", 0)
.transition()
.duration(800)
.attr("r", 30);
Элементы появляются плавно.
При удалении элементов:
svg.selectAll("circle")
.data(data)
.exit()
.transition()
.duration(500)
.attr("opacity", 0)
.remove();
Объекты сначала исчезают, затем удаляются из DOM.
Переходы часто запускаются через пользовательские действия.
svg.selectAll("circle")
.on("mouseover", function() {
d3.select(this)
.transition()
.attr("r", 50);
});
.on("mouseout", function() {
d3.select(this)
.transition()
.attr("r", 20);
});
d3.select("circle")
.interrupt();
Текущий переход будет остановлен.
D3 поддерживает именование анимаций.
.transition("move")
Это позволяет управлять конкретными переходами независимо друг от друга.
.transition()
.on("start", () => {
console.log("Старт");
});
.transition()
.on("end", () => {
console.log("Завершение");
});
.transition()
.on("interrupt", () => {
console.log("Прервано");
});
path.transition()
.attr("d", newLine);
area.transition()
.attr("d", newArea);
arc.transition()
.attrTween("d", arcTween);
xAxis.transition()
.duration(1000)
.call(d3.axisBottom(scale));
svg.selectAll("rect")
.data(data)
.transition()
.delay((d, i) => i * 50)
.duration(500)
.attr("y", d => height - d)
.attr("height", d => d);
При работе с большими объёмами данных необходимо учитывать нагрузку на браузер.
Минимизировать количество DOM-элементов
SVG плохо масштабируется при десятках тысяч объектов.
Избегать тяжёлых теней и фильтров
CSS-фильтры могут значительно снижать FPS.
Использовать transform вместо x/y
Трансформации обычно быстрее, поскольку активируют GPU-ускорение.
Сокращать количество одновременно анимируемых элементов
Большое число параллельных переходов перегружает поток рендеринга.
selection
.transition()
.attr("x", 100);
selection
.transition()
.attr("x", 300);
Второй переход прервёт первый.
.attr("opacity", 0)
.transition()
.attr("opacity", 1)
Без начального состояния эффект появления может отсутствовать.
.attr("width", "100%")
Некоторые строковые значения D3 не способен корректно интерполировать.
В крупных проектах рекомендуется:
const transition = d3.transition()
.duration(1200)
.ease(d3.easeCubicInOut);
svg.selectAll("circle")
.data(data)
.join("circle")
.attr("cx", d => d.x)
.attr("cy", d => d.y)
.attr("r", 0)
.style("fill", "steelblue")
.transition(transition)
.delay((d, i) => i * 80)
.attr("r", d => d.radius)
.style("fill", "orange");
В этом примере используются: