如何使用d3.js沿着一个圆弧中的textPath居中(水平和垂直)文本? [英] How to center (horizontal and vertical) text along an textPath inside an arc using d3.js?
问题描述
用d3.js玩了一段时间,看了很多例子,我能绘制多个弧。每个以特定的度数和半径开始和结束。
var dataset = {
2 [{degree1:0,degree2:1.5707963267949,
label:示例文本测试},
{degree1:1.5707963267949,degree2:3.1415926535898,
label:Lorem ipsum sample text},
{degree1:3.1415926535898,degree2:4.7123889803847,
label:Sample Text Text},
{ degree1:4.7123889803847,degree2:6.2831853071796,
label:Lorem ipsum}],
1:[{degree1:0,degree2:3.1415926535898,
label:Sample},
{degree1:3.1415926535898,degree2:6.2831853071796,
label:Text}],
0 [{degree1:0,degree2:6.2831853071796,
label:}]
},
width = 450,
height = 450,
radius = 75;
//帮助方法
var innerRadius = function(d,i,j){
return 1 + radius * j;
};
var outerRadius = function(d,i,j){
return radius *(j + 1);
};
var startAngle = function(d,i,j){
return d.data.degree1;
};
var endAngle = function(d,i,j){
return d.data.degree2;
};
var pie = d3.layout.pie()
.sort(null);
var arc = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius)
.startAngle(startAngle)
。 endAngle(endAngle);
var svg = d3.select('body')。append('svg')
.attr('width',width)
.attr height)
.append('g')
.attr('transform','translate('+(width>> 1)+','+(height>> 1) +')');
var level = svg.selectAll('g')
.data(function(d){
return d3.values(dataset);
})
.enter()
.append('g');
var entry = level.selectAll('g')
.data(function(d,i){
return pie(d);
})
.enter()
.append('g');
entry.append('path')
.attr('fill','#aaa')
.attr('d',arc)
。 attr('id',function(d,i,j){
return'arc'+ i +' - '+ j;
}
var label = entry.append('text')
.style('font-size','20px')
.attr('dx',function ,i,j){
return Math.round((d.data.degree2 - d.data.degree1)* 180 / Math.PI);
})
.attr dy',函数(d,i,j){
return((radius *(j + 1)) - (1 + radius * j))> 1;
}
label.append('textPath')
.attr('xlink:href',function(d,i,j){
return'#arc '+ i +' - '+ j;
})
.style('fill','#000')
.text(function(d){
return d .data.label;
});
请参阅。
这是一种比计算 dx
和 dy
。
建议进一步提高文本的质量和中心,例如您可能需要将文本呈现
设置为 optimizeLegibility
并与基线一起播放。
After playing a while with d3.js and looking at a lot of examples, I was able to draw multiple arcs. Each one starting and ending at an specific degree and and given radius.
var dataset = {
"2":[{"degree1":0, "degree2":1.5707963267949,
"label":"Sample Text Test"},
{"degree1":1.5707963267949, "degree2":3.1415926535898,
"label":"Lorem ipsum sample text"},
{"degree1":3.1415926535898, "degree2":4.7123889803847,
"label":"Sample Text Text"},
{"degree1":4.7123889803847, "degree2":6.2831853071796,
"label":"Lorem ipsum"}],
"1":[{"degree1":0, "degree2":3.1415926535898,
"label":"Sample"},
{"degree1":3.1415926535898, "degree2":6.2831853071796,
"label":"Text"}],
"0":[{"degree1":0, "degree2":6.2831853071796,
"label":""}]
},
width = 450,
height = 450,
radius = 75;
// Helper methods
var innerRadius = function(d, i, j) {
return 1 + radius * j;
};
var outerRadius = function(d, i, j) {
return radius * (j + 1);
};
var startAngle = function(d, i, j) {
return d.data.degree1;
};
var endAngle = function(d, i, j) {
return d.data.degree2;
};
var pie = d3.layout.pie()
.sort(null);
var arc = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius)
.startAngle(startAngle)
.endAngle(endAngle);
var svg = d3.select('body').append('svg')
.attr('width', width)
.attr('height', height)
.append('g')
.attr('transform', 'translate(' + (width >> 1) + ',' + (height >> 1) + ')');
var level = svg.selectAll('g')
.data(function(d) {
return d3.values(dataset);
})
.enter()
.append('g');
var entry = level.selectAll('g')
.data(function(d, i) {
return pie(d);
})
.enter()
.append('g');
entry.append('path')
.attr('fill', '#aaa')
.attr('d', arc)
.attr('id', function(d, i, j) {
return 'arc' + i + '-' + j;
});
var label = entry.append('text')
.style('font-size', '20px')
.attr('dx', function(d, i, j) {
return Math.round((d.data.degree2 - d.data.degree1) * 180 / Math.PI);
})
.attr('dy', function(d, i, j) {
return ((radius * (j + 1)) - (1 + radius * j)) >> 1;
});
label.append('textPath')
.attr('xlink:href', function(d, i, j) {
return '#arc' + i + '-' + j;
})
.style('fill', '#000')
.text(function(d) {
return d.data.label;
});
See http://jsfiddle.net/3FP6P/2/ :
But some problem still exists:
- How to center (horizonal und vertical) an text along an textpath of an any length inside an arc described by innerRadius, outerRadius, startAngle and endAngle?
- The text occurs sometimes bold, sometimes not. Why?
- The character spacing does not appear to be the same as if it is written inside a . Some letters stick more together as other ones. Why?
- The letters are not located directly on the path. Some seem to have a little slip up or down. Why?
Vertical alignment
You can use another arc with radius (innerRadius + outerRadius) / 2
and use it as the textPath
for the labels.
Note that even if you set the innerRadius == outerRadius
, D3 will draw an path which moves clockwise and then anti-clockwise to doubles over itself. This becomes important while trying to figure out the horizontal centre of the path: it is at the 25%
and 75%
points while 0%
and 50%
points lie on the two tips of the arc.
Horizontal alignment
Use text-anchor: middle
on the text element and set startOffset
to 25%
(or 75%
) on the textPath
.
Demo.
This is a more robust way than calculating the dx
and dy
by hand.
You should try out Lars's suggestions to further improve the quality and centring of the text, e.g. you might want to set text-rendering
to optimizeLegibility
and play with the baseline a bit.
这篇关于如何使用d3.js沿着一个圆弧中的textPath居中(水平和垂直)文本?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!