Нажав кнопку node в d3 с кнопки за пределами svg

Я создал граф, ориентированный на силу, используя D3 и отображающий идентификатор узлов в нормальном div. Мне нужно выделить node, идентификатор которого был нажат в div. Я искал идентификатор node и, используя обычный javascript, пытался щелкнуть его, но он не работает.

Ответ 1

В общем случае, если пользователь взаимодействует с элементом A, как вы выбираете (а затем модифицируете) связанные элементы B? Существует много способов достижения этого, но здесь есть три общих подхода.

Вариант 1. Для взаимно-однозначных сопоставлений выберите по id.

Если каждый элемент в имеет ровно один соответствующий элемент в B, вы можете выбрать связанный элемент B по id, например d3.select("#foo"), чтобы выбрать <div id="foo">.

Этот подход требует установки идентификатора для каждого элемента в B с помощью selection.attr. Это проще всего, если ваши данные имеют встроенный уникальный идентификатор, например d.name или d.id:

b.attr("id", function(d) { return d.id; });

Затем, чтобы включить щелчок по элементам A, чтобы изменить цвет заливки соответствующего элемента в B, используйте selection.on, чтобы зарегистрировать нажмите кнопку прослушивания, а затем выберите по id:

a.on("click", function(d) {
  d3.select("#" + d.id).style("fill", "red");
});

Идентификаторы должны быть уникальными и valid. Например, идентификатор должен начинаться с буквы, а не числа, и не может содержать пробелов. Если ваши данные еще не имеют уникального идентификатора, вы можете создать его из индекса, например

b.attr("id", function(d, i) { return "b-" + i; });

И позже, предполагая, что элементы A находятся в одном порядке,

a.on("click", function(d, i) {
  d3.select("#b-" + i).style("fill", "red");
});

Вы также можете перебирать свой массив данных для создания уникального идентификатора.

Вариант 2. Для сопоставлений "один ко многим" выберите по классу.

Чтобы выбрать элементы класса "foo", такие как <div class="foo">, скажем d3.selectAll(".foo"). Используйте этот подход, если какой-либо элемент из A соответствует нескольким элементам в B. Например, если у вас есть ориентированный на силу график, показывающий отношения между учениками, вы можете покрасить узлы на основе каждого студенческого года, а затем использовать легенду для переключения видимость каждого года.

Как и в предыдущем подходе, вы можете использовать selection.attr, чтобы установить атрибут "class". В этом случае атрибут класса не является уникальным, поэтому он может исходить из свойства d.type в данных:

b.attr("class", function(d) { return d.type; })

Если у вас несколько легенд для разных категориальных атрибутов данных, вы также можете быть более конкретными и префикс имени класса. Чтобы продолжить пример студенческого года:

b.attr("class", function(d) { return "year-" + d.year; })

Установка атрибута класса заменит все ранее установленные классы, поэтому, если вы хотите применить несколько классов к элементам, вам нужно объединить их вместе с пробелом при установке атрибута class.

Затем, чтобы включить щелчок по элементам A, чтобы изменить цвет заливки соответствующих элементов в B, используйте selection.on, чтобы зарегистрировать прослушиватель кликов, а затем выберите по классу:

a.on("click", function(d) {
  d3.selectAll("." + d.type).style("fill", "red");
});

Обратите внимание, что здесь мы используем selectAll вместо select; потому что мы хотим выбрать все соответствующие элементы, а не только первую. Опять же, вам нужно убедиться, что атрибут класса valid.

Вариант 3. Для всего остального выберите и фильтруйте данные.

Предыдущие два подхода генерируют идентификаторы и классы, чтобы браузер мог индексировать элементы в B для эффективного выбора. Для небольшого количества элементов или когда требуются более общие методы выбора, вы можете опустить указание атрибутов "id" или "class" и просто выбрать вручную selection.filter.

Позвольте назвать привязку, связанную с каждым элементом в da, и привязку к каждому элементу в B db. Теперь все, что нам нужно сделать, это определить выражение, которое возвращает true, когда da соответствует db. Например, если мы хотим отфильтровать по типу:

a.on("click", function(da) {
  b.filter(function(db) { return da.type == db.type; }).style("fill", "red");
});

Предпочтительны первые два варианта, но иногда удобна ручная фильтрация, например, когда у вас есть ползунок диапазона и вы хотите фильтровать на основе количественной переменной.

Ответ 2

Когда вы пишете:

... и с помощью обычного javascript попытался щелкнуть его...

что вы имеете в виду?

Если вы имеете в виду, что вы написали код вроде:

mySVGElement.click();

то это ваша проблема. Не все элементы DOM имеют метод click(), такой как <button> или <input…>. Вместо этого вам нужно имитировать и запустить собственное событие click:

function simulateClick(elementToClick){
  var evt = document.createEvent("MouseEvents");
  evt.initMouseEvent("click", true, true, window,
    0, 0, 0, 0, 0, false, false, false, false, 0, null);
  var canceled = !elementToClick.dispatchEvent(evt);
  return canceled; //Indicate if `preventDefault` was called during handling
}