I'm trying to create a radial line chart with hours displayed in the middle of it. I'm getting the problem with rendering the text as on the picture below (red highlighted area).
var xAxis = svg.selectAll('.radial').append("g");
var xTick = xAxis
// .selectAll("g")
.selectAll(".radial")
.data(x.ticks(23))
.enter().append("g")
.attr("text-anchor", "middle")
.attr("transform", function(d) {
return "rotate(" + ((x(d)) * 180 / Math.PI - 90) + ")translate(" + innerRadius + ",0)";
});
xTick.append("line")
.attr("x2", -5)
.attr("stroke", "#595D5C");
xTick.append("text")
.attr("transform", function(d) {
var angle = x(d.key);
return ((angle < Math.PI / 2) || (angle > (Math.PI * 3 / 2))) ? "rotate(90)translate(0,22)" : "rotate(-90)translate(0, -15)"; })
.text(function(d) {
return d;
})
.style("font-size", 10)
.attr("color", "#595D5C")
.attr("opacity", 1)
What am I doing incorrectly?
const margin = {top: 20, right: 10, bottom: 20, left: 10};
const width = 650 - margin.left - margin.right,
height = 650 - margin.top - margin.bottom;
const innerRadius = 100,
outerRadius = Math.min(width, height) / 2 - 6;
const formatHour = d3.timeFormat("%I %p")
const fullCircle = 2 * Math.PI * 23/24;
const y = d3.scaleLinear()
.range([innerRadius, outerRadius]);
const x = d3.scaleLinear()
x.range([0, fullCircle]);
const line = d3.lineRadial()
.angle(function(d) { return x(d.key); })
.radius(function(d) { return y(d.value); })
.curve(d3.curveCardinalClosed)
data = [];
for (i=0;i<24;i++){data.push({key:i, value:Math.round(Math.random()*5), class:0})};
const svg = d3.select("body").append("svg").attr("width", width).attr("height", height);
const gSelect = svg.selectAll('.radial').data(data);
gSelect.exit()
.classed('radial', false)
.attr('opacity', 0.8)
.transition()
.attr('opacity', 0)
.remove();
// current.interrupt();
var gEnter = gSelect.enter().append("g")
// const g = svg
// .append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")")
.classed('radial', true);
const exit = gSelect.exit().classed('radial', false);
exit
.attr('opacity', 0.8)
.transition()
.attr('opacity', 0)
.remove();
const mean = [];
x.domain(d3.extent(data, function(d) { return d.key; }));
y.domain(d3.extent(data, function(d) { return d.value; }));
// var linePlot = gSelect.append("path")
var linePlot = d3.selectAll('.radial').append("path")
.datum(data)
.attr("fill", "url(#gradientRainbow)")
.attr("stroke", "#213946")
.attr("stroke-width", 1)
.attr('z-index', 200)
.attr("d", line);
var numColors = 10;
var colorScale = d3.scaleLinear()
.domain([0,(numColors-1)/2,numColors-1])
.range(["#F5D801", "#74D877", "#2A4858"])
.interpolate(d3.interpolateHcl);
var gradient = d3.selectAll('.radial').append("defs").append("radialGradient")
.attr("id", "gradientRainbow")
.attr("gradientUnits", "userSpaceOnUse")
.attr("cx", "0%")
.attr("cy", "0%")
.attr("r", "45%")
.selectAll("stop")
.data(d3.range(numColors))
.enter().append("stop")
.attr("offset", function(d,i) { return (i/(numColors-1)*50 + 40) + "%"; })
.attr("stop-color", function(d) { return colorScale(d); });
var yAxis = d3.selectAll('.radial').append("g")
.attr("text-anchor", "middle");
var yTick = yAxis
.selectAll(".radial")
// .selectAll("g")
.data(y.ticks(5))
.enter().append("g");
yTick.append("circle")
.attr("fill", "none")
.attr("stroke", "#D8D8D8")
.attr("opacity", 0.5)
.attr("r", function(d) {return y(d)});
//add avg
yAxis.append("circle")
.attr("fill", "none")
.attr("stroke", "#2A41E5")
.attr("stroke-width", 3)
.attr("r", function() { return y(mean) });
yAxis.append("circle")
.attr("fill", "white")
.attr("stroke", "black")
.attr("opacity", 1)
.attr("r", function() { return y(y.domain()[0])});
yTick.append("text")
.attr("y", function(d) { return -y(d); })
.attr("dy", "0.35em")
.text(function(d, i) {
if (d === 0) {
return ""
}
else {
return d
}
});
var xAxis = svg.selectAll('.radial').append("g");
var xTick = xAxis
// .selectAll("g")
.selectAll(".radial")
.data(x.ticks(24))
.enter().append("g")
.attr("text-anchor", "middle")
.attr("transform", function(d) {
return "rotate(" + ((x(d)) * 180 / Math.PI - 90) + ")translate(" + innerRadius + ",0)";
});
xTick.append("line")
.attr("x2", -5)
.attr("stroke", "#595D5C");
xTick.append("text")
.attr("transform", function(d) {
var angle = x(d.key);
return ((angle < Math.PI / 2) || (angle > (Math.PI * 3 / 2))) ? "rotate(90)translate(0,22)" : "rotate(-90)translate(0, -15)"; })
.text(function(d) {
return d;
})
.style("font-size", 10)
.attr("color", "#595D5C")
.attr("opacity", 1)
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-scale/1.0.7/d3-scale.min.js"></script>
The range of x
axis is defined as [0, fullCircle]
and that is a problem - both 0
and a fullCircle
represent the same point on the axis (0 degree = 360 degrees).
Here is a very simple fix for that problem:
const fullCircle = 2 * Math.PI * 23/24;
And you can try running the code snippet to see it working.