ZoomTransform в D3.js представляет собой центральный механизм управления состоянием масштабирования и перемещения сцены при работе с интерактивной визуализацией. В основе лежит объект трансформации, инкапсулирующий три ключевых параметра: коэффициент масштабирования и смещения по осям координат. Именно этот объект становится единым источником истины для всех операций zoom и pan.
Объект трансформации в D3.js обычно имеет вид:
Эта тройка параметров формирует аффинное преобразование, которое применяется к сцене:
x' = k * x + tx
y' = k * y + ty
где tx и ty соответствуют значениям x и y в ZoomTransform.
Фактически ZoomTransform описывает, как текущая система координат отображается на экранную плоскость. Это позволяет отделить данные от их визуального представления и управлять отображением независимо от источника данных.
Поведение zoom в D3.js задаётся через:
const zoom = d3.zoom()
.scaleExtent([1, 10])
.translateExtent([[0, 0], [width, height]])
.on("zoom", handleZoom);
При взаимодействии пользователя с графикой (колёсико мыши, drag) D3 автоматически создаёт новый объект ZoomTransform и передаёт его в событие:
function handleZoom(event) {
const transform = event.transform;
}
event.transform всегда содержит актуальное состояние
масштаба и смещения.
Состояние трансформации можно получить напрямую из DOM-элемента:
const transform = d3.zoomTransform(svg.node());
Этот вызов возвращает последний применённый ZoomTransform, связанный с указанным элементом. Это особенно важно при синхронизации нескольких визуальных компонентов или при внешнем управлении масштабированием.
ZoomTransform часто применяется к группе элементов
<g>:
g.attr("transform", event.transform);
D3 автоматически преобразует объект трансформации в строку:
translate(x, y) scale(k)
Порядок операций имеет значение: сначала масштабирование, затем перенос.
ZoomTransform является частным случаем матричного преобразования 3×3:
| k 0 x |
| 0 k y |
| 0 0 1 |
Такое представление позволяет комбинировать несколько трансформаций через умножение матриц, что критично при последовательных zoom и pan операциях.
Одной из ключевых возможностей ZoomTransform является обратное преобразование координат:
const [x, y] = transform.invert([px, py]);
Это позволяет переводить экранные координаты обратно в систему данных. Данный механизм используется при:
Инверсия выполняется через обратную матрицу трансформации:
x_data = (x_screen - tx) / k
y_data = (y_screen - ty) / k
ZoomTransform тесно интегрируется с осями D3:
const newXScale = transform.rescaleX(xScale);
const newYScale = transform.rescaleY(yScale);
Эти функции создают новые шкалы, адаптированные под текущий zoom. Это критично для корректного отображения осей:
Начальным состоянием трансформации является:
d3.zoomIdentity
Он эквивалентен:
k = 1
x = 0
y = 0
Это нейтральная трансформация, не изменяющая координатную систему. Любая новая трансформация строится относительно этого состояния через методы:
transform.scale(k)
transform.translate(x, y)
ZoomTransform можно задавать вручную:
svg.call(zoom.transform, d3.zoomIdentity.translate(100, 50).scale(2));
В этом случае D3 пересчитывает внутреннее состояние и генерирует соответствующее событие zoom, синхронизируя визуализацию.
ZoomTransform работает совместно с ограничениями:
Эти параметры влияют на допустимые значения x, y и k, предотвращая выход визуализации за заданные границы.
Последовательные действия пользователя формируют цепочку трансформаций:
T_total = T3 × T2 × T1
Каждое новое событие zoom создаёт новую матрицу, умножаемую на предыдущую. D3 хранит итоговый ZoomTransform как результат накопления всех операций.
При обработке событий важно учитывать текущую трансформацию:
svg.on("click", (event) => {
const transform = d3.zoomTransform(svg.node());
const coords = transform.invert(d3.pointer(event));
});
Это позволяет всегда работать с актуальной системой координат, независимо от масштаба и смещения.
ZoomTransform используется для согласования нескольких графических слоёв:
Все элементы получают одинаковый transform:
layer1.attr("transform", transform);
layer2.attr("transform", transform);
Это обеспечивает единое поведение всей сцены при взаимодействии пользователя.
В случае использования Canvas трансформация применяется не через атрибут transform, а через контекст:
context.save();
context.translate(transform.x, transform.y);
context.scale(transform.k, transform.k);
ZoomTransform в этом случае остаётся универсальным контейнером состояния, независимым от способа рендеринга.
При скачкообразных изменениях масштаба D3 интерполирует состояние между предыдущим и новым ZoomTransform, обеспечивая плавность перехода. Это особенно заметно при:
ZoomTransform может применяться к точкам напрямую:
const p = transform.apply([x, y]);
Это прямое преобразование данных в экранные координаты без привязки к DOM. Используется при вычислении геометрии объектов и построении кастомных визуальных элементов.
Порядок scale и translate критически важен. В D3 используется соглашение:
Это означает, что смещение также масштабируется при изменении k:
x_screen = k * x_data + x_offset
При изменении масштаба без корректировки x и y визуальное положение может “прыгать”, если не учитывать эту зависимость.
ZoomTransform фактически заменяет необходимость ручного хранения:
Вместо этого используется единый объект, который полностью описывает состояние визуального пространства в любой момент времени.