Lc0rE
Lc0rE

Reputation: 2346

D3.js: create a fixed number of elements

I'm trying to create a fixed number of elements using D3, taking this value from a json file. This means that, if the given json data is n, I want to print n elements into my svg.

This is my code:

    // Defining the size of the svg element
    var w = 1000;
    var h = 50;

    // Defining the dataset
    d3.json("people.json", function(dataset) {

    // Iterating through the json
    for(var i=0; i<dataset.length; i++) {

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

            // Iterating through the value
            for(var j=0; j<dataset[i].age; j++) {

                svg.selectAll("rect")
                        .data(dataset)
                        .enter()
                        .append("rect")
                        .attr("width", 20)
                        .attr("height", 20)
                        .attr("x", function(d, j) { return j * 55 })
            }

        }

    });

This is my json example file (totally random values for ages):

  [{
    "name": "Larry",
    "last": "Page",
    "country": "USA",
    "city": "Mountain View",
    "age": 32
  }, {
    "name": "Sergey",
    "last": "Bean",
    "country": "USA",
    "city": "Mountain View",
    "age": 37
  }, {
    "name": "Bill",
    "last": "Gates",
    "country": "USA",
    "city": "Seattle",
    "age": 60
  }, {
    "name": "Mark",
    "last": "Zuckemberg",
    "country": "USA",
    "city": "Palo Alto",
    "age": 35
  }, {
    "name": "Sergio",
    "last": "Marchionne",
    "country": "Italy",
    "city": "Milan",
    "age": 65
  }
]

My expected result should be something like that ( [-] --> svg rectangle)

  1. Larry Page: [-][-][-][-][-][-][-][-][-][-][-][-][-][-][-][-][-][-][-][-][-][-][-][-][-][-][-][-][-][-][-][-]

  2. Sergey Bean: [-][-][-][-][-][-][-][-][-][-][-][-][-][-][-][-][-][-][-][-][-][-][-][-][-][-][-][-][-][-][-][-][-][-][-]

and so on...

Can you help me to understand what I'm doing wrong?

Thanks!

Upvotes: 3

Views: 1130

Answers (2)

ksav
ksav

Reputation: 20821

You could do it like this:

var dataset = [{
  "name": "Larry",
  "last": "Page",
  "country": "USA",
  "city": "Mountain View",
  "age": 32
}, {
  "name": "Sergey",
  "last": "Bean",
  "country": "USA",
  "city": "Mountain View",
  "age": 37
}, {
  "name": "Bill",
  "last": "Gates",
  "country": "USA",
  "city": "Seattle",
  "age": 60
}, {
  "name": "Mark",
  "last": "Zuckemberg",
  "country": "USA",
  "city": "Palo Alto",
  "age": 35
}, {
  "name": "Sergio",
  "last": "Marchionne",
  "country": "Italy",
  "city": "Milan",
  "age": 65
}];

// Defining the size of the svg element
var w = 1000;
var h = 500;
var itemH = 10;
var itemW = 3;
var padding = 2;


// Append svg element
var svg = d3.select("body").append("svg")
  .attr("width", w)
  .attr("height", h);

// Append groups for each in dataset
var group = svg.selectAll("g")
  .data(dataset)
  .enter()
  .append('g');

// Each group
group.each(function(d, i) {

  //console.log(d);
  var age = d.age;

  var self = d3.select(this);

  // Transform the group in Y
  self.attr('transform', function() {
    return 'translate(0,' + (i * (itemH + padding)) + ')';
  });

  // Append rect forEach from 0 - age
  d3.range(age).forEach(function(i) {
    //console.log(i);

    self.append('rect')
      .attr('width', itemW)
      .attr('height', itemH)
      .attr('x', function() {
        return i * (itemW + padding);
      });
  });
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>


<body></body>

Upvotes: 1

altocumulus
altocumulus

Reputation: 21578

The pure D3 approach would require no for-loops at all (like mentioned by Gerardo Furtado in his comment) and will be something along the following lines:

d3.select("body").selectAll("svg")
  .data(dataset)              // Bind the entire dataset
  .enter().append("svg")      // Append one svg per object in dataset
  .selectAll("rect")
    .data(function(d) {       // Inherit data from svg by mapping of objects
      // Create an array of number of required rects
      return d3.range(d.age).map(function(d) { return d*15; }); 
    })
    .enter().append("rect")   // Append rects per svg
      .attr("x", function(d) {
        return d;             // Position was calculated in above mapping in data()
      });

This is all you need to draw the graph you are after (attributes left aside). For a full example setting all values have a look at the following example:

var dataset =   [{
    "name": "Larry",
    "last": "Page",
    "country": "USA",
    "city": "Mountain View",
    "age": 32
  }, {
    "name": "Sergey",
    "last": "Bean",
    "country": "USA",
    "city": "Mountain View",
    "age": 37
  }, {
    "name": "Bill",
    "last": "Gates",
    "country": "USA",
    "city": "Seattle",
    "age": 60
  }, {
    "name": "Mark",
    "last": "Zuckemberg",
    "country": "USA",
    "city": "Palo Alto",
    "age": 35
  }, {
    "name": "Sergio",
    "last": "Marchionne",
    "country": "Italy",
    "city": "Milan",
    "age": 65
  }
];

// Defining the size of the svg element
var w = 1000;
var h = 50;

// Defining the dataset
//d3.json("people.json", function(dataset) {

  d3.select("body")
    .selectAll("svg")
    .data(dataset)              // Bind the entire dataset
    .enter().append("svg")      // Append one svg per object in dataset
      .attr("width", w)
      .attr("height", h)
    .selectAll("rect")
      .data(function(d) {       // Inherit data from svg by mapping of objects
        // Create an array of number of required rects
        return d3.range(d.age).map(function(d) { return d*15; }); 
      })
      .enter().append("rect")   // Append rects per svg
        .attr("width", 10)
        .attr("height",10)
        .attr("x", function(d) {
          return d;             // Position was calculated in above mapping in data()
        });


//});
<script src="https://d3js.org/d3.v4.js"></script>

Upvotes: 2

Related Questions