如何使用d3.js沿弧内的textPath居中(水平和垂直)文本?

Ric*_*tag 4 javascript svg text path d3.js

在与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;
    });
Run Code Online (Sandbox Code Playgroud)

http://jsfiddle.net/3FP6P/2/:

在此输入图像描述

但仍存在一些问题:

  1. 如何在innerRadius,outerRadius,startAngle和endAngle描述的弧内的任意长度的文本路径中居中(水平和垂直)文本?
  2. 文本有时是粗体,有时不是.为什么?
  3. 字符间距似乎与写在a中的字符间距不同.有些字母和其他字母一样粘在一起.为什么?
  4. 字母不直接位于路径上.有些人似乎有点滑倒或下滑.为什么?

mus*_*_ut 9

垂直对齐

您可以使用另一个半径弧(innerRadius + outerRadius) / 2并将其用作textPath标签.

请注意,即使您设置了innerRadius == outerRadius,D3也会绘制一条顺时针方向移动的路径,然后逆时针方向移动一倍.这在尝试找出路径的水平中心时变得很重要:它位于25%75%点上,0%50%点位于弧的两个尖端上.

水平对齐

text-anchor: middle在文本元素上使用并设置startOffset25%(或75%)textPath.

演示.

这比计算dxdy手动更有效.

你应该尝试拉斯的建议,以进一步提高文本的质量和定心,例如,你可能需要设置text-renderingoptimizeLegibility与基线玩了一下.

  • 您可能需要`startOffset`,而不是`offsetStart`,请参阅http://www.w3.org/TR/SVG11/text.html#TextPathElementStartOffsetAttribute. (2认同)

Lar*_*off 5

问题2-4是由于字体渲染引起的。在我的浏览器中,间距和字符大小等是一致的。您可以尝试使用该text-rendering属性来改进事情。

要使文本居中,您需要设置alignment-baseline和/或dominant-baseline属性。

如果这仍然没有给您想要的结果,请尝试减小字体大小。这可能会有所帮助,因为角色的轻微旋转将不太明显。