2012-02-09 3 views
7

Я добавляю узлы графа макет силы, как это:Как добавить составной узел в макете D3?

var node = vis.selectAll("circle.node") 
    .data(nodes) 
    .enter() 
    .append("circle") 
    .attr("class", "node") 
    .attr("cx", function(d) { return d.x; }) 
    .attr("cy", function(d) { return d.y; }) 
    .attr("r", 5) 
    .style("fill", function(d) { return fill(d.group); }) 
    .call(force.drag); 

Есть ли способ, чтобы добавить составные элементы SVG как узлы? То есть Я хочу добавить гиперссылку для каждого круга, так что мне нужно что-то вроде этого:

<a href="whatever.com"><circle ...></circle></a>

ответ

32

Создание элемента «соединения» так просто, как добавление одного или нескольких детей к другому элементу. В вашем примере вы хотите связать свои данные с выбором из <a> элементов и дать каждому <a> одному ребенку <circle>.

Прежде всего, вы должны выбрать "a.node" вместо "circle.node". Это связано с тем, что ваши гиперссылки будут родительскими элементами. Если нет очевидного родительского элемента, и вы просто хотите добавить несколько элементов для каждой точки привязки, используйте <g>, элемент группы SVG.

Затем вы хотите добавить один элемент <a> к каждому узлу в выборе ввода. Это создает ваши гиперссылки. После установки каждого атрибута гиперссылки, вы хотите дать ему <circle> ребенка. Просто: просто позвоните .append("circle").

var node = vis.selectAll("a.node") 
    .data(nodes); 

// The entering selection: create the new <a> elements here. 
// These elements are automatically part of the update selection in "node". 
var nodeEnter = node.enter().append("a") 
    .attr("class", "node") 
    .attr("xlink:href", "http://whatever.com") 
    .call(force.drag); 

// Appends a new <circle> element to each element in nodeEnter. 
nodeEnter.append("circle") 
    .attr("r", 5) 
    .style("fill", function(d) { return fill(d.group); }) 

node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }); 

Напомним, что D3, в первую очередь действует на выборов узлов. Поэтому вызов .append() при вводе выбор означает, что каждый узел в списке получает новый ребенок. Мощный материал!

Еще одна вещь: SVG имеет its own <a> element, что я имел в виду выше. Это отличается от HTML! Как правило, вы используете только SVG-элементы с SVG и HTML с HTML.

Благодаря @mbostock за то, что я уточнил, как именовать переменные.

+0

Хотя я понимаю, почему это работает для создания, разве это не прерывается при обновлении? Поскольку append() объединяет элементы ввода и обновления, не будет ли он добавлять новый круг к старым узлам при каждом вызове обновления? –

+0

Я обновил этот пример, чтобы сделать его более ясным. selection.append не * объединяет * любые выборы, но selection.enter(). append автоматически добавляет элементы к выбору обновлений. В моем исходном примере был vis.selectAll (...) .data (...) .enter(). Append (...). Это только добавляет элементы к выбору ввода, поэтому проблем нет; ключевым моментом является то, что выбор ввода первоначально содержит только заполнители для * новых * элементов, которые еще не существуют. –

10

Ответ Джейсону Дэвису (поскольку stackoverflow ограничивает длину комментариев ответа ...): Отличный ответ. Однако будьте осторожны с цепочкой методов; обычно вы хотите, чтобы node ссылался на внешний элемент привязки, а не на элемент внутреннего круга. Поэтому я рекомендовал бы небольшое изменение:

var node = vis.selectAll("a.node") 
    .data(nodes) 
    .enter().append("a") 
    .attr("class", "node") 
    .attr("xlink:href", "http://whatever.com") 
    .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }) 
    .call(force.drag); 

node.append("circle") 
    .attr("r", 5) 
    .style("fill", function(d) { return fill(d.group); }); 

Я также заменил сй вид круга и Сайте атрибуты с преобразованием на содержащем анкерный элементе; либо один будет работать. Вы можете рассматривать svg: a элементы как svg: g (оба являются контейнерами), что приятно, если вы хотите добавить метки позже.

+0

Спасибо! Я немного изменил первый пример (удалил «var node =', поскольку он лишний и потенциально запутанный, когда вы указываете).Второй пример с переменными согласуется с вашим, хотя я согласен, что преобразование, вероятно, более полезно. –