SVG Adding radial gradient to donut chart - javascript

I'm drawing charts with d3.js.
Is it possible to add radial gradients to donut chart, how on this picture?

Assuming the arc parts are path elements that are filled you can use a radial gradient to get that result.
See this similar question, we can reuse the example to arrive at:
var dataset = {
apples: [53245, 28479, 19697, 24037, 40245],
};
var width = 460,
height = 300,
radius = Math.min(width, height) / 2;
var color = d3.scale.category20();
var pie = d3.layout.pie()
.sort(null);
var arc = d3.svg.arc()
.innerRadius(radius - 100)
.outerRadius(radius - 50);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var grads = svg.append("defs").selectAll("radialGradient").data(pie(dataset.apples))
.enter().append("radialGradient")
.attr("gradientUnits", "userSpaceOnUse")
.attr("cx", 0)
.attr("cy", 0)
.attr("r", "100%")
.attr("id", function(d, i) { return "grad" + i; });
grads.append("stop").attr("offset", "15%").style("stop-color", function(d, i) { return color(i); });
grads.append("stop").attr("offset", "20%").style("stop-color", "white");
grads.append("stop").attr("offset", "27%").style("stop-color", function(d, i) { return color(i); });
var path = svg.selectAll("path")
.data(pie(dataset.apples))
.enter().append("path")
.attr("fill", function(d, i) { return "url(#grad" + i + ")"; })
.attr("d", arc);
Jsfiddle: http://jsfiddle.net/X8hfm/

Related

D3 pie chart doesnot showing the color

My code is like this. Can you say what is the error? My color is not showing properly although the section text is showing. the data set is the death rate of the US over time.
function clicked(d,i) {
var dataset = [d.females, d.males];
var pcolor = ["green", "pink"];
var outerRadius = 60;
var innerRadius = 0;
var arc = d3.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);
var pie = d3.pie();
//Easy colors accessible via a 10-step ordinal scale
//var color = d3.scaleOrdinal(d3.schemeCategory10);
//Set up groups
var arcs = svg.selectAll("g.arc")
.data(pie(dataset))
.enter()
.append("g")
.attr("class", "arcs")
.attr("transform", "translate(" + outerRadius + "," + outerRadius + ")");
//Draw arc paths
arcs.append("path")
.attr("d", arc)
.attr("fill", function(d, i) {
console.log(d);
return pcolor(i);
});
//Labels
arcs.append("text")
.attr("transform", function(d) {
return "translate(" + arc.centroid(d) + ")";
})
.attr("text-anchor", "middle")
.text(function(d) {
return d.value;
});
}

SVG line out of arc starting position - d3.js

