How to center (horizontal and vertical) text along an textPath inside an arc using d3.js?

d3.js, javascript, path, svg, text

Solution

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.

Problem

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?

Original source