Manipulando conjuntos de elementos usando D3.js

Recentemente, tive um olhar mais de perto os exemplos D3.js . Infelizmente, nenhum deles aplica a funcionalidade D3 principal (mudando elementos quando os dados mudam com enter (), update () e exit ()) para conjuntos de elementos. Digamos que eu queira visualizar algo como o gráfico de bolhas , mas quero vinculá-lo aos dados, atualizando todos os elementos que correspondem a um datum (o círculo colorido e o texto) quando o datum muda. Os exemplos atuais renderizam tudo apenas uma vez, mas não oferecem suporte à atualização ou à saída de elementos.

O exemplo do gráfico de bolhas é estático, ele só precisa reagir aos elementos inseridos. Atualizar e sair de elementos não importa. Portanto, atualizar e sair é o que temos que implementar adicionalmente em nosso exemplo para realmente manipular vários elementos para cada datum.

Vamos supor que queremos apenas exibir e atualizar um gráfico de barras simples:

var svg = d3.select("div").append("svg")
.attr("width", 800)
.attr("height", 220);

var data = [0.2,0.4,0.3,0.6];
var node;
var scale = d3.scale.linear()
.domain([0,1])
.range([0,800]);
var color = d3.scale.category20c();

// functions to calculate y positions
var y_rect = function(d,i) { return i*40+16; };
var y_text = function(d,i) { return i*40+30; };

function update(data)
{
// initial select, like all D3 examples, bind it to data
node
= svg.selectAll(".node")
.data(data, String)

// update changing elements with new percentage and bar width
node
.each(function(d, i) {
single
= d3.select(this)
single
.selectAll("rect")
.transition()
.attr("width", scale)
.attr("y", y_rect(d,i))
.duration(300)

single
.selectAll("text")
.transition()
.attr("y", y_text(d,i))
.text(function() { return Math.round(d*100) + "%"; })
.duration(300)
})

// Create entering nodes with the bar (<rect>) and the percentage (<text>)
// grouped in a <g class="node"> element
var enter = node.enter().append("g")
.attr("class", "node")

enter
.append("rect")
.attr("width", scale)
.attr("height", 20)
.attr("x", 20)
.attr("y", y_rect)
.style("fill", color)
.attr("rx", "5px")
.attr("ry", "5px")

enter
.append("text")
.text(function(d,i) { return Math.round(d*100) + "%"; })
.style("fill", "#000")
.attr("x", function(d,i) { return scale(d)-8; })
.attr("y", y_text)
.style("text-anchor", "right")

// Add a fade in transition to all entering elements and child elements
enter
.selectAll("*")
.style("opacity", 0)
.transition()
.duration(300)
.style("opacity", 1)

// fade out and remove all exiting elements
node
.exit()
.style("opacity", 1)
.transition()
.duration(300)
.style("opacity", 0)
.remove()
}

update
(data);

Você pode tentar alterar os dados por meio dos botões no exemplo ao vivo .

Usando os recursos de seleção do D3, não é difícil ter um dado correspondendo a vários elementos renderizados, mas é algo que está faltando nos exemplos até agora.