score:2

Accepted answer

If a single datum attribute can be checked to see if the bound data has changed, one method would be to track that attribute as a property using selection.property and a custom property such as type. When appending the data you could define the property fairly easily:

  .append("circle")
  .property("type",function(d) { return d.type; });

Then, when updating, you could filter based on which data are matching or not matching the property:

  circles.data(newdata)
    .filter(function(d) {
      return d.type != d3.select(this).property("type")
    })

This filter will return those elements that have changed their type. Now we can re-assign the property to reflect the new type and transition those filtered elements.

The snippet below should demonstrate this, the datum is just a number one or two (represented by blue and orange), and is used to set the property type. Click on the svg to update the data, only those circles which change their datum will temporarily change their radius, while also changing their color to reflect their new datum.

var svg = d3.select("body")
  .append("svg")
  .attr("width",400)
  .attr("height",400);
  
var circles = svg.selectAll("circle")
  .data(data())
  .enter("circle")
  .append("circle")
  .attr("cy",function(d,i) {
    return Math.floor(i/5) * 40 + 20;
  })
  .attr("cx", function(d,i) {
    return i%5 * 40 + 20
  })
  .attr("r", 8)
  .attr("fill",function(d) { return (d) ? "steelblue" : "orange"})
  .property("type",function(d) { return d; });
  
// update on click:
svg.on("click", function() {
  circles.data(data())
    .filter(function(d) {
      return d != d3.select(this).property("type") // filter out unchanged data
    })
    .property("type",function(d) { return d; })  // update to reflect new data
    .transition()
    .attr("r", 20)
    .attr("fill","crimson")
    .duration(500)
    .transition()
    .attr("fill",function(d) { return (d) ? "steelblue" : "orange" })
    .attr("r",8)
    .duration(500);
})
  

function data() {
  var output = [];
  d3.range(20).map(function(d) {
    output.push(Math.round(Math.random()));
  })
  return output;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>


Related Query