如何使用 d3.js 在弧内沿 textPath 居中(水平和垂直)文本?
Posted
技术标签:
【中文标题】如何使用 d3.js 在弧内沿 textPath 居中(水平和垂直)文本?【英文标题】:How to center (horizontal and vertical) text along an textPath inside an arc using d3.js? 【发布时间】:2013-12-25 04:10:48 【问题描述】:在玩了一段时间 d3.js 并查看了很多示例之后,我能够绘制多条弧线。每一个都以特定的度数和给定的半径开始和结束。
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;
);
见http://jsfiddle.net/3FP6P/2/:
但还是有一些问题:
-
如何在由 innerRadius、outerRadius、startAngle 和 endAngle 描述的弧内沿任意长度的文本路径居中(水平和垂直)文本?
文本有时会显示为粗体,有时不是。为什么?
字符间距似乎与写在 .有些字母像其他字母一样粘在一起。为什么?
字母不直接位于路径上。有些似乎有一点向上或向下滑动。为什么?
【问题讨论】:
【参考方案1】:垂直对齐
您可以使用另一个半径为(innerRadius + outerRadius) / 2
的弧并将其用作标签的textPath
。
请注意,即使您设置了innerRadius == outerRadius
,D3 也会绘制一条顺时针然后逆时针移动的路径,使其自身翻倍。这在试图找出路径的水平中心时变得很重要:它位于25%
和75%
点,而0%
和50%
点位于路径的两个尖端弧线。
水平对齐
在文本元素上使用text-anchor: middle
,并在textPath
上将startOffset
设置为25%
(或75%
)。
Demo.
这比手动计算dx
和dy
更可靠。
您应该尝试 Lars 的建议以进一步提高文本的质量和居中,例如您可能想将text-rendering
设置为optimizeLegibility
并稍微调整一下基线。
【讨论】:
您可能指的是startOffset
,而不是offsetStart
,请参阅w3.org/TR/SVG11/text.html#TextPathElementStartOffsetAttribute。
@ErikDahlström 谢谢。修好了。
这很整洁。谢谢!【参考方案2】:
问题 2-4 是因为字体渲染。在我的浏览器中,间距和字符大小等是一致的。您可以尝试使用text-rendering
attribute 来改进。
要使文本居中,您需要设置alignment-baseline
和/或dominant-baseline
属性。
如果这仍然无法为您提供所需的结果,请尝试减小字体大小。这可能会有所帮助,因为角色的轻微旋转会不太明显。
【讨论】:
垂直对齐使用alignment-baseline
对我有用。以上是关于如何使用 d3.js 在弧内沿 textPath 居中(水平和垂直)文本?的主要内容,如果未能解决你的问题,请参考以下文章