-
-
Save NPashaP/9994181 to your computer and use it in GitHub Desktop.
license: gpl-3.0 |
!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.layout.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.layout.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; | |
}(); |
<!DOCTYPE html> | |
<meta charset="utf-8"> | |
<style> | |
body { | |
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; | |
width: 960px; | |
height: 500px; | |
position: relative; | |
} | |
path.slice{ | |
stroke-width:2px; | |
} | |
polyline{ | |
opacity: .3; | |
stroke: black; | |
stroke-width: 2px; | |
fill: none; | |
} | |
svg text.percent{ | |
fill:white; | |
text-anchor:middle; | |
font-size:12px; | |
} | |
</style> | |
<body> | |
<button onClick="changeData()">Change Data</button> | |
<script src="http://d3js.org/d3.v3.min.js"></script> | |
<script src="Donut3D.js"></script> | |
<script> | |
var salesData=[ | |
{label:"Basic", color:"#3366CC"}, | |
{label:"Plus", color:"#DC3912"}, | |
{label:"Lite", color:"#FF9900"}, | |
{label:"Elite", color:"#109618"}, | |
{label:"Delux", color:"#990099"} | |
]; | |
var svg = d3.select("body").append("svg").attr("width",700).attr("height",300); | |
svg.append("g").attr("id","salesDonut"); | |
svg.append("g").attr("id","quotesDonut"); | |
Donut3D.draw("salesDonut", randomData(), 150, 150, 130, 100, 30, 0.4); | |
Donut3D.draw("quotesDonut", randomData(), 450, 150, 130, 100, 30, 0); | |
function changeData(){ | |
Donut3D.transition("salesDonut", randomData(), 130, 100, 30, 0.4); | |
Donut3D.transition("quotesDonut", randomData(), 130, 100, 30, 0); | |
} | |
function randomData(){ | |
return salesData.map(function(d){ | |
return {label:d.label, value:1000*Math.random(), color:d.color};}); | |
} | |
</script> | |
</body> |
Hi, great piece of code for creating a 3D pie chart. Is the code shared under some licence? Is it free to use?
Hi NPashaP, Great implementation, but just want to confirm that, Is it free to use? Is the code shared under some license?
Hi NPashaP, Really great implementation. I'd also like to know about the license.
i tried to implement tool tip with above code. but it seems to be not working. If Possible write code related Tooltip and legend.
if values more than 5 entire d3 chart is disturbing.
EX; Donut3D.draw("quotesDonut", randomData(), 450, 150, 250, 150, 50, 10,9);
try with above code
Nice! Remember that to use this chart you must download the OLDER version of d3.js, this does not work on v4.
Nice! Remember that to use this chart you must download the OLDER version of d3.js, this does not work on v4.
For the latest version of d3.js v5 change d3.layout.pie()
to d3.pie()
at two lines (77 and 95) in Donut3D.js as follows:
77: var _data = d3.layout.pie().sort(null).value(function(d) {return d.value;})(data);
77: var _data = d3.pie().sort(null).value(function(d) {return d.value;})(data);
95: var _data = d3.layout.pie().sort(null).value(function(d) {return d.value;})(data);
95: var _data = d3.pie().sort(null).value(function(d) {return d.value;})(data);
Do not forget to change the d3.js version v3 to v5 or v4 at line 28 in index.html as follows:
28: <script src="http://d3js.org/d3.v3.min.js"></script>
28: <script src="http://d3js.org/d3.v5.min.js"></script>
or <script src="http://d3js.org/d3.v4.min.js"></script>
This is because of the namespace flattening since v4, please refer to the Changes in D3 5.0 https://github.com/d3/d3/blob/master/CHANGES.md#shapes-d3-shape
You can make it responsive too
var svg = d3.select(".donut").append("svg").attr("width",100+"%").attr("height",100+"%").attr("viewBox","0 0 520 390");
Where is the label in this graph??? how can identify which % is of which label???
Hi NPashaP. Great Gist! What is the license associated with your code? Thanks.