我有一个小D3脚本:
<script>
d3.csv("../data/school_attendance.csv", function(data) {
// Use d3.pie() to create and configure the data that we need in a format that we can enter into.
let arc_data = d3.pie().value(d => d['YTD Enrollment(Avg)']).padAngle(d => 0.0115)(data);
// Create the arc factory function that will render each data segment.
let arc = d3.arc().innerRadius(75).outerRadius(160);
// Run through each element of arc_data, creating and appening the arc for each one.
d3.select("svg")
.append("g")
.attr("id", "transform")
.attr("transform", "translate(400, 200)")
.selectAll('path')
.data(arc_data)
.enter()
.append('path')
.attr('d', arc)
.attr('fill', 'steelblue');
// Use arc and arc_data to calculate centroids, and from there to calculate.
arc_data.forEach(function(d, i) {
[x, y] = arc.centroid(d);
let label = d.data['District']
// let rotation = d['startAngle'] * 180 / Math.PI;
let rotation = d['startAngle'] / Math.PI / 2
d3.select("#transform").append("text")
.attr("x", x).attr("y", y)
.attr("text-anchor", "middle").attr("alignment-baseline", "middle")
.attr("transform", "rotate(" + rotation + ")")
.text(label);
})
})
</script>
这会产生以下输出:
我想旋转文字标签,使它们出现在每个弧段的中间。
然而,在我看来,显而易见的答案是:
let rotation = d['startAngle'] / Math.PI / 2 * 360 - 90;
不能按预期工作:
我的错误是什么,我应该怎么做才能解决它?
答案 0 :(得分:3)
在我看来,其中一个问题是使用x
设置标签的y
和attr
位置。而不是那样,翻译它们:
.attr("transform", "translate(" + [x,y] + ")");
之后,数学来了:
var rotation = (d.startAngle/2 + d.endAngle/2) * 180/Math.PI;
但是上述变量存在将所有文本从甜甜圈中心定位到边界的问题,并且一些标签(在甜甜圈的左侧)最终颠倒,从右到左。当我们从左边读到写字时,在我看来这个三元组更优雅:
var rotation = d.endAngle < Math.PI ?
(d.startAngle/2 + d.endAngle/2) * 180/Math.PI :
(d.startAngle/2 + d.endAngle/2 + Math.PI) * 180/Math.PI ;
这是一个演示:
const width = 400
const height = 400;
const radius = Math.min(width, height) / 2.5;
const totals = [{
"name": "District A",
"value": 20
}, {
"name": "District B",
"value": 50
}, {
"name": "District C",
"value": 30
}, {
"name": "District D",
"value": 20
}, {
"name": "District E",
"value": 50
}, {
"name": "District F",
"value": 30
}];
const color = d3.scaleOrdinal()
.range(['#869099', '#8c7853', '#007d4a']);
const arc = d3.arc()
.outerRadius(radius - 10)
.innerRadius(40);
const pie = d3.pie()
.sort(null)
.value((d) => {
return d.value
});
const svg = d3.select('body').append('svg')
.attr('width', width)
.attr('height', height)
.append('g')
.attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')');
const g = svg.selectAll('.arc')
.data(pie(totals))
.enter()
.append('g')
.attr('class', 'arc');
g.append('path')
.attr('d', arc)
.style('fill', 'steelblue')
.style('stroke', 'white');
pie(totals).forEach(function(d, i) {
[x, y] = arc.centroid(d);
let label = d.data.name;
var rotation = d.endAngle < Math.PI ? (d.startAngle / 2 + d.endAngle / 2) * 180 / Math.PI : (d.startAngle / 2 + d.endAngle / 2 + Math.PI) * 180 / Math.PI;
svg.append("text")
.attr("text-anchor", "middle").attr("alignment-baseline", "middle")
.attr("transform", "translate(" + [x, y] + ") rotate(-90) rotate(" + rotation + ")")
.text(label);
})
<script src="https://d3js.org/d3.v4.min.js"></script>