block by davo 920543babb3f4e414f656cda503cdc16

Transition Between Three Views

Full Screen

Built with blockbuilder.org

index.html

<!DOCTYPE html>
<meta charset="utf-8">
<style>

.axis {
  font: 12px sans-serif;
}

.axis path,
.axis line {
  fill: none;
  stroke: #000;
  shape-rendering: crispEdges;
}

.x.axis path {
  display: none;
}

</style>
<body>


<script src="https://d3js.org/d3.v3.min.js"></script>
<script>

    var m = [50, 50, 50, 50],
        w = 960 - m[1] - m[3],
        h = 450 - m[0] - m[2];

    var x,
        y,
        duration = 2000,
        delay = 500;
        
    var x2,
        y2;

    //var color = d3.scale.category10();
// set color
var color = d3.scale.category20();
  
    var svg = d3.select("body").append("svg")
        .attr("width", w + m[1] + m[3])
        .attr("height", h + m[0] + m[2])
        .append("g")
        .attr("transform", "translate(" + m[3] + "," + m[0] + ")");

    var pie = d3.layout.pie()
        .value(function(d) {
            return d.count;
        });

    var arc = d3.svg.arc();


d3.csv("fruit.csv", function(error, data) {
    data.forEach(function(d) {
        d.fruit = d.Fruit;
        d.count = +d.Count;
    });
  
    x = d3.scale.ordinal()
          .domain(data.map(function(d) { return d.fruit; }))
          .rangeRoundBands([0, w], .2);
    y = d3.scale.linear()
          .domain([d3.max(data.map(function(d) { return d.count; })), 0])
          .range([0, h]);
    x2 = d3.scale.ordinal()
                   .domain(data.map(function(d) { return d.fruit; }))
                   .range([0, w]);

   // add pie but do not diaplay it
    var g = svg.selectAll(".symbol")
        .data(function() { return pie(data); })
        .enter()
        .append("g")
        .attr("class", "symbol");

     g.append("rect")
        .style("fill", function(d) {
            return color(d.data.fruit);
        })
        .attr("x", function(d){
            return x(d.data.fruit);
        })
        .attr("y", function(d){
            return y(d.data.count);
        })
        .attr("width", x.rangeBand())
        .attr("height", function(d) {
                return h - y(d.data.count);
            })
        .attr("rx", 0)
        .attr("ry", 0);
            
    //draw bar chart first 
        g.append("path")
        .style("fill", function(d) {
            return color(d.data.fruit);
        });

        g.append("text")
        .attr("transform", function(d){
            return "translate(" + (x(d.data.fruit)+x.rangeBand()/3) + "," + (h+20) + ")";
        })
        .text(function(d) {
            return d.data.fruit;
        });
    //then use path element of bars do transition;

    // without button
    toPie();

});

function toPie(){
    var g = svg.selectAll(".symbol");

    g.selectAll("rect").remove();

    g.selectAll("path")
        .transition()
        .duration(duration)
        .tween("arc", arcTween);

    //The idea here is to first draw an arc like a bar,
    //then tween the bar-like arc to the donut arc. 
    //Thus, the fruit is find the initial bar size and position:
    //The initial bar height is approximated by the length of 
    //outside arc: barHeight = init_OuterRadius * init_Angle. 
    //So we can get the startAngle shown in f;
    //(Note that: the measure of angle in d3 starts from vertical y:
    // y    angle
    // |    /   
    // |   /        
    // |  /             
    // |o/
    // |/      
    // )                                       
    function arcTween(d) {
        var path = d3.select(this),
            text = d3.select(this.parentNode).select("text"),
            x0 = x(d.data.fruit),
            y0 = h - y(d.data.count); //initial height

        return function(t) {
            var r = h / 2 / Math.min(1, t + 1e-3),
                //a is stepping factor, starting from 1 to 0,
                //as the timer t goes.
                //A simper alternative: a = 1 - t;
                a = Math.cos(t * Math.PI / 2),
                xx = (-r + (a) * (x0 + x2.rangeBand()) + (1-a)*(w + h)/2),
                yy = ((a) * h + (1 - a) * h/2),
                f = {
                    innerRadius: (r - x.rangeBand() / (2 - a)) * a,
                    outerRadius: r,
                    //endAngle:0,
                    startAngle: a * (Math.PI / 2 - y0 / r) + (1 - a) * d.startAngle,
                    endAngle: a * (Math.PI / 2) + (1 - a) * d.endAngle
                };
            path.attr("transform", "translate(" + xx + "," + yy + ")");
            path.attr("d", arc(f));
            text.attr("transform", "translate(" + arc.centroid(f) + ")translate(" + xx + "," + yy + ")rotate(" + ((f.startAngle + f.endAngle) / 2 + 3 * Math.PI / 2) * 180 / Math.PI + ")");
        };
    }
}

function toBar(){
    var g = svg.selectAll(".symbol");

    //g.selectAll("rect").remove();

    g.selectAll("path")
        .transition()
        .duration(duration)
        .tween("arc", arcTween);

    //The idea here is to first draw an arc like a bar,
    //then tween the bar-like arc to the donut arc. 
    //Thus, the fruit is find the initial bar size and position:
    //The initial bar height is approximated by the length of 
    //outside arc: barHeight = init_OuterRadius * init_Angle. 
    //So we can get the startAngle shown in f;
    //(Note that: the measure of angle in d3 starts from vertical y:
    // y    angle
    // |    /   
    // |   /        
    // |  /             
    // |o/
    // |/      
    // )                                       
    function arcTween(d) {
        var path = d3.select(this),
            text = d3.select(this.parentNode).select("text"),
            x0 = x2(d.data.fruit),
            y0 = h - y2(d.data.count); //initial height
    var x2 = d3.scale.ordinal()
                   .domain(fruit.map(function(d) { return d.fruit; }))
                   .range([0, w]);
    var y2 = y; 
        return function(t) {
            t = 1-t;
            var r = h / 2 / Math.min(1, t + 1e-3),
                //a is stepping factor, starting from 1 to 0,
                //as the timer t goes.
                //A simper alternative: a = 1 - t;
                a = Math.cos(t * Math.PI / 2),
                xx = (-r + (a) * (x0 + x.rangeBand()) + (1 - a) * (w + h) / 2),
                yy = ((a) * h + (1 - a) * h / 2),
                f = {
                    innerRadius: (r - x.rangeBand() / (2 - a)) * a,
                    outerRadius: r,
                    startAngle: a * (Math.PI / 2 - y0 / r) + (1 - a) * d.startAngle,
                    endAngle: a * (Math.PI / 2) + (1 - a) * d.endAngle
                };


            path.attr("transform", "translate(" + xx + "," + yy + ")");
            path.attr("d", arc(f));
            text.attr("transform", "translate(" + arc.centroid(f) + ")translate(" + xx + "," + yy + ")rotate(" + ((f.startAngle + f.endAngle) / 2 + 3 * Math.PI / 2) * 180 / Math.PI + ")");
        };
    }
}

</script>
</body>

fruit.csv

Fruit,Count
Apple,12
Pear,4
Orange,13
Cherry,13
Blueberry,8
Banana,2
Peach,13
Lemon,5
Watermelon,15
Lime,24
Mango,16
Grape,10
Kiwi,8
Pineapple,15
Date,20