В обработчиках событий D3.js доступ к связанным данным определяется тем, как именно выполнялось связывание данных с DOM-элементами и каким способом вызывается callback-функция. Каждый обработчик получает контекст элемента, исходное событие браузера и, при стандартном использовании, объект данных, привязанный к этому элементу через механизм data binding.
В D3.js контекст this внутри обработчика событий
указывает на DOM-элемент, к которому был привязан слушатель. Это
ключевой механизм, позволяющий связывать визуальное представление с
данными без необходимости внешних структур хранения.
При стандартной регистрации обработчика:
selection.on("click", function(event, d) {
// this — DOM-элемент
// d — данные, связанные с элементом
});
В актуальных версиях D3 (v6 и выше) обработчик получает два аргумента:
event — объект события браузераd — данные, ассоциированные с элементомТакой порядок аргументов фиксирован и заменяет устаревшую модель с
глобальным d3.event.
Основной источник данных внутри обработчика — результат привязки
через data():
const circles = svg.selectAll("circle")
.data(dataset)
.enter()
.append("circle")
.on("click", function(event, d) {
// d соответствует элементу dataset
});
Каждый элемент selection получает свой объект данных. Это значение
d является наиболее прямым способом доступа к информации
внутри обработчика.
Важно учитывать, что данные не извлекаются из DOM автоматически — они сохраняются внутри внутренней структуры D3 и доступны через API выборки.
Если необходимо получить данные без аргумента d,
используется d3.select(this).datum():
.on("click", function(event) {
const data = d3.select(this).datum();
});
Этот подход полезен в случаях, когда:
dМетод datum() возвращает объект, ассоциированный с
элементом, либо undefined, если привязка отсутствует.
При работе с событиями важно различать два уровня DOM-элементов:
event.target — элемент, на котором фактически произошло
событиеevent.currentTarget — элемент, на который навешан
обработчикВ D3 это различие становится критичным при вложенной структуре элементов:
.on("click", function(event, d) {
const directTarget = event.target;
const boundElement = event.currentTarget;
});
currentTarget соответствует this, тогда как
target может указывать на внутренние элементы SVG
(например, path внутри g).
Для интерактивной графики часто требуется доступ к координатам
указателя. D3 предоставляет утилиту d3.pointer, которая
учитывает трансформации SVG и контейнеров:
.on("mousemove", function(event, d) {
const [x, y] = d3.pointer(event, this);
});
Передача this важна, так как координаты вычисляются
относительно конкретного элемента-контейнера.
Если this не передавать, координаты будут рассчитаны
относительно текущего контейнера по умолчанию, что может приводить к
смещениям при вложенных группах <g>.
Хотя D3 предоставляет прямой доступ к данным через d,
иногда используются дополнительные уровни абстракции:
const scale = d3.scaleLinear().domain([0, 100]);
selection.on("click", function(event, d) {
const value = scale(d.value);
});
В таких случаях обработчик оперирует уже преобразованными данными, но
исходный объект d остаётся доступным для полной контекстной
информации.
D3 не ограничивает модификацию объекта d. Изменения
отражаются в состоянии визуализации при последующем обновлении:
.on("click", function(event, d) {
d.active = !d.active;
d.value += 10;
});
Такой подход характерен для паттерна mutable data binding, при котором визуальное состояние синхронизируется через повторный вызов join/update.
При необходимости обновления интерфейса после изменения данных используется повторный вызов selection:
svg.selectAll("circle")
.data(dataset)
.attr("r", d => d.value);
В иерархических структурах SVG часто требуется доступ к данным родительского узла. Это реализуется через повторный выбор DOM-узла:
.on("click", function(event, d) {
const parentData = d3.select(this.parentNode).datum();
});
Такая техника используется при работе с деревьями, диаграммами вложенности и группировками.
В момент создания элементов через enter() данные уже
присутствуют, но доступ к this может отличаться в
зависимости от стадии построения DOM:
const items = svg.selectAll("g")
.data(data)
.enter()
.append("g")
.on("click", function(event, d) {
// d доступен сразу после append
});
Важно учитывать, что обработчики, назначенные до завершения рендера, сохраняют корректную связь с данными, поскольку D3 фиксирует binding на этапе создания элементов.
При использовании d3-dispatch данные могут передаваться
через пользовательские события:
const dispatch = d3.dispatch("custom");
dispatch.on("custom", function(event, d) {
// доступ к d через dispatch
});
Это позволяет разделять источник данных и обработчик, сохраняя единый формат передачи состояния.
Частая проблема возникает при использовании стрелочных функций:
selection.on("click", (event, d) => {
// this не привязан к элементу
});
Стрелочные функции не создают собственного this, поэтому
доступ к DOM-элементу через this становится невозможным. В
таких случаях необходимо использовать event.currentTarget
или отказаться от стрелочной функции.
Ещё один источник ошибок — попытка доступа к d вне
D3-контекста:
function handler() {
console.log(d); // d не определён
}
Переменная d существует только в сигнатуре обработчика
D3.
D3 строится на принципе связки данных и DOM без промежуточного состояния. В обработчиках событий это выражается в прямом доступе к объекту данных и возможности немедленно использовать его для изменения визуального представления:
.on("click", function(event, d) {
d.selected = true;
d3.select(this)
.classed("active", true);
});
Состояние элемента фактически дублируется между объектом данных и атрибутами DOM, что требует согласованного подхода при обновлении.
При запуске анимаций внутри событий данные остаются доступны в замыкании:
.on("click", function(event, d) {
d3.select(this)
.transition()
.duration(500)
.attr("opacity", 0.5);
});
Объект d может использоваться для параметризации
анимации, включая длительность, задержку и целевые значения.
Хотя основной доступ к данным осуществляется через d,
иногда требуется индекс элемента в выборке:
selection.on("click", function(event, d, i) {
// i — индекс элемента
});
Индекс полезен при работе с массивами фиксированной структуры, где положение элемента имеет семантическое значение.
Внутренняя модель обработки событий в D3 можно представить как трёхуровневую структуру:
event — информация о взаимодействии пользователяthis / currentTarget — DOM-узел, связанный с
обработчикомd — объект данных, привязанный через data joinКомбинация этих трёх источников формирует полный контекст, необходимый для управления визуализацией без внешнего состояния и дополнительных хранилищ.