hiyume hiyume - 1 year ago 91
Javascript Question

geographic sort function for d3's pack layout

Using d3's pack layout, I made some bubbles associated with states. Current test script: https://jsfiddle.net/80wjyxp4/4/. They're colored according to region. You'll note Texas is in the "NW", California in the "SE", etc.


How would you geographically sort the circles in pack-layout?

One hack way might use the default

. This sort starts with the first data point (in this case, AK) and then adds bubbles in a counterclockwise direction. I could hand-sort data to be input in an order that approximates state positions, and add in blank circles to move edge circles around.

I'm interested about better ideas. Would it be better to use a modified force layout, like http://bl.ocks.org/mbostock/1073373? The
seems useful.

enter image description here

  1. Started with pack layout, to get circle radii
  2. used state centroids from this modified force layout http://bl.ocks.org/mbostock/1073373
  3. Contrived to avoid overlaps using collisions https://bl.ocks.org/mbostock/7881887

The code is here: https://jsfiddle.net/xyn85de1/. It does NOT run because I can't get data for the topojson file, at http://bl.ocks.org/mbostock/raw/4090846/us.json, from the link, and the file is too large to copy-paste. Download to your own server then run.

It has a hover-title text and transitions in, but ends up looking like this:


Spacing and stuff is modifiable with different parameters. The circles are approximately sorted geographically. MO is that big gold one in the middle; AK and HI are dark blue to the left; CA is lower left in pink; TX is at the bottom in light blue. And so on. Code: After collecting all data (location data for init position of circles), along with the state name, value, area (for color coding) into the nodes variable:

// circles
var circles = svg.selectAll("g") //g
    .attr("transform", function(d) {
        return "translate(" + -d.x + "," + -d.y + ")";
    .attr("transform", function(d) {
        return "translate(" + d.x + "," + d.y + ")";
    .attr("r", function(d) {return d.r;})
    .attr("fill", function(d) { return color(d.area); })
    .call(force.drag); // lets you change the orientation

// title text
    .text(function(d) { return d.state + ": " + format(d.value) + " GWh"; });

// // text // doesn't work :/ porque?
// circles.append("text")
//     .attr("dy", ".3em")
//     //.style("text-anchor", "middle")
//     .text(function(d) { return d.state.substring(0, d.r / 3); });

// circle tick function
function tick(e) {
        .attr("cx", function(d) { return d.x; })
        .attr("cy", function(d) { return d.y; });

// on("tick") has to be placed down here, not up there
// because else the function runs asynchronously
// enters an undefined 'node' as the function
// and is sad and won't run.
// ALSO I can't figure out how to move tick to accept 'circles'
// as a function argument so it's going to be a local function qq
    .on("tick", tick)