Skip to content

Instantly share code, notes, and snippets.

@tcjr
Created April 25, 2012 21:03
Show Gist options
  • Select an option

  • Save tcjr/12d053afef31e18ac50a to your computer and use it in GitHub Desktop.

Select an option

Save tcjr/12d053afef31e18ac50a to your computer and use it in GitHub Desktop.

Revisions

  1. tcjr created this gist Apr 25, 2012.
    170 changes: 170 additions & 0 deletions d3-fun.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,170 @@
    define([
    'dojo/ready',
    '../data/songs',
    '../nav',
    'raw/d3.v2.min' // Non-AMD. This Defines the global variable d3
    ],function(ready, songStore){

    var thePage = {};


    var color = d3.scale.category20c();

    function maxY(d) {
    return d.children ? Math.max.apply(Math, d.children.map(maxY)) : d.y + d.dy;
    }

    // http://www.w3.org/WAI/ER/WD-AERT/#color-contrast
    function brightness(rgb) {
    return rgb.r * .299 + rgb.g * .587 + rgb.b * .114;
    }

    function isParentOf(p, c) {
    //console.debug("iPO called with %o,%o",p,c)
    if (p === c) return true;
    if (p.values) {
    return p.values.some(function(d) {
    return isParentOf(d, c);
    });
    }
    return false;
    }


    console.debug("d3 = %o", d3);
    ready(function(){

    var nested = d3.nest()
    .key(function(d) { return d['Genre']; }).sortKeys(d3.ascending)
    .key(function(d) { return d['Artist']; }).sortKeys(d3.ascending)
    .entries(songStore.data)

    console.debug("nested songStore is %o", nested);


    var w = 840,
    h = w,
    r = w / 2,
    x = d3.scale.linear().range([0, 2 * Math.PI]),
    y = d3.scale.pow().exponent(1.3).domain([0, 1]).range([0, r]),
    p = 5,
    duration = 1000;

    var div = d3.select('#vis');

    var vis = div.append("svg")
    .attr("width", w + p * 2)
    .attr("height", h + p * 2)
    .append("g")
    .attr("transform", "translate(" + (r + p) + "," + (r + p) + ")");

    div.append("p")
    .attr("id", "intro")
    .text("Click to zoom!");


    var partition = d3.layout.partition()
    .value(function(d) { console.debug("value called; d=%o; returning %o",d, 5.8-d.depth); return 5.8-d.depth; }); //?????

    var arc = d3.svg.arc()
    .startAngle(function(d) { return Math.max(0, Math.min(2 * Math.PI, x(d.x))); })
    .endAngle(function(d) { return Math.max(0, Math.min(2 * Math.PI, x(d.x + d.dx))); })
    .innerRadius(function(d) { return Math.max(0, d.y ? y(d.y) : d.y); })
    .outerRadius(function(d) { return Math.max(0, y(d.y + d.dy)); });

    var nodes = partition
    .children(function(n){ return n.values; })
    .nodes({key:"Genres", values:nested})

    console.debug("nodes = %o", nodes)

    var path = vis.selectAll("path").data(nodes);
    path.enter().append("path")
    .attr("id", function(d, i) { return "path-" + i; })
    .attr("d", arc)
    .attr("fill-rule", "evenodd")
    //.style("fill", function(d) { return color((d.children ? d : d.parent).Key); })
    .style("fill", function(d) {
    return color( d.key ? d.key : d.parent.key );
    })
    .on("click", click);


    var text = vis.selectAll("text").data(nodes);

    var textEnter = text.enter().append("text")
    .style("opacity", 1)
    // .style("fill", function(d) {
    // return brightness(d3.rgb(colour(d))) < 125 ? "#eee" : "#000";
    // })
    .attr("text-anchor", function(d) {
    return x(d.x + d.dx / 2) > Math.PI ? "end" : "start";
    })
    .attr("dy", ".2em")
    .attr("transform", function(d) {
    var multiline = (d.name || "").split(" ").length > 1,
    angle = x(d.x + d.dx / 2) * 180 / Math.PI - 90,
    rotate = angle + (multiline ? -.5 : 0);
    return "rotate(" + rotate + ")translate(" + (y(d.y) + p) + ")rotate(" + (angle > 90 ? -180 : 0) + ")";
    })
    .on("click", click);
    textEnter.append("tspan")
    .attr("x", 0)
    .text(function(d) {
    // quick and dirty for now
    return (d.depth==3) ? d['Name'] :
    (d.depth==1 || d.depth==2) ? d.key : '';
    });
    // textEnter.append("tspan")
    // .attr("x", 0)
    // .attr("dy", "1em")
    // .text(function(d) { return d.depth ? d.name.split(" ")[1] || "" : ""; });

    //

    function click(d) {
    path.transition()
    .duration(duration)
    .attrTween("d", arcTween(d));

    // Somewhat of a hack as we rely on arcTween updating the scales.
    text
    .style("visibility", function(e) {
    return isParentOf(d, e) ? null : d3.select(this).style("visibility");
    })
    .transition().duration(duration)
    .attrTween("text-anchor", function(d) {
    return function() {
    return x(d.x + d.dx / 2) > Math.PI ? "end" : "start";
    };
    })
    .attrTween("transform", function(d) {
    var multiline = (d.name || "").split(" ").length > 1;
    return function() {
    var angle = x(d.x + d.dx / 2) * 180 / Math.PI - 90,
    rotate = angle + (multiline ? -.5 : 0);
    return "rotate(" + rotate + ")translate(" + (y(d.y) + p) + ")rotate(" + (angle > 90 ? -180 : 0) + ")";
    };
    })
    .style("opacity", function(e) { return isParentOf(d, e) ? 1 : 1e-6; })
    .each("end", function(e) {
    d3.select(this).style("visibility", isParentOf(d, e) ? null : "hidden");
    });
    }

    // Interpolate the scales!
    function arcTween(d) {
    var my = maxY(d),
    xd = d3.interpolate(x.domain(), [d.x, d.x + d.dx]),
    yd = d3.interpolate(y.domain(), [d.y, my]),
    yr = d3.interpolate(y.range(), [d.y ? 20 : 0, r]);
    return function(d) {
    return function(t) { x.domain(xd(t)); y.domain(yd(t)).range(yr(t)); return arc(d); };
    };
    }


    });

    return thePage;
    });