I'm trying to achieve this
but this is currently what I have
Essentially all I need to do is figure out how to have the lines emanating out from the circle starting at the arc start.
My question is exactly that, how can I translate the arc starting position into the x1,y1 attribute of an svg line. Below is the code that I currently have pertaining to drawing the lines:
// Draw lines emanating out
g.append('line')
.attr('class', 'outer-line')
.attr('x1', function(d) {
return 0;
})
.attr('x2', 0)
.attr('y1', -radius)
.attr('y2', -radius-150)
.attr('stroke', function(d, i) {
return color(i);
})
.attr('stroke-width','2')
.attr("transform", function(d) {
return "rotate(" + (d.startAngle+d.endAngle)/2 * (180/Math.PI) + ")";
});
If I understand your problem correctly, you can use just d.startAngle:
g.attr("transform", function(d) {
return "rotate(" + d.startAngle * (180/Math.PI) + ")";
});
Check here an example (click on "run code snippet"):
var dataset = [300, 200, 400, 200, 300, 100, 50];
var width = 460,
height = 300,
radius = Math.min(width, height) / 2;
var color = d3.scale.category20();
var pie = d3.layout.pie()
.sort(null);
var arc = d3.svg.arc()
.innerRadius(radius - 100)
.outerRadius(radius - 50);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var path = svg.selectAll("path")
.data(pie(dataset))
.enter().append("path")
.attr("fill", function(d, i) { return color(i); })
.attr("d", arc);
var g = svg.selectAll(".groups")
.data(pie(dataset))
.enter()
.append("g");
g.append('line')
.attr('class', 'outer-line')
.attr('x1', 0)
.attr('x2', 0)
.attr('y1', -radius + 50)
.attr('y2', -radius)
.attr('stroke', 'black')
.attr('stroke-width','2')
.attr("transform", function(d) {
return "rotate(" + d.startAngle * (180/Math.PI) + ")";
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

Trying to incorporate svg circle within a d3 donut

I am trying to add a SVG circle within my d3 donut. My SVG circle displays the percentage as a fill of circle, for example, if the D3 donut is at 50%, the SVG will show 50% filled. I want to put the SVG circle within the inside of my D3 donut.
Here is my codepen for this. http://codepen.io/iamsok/pen/MwdPpx
class ProgressWheel {
constructor(patient, steps, container){
this._patient = patient;
this._steps = steps;
this.$container = $(container);
var τ = 2 * Math.PI,
width = this.$container.width(),
height = this.$container.height(),
innerRadius = Math.min(width,height)/4,
//innerRadius = (outerRadius/4)*3,
fontSize = (Math.min(width,height)/4);
var tooltip = d3.select(".tooltip");
var status = {
haveNot: 0,
taken: 1,
ignored: 2
}
var daysProgress = patient.progress
var percentComplete = Math.round(_.countBy(daysProgress)[status.taken] / daysProgress.length * 100);
var participation = 100;
var color = ["#CCC", "#FDAD42", "#EFD8B5"];
var pie = d3.layout.pie()
.value(function(d) { return 1; })
.sort(null);
var arc = d3.svg.arc();
var svg = d3.select(container).append("svg")
.attr("width", '100%')
.attr("height", '100%')
.attr('viewBox','0 0 '+Math.min(width,height) +' '+Math.min(width,height) )
.attr('preserveAspectRatio','xMinYMin')
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var innerCircle = d3.select("svg")
.append("svg")
.attr("width", 250)
.attr("height", 250);
var grad = innerCircle.append("defs")
.append("linearGradient").attr("id", "grad")
.attr("x1", "0%").attr("x2", "0%").attr("y1", "100%").attr("y2", "0%");
grad.append("stop").attr("offset", percentComplete + "%").style("stop-color", "lightblue");
grad.append("stop").attr("offset", percentComplete + "%").style("stop-color", "white");
innerCircle.append("circle")
.attr("r", 40)
.attr("cx", 70)
.attr("cy", 70)
.style("stroke", "black")
.style("fill", "url(#grad)");
var gs = svg.selectAll(".arc")
.data(pie(daysProgress))
.enter().append("g")
.attr("class", "arc");
var path = gs.append("path")
.attr("fill", function(d, i) { return color[d.data]; })
.attr("d", function(d, i, j) { return arc.innerRadius(innerRadius+(20*j)).outerRadius(innerRadius+20+(20*j))(d); })
.attr("class", function(d, i, j) { if (i>=participation && j<1) return "passed" ; })
svg.append("text")
.attr("dy", "0.5em")
.style("text-anchor", "middle")
.attr("class", "inner-circle")
.attr("fill", "#36454f")
.text(Math.round(_.countBy(daysProgress)[status.taken] / daysProgress.length * 100) + "%");
}
}
var patient = {progress: [0, 2, 2, 1, 0, 0, 0, 1, 1, 0, 1, 1, 2, 2]}
var progressWheel = new ProgressWheel(patient, 14, '.chart-container' )
Simply put the d3 donut and inner circle under the same svg so that they have the same coordinate system.
Check out here http://codepen.io/anon/pen/ojbQNE
Modified code is on codepen

Pie chart rotation using d3.js

Im new to d3.js im able to create donut chart and im able to rotate chart but i dont want labels on chart to rotate. Can anyone help how to proceed. how shall i make sure that labels on chart should not rotate
var dataset = [
{
count: 10
},
{
count: 20
},
{
label: 'Cantaloupe',
count: 30
}
];
var width = 360;
var height = 360;
var radius = 100;
var color = d3.scale.ordinal()
.range(["red", "blue", "green"]);
var svg = d3.select('body')
.append('svg')
.attr('width', width)
.attr('height', height)
.append('g')
.attr('transform', 'translate(' + (width / 2) +
',' + (height / 2) + ')');
var arc = d3.svg.arc()
.innerRadius(radius - 60)
.outerRadius(radius);
var pie = d3.layout.pie()
.value(function (d) {
return d.count;
});
var arcs = svg.selectAll('.arc')
.data(pie(dataset))
.enter()
.append('g')
.attr("class", "arc");
arcs.append("path")
.attr("d", arc)
.attr("fill", function (d) {
return color(d.data.count);
})
.on("click", function (d) {
var curAngle = 180;
svg.attr("transform", "translate(" + width / 2 + "," + height / 2 + ") rotate(" + curAngle + ")");
});
arcs.append("text")
.attr("transform", function (d) {
return "translate(" + arc.centroid(d) + ")";
}).attr("text-anchor", "middle")
.attr("font-size", "1.5em")
.text(function (d) {
return d.data.count
});

How do I increase the inner radius of a specific arc segment?

I have a pie chart and I want to increase the inner radius of the arc the user mouses over.
For example, if I mouse over the arc with 161, I want only the inner radius of that arc segment to increase.
How would I do this?
// arc radius
var radius = 200;
var p = Math.PI *2; //full circle
var data = [11,12,51,21,31,58,41,13,14,31,71,31,51,71,16,41,31,161];
var data1 = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18];
var width = 1000;
var height = 1000;
//========== color scale ==========//
var colorScale = d3.scale.ordinal()
.range(['#FFEBEB', '#FFC2C2', '#FFADAD', '#FF9999', '#FF7070', '#FF5C5C', '#FF4747',
'#FF1F1F', '#FF0A0A', '#F50000', '#CC0000', '#A30000', '#8F0000', '#660000', '#520000', '#3D0000', '#290000', '#140000']);
//========== Create canvas and arc ==========//
var canvas = d3.select("body")
.append("svg")
.attr("height", height)
.attr("width", width);
var group = canvas.append("g")
.attr("transform", "translate(" + width/2 + ",500)");
var arc = d3.svg.arc()
.innerRadius(radius-50)
.outerRadius(radius);
var pie = d3.layout.pie()
.value(function (d){return d;});
var sorted = data.sort(function(a,b){return a-b});
var arcs = group.selectAll(".arc")
.data(pie(sorted))
.enter()
.append("g")
.attr("class", "arc");
arcs.append("path")
.attr("d", arc)
.style('stroke', 'white')
.style('stroke-width', 2)
.attr("fill", function(d, i){return colorScale(d.data);});
arcs.append("text")
.attr("transform", function(d){
return "translate(" + arc.centroid(d) +")";
})
.attr("text-anchor", "middle")
.text(function(d){return d.data});
//======== mouse over/out =========//
var prevColor;
arcs.on("mouseover", function(d){
prevColor = d3.select(this).select("path").attr("fill");
d3.select(this).select("path")
.attr("fill", "black");
})
.on("mouseout", function(d){
d3.select(this).select("path")
.attr("fill", prevColor);
});
http://jsfiddle.net/64vFq/
If I understand you correctly, it looks like you can just change this line:
var arc = d3.svg.arc()
.innerRadius(radius-50)
.outerRadius(radius);
I changed it to this and it produced a decent result:
var arc = d3.svg.arc()
.innerRadius(radius-150)
.outerRadius(radius);
(increase the 50 to make the part the user can mouse over larger; decrease it for the opposite effect)
I found a solution that seems to work pretty well.
All you need to do is create another arc (a bigger one)
var biggerArc = d3.svg.arc().outerRadius(radius+10).innerRadius(radius - 40);
then add it to your mouseover
arcs.on("mouseover", function (d) {
prevColor = d3.select(this).select("path").attr("fill");
d3.select(this).select("path").attr("fill", "black");
d3.select(this).select("path").transition()
.duration(100)
.attr("d", biggerArc);
}).on("mouseout", function (d) {
d3.select(this).select("path").attr("fill", prevColor);
d3.select(this).select("path").transition()
.duration(100)
.attr("d", arc);
});

Categories