D3 with labels and percentages?
We are looking for a radial graph that looks like this. What's most interesting about this chart is the percentage. We searched for about three days and we didn't find anything that uses the library d3.js
.
We found these two solid gauge charts, one from amcharts and the other from anycharts , but neither has a clear meaning. Highcharts also has something similar, but no labels. Also, they don't use d3, not open source.
Any help is appreciated.
Thank.
source to share
It can be easily coded from scratch
You can get the coordinate of the end or start of a segment using a function centroid
, after which you can add text here and rotate it accordingly.
var data = [45,33,66,50,90]
var svg = d3.select('#result').append('svg').attr('width',500).attr('height',500)
var arcs = data.map((v,i)=>{
return d3.svg.arc().innerRadius(i*20+60).outerRadius((i+1)*20-5+60)
});
var pieData = data.map((v,i)=>{
return [{value:v*0.75,arc:arcs[i]},{value:(100-v)*0.75,arc:arcs[i]},{value:100*0.25,arc:arcs[i]}]
})
var pie = d3.layout.pie()
.sort(null)
.value(d=>d.value)
var g = svg.selectAll('g').data(pieData).enter().append('g').attr('transform','translate(250,250) rotate(180)').attr('fill-opacity',(d,i)=>2/(i+1))
// progress
g.selectAll('path').data(d=>{return pie(d)}).enter().append('path').attr('d',d=>{return d.data.arc(d)})
.attr('fill',(d,i)=>i==0?'blue':'none')
svg.selectAll('g').each(function(d){
var el = d3.select(this);
el.selectAll('path').each((r,i)=>{
if(i==1){
var centroid = r.data.arc.centroid({startAngle:r.startAngle+0.05,endAngle:r.startAngle+0.001+0.05})
g.append('text').text(100-Math.floor(r.value)+'%').attr('transform',`translate(${centroid[0]},${centroid[1]}) rotate(${180/Math.PI*(r.startAngle)+7})`).attr('alignment-baseline','middle')
}
})
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id='result'></div>
source to share
I also need a diagram of this type.
My code looks like this: inject a responsive graph according to the width of the parent. for this you need to get the width of the parent and assign it to a variablevar width
Hope this code helps you.
var width = 300;
var arcSize = (6 * width / 100);
var innerRadius = arcSize * 3;
var data = [
{value: 45, label: "label_1", color: '#ff0000'},
{value: 33, label: "label_2", color: '#00ff00'},
{value: 66, label: "label_3", color: '#0000ff'},
{value: 50, label: "label_4", color: '#ffff00'},
{value: 90, label: "label_5", color: '#ff0099'}
];
function render() {
var svg = d3.select('#result').append('svg').attr('width', width).attr('height', width);
var arcs = data.map(function (obj, i) {
return d3.svg.arc().innerRadius(i * arcSize + innerRadius).outerRadius((i + 1) * arcSize - (width / 100) + innerRadius);
});
var arcsGrey = data.map(function (obj, i) {
return d3.svg.arc().innerRadius(i * arcSize + (innerRadius + ((arcSize / 2) - 2))).outerRadius((i + 1) * arcSize - ((arcSize / 2)) + (innerRadius));
});
var pieData = data.map(function (obj, i) {
return [
{value: obj.value * 0.75, arc: arcs[i], object: obj},
{value: (100 - obj.value) * 0.75, arc: arcsGrey[i], object: obj},
{value: 100 * 0.25, arc: arcs[i], object: obj}];
});
var pie = d3.layout.pie().sort(null).value(function (d) {
return d.value;
});
var g = svg.selectAll('g').data(pieData).enter()
.append('g')
.attr('transform', 'translate(' + width / 2 + ',' + width / 2 + ') rotate(180)');
var gText = svg.selectAll('g.textClass').data([{}]).enter()
.append('g')
.classed('textClass', true)
.attr('transform', 'translate(' + width / 2 + ',' + width / 2 + ') rotate(180)');
g.selectAll('path').data(function (d) {
return pie(d);
}).enter().append('path')
.attr('id', function (d, i) {
if (i == 1) {
return "Text" + d.data.object.label
}
})
.attr('d', function (d) {
return d.data.arc(d);
}).attr('fill', function (d, i) {
return i == 0 ? d.data.object.color : i == 1 ? '#D3D3D3' : 'none';
});
svg.selectAll('g').each(function (d, index) {
var el = d3.select(this);
var path = el.selectAll('path').each(function (r, i) {
if (i === 1) {
var centroid = r.data.arc.centroid({
startAngle: r.startAngle + 0.05,
endAngle: r.startAngle + 0.001 + 0.05
});
var lableObj = r.data.object;
g.append('text')
.attr('font-size', ((5 * width) / 100))
.attr('dominant-baseline', 'central')
/*.attr('transform', "translate(" + centroid[0] + "," + (centroid[1] + 10) + ") rotate(" + (180 / Math.PI * r.startAngle + 7) + ")")
.attr('alignment-baseline', 'middle')*/
.append("textPath")
.attr("textLength", function (d, i) {
return 0;
})
.attr("xlink:href", "#Text" + r.data.object.label)
.attr("startOffset", '5')
.attr("dy", '-3em')
.text(lableObj.value + '%');
}
if (i === 0) {
var centroidText = r.data.arc.centroid({
startAngle: r.startAngle,
endAngle: r.startAngle
});
var lableObj = r.data.object;
gText.append('text')
.attr('font-size', ((5 * width) / 100))
.text(lableObj.label)
.attr('transform', "translate(" + (centroidText[0] - ((1.5 * width) / 100)) + "," + (centroidText[1] + ") rotate(" + (180) + ")"))
.attr('dominant-baseline', 'central');
}
});
});
}
render()
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id="result"></div>
source to share