D3

I wrote a small demo in D3 to visualize table data for a client. I'm not sure whether I got sales, but ended up using a tool that I haven't used for some while.

D3 doesn't do much for you to start with. It doesn't do much of assumptions of what you're going to draw, and mostly it's just bunch of pieces you can use to build a graph out of. I like that.

I'm annoyed that documentation doesn't show whether there's a way to calculate the margins needed by the graph axes instead of having to guess their size.

Another annoyance is that when you search for how to respond to resize with d3, people will promote using css code meant for "responsive SVG" that scales the content but doesn't allow you to readjust for aspect ratio changes.

The respond to window.resize isn't exactly what you want for responding to svg element resize, but there appears to be a polyfill that solves this.

I don't have much of other opinions or bother to write observations at the moment, so I decided to instead write a small interactive toy to embed it along this page, with its source code.

Source code:

var toy = d3.select('#circle_toy');

circles = []

// Phyllotaxis pattern, this is actually new to me, and I'm
// going to read more about it eventually. I copied it
// from an another demo so I would get the circles
// initially apart without collision checking.
var golden_ratio = Math.sqrt(5)/2 - 0.5;
var golden_angle = golden_ratio * (2 * Math.PI);

for (var i = 0, n = 40; i < n; ++i) {
  var ratio = (i+10) / (n+10);
  var angle = i * golden_angle;
  var spiral_rad = ratio * 80;
  circles.push({
    x: 100 + Math.sin(angle) * spiral_rad,
    y: 100 + Math.cos(angle) * spiral_rad
  });
}

toy.selectAll('circle')
  .data(circles)
  .enter()
  .append('circle')
  .attr('cx', function(c){return c.x;})
  .attr('cy', function(c){return c.y;})
  .attr('r', 5)
  .attr('fill', function(c,i){return d3.schemeCategory10[i%10];})
  .on('click', change_circle_position)
  .style('cursor', 'pointer');

function change_circle_position(d, k){
  d.x = Math.random() * 190 + 5;
  d.y = Math.random() * 190 + 5;
  d3.select(this).transition()
    .duration(1000)
    .attr('cx', function(c){return c.x;})
      .attr('cy', function(c){return c.y;})
    .on('end', function(){
        toy.selectAll('circle').each(function(p,i){
            if (i == k) return;
            dx = p.x - d.x;
            dy = p.y - d.y;
            if (dx*dx + dy*dy < 10*10) {
                change_circle_position.apply(this, [p,i]);
            }
        });
    });
}

Similar posts