Why is the .getComputedTextLength() not working?

I am trying to find the length of a SVG Text element.
I can select the node and display the node but the .getComputedTextLength() on the node is returning zero.

I have a function that does basically the same thing, but it returns the correct length.

  for (let i = 0; i < 23; i++) {  
    svg.append('text')
      .style("font-size", "24px")
      .style("font-family", "sans-serif")
      .attr('x',10)
      .attr('y',32.75*i)
      .attr('id', `T${i}`)
      .text(reo[i].Māori);
    let s = svg.selectAll(`#T${i}`).node()//.getComputedTextLength()

    console.log('s',s,s.getComputedTextLength(), textSize(reo[i].Māori))  // y s.getComputedTextLength() no works? 

Try maybe to append the node to the DOM, then compute the text sizes, then remove the node again before returning it.

document.body.appendChild(svg.node());
// compute lengths

return document.body.removeChild(svg.node());

1 Like

It’s odd (to me) that I can do a selectAll() on the DOM for the Text element’s ID because that implies to me that it is appended to the DOM.

Oh well I will be using the textSize() function to work out the elements width and height. Thanks for the help @Fil

function textSize(text) {
  let container = d3.select('body').append('svg');
  container.append('text')

    .style("font-size", "24px")      // todo: these need to be passed to the function or a css style
    .style("font-family", "sans-serif")
    .text(text);

  let sel = container.selectAll('text').node()
  let width = sel.getComputedTextLength()
  let height = sel.getExtentOfChar(0).height
  container.remove()
  return {width, height}
}
1 Like

There’s a difference between d3.selectAll() and container.selectAll(). The former works like document.querySelectorAll(), in which case any elements to be matched have to be attached to the document (the DOM), i.e. be children of it.
The latter queries the children of container. Example:

html`<div>
  <p>first</p>
  <p>second</p>
</div>`.querySelectorAll('p')

selects all p elements that are children of the outermost element (the div).

Regarding getComputedTextLength(): As a rule of thumb, whenever a DOM method has computed in its name, it requires the browser to first draw the element in order to figure out the final size/shape/etc. And for that, the element has to be attached to the DOM.


Fun fact: DOM elements have a property isConnected that tells you if the element is attached to the DOM. Here’s a little experiment for you to try, consisting of two cells:

mutable connected = null
{
  const element = html`<p>I'm connected!`;
  mutable connected = element.isConnected;
  await Promises.delay(1000);
  yield element;
  mutable connected = element.isConnected;  
}
1 Like

Thanks @mootari I am not longer confused :smiley: Awesome explanation.

1 Like