Comment centrer (horizontal et vertical) le texte le long d'un TextPath à l'intérieur d'un arc en utilisant d3.js?

Après avoir joué un peu avec d3.js et en regardant beaucoup d'exemples, j'ai pu dessiner plusieurs arcs. Chacun commence et se termine à un degré spécifique et à un rayon donné.

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; }); 

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

Entrez la description de l'image ici

Mais il existe encore un problème:

  1. Comment centrer (horizontal et vertical) un texte le long d'un chemin de texte d'une longueur quelconque dans un arc décrit par innerRadius, outerRadius, startAngle et endAngle?
  2. Le texte se produit parfois gras, parfois non. Pourquoi?
  3. L'espacement des caractères ne semble pas être le même que s'il est écrit à l'intérieur d'un. Certaines lettres s'accrochent comme autres. Pourquoi?
  4. Les lettres ne se trouvent pas directement sur le chemin. Certains semblent avoir un peu de glissement vers le haut ou vers le bas. Pourquoi?

Alignement vertical

Vous pouvez utiliser un autre arc avec rayon (innerRadius + outerRadius) / 2 et l'utiliser comme textPath pour les étiquettes.

Notez que même si vous définissez innerRadius == outerRadius , D3 dessine un chemin qui se déplace dans le sens des aiguilles d'une montre, puis dans le sens inverse des aiguilles d'une montre pour doubler sur lui-même. Cela devient important tout en essayant de comprendre le centre horizontal du chemin: il est à 25% et 75% points tandis que 0% et 50% points se situent sur les deux pointes de l'arc.

Alignement horizontal

Utilisez le text-anchor: middle sur l'élément de texte et définissez startOffset à 25% (ou 75% ) sur le textPath .

Démonstration .

C'est un moyen plus robuste que de calculer le dx et dy à la main.

Vous devriez essayer les suggestions de Lars pour améliorer encore la qualité et le centrage du texte, par exemple, vous voudrez peut-être configurer le text-rendering de text-rendering pour optimizeLegibility et jouer un peu avec la ligne de base.

Les problèmes 2-4 sont en raison du rendu des polices. Dans mon navigateur, l'espacement et la taille des caractères etc. sont cohérents. Vous pouvez essayer de jouer avec l' attribut de text-rendering pour améliorer les choses.

Pour que le texte soit centré, vous devez définir les attributs d' alignment-baseline et / ou dominant-baseline .

Si cela ne vous donne toujours pas les résultats que vous recherchez, essayez de diminuer la taille de la police. Cela peut aider car une légère rotation d'un personnage sera moins visible.