2012-01-05 7 views
66

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

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

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

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. Я подозреваю, что это неправильный способ загрузить этот узел в качестве объекта d3, но я не могу найти другой способ загрузить его без повторения всех узлов, чтобы найти те, которые соответствуют цели или источнику ссылки. Чтобы поддерживать работоспособность, я не хочу перебирать все узлы больше, чем необходимо.

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

enter image description here

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

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

ответ

86

Ошибка в том, что вы выбираете объекты данных (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) { 
    // ??? 
} 

дорогой способ сделать это, чтобы перебрать все ссылки и посмотреть, если есть ссылка, которая соединяет и б:.

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; 
}); 

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

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

+1

Это отлично работает @mbostock, большое вам спасибо: D Я обновил [jsfiddle] (http://jsfiddle.net/xReHA/1/) с вашим решением. –

+1

Удалено ненужное обращение к стилю по ссылке: http://jsfiddle.net/xReHA/2/ –

+0

Майк, это решение было просто красиво. Просто говорю'. – Vivek