|
var data = [ |
|
{v: 350, t: 90, c:[50,25,25]}, |
|
{v: 250, t: 50, c:[10,20]}, |
|
{v: 220, t: 17.5, c:[10,10]}, |
|
{v: 200, t: 30, c:[75,25]}, |
|
{v: 100, t: 55, c:[5,15]}, |
|
{v: 80, t: 50, c:[10,20]}, |
|
{v: 50, t: 67.5} |
|
]; |
|
//Is it necessary for data to have values beyond first one..because just subtract |
|
// -> cannot visualise magical unaccounted values |
|
//Data is structured in val of outerRadius + width of slice (time) |
|
//What if the data was represented as a circular linked list.... |
|
|
|
generateDonut(data); |
|
|
|
function generateDonut(data){ |
|
const h = 1000; |
|
const w = 1000; |
|
const smallestDim = Math.min(h,w) |
|
const innerRadius = smallestDim/10; |
|
const startAngle = -1*Math.PI; |
|
|
|
const rScale = d3.scale.linear() |
|
.domain([0,d3.max(data, function(d) { return d.v; })]) |
|
.range([0, smallestDim/2-innerRadius]); |
|
|
|
var pie = d3.layout.pie() |
|
.value(function(d){ return d.t || 10; }) |
|
.startAngle(startAngle) |
|
.endAngle(startAngle + 2*Math.PI) |
|
.sort(function(a,b) { a.v < b.v; }) //setting the order of the slices |
|
|
|
var arc = d3.svg.arc() |
|
//If set inner + outer radius it is not contained in the dom object.... |
|
|
|
var svg = d3.select("#chartArea").append("svg") |
|
.attr("width", w) |
|
.attr("height", h) |
|
.append("g") |
|
.attr("transform", "translate(" + w / 2 + "," + h / 2 + ")"); |
|
|
|
const colour = d3.scale.category20b(); |
|
var pieData = pie(data) |
|
|
|
svg.selectAll("path") |
|
.data(pieData) |
|
.enter().append("path") |
|
.each(function(d, i) { |
|
d.outerRadius = innerRadius + rScale(d.data.v) //might want to scale d.data.h... |
|
d.innerRadius = innerRadius |
|
d.startAngle = startAngle //This makes all arcs have 1 origin -> looks nice |
|
}) |
|
.attr("d", arc) |
|
.style('fill', function(d) { return colour(d.outerRadius); }) |
|
.each(function(d,i) { createOffShoot(d, i); }) |
|
|
|
//Bind data to this instead, have 1 g element for each slice + offshoot? |
|
function createOffShoot(d, i) { |
|
const nextSlice = i === pieData.length - 1 ? pieData[0] : pieData[i+1] |
|
const h = rScale(200) |
|
const angle = d.endAngle * 180 / Math.PI - 90; |
|
|
|
const offshoots = d.data.c || []; |
|
offshoots.forEach(function(offshoot, i2) { |
|
const offset = rScale(d3.sum(offshoots.slice(0,i2))) |
|
const width = rScale(offshoot) |
|
|
|
const x = (d.outerRadius - offset) * Math.sin(d.endAngle); |
|
const y = -1 * (d.outerRadius - offset) * Math.cos(d.endAngle); |
|
|
|
const points = x+','+y+' '+(x-width)+','+y+' '+ |
|
(x-width)+','+(y+h)+' '+(x-width/2)+','+(y+Math.sin(Math.PI/3)*width+h)+' '+ |
|
x+','+(y+h) |
|
|
|
//Since all the coordinate of the rect + triangle is known.... -> make polygon? |
|
var outflow = svg.append('g') |
|
.attr('transform', 'rotate(' + angle + ',' + x + ',' + y +')') |
|
.attr('fill', colour(d.outerRadius)) |
|
.attr('stroke', "orange") |
|
outflow.append('polygon') |
|
.attr('points', points) |
|
}) |
|
} |
|
} |