Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
198 views
in Technique[技术] by (71.8m points)

javascript - Compare/Diff new data with previous data on d3.js update

I'd like to represent the difference between the current data set and the previous data set, as calculated by the client.

Imagine I already have three circles, bound to the data [1, 2, 3]. Now I'd like to update the data and do something based on the difference between the new values and the old?

var new_data = [2, 2, 2]; // This is the new data I'd like to compare with the old

svg.selectAll("circle").data(new_data)
    .transition().duration(2000)
.attr("fill", "red") // e.g. I'd like to colour the circles red if the change
                     // is negative, blue if positive, black if no change.
.attr("r", function(d) { return d * 10; });

Here's a JSFiddle with the above code set into an example.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You have two options for saving the old data attached to an element in order to identify changes after a new data join.

The first option, as you suggested, is to use data attributes. This SO Q&A describes that approach. Things to consider:

  • all your data values will get coerced to strings
  • you'll need a separate method call/attribute for each aspect of the data
  • you're manipulating the DOM, so it could slow things down if you've got a lot of elements or lot of data for each
  • the data is now part of the DOM, so can be saved with the image or accessed by other scripts

The second option is to store the data as a Javascript property of the DOM object for the element, in the same way that d3 stores the active data as the __data__ property. I've discussed this method in this forum post.

The general approach:

selection = selection.property(" __oldData__", function(d){ return d; } ); 
                        //store the old data as a property of the node
                    .data(newData, dataKeyFunction);  
                        //over-write the default data property with new data
                        //and store the new data-joined selection in your variable

selection.enter() /*etc*/;  

selection.attr("fill",  function(d) {
                 // Within any d3 callback function,
                 // you can now compare `d` (the new data object)
                 // with `this.__oldData__` (the old data object).
                 // Just remember to check whether `this.__oldData__` exists
                 // to account for the just-entered elements.

                if (this.__oldData__) { //old data exists

                  var dif = d.value - this.__oldData__.value; 
                  return (dif) ? //is dif non-zero?
                         ( (dif > 0)? "blue" : "red" ) :
                         "black" ; 
                } else {
                  return "green"; //value for new data
                }

            });

selection.property("__oldData__", null); 
          //delete the old data once it's no longer needed
          //(not required, but a good idea if it's using up a lot of memory)

You can of course use any name for the old data property, it's just convention to throw a lot of "_" characters around it to avoid messing up any of the browser's native DOM properties.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...