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/ :
Mais il existe encore un problème:
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.