Выделите выбранный node, его ссылки и его дочерние элементы в графе D3

Я работаю над графиком, ориентированным на силу в D3. Я хочу выделить mouseover'd node, его ссылки и его дочерние узлы, установив все остальные узлы и ссылки на меньшую непрозрачность.

В этом примере http://jsfiddle.net/xReHA/, я могу погасить все ссылки, а узлы затем исчезают в связанных ссылках, но, до сих пор я не мог элегантно исчезать в связанных узлах, являющихся дочерними элементами текущего mouseover'd node.

Это ключевая функция из кода:

function fade(opacity) {
    return function(d, i) {
        //fade all elements
        svg.selectAll("circle, line").style("opacity", opacity);

        var associated_links = svg.selectAll("line").filter(function(d) {
            return d.source.index == i || d.target.index == i;
        }).each(function(dLink, iLink) {
            //unfade links and nodes connected to the current node
            d3.select(this).style("opacity", 1);
            //THE FOLLOWING CAUSES: Uncaught TypeError: Cannot call method 'setProperty' of undefined
            d3.select(dLink.source).style("opacity", 1);
            d3.select(dLink.target).style("opacity", 1);
        });
    };
}

Я получаю ошибку Uncaught TypeError: Cannot call method 'setProperty' of undefined, когда пытаюсь установить непрозрачность элемента, загруженного из source.target. Я подозреваю, что это неправильный способ загрузить этот node в качестве объекта d3, но я не могу найти другой способ загрузить его, не повторяя все узлы, чтобы найти те, которые соответствуют цели или источнику ссылки. Чтобы поддерживать работоспособность, я не хочу перебирать все узлы больше, чем необходимо.

Я взял пример затухания ссылок из http://mbostock.github.com/d3/ex/chord.html:

enter image description here

Однако это не показывает, как изменить связанные дочерние узлы.

Любые хорошие предложения о том, как решить или улучшить это, будут яростно поддержаны:)

Ответ 1

Ошибка заключается в том, что вы выбираете объекты данных (d.source и d.target), а не элементы DOM, связанные с этими объектами данных.

У вас есть подсветка строки, но я бы, вероятно, объединил ваш код в одну итерацию, например:

 link.style("opacity", function(o) {
   return o.source === d || o.target === d ? 1 : opacity;
 });

Выделение соседних узлов сложнее, потому что вам нужно знать соседей для каждого node. Эта информация не так легко определить с помощью ваших текущих структур данных, так как все, что у вас есть в виде массива узлов и массива ссылок. Забудьте DOM на секунду и спросите себя, как вы определяете, являются ли два узла a и b соседями?

function neighboring(a, b) {
  // ???
}

Дорогой способ сделать это - перебрать все ссылки и посмотреть, есть ли связь, соединяющая a и b:

function neighboring(a, b) {
  return links.some(function(d) {
    return (d.source === a && d.target === b)
        || (d.source === b && d.target === a);
  });
}

(Предполагается, что ссылки неориентированы. Если вы хотите выделить только соседей с прямым соединением, то удалите вторую половину элемента OR.)

Более эффективный способ вычислить это, если вам нужно делать это часто, - это иметь карту или матрицу, которая позволяет искать постоянный поиск для проверки того, являются ли a и b соседями. Например:

var linkedByIndex = {};
links.forEach(function(d) {
  linkedByIndex[d.source.index + "," + d.target.index] = 1;
});

Теперь вы можете сказать:

function neighboring(a, b) {
  return linkedByIndex[a.index + "," + b.index];
}

И, таким образом, вы можете теперь перебирать узлы и правильно обновлять их непрозрачность:

node.style("opacity", function(o) {
  return neighboring(d, o) ? 1 : opacity;
});

(Вы также можете воспользоваться специальным случаем самой привязанной по ссылке ссылкой, либо установив собственную ссылку для каждого node в linkedByIndex, либо путем тестирования для d непосредственно при вычислении стиля или с помощью a! important css :hover.)

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