Is it possible to center my text vertically in the ARC`s?
If you look at my example, you can see that the text in the first ring has a lot of space at the top and is not centered correctly.
I tried text-align and content-align for every “textPath”, but neither worked.
I would be very grateful for any advice!
Kind Regards Jegor
Using library D3.v7.js
// Data
const data1 = {
"name": "AB-C-1 <br> Dept.15 <br> Marketing <br> Müller",
"id": 1,
"children": [{
"name": "Topic A <br> Description <br> Dept.15 <br> Marketing <br> Müller ",
"id": 2,
"size": 2
}, {
"name": "Topic B <br> test",
"id": 3,
"size": 3
}, {
"name": "Topic C",
"id": 4,
"size": 4
}]
};
//-------------------------------------------------------------------------------------------
// Declare variables
let i_region_static_id = "sunburst",
parentDiv = document.getElementById(i_region_static_id),
width = parentDiv.clientWidth,
height = 450,
root,
rootDepth,
x,
y,
color = d3.scaleOrdinal(d3.schemeCategory10);
maxRadius = (Math.min(width, height) / 2) - 5;
const partition = d3.partition();
//-----------------------------------------------------------------------------------
// SVG-Element
let svg = d3.select('#' + i_region_static_id).append('svg')
.style('width', width)
.style('height', height)
.attr('viewBox', `${-width / 2} ${-height / 2} ${width} ${height}`)
//-----------------------------------------------------------------------------------
// X-Scale
x = d3.scaleLinear()
.range([0, 2 * Math.PI])
.clamp(true);
//-----------------------------------------------------------------------------------
// Y-Scale
y = d3.scaleSqrt()
.range([maxRadius * .1, maxRadius]);
//-----------------------------------------------------------------------------------
// Create Arc generator
const arc = d3.arc()
.startAngle(d => x(d.x0))
.endAngle(d => x(d.x1))
.innerRadius(d => Math.max(0, y(d.y0)))
.outerRadius(d => Math.max(0, y(d.y1)))
//-----------------------------------------------------------------------------------
const middleArcLine = d => {
const halfPi = Math.PI / 2;
const angles = [x(d.x0) - halfPi, x(d.x1) - halfPi];
const r = Math.max(0, (y(d.y0) + y(d.y1)) / 2);
const middleAngle = (angles[1] + angles[0]) / 2;
const invertDirection = middleAngle > 0 && middleAngle < Math.PI; // On lower quadrants write text ccw
if (invertDirection) {
angles.reverse();
}
const path = d3.path();
path.arc(0, 0, r, angles[0], angles[1], invertDirection);
return path.toString();
}
function wrap(text, index) {
text.each(function() {
var text = d3.select(this),
letters = text.text().split(' <br> ').reverse(),
letter,
line = [],
lineNumber = 0,
lineHeight = 1.1, // ems
y = text.attr("y"),
//dy = parseFloat(text.attr("dy")),
textPath = text.append("textPath") // Add a textPath element
.attr('startOffset', '50%')
.attr('fill', d => 'black')
.attr('xlink:href', function(d) {
return "#hiddenArc" + index;
}),
tspan = textPath.append('tspan') // Inslide textPath, add a tspan element, for offset feature later.
while (letter = letters.pop()) {
line.push(letter);
tspan.text(line.join(""));
if (line.length > 1) {
// if (tspan.node().getComputedTextLength() > width) {
line.pop();
tspan.text(line.join(""));
line = [letter];
textPath = text.append("textPath")
.attr('startOffset', '50%')
.attr('fill', d => 'black')
.attr('xlink:href', function(d, i) {
return "#hiddenArc" + index;
}),
// Add a tspan element to offset the wrapped letters from the previous line
tspan = textPath.append("tspan")
.attr('dy', ++lineNumber + 'em')
//.attr('text-anchor', 'middle')
.text(letter);
}
}
});
}
//-------------------------------------------------------------------------------------------
// Initialize and Update sun
function updateSun(pData) {
const valueAccessor = (d) => d.size;
root = d3.hierarchy(pData); //set data
valueAccessor == null ? root.count() : root.sum((d) => Math.max(0, valueAccessor(d)));
// Sortiert Nodes
root.sort((d) => d3.descending(d.value))
const slice = svg.selectAll('g.slice')
.data(
partition(root).descendants(),
function(d) {
return d.data.id;
}
);
// Enter Section
const newSlice = slice.enter()
.append('g').attr('class', 'slice')
.attr('display', d => d.depth < 2 ? null : 'none') // Hide levels lower depth
.each(function(d, i) {
// Append main-arc
d3.select(this).append('path')
.attr('class', 'main-arc')
.attr('d', arc)
.style('fill', d => (d.data.color == undefined) ? color((d.children ? d : d.parent).data.name) : d.data.color)
// Append hidden-arc
d3.select(this).append('path')
.attr('class', 'hidden-arc')
.attr('d', middleArcLine)
.attr('id', 'hiddenArc' + i)
// Append text
d3.select(this).append('text')
.attr('text-anchor', 'end')
.text(function(d) {
return d.data.name;
})
.style('fill', 'none')
.call(wrap, i);
})
}
//-------------------------------------------------------------------------------------------
updateSun(data1)
.slice {
cursor: pointer;
}
.slice .main-arc {
stroke: #fff;
stroke-width: 1px;
}
.slice .hidden-arc {
fill: none;
}
.slice text {
pointer-events: none;
text-anchor: middle;
}
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
<body>
<div id="sunburst"></div>
<script src="https://d3js.org/d3.v7.js" charset="utf-8"></script>
</body>
</html>