Join us at FabCon Atlanta from March 16 - 20, 2026, for the ultimate Fabric, Power BI, AI and SQL community-led event. Save $200 with code FABCOMM.
Register now!To celebrate FabCon Vienna, we are offering 50% off select exams. Ends October 3rd. Request your discount now.
Hello,
Setting dominant-baseline to middle isn't working for all fonts in cases where the text height exceeds svg height. I am trying to vertically center text on top of a rect element. Some fonts appear too low and others too high, while some appear just right. In short, some fonts are squat and some are tall. Is there a way for me to measure the actual glyphs, without the line height and bounding box of the whole text element?
Thanks
Emma
kpiTextHeight = Math.round(textMeasurementService.measureSvgTextHeight(kpiTextProperties));
I have tried playing with baselineDelta but it doesn't seem to change much with the font.
this.kpiText
.attr('text-anchor','middle')
.attr('dominant-baseline','central')
.attr('font-size',kpiFontSize+'pt')
.attr('y', 0 )
.attr('dy', 0)
.attr('y', kpiRectHeight/2 )
// .attr('dy', -kpiFontSize/2)
.attr('font-family',kpiFont)
.attr('x',svgWidth/2)
.attr('fill', settings.kpiTextCard.kpiFontColorSlice.value.value)
.attr('class','kpiNumber')
.text(kpiValue);
this.kpiText sits within a group, which also contains a rect element of height kpiRectHeight.
@VizDataLtd In order to vertically center a svg text to a svg rect, this should be the config
const text = svg.append('text')
.each(
function(_, i) {
// taget element for alignment
const rect = /*get the rect node either with vanilla or d3*/ document.querySelector('rect');
//get x+ half of width
const midX = parseFloat(rect.getAttribute('x')) + parseFloat(rect.getAttribute('width')) / 2;
//get y+ half of height
const midY = parseFloat(rect.getAttribute('y')) + parseFloat(rect.getAttribute('height')) / 2;
d3.select(this)
.attr('x', midX)
.attr('y', midY)
// aligns as per the text length
.attr('text-anchor', 'middle')
.attr('dominant-baseline', 'middle')
.text('Lorem Ipsum')
.attr('font-size', '140px')
}
)
<div id="viz">
<svg id="svg" viewBox="0 0 1280 600">
<rect class="svg_container" width="1280" height="600" fill="#EFEFEF" stroke="black"></rect>
<text x="640" y="300" text-anchor="middle" dominant-baseline="middle" font-size="140px">Lorem Ipsum</text>
</svg>
</div>
Thanks, yes, that should work but it wasn't working at the extremes. I added a red line at the vertical midpoint and compared fonts. For anyone struggling with the same thing, I worked out that some fonts just sit lower. Constantia, for example, sits below the others. So while my visual works brilliantly with Arial and Times New Roman, I don't think there is a fix for some fonts.
If you are using an external font (which I always do) it might be worth to wrap your calculations in Document: fonts promise and use font-display: block; to ensure that the coordinates are only applied once the external fonts are loaded and not before that.