|
!function(){ |
|
var Donut3D={}; |
|
|
|
function pieTop(d, rx, ry, ir ){ |
|
if(d.endAngle - d.startAngle == 0 ) return "M 0 0"; |
|
var sx = rx*Math.cos(d.startAngle), |
|
sy = ry*Math.sin(d.startAngle), |
|
ex = rx*Math.cos(d.endAngle), |
|
ey = ry*Math.sin(d.endAngle); |
|
|
|
var ret =[]; |
|
ret.push("M",sx,sy,"A",rx,ry,"0",(d.endAngle-d.startAngle > Math.PI? 1: 0),"1",ex,ey,"L",ir*ex,ir*ey); |
|
ret.push("A",ir*rx,ir*ry,"0",(d.endAngle-d.startAngle > Math.PI? 1: 0), "0",ir*sx,ir*sy,"z"); |
|
return ret.join(" "); |
|
} |
|
|
|
function pieOuter(d, rx, ry, h ){ |
|
var startAngle = (d.startAngle > Math.PI ? Math.PI : d.startAngle); |
|
var endAngle = (d.endAngle > Math.PI ? Math.PI : d.endAngle); |
|
|
|
var sx = rx*Math.cos(startAngle), |
|
sy = ry*Math.sin(startAngle), |
|
ex = rx*Math.cos(endAngle), |
|
ey = ry*Math.sin(endAngle); |
|
|
|
var ret =[]; |
|
ret.push("M",sx,h+sy,"A",rx,ry,"0 0 1",ex,h+ey,"L",ex,ey,"A",rx,ry,"0 0 0",sx,sy,"z"); |
|
return ret.join(" "); |
|
} |
|
|
|
function pieInner(d, rx, ry, h, ir ){ |
|
var startAngle = (d.startAngle < Math.PI ? Math.PI : d.startAngle); |
|
var endAngle = (d.endAngle < Math.PI ? Math.PI : d.endAngle); |
|
|
|
var sx = ir*rx*Math.cos(startAngle), |
|
sy = ir*ry*Math.sin(startAngle), |
|
ex = ir*rx*Math.cos(endAngle), |
|
ey = ir*ry*Math.sin(endAngle); |
|
|
|
var ret =[]; |
|
ret.push("M",sx, sy,"A",ir*rx,ir*ry,"0 0 1",ex,ey, "L",ex,h+ey,"A",ir*rx, ir*ry,"0 0 0",sx,h+sy,"z"); |
|
return ret.join(" "); |
|
} |
|
|
|
function getPercent(d){ |
|
return (d.endAngle-d.startAngle > 0.2 ? |
|
Math.round(1000*(d.endAngle-d.startAngle)/(Math.PI*2))/10+'%' : ''); |
|
} |
|
|
|
Donut3D.transition = function(id, data, rx, ry, h, ir){ |
|
function arcTweenInner(a) { |
|
var i = d3.interpolate(this._current, a); |
|
this._current = i(0); |
|
return function(t) { return pieInner(i(t), rx+0.5, ry+0.5, h, ir); }; |
|
} |
|
function arcTweenTop(a) { |
|
var i = d3.interpolate(this._current, a); |
|
this._current = i(0); |
|
return function(t) { return pieTop(i(t), rx, ry, ir); }; |
|
} |
|
function arcTweenOuter(a) { |
|
var i = d3.interpolate(this._current, a); |
|
this._current = i(0); |
|
return function(t) { return pieOuter(i(t), rx-.5, ry-.5, h); }; |
|
} |
|
function textTweenX(a) { |
|
var i = d3.interpolate(this._current, a); |
|
this._current = i(0); |
|
return function(t) { return 0.6*rx*Math.cos(0.5*(i(t).startAngle+i(t).endAngle)); }; |
|
} |
|
function textTweenY(a) { |
|
var i = d3.interpolate(this._current, a); |
|
this._current = i(0); |
|
return function(t) { return 0.6*rx*Math.sin(0.5*(i(t).startAngle+i(t).endAngle)); }; |
|
} |
|
|
|
var _data = d3.pie().sort(null).value(function(d) {return d.value;})(data); |
|
|
|
d3.select("#"+id).selectAll(".innerSlice").data(_data) |
|
.transition().duration(750).attrTween("d", arcTweenInner); |
|
|
|
d3.select("#"+id).selectAll(".topSlice").data(_data) |
|
.transition().duration(750).attrTween("d", arcTweenTop); |
|
|
|
d3.select("#"+id).selectAll(".outerSlice").data(_data) |
|
.transition().duration(750).attrTween("d", arcTweenOuter); |
|
|
|
d3.select("#"+id).selectAll(".percent").data(_data).transition().duration(750) |
|
.attrTween("x",textTweenX).attrTween("y",textTweenY).text(getPercent); |
|
} |
|
|
|
Donut3D.draw=function(id, data, x /*center x*/, y/*center y*/, |
|
rx/*radius x*/, ry/*radius y*/, h/*height*/, ir/*inner radius*/){ |
|
|
|
var _data = d3.pie().sort(null).value(function(d) {return d.value;})(data); |
|
|
|
var slices = d3.select("#"+id).append("g").attr("transform", "translate(" + x + "," + y + ")") |
|
.attr("class", "slices"); |
|
|
|
slices.selectAll(".innerSlice").data(_data).enter().append("path").attr("class", "innerSlice") |
|
.style("fill", function(d) { return d3.hsl(d.data.color).darker(0.7); }) |
|
.attr("d",function(d){ return pieInner(d, rx+0.5,ry+0.5, h, ir);}) |
|
.each(function(d){this._current=d;}); |
|
|
|
slices.selectAll(".topSlice").data(_data).enter().append("path").attr("class", "topSlice") |
|
.style("fill", function(d) { return d.data.color; }) |
|
.style("stroke", function(d) { return d.data.color; }) |
|
.attr("d",function(d){ return pieTop(d, rx, ry, ir);}) |
|
.each(function(d){this._current=d;}); |
|
|
|
slices.selectAll(".outerSlice").data(_data).enter().append("path").attr("class", "outerSlice") |
|
.style("fill", function(d) { return d3.hsl(d.data.color).darker(0.7); }) |
|
.attr("d",function(d){ return pieOuter(d, rx-.5,ry-.5, h);}) |
|
.each(function(d){this._current=d;}); |
|
|
|
slices.selectAll(".percent").data(_data).enter().append("text").attr("class", "percent") |
|
.attr("x",function(d){ return 0.6*rx*Math.cos(0.5*(d.startAngle+d.endAngle));}) |
|
.attr("y",function(d){ return 0.6*ry*Math.sin(0.5*(d.startAngle+d.endAngle));}) |
|
.text(getPercent).each(function(d){this._current=d;}); |
|
} |
|
|
|
this.Donut3D = Donut3D; |
|
}(); |