Skip to content

Instantly share code, notes, and snippets.

@davo
Forked from DarienLiang/.block
Created August 6, 2019 15:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save davo/920543babb3f4e414f656cda503cdc16 to your computer and use it in GitHub Desktop.
Save davo/920543babb3f4e414f656cda503cdc16 to your computer and use it in GitHub Desktop.
Transition Between Three Views
license: mit
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
<!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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment