Um die Etiketten zu wickeln, müssen Sie Mikes Lösung anpassen, um mit textPath
Elementen umzugehen.
Dafür brauchen wir mehrere Dinge:
1. die zur Verfügung stehende Breite Holen, die
wickeln sollten die Etiketten erreichen Sie die Länge des Bogens berechnen konnte selbst, aber ich habe dies getan, indem Berechnen des Segments, das von den Endpunkten Ihrer unsichtbaren Pfade erstellt wird, denen Ihre Labels folgen. Dies wird uns auch einen kleinen Seitenrand geben, da die Länge des Segments kürzer ist als die Länge des Bogens.
Der Abstand zwischen zwei Punkten berechnet sich wie folgt:
d = sqrt((x2 - x1)^2 + (y2 - y1)^2)
2. Wickeln Sie die Etiketten, wenn sie reich verfügbare Breite und halten die
für diesen einen zum Zentrum ausgerichtet Verwaltung, hatte ich in die SVG
Dokumentation über die textPath
element zu graben, um zu sehen, wie es entlang der Y-Achse gewickelt und verschoben werden kann.
Anfangs habe ich versucht, mehrere textPath
Elemente innerhalb eines text
Labels zu setzen, aber ich konnte es nicht schaffen, sie entlang der y-Achse zu verschieben. Es stellt sich heraus, dass Sie dafür tspan
Elemente innerhalb textPath
Elemente hinzufügen müssen. Aber hier entstand ein anderes Problem - ich konnte es nicht schaffen, sie zentriert zu halten.
Um eine Verschiebung entlang der y-Achse und der zentralen Ausrichtung zu erreichen, müssen Sie am Ende ein Element textPath
(für horizontale Ausrichtung) mit einem Element tspan
innen verwenden (für vertikale Ausrichtung).
3. Wickeln Sie die Etiketten mit den Buchstaben, nicht durch Worte
dies der Punkt ist, dass ich angenommen habe, dass man nämlich Brief Verpackung benötigen (im Moment des Schreibens, ich habe nicht die Antwort aus OP), weil auf kleinen Größen Ihres Diagramms Wörter zu lang sind, um in eine Zeile zu passen.
Dies war das einfachste Problem zu lösen.Gerade die Spaltung einstellen und Fügeoperationen von Worten zu Buchstaben wechseln:
letters = text.text().split('').reverse(); // instead of .split(/\s+/)
...
tspan.text(line.join("")); // instead of .join(" ")
Und hier ist der gesamte Code, der geändert wurde, mit Bemerkungen:
outerSvg.selectAll(".outerCircleText")
.data(pie(behaviorsDatasetOuterCircle))
.enter().append("text")
.attr("class", "outerCircleText")
//Move the labels below the arcs for those slices with an end angle greater than 90 degrees
.attr("dy", function (d, i) {
d.i = i;
return (d.startAngle >= 90 * Math.PI/180 ? 18 : -11);
})
.text(function(d) { return d.data.name; })
.call(wrap); // Do not add `textPath` elements here. Instead, add them in the `wrap` function
function wrap(text) {
text.each(function() {
var text = d3.select(this),
letters = text.text().split('').reverse(),
letter,
line = [],
lineNumber = 0,
lineHeight = 1.1, // ems
y = text.attr("y"),
dy = parseFloat(text.attr("dy")),
textPath = text.text(null).append("textPath") // Add a textPath element
.attr("startOffset", '50%')
.style("text-anchor", "middle")
.attr("xlink:href", function(d) { return "#outerArc" + d.i; }),
tspan = textPath.append('tspan'), // Inslide textPath, add a tspan element, for offset feature later.
path = d3.select(text.select('textPath').attr('xlink:href')); // Get the path to compute width of text later.
var startLoc = /M(.*?)A/;
var newStart = path.attr('d').match(startLoc)[1];
var newEnd = path.attr('d').indexOf(' 0 0 0 ') > -1
? path.attr('d').split(' 0 0 0 ')[1]
: path.attr('d').split(' 0 0 1 ')[1] ;
// Compute the start/end coordinate points of the arc that the text will follow.
var x1 = parseFloat(newStart.split(' ')[0]),
y1 = parseFloat(newStart.split(' ')[1]),
x2 = parseFloat(newEnd.split(' ')[0]),
y2 = parseFloat(newEnd.split(' ')[1]);
// Compute the length of the segment between the arc start/end points. This will be the
// width which the labels should wrap when reaching it.
var width = Math.sqrt(Math.pow((x2 - x1), 2) + Math.pow((y2 - y1), 2));
// And then we go on (with slight changes) with the example from Mike Bostock
// from here https://bl.ocks.org/mbostock/7555321
while (letter = letters.pop()) {
line.push(letter);
tspan.text(line.join(""));
if (tspan.node().getComputedTextLength() > width) {
line.pop();
tspan.text(line.join(""));
line = [letter];
// Instead of adding only a tspan element, add a new textPath so that the wrapped
// letters will be aligned to center. Without it, the letters will start drawing
// from right with part of them invisible, like if the labels are not wrapped.
textPath = text.append("textPath")
.attr("startOffset", '50%')
.style("text-anchor", "middle")
.attr("xlink:href", function(d) { return "#outerArc" + d.i; }),
// Add a tspan element to offset the wrapped letters from the previous line
tspan = textPath.append("tspan")
.attr('dy', '1em')
.attr('text-anchor', 'middle')
.text(letter);
}
}
});
}
Am Ende war es eine interessante Herausforderung . Here ist eine Verzweigung Ihres Codepen mit einem Arbeitsbeispiel (die Änderungen beginnen mit Zeile 749).
Der Codepen hat nur die äußeren Etiketten umwickelt. Ich habe die inneren Etiketten für Sie gelassen, um den hier beschriebenen Ansatz zu implementieren. Viel Glück damit!
Möchten Sie mit Wörtern oder Buchstaben umbrechen? (für den Fall, dass ein Wort nicht in den verfügbaren Platz passt) – iulian
Ich wollte mit Worten, aber von jetzt an denke ich, es wird nicht schwer sein, Ihre Lösung zu transformieren, um meine Bedürfnisse zu erfüllen – bumbeishvili
hmm ... Es war schwer: s – bumbeishvili