Выделите выбранный узел, его связи и его дочерние элементы в графе, ориентированном на силу D3
Я работаю над силовым ориентированным графом в D3. Я хочу выделить узел наведения курсора мыши, его ссылки и его дочерние узлы, установив все другие узлы и ссылки на более низкую непрозрачность.
в этом примере,http://jsfiddle.net/xReHA/, я могу исчезать все ссылки и узлы, а затем исчезать в подключенных ссылках, но до сих пор я не смог элегантно исчезать в подключенных узлах, которые являются дочерними элементами текущего наведения мыши узел.
Это ключевая функция из кода:
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
ошибка при попытке установить непрозрачность на элемент, который я загрузил из источника.цель. Я подозреваю, что это не правильный способ загрузить этот узел как объект d3, но я не могу найти другой способ загрузить его, не повторяя все узлы снова, чтобы найти те, которые соответствуют цели или источнику ссылки. Чтобы сохранить производительность разумной, я не хочу перебирать все узлы больше, чем необходимый.
Я взял пример выцветания ссылок из http://mbostock.github.com/d3/ex/chord.html:
однако, это не показывает, как изменить узел, подключенный ребенка.
любые хорошие предложения о том, как решить или улучшить это будет яростно upvoted :)
1 ответ:
ошибка заключается в том, что вы выбираете объекты данных (D.source и D.target), а не элементы DOM, связанные с этими объектами данных.
у вас есть подсветка строки, но я бы, вероятно, объединил ваш код в одну итерацию, например:
link.style("opacity", function(o) { return o.source === d || o.target === d ? 1 : opacity; });
выделение соседних узлов сложнее, потому что вам нужно знать соседей для каждого узла. Эту информацию не так легко определить с текущими данными структуры, так как все у вас есть как массив узлов, так и массив ссылок. Забудьте о 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); }); }
(это предполагает, что ссылки неориентированы. Если вы хотите выделить только подключенные вперед соседи, то исключите второй половина операционной.)
более эффективный способ вычисления этого, если вам приходится делать это часто,-это иметь карту или матрицу, которая позволяет постоянно проверять, являются ли 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; });
(вы также можете выбрать специальный случай, когда сама ссылка mouseovered, либо установив a само-ссылка для каждого узла в
linkedByIndex
, или путем тестирования наd
непосредственно при вычислении стиля, или с помощью a !важно css:hover
стиль.)последнее, что я бы изменил в вашем коде,-это использовать непрозрачность заполнения и непрозрачность штриха, а не непрозрачность, потому что они обеспечивают гораздо лучшую производительность.