Here in my d3 radial chart, I am trying to get the label text just above the segment arcs instead of keeping outside the outer circle.
var width = 360,
height = 300,
barHeight = height / 2 - 40;
var formatNumber = d3.format("s");
var color = d3.scale.ordinal()
.range(["#F15D5D","#FAD64B"]);
var svg = d3.select('#chart').append("svg")
.attr("width", width)
.attr("height", height)
.attr('class','radial')
.append("g")
.attr("transform", "translate(" + width/2 + "," + height/2 + ")");
var data = [{
"name": "ABC",
"value":4
},
{
"name": "XYZ",
"value":5
},{
"name": "DEF",
"value":2
},
{
"name": "GHI",
"value":3
},{
"name": "JKL",
"value":1
}];
data.sort(function(a,b) { return b.value - a.value; });
var extent = [0, d3.max(data, d=>d.value)];
var barScale = d3.scale.linear()
.domain(extent)
.range([0, barHeight]);
var keys = data.map(function(d,i) { return d.name; });
var numBars = keys.length;
// X scale
var x = d3.scale.linear()
.domain(extent)
.range([0, -barHeight]);
// X axis
var xAxis = d3.svg.axis()
.scale(x).orient("left")
.ticks(3)
.tickFormat(formatNumber);
// Inner circles
var circles = svg.selectAll("circle")
.data(x.ticks(5))
.enter().append("circle")
.attr("r", function(d) {return barScale(d);})
.style("fill", "none")
//.style("stroke", "black")
//.style("stroke-dasharray", "2,2")
.style("stroke-width",".5px");
// Create arcs
var arc = d3.svg.arc()
.startAngle(function(d,i) {
var a = (i * 2 * Math.PI) / numBars;
var b = ((i + 1) * 2 * Math.PI) / numBars;
var d = (b-a) / 4;
var x = a+d;
var y = b-d;
return x;//(i * 2 * Math.PI) / numBars;
})
.endAngle(function(d,i) {
var a = (i * 2 * Math.PI) / numBars;
var b = ((i + 1) * 2 * Math.PI) / numBars;
var d = (b-a) / 4;
var x = a+d;
var y = b-d;
return y;//((i + 1) * 2 * Math.PI) / numBars;
})
.innerRadius(0);
// Render colored arcs
var segments = svg.selectAll("path")
.data(data)
.enter().append("path")
.each(function(d) { d.outerRadius = 0; })
.style("fill", function (d) { return color(d.name); })
.attr("d", arc);
// Animate segments
segments.transition().ease("elastic").duration(1000).delay(function(d,i) {return (25-i)*50;})
.attrTween("d", function(d,index) {
var i = d3.interpolate(d.outerRadius, barScale(+d.value));
return function(t) { d.outerRadius = i(t); return arc(d,index); };
});
// Outer circle
svg.append("circle")
.attr("r", barHeight)
.classed("outer", true)
.style("fill", "none")
//.style("stroke", "black")
.style("stroke-width",".5px");
// Apply x axis
svg.append("g")
.attr("class", "x axis")
.call(xAxis);
// Labels
var labelRadius = barHeight * 1.025;
var labels = svg.append("g")
.classed("labels", true);
labels.append("def")
.append("path")
.attr("id", "label-path")
.attr("d", "m0 " + -labelRadius + " a" + labelRadius + " " + labelRadius + " 0 1,1 -0.01 0");
labels.selectAll("text")
.data(keys)
.enter().append("text")
.style("text-anchor", "middle")
.style("font-weight","bold")
.style("fill", function(d, i) {return "#555";})
.append("textPath")
.attr("xlink:href", "#label-path")
.attr("startOffset", function(d, i) {return i * 100 / numBars + 50 / numBars + '%';})
.text(function(d) {return d.toUpperCase(); });
We can set the position of the <defs>
's paths using the same data you used to create the arcs.
First, let's create an enter selection:
var labels = svg.selectAll("foo")
.data(data)
.enter()
.append("g")
.classed("labels", true);
Then, we append the paths using the barScale
for each value (hardcoded padding of 4px here):
labels.append("def")
.append("path")
.attr("id", (d, i) => "label-path" + i)
.attr("d", d => "m0 " + -(barScale(d.value) + 4) +
" a" + (barScale(d.value) + 4) + " " +
(barScale(d.value) + 4) + " 0 1,1 -0.01 0");
Please notice that we have to use unique IDs. Then, we change the IDs in the text-paths:
.attr("xlink:href", (d, i) => "#label-path" + i)
Here is your updated fiddle: https://jsfiddle.net/qt3e0rex/
And the same code in the Stack snippet:
var width = 360, height = 300, barHeight = height / 2 - 40; var formatNumber = d3.format("s"); var color = d3.scale.ordinal() .range(["#F15D5D", "#FAD64B"]); var svg = d3.select('body').append("svg") .attr("width", width) .attr("height", height) .attr('class', 'radial') .append("g") .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")"); var data = [{ "name": "ABC", "value": 4 }, { "name": "XYZ", "value": 5 }, { "name": "DEF", "value": 2 }, { "name": "GHI", "value": 3 }, { "name": "JKL", "value": 1 }]; data.sort(function(a, b) { return b.value - a.value; }); var extent = [0, d3.max(data, d => d.value)]; var barScale = d3.scale.linear() .domain(extent) .range([0, barHeight]); var keys = data.map(function(d, i) { return d.name; }); var numBars = keys.length; // X scale var x = d3.scale.linear() .domain(extent) .range([0, -barHeight]); // X axis var xAxis = d3.svg.axis() .scale(x).orient("left") .ticks(3) .tickFormat(formatNumber); // Inner circles var circles = svg.selectAll("circle") .data(x.ticks(5)) .enter().append("circle") .attr("r", function(d) { return barScale(d); }) .style("fill", "none") //.style("stroke", "black") //.style("stroke-dasharray", "2,2") .style("stroke-width", ".5px"); // Create arcs var arc = d3.svg.arc() .startAngle(function(d, i) { var a = (i * 2 * Math.PI) / numBars; var b = ((i + 1) * 2 * Math.PI) / numBars; var d = (b - a) / 4; var x = a + d; var y = b - d; return x; //(i * 2 * Math.PI) / numBars; }) .endAngle(function(d, i) { var a = (i * 2 * Math.PI) / numBars; var b = ((i + 1) * 2 * Math.PI) / numBars; var d = (b - a) / 4; var x = a + d; var y = b - d; return y; //((i + 1) * 2 * Math.PI) / numBars; }) .innerRadius(0); // Render colored arcs var segments = svg.selectAll("path") .data(data) .enter().append("path") .each(function(d) { d.outerRadius = 0; }) .style("fill", function(d) { return color(d.name); }) .attr("d", arc); // Animate segments segments.transition().ease("elastic").duration(1000).delay(function(d, i) { return (25 - i) * 50; }) .attrTween("d", function(d, index) { var i = d3.interpolate(d.outerRadius, barScale(+d.value)); return function(t) { d.outerRadius = i(t); return arc(d, index); }; }); // Outer circle svg.append("circle") .attr("r", barHeight) .classed("outer", true) .style("fill", "none") //.style("stroke", "black") .style("stroke-width", ".5px"); // Apply x axis svg.append("g") .attr("class", "x axis") .call(xAxis); // Labels var labelRadius = barHeight * 1.025; var labels = svg.selectAll("foo") .data(data) .enter() .append("g") .classed("labels", true); labels.append("def") .append("path") .attr("id", (d, i) => "label-path" + i) .attr("d", d => "m0 " + -(barScale(d.value) + 4) + " a" + (barScale(d.value) + 4) + " " + (barScale(d.value) + 4) + " 0 1,1 -0.01 0"); labels.append("text") .style("text-anchor", "middle") .style("font-weight", "bold") .style("fill", function(d, i) { return "#555"; }) .append("textPath") .attr("xlink:href", (d, i) => "#label-path" + i) .attr("startOffset", function(d, i) { return i * 100 / numBars + 50 / numBars + '%'; }) .text(function(d) { return d.name.toUpperCase(); });
body { background-color:#fff; } .axis path, .axis line { fill: none; shape-rendering: crispEdges; } .x.axis path { display: none; } .tick text, line { display:none; } circle { stroke:#ccc; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.