Ball Pit Graph

by eprouver

HTML

<!-- Perfect square indication of event types -->
<!-- event types by color fitted into a square of circles -->
<!-- used for an infographic -->
<button onclick="newGraph()">New Ball Pit</button>
<div id="holder"></div>

CSS

svg{
    width: 100%;
    height: auto;
    max-height: 80vh;
}

JavaScript

function newGraph(){
document.getElementById('holder').innerHTML = '';
var data = [];
var num = 1 + ~~(Math.random() * 50);

//Generate fake data;
for(var i = 0; i < num; i++){
 data.push({
    "description": {
      "subject": {
        "_id": ~~(Math.random() * 3) + 1
      }
    },
    "startdate": ~~(Math.random() * 1000) 
  });
}

var width = 500,
height = 500;

function nextSquare(n){
    s = Math.sqrt(n);

    while(s % 1 != 0){
        n += 1;
        s = Math.sqrt(n);
    }
    
    return Math.sqrt(n)
}

var svg = d3.select('#holder').append("svg")
  .attr("width", width)
  .attr('viewBox', '0 0 ' + width + ' ' + height);

var sides = nextSquare(data.length);
var colors = d3.scale.category10().domain(0, 19);

data = data.sort(function(b,a){
    return b.startdate - a.startdate;
});

var y = d3.scale.ordinal()
  .domain(d3.range(0, sides))
  .rangeRoundBands([0, height]);

var x = d3.scale.ordinal()
  .domain(d3.range(0, sides))
  .rangeRoundBands([0, width]);

var band =  Math.abs(x.rangeBand()) / 2;

var i = 0;
for(var r = 0; r < sides; r++){
    for(var c = 0; c < sides; c++){
        svg.append('circle').datum(data[i] || {})
        .attr('class', 'dot')
        .attr('r', band - 5)
        .attr('cy', band + (2 * band * r) )
        .attr('cx', band + (2 * band * c) )
        .attr('fill', '#ccc')
        .transition()
        .duration(300)
        .delay(i*100)
        .attr('fill', function(d){
            if(!d.description){
                return '#ccc'
            }
            
            return colors(d.description.subject._id);
        })
        i++;
    }
}
}

newGraph();