In the code below, I was able to determine the yOffset
value by trial and error.
I would prefer to calculate the value instead so the text will be vertically centered.
How can I do that?
The documentation for the SVG Text element says:
The y coordinate of the starting point of the text baseline, or the y coordinate of each individual glyph if a list of values is provided. Value type: List of (|) ; Default value: 0; Animatable: yes
So, I need to be able to determine what the baseline is to solve this problem generally. How can I do that?
function measureSVGText(text, fontSize, fontFamily) {
// Create an offscreen SVG element
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
svg.setAttribute("xmlns", "http://www.w3.org/2000/svg");
svg.setAttribute("width", "0");
svg.setAttribute("height", "0");
svg.style.position = "absolute";
svg.style.top = "-9999px";
svg.style.left = "-9999px";
// Create a text element
const textElement = document.createElementNS(
"http://www.w3.org/2000/svg",
"text"
);
textElement.setAttribute("x", "0");
textElement.setAttribute("y", "0");
textElement.style.fontSize = fontSize;
textElement.style.fontFamily = fontFamily;
textElement.textContent = text;
// Append the text element to the SVG
svg.appendChild(textElement);
document.body.appendChild(svg);
// Get the bounding box of the text element
const bbox = textElement.getBBox();
const roundedBBox = svg.createSVGRect();
roundedBBox.width = Math.ceil(bbox.width);
roundedBBox.height = Math.ceil(bbox.height);
// Remove the SVG element from the DOM
document.body.removeChild(svg);
return roundedBBox;
}
function createSVGLabel(text) {
const padding = 4;
const fontSize = 10;
const fontFamily = "Roboto";
const bbox = measureSVGText(text, `${fontSize}px`, fontFamily);
const svgWidth = bbox.width + padding * 2;
const svgHeight = bbox.height + padding * 2;
const yOffset = 13;
const svg =
'<?xml version="1.0"?>' +
`<svg width="${svgWidth}" height="${svgHeight}" viewBox="0 0 ${svgWidth} ${svgHeight}" version="1.1" xmlns="http://www.w3.org/2000/svg">` +
`<rect width="${svgWidth}" height="${svgHeight}" rx="10" ry="10" style="fill:white" />` +
`<text x="4" y="${yOffset}" font-family="${fontFamily}" font-size="${fontSize}" fill="black">${text}</text>` +
"</svg>";
return svg;
}
const label = createSVGLabel("00000");
const parser = new DOMParser();
const labelDocument = parser.parseFromString(label, "image/svg+xml");
const labelNode = labelDocument.getElementsByTagName("svg")[0];
const container = document.getElementById("container");
container.appendChild(labelNode);
<div id="container" style="width: 200px; height: 200px; background-color: black;">
</div>
Just set dominant-baseline="central"
function measureSVGText(text, fontSize, fontFamily) {
// Create an offscreen SVG element
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
svg.setAttribute("xmlns", "http://www.w3.org/2000/svg");
svg.setAttribute("width", "0");
svg.setAttribute("height", "0");
svg.style.position = "absolute";
svg.style.top = "-9999px";
svg.style.left = "-9999px";
// Create a text element
const textElement = document.createElementNS(
"http://www.w3.org/2000/svg",
"text"
);
textElement.setAttribute("x", "0");
textElement.setAttribute("y", "0");
textElement.style.fontSize = fontSize;
textElement.style.fontFamily = fontFamily;
textElement.textContent = text;
// Append the text element to the SVG
svg.appendChild(textElement);
document.body.appendChild(svg);
// Get the bounding box of the text element
const bbox = textElement.getBBox();
const roundedBBox = svg.createSVGRect();
roundedBBox.width = Math.ceil(bbox.width);
roundedBBox.height = Math.ceil(bbox.height);
// Remove the SVG element from the DOM
document.body.removeChild(svg);
return roundedBBox;
}
function createSVGLabel(text) {
const padding = 4;
const fontSize = 10;
const fontFamily = "Roboto";
const bbox = measureSVGText(text, `${fontSize}px`, fontFamily);
const svgWidth = bbox.width + padding * 2;
const svgHeight = bbox.height + padding * 2;
const svg =
'<?xml version="1.0"?>' +
`<svg width="${svgWidth}" height="${svgHeight}" viewBox="0 0 ${svgWidth} ${svgHeight}" version="1.1" xmlns="http://www.w3.org/2000/svg">` +
`<rect width="${svgWidth}" height="${svgHeight}" rx="10" ry="10" style="fill:white" />` +
`<text x="4" y="${svgHeight / 2}" font-family="${fontFamily}" font-size="${fontSize}" fill="black" dominant-baseline="central">${text}</text>` +
"</svg>";
return svg;
}
const label = createSVGLabel("00000");
const parser = new DOMParser();
const labelDocument = parser.parseFromString(label, "image/svg+xml");
const labelNode = labelDocument.getElementsByTagName("svg")[0];
const container = document.getElementById("container");
container.appendChild(labelNode);
<div id="container" style="width: 200px; height: 200px; background-color: black;">
</div>