Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

D3 get previous element in .data()

How can I get the value of the previous element of the dataset passed to .data() in d3?

I know in a callback I cant do something like

function(d,i) { console.log(d, i); })

for example, to print the data element and its index to the console. But how can i reference the previous element?

Like d[i-1] or something?

like image 973
brno792 Avatar asked Dec 31 '14 02:12

brno792


2 Answers

You can get the value of previous element like this.

var texts = svg.selectAll("text")
    .data(data)
    .enter()
    .append("text")
    .attr("x",function(d){ return d.x; })
    .attr("y",function(d){ return d.y; })
    .text(function(d){ return d.name; });

texts.attr(...,function(d,i){
         ......
         var prevData = texts.data()[i-1]; //check whether i>0 before this code
         .......
     });

Here is a small example JSFiddle , Mouse over the texts to see the functionality.

like image 169
Gilsha Avatar answered Nov 09 '22 01:11

Gilsha


There is no built in way to do it, but you can achieve it in all kinds of ways, including

Scope:

var data = ['a','b','c','d']
d3.select('.parent').selectAll('.child')
  .data(data)
.enter()
  .append('div')
  .attr('class', 'child')
  .text(function(d,i) {
    return "previous letter is " + data[i-1];
  });

Linking (works even if they're Strings, as in this example):

var data = ['a','b','c','d']
for(var i = 0; i < data.length; i++) { data[i].previous = data[i-1]; }
d3.select('.parent').selectAll('.child')
  .data(data)
...
.text(function(d,i) {
  return "previous letter is " + d.previous
});

Via the parent node (Experimental):

var data = ['a','b','c','d']
d3.select('.parent').selectAll('.child')
  .data(data)
...
.text(function(d,i) {
  var parentData = d3.select(this.parentNode).selectAll('.child').data();
  // NOTE: parentData === data is false, but parentData still deep equals data
  return "previous letter is " + parentData[i-1];
});

Related to the last example, you can even try to find the sibling DOM node immediately preceding this node. Something like

...
.text(function(d,i) {
  var previousChild = d3.select(this.parentNode).select('.child:nth-child(' + i + ')')
  return "previous letter is " + previousChild.datum();
})

but the last two can fail in all kinds of ways, like if the DOM nodes aren't ordered the same as data, or if there are other unrelated DOM nodes within the parent.

like image 8
meetamit Avatar answered Nov 09 '22 01:11

meetamit