3

The example looks like this:

a=[1,2,3,4,5];
svg.selectAll("rect").data(a)
a[1]=10;
a[4]=50;
svg.selectAll("rect").data(a)

The second and the fifth elements of a are changed. And I want to ONLY select these two elements and set their color as red. However, I don't know how to do that, or in other words, select these changed element in d3.js. (As I understand, enter() can't do this job). Does anyone have ideas about this?

mdml
  • 22,442
  • 8
  • 58
  • 66
Hanfei Sun
  • 45,281
  • 39
  • 129
  • 237

2 Answers2

7

There might be a better way of doing this:

//update data array
a[4]=50;

//color update elements
svg.selectAll('rect')
    .filter(function(d, i){ return d != a[i]; })
    .style('color', 'red')

//bind updated data
svg.selectAll('rect').data(a)
Adam Pearce
  • 9,243
  • 2
  • 38
  • 35
  • Well, that's a short and sweet alternative. A bit counter-intuitive, to update the style before updating the data, but it should do it. Only problem I can see is if (a) you set a long transition on the style change and (b) you are dealing with live interactive events, then things might get out of order. – AmeliaBR Dec 24 '13 at 19:29
  • Another potential issue: if you have an array of objects instead of primitives and update the data in place - a[0].value = 100; - .datum() of each DOM element will also update and filter won't find any differences. – Adam Pearce Dec 24 '13 at 20:23
6

You need a way to store the old data value so that you can compare it against the new one. Maybe add a custom data attribute like this:

a=[1,2,3,4,5];
svg.selectAll("rect").data(a)
    .attr("data-currentVal", function(d){return d});
a[1]=10;
a[4]=50;
svg.selectAll("rect").data(a)
    .style("fill", function(d) {
       if (d3.select(this).attr("data-currentVal") != d) {return red;}
       else {return black;}
    });

Live example (slightly fancied up so you can see the changes happening):
http://fiddle.jshell.net/5Jm5w/1/

Of course, for the more common example where d is a complex object, you would need to have a way of accessing it's value(s) as a unique string, since the attribute value would always be coerced to string. For example, if you have an (x,y) point, you would need to create a named helper function like dToString = function(d) {return "(" + d.x + "," + d.y + ")";}, and then pass in the name of that function when you set the attribute, and use it again when you compare the old and new.

AmeliaBR
  • 27,344
  • 6
  • 86
  • 119