2

The following code works for D3 V3, but not D3 V4, how to rectify it?

<!DOCTYPE html>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.2.8/d3.min.js" type="text/JavaScript"></script>
<!--script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.9/d3.js" type="text/JavaScript"></script-->
<body></body>
<script>
var dataset = [[1,3,3,5,6,7],[3,5,8,3,2,6],[9,0,6,3,6,3],[3,4,4,5,6,8],[3,4,5,2,1,8]];

var svg = d3.select("body")
        .append("svg")
        .attr("width", 500)
        .attr("height", 500);


svg.append("g")
        .selectAll("g")
        .data(dataset)
        .enter()
        .append("g") //removing
        .selectAll("text") // these
        .data( function(d,i,j) { return d; } ) //lines
        .enter() //text displays normally
        .append("text")
        .text( function(d,i,j) { return d; } )
        .attr("x", function(d,i,j) { console.log(j);return (i * 20) + 40; })
        .attr("y", function(d,i,j) { return (j * 20) + 40; })
        .attr("font-family", "sans-serif")
        .attr("font-size", "20px")


</script>
william007
  • 17,375
  • 25
  • 118
  • 194

1 Answers1

4

The explanation here is simple, and it was the subject of this answer of mine: the third argument has changed from D3 v3 to D3 v4.

This is the problematic line:

.attr("y", function(d,i,j) { return (j * 20) + 40; })
//the 3rd argum. -------^            ^--- using the 3rd argument

In D3 v3, the third argument is the index of the parent group. However, in v4, the third argument is the current group. The changelog is clear:

The arguments passed to callback functions has changed slightly in 4.0 to be more consistent. The standard arguments are the element’s datum (d), the element’s index (i), and the element’s group (nodes), with this as the element.

But there is a way to achieve what you want in v4! The same changelog says:

The slight exception to this convention is selection.data, which is evaluated for each group rather than each element; it is passed the group’s parent datum (d), the group index (i), and the selection’s parents (parents), with this as the group’s parent. (emphasis mine)

Thus, we can use the data() method to get the group's index.

Here, I'm using a local variable...

var local = d3.local();

... to get the index inside data():

.data( function(d,i) { 
    local.set(this, i);
    return d;
})

Then, using it to set the y position:

.attr("y", function(d) {
    return (local.get(this) * 20) + 40;
})

Here is your code with that change:

var dataset = [
  [1, 3, 3, 5, 6, 7],
  [3, 5, 8, 3, 2, 6],
  [9, 0, 6, 3, 6, 3],
  [3, 4, 4, 5, 6, 8],
  [3, 4, 5, 2, 1, 8]
];

var svg = d3.select("body")
  .append("svg")
  .attr("width", 500)
  .attr("height", 500);

var local = d3.local();

svg.append("g")
  .selectAll("g")
  .data(dataset)
  .enter()
  .append("g")
  .selectAll("text")
  .data(function(d, i) {
    local.set(this, i)
    return d;
  })
  .enter()
  .append("text")
  .text(function(d, i, j) {
    return d;
  })
  .attr("x", function(d, i, j) {
    return (i * 20) + 40;
  })
  .attr("y", function(d) {
    return (local.get(this) * 20) + 40;
  })
  .attr("font-family", "sans-serif")
  .attr("font-size", "20px")
<script src="https://d3js.org/d3.v4.min.js"></script>
Gerardo Furtado
  • 100,839
  • 9
  • 121
  • 171
  • @GerardoFurtado Thanks! I have another follow up question: https://stackoverflow.com/questions/46630697/text-and-rectangle-not-align Hope you could take a look too! – william007 Oct 08 '17 at 11:42
  • @william007 I just looked at it and the solution is simple. However, it's a good behaviour here at S.O. acknowledging an answer you received (this one) before asking for further help. – Gerardo Furtado Oct 08 '17 at 11:54
  • @GerardoFurtado Done it :) – william007 Oct 08 '17 at 11:55