Search code examples
javascripthtmlnode.jsdomvuejs3

How to get coordinates of multi-line span element?


I'd think this would be simple/common but can't find it anywhere after months of looking. I would like to edit segments of a paragraph but have the input element overlay on the section being edited. Y coordinates are easy, but to get where the span element is when it goes into a second line, it gives me the left offset of the second line instead of the first -- and I understand the logic of why. But what convoluted mind-numbing method can I use to get the position of the first line?

let strings = [
    'Lorem ipsum dolor sit amet, ...{{ autogenerated Lorem Ipsum }}
              ];

strings = strings.map((str) => str.replace(/(\.|\?|\!)/g, '$1 |||'));
<template>
<p>
   <span v-for="(content, index) in strings"></span></p></template>

Yes, it's Vue3 but it doesn't really matter to the question. And the code that I'm trying right now has a whole bunch of ref(null) etc so I'm just skipping all that. I'm just trying

target.getBoundingClientRect().left // target.getBoundingClientRect().x is the same

How can I get the x position of where my span element begins?


Solution

  • For anyone landing here - as I did - looking for the answer to the title, although @yoduh answers the question (left boundary of the first line), @Alohci's reference to getClientRects() answers better the title (coordinates of multi-line element), because the latter returns the coordinates of every line in the element, so you can loop through them.

    The example below outputs in the console all the coordinates (x, y, width, height, top, right, bottom, left) for every line of text in the element:

    function showCoordinates(target) {
       var linesCoords = target.getClientRects();
       for (var i = 0; i < linesCoords.length; i++) {
          console.log(linesCoords[i]);
       }
    }
    var my_element = document.getElementById('MY_SPAN');
    showCoordinates(my_element);
    

    In the next example, the function returns and X/Y object for the desired line, or null if the line does not exist:

    function getXY(target,linenumber) {
       var linesCoords = target.getClientRects();
       return linesCoords[linenumber] ? {x: linesCoords[linenumber].x, y: linesCoords[linenumber].y} : null;
    }
    var my_element = document.getElementById('MY_SPAN');
    // Get third line of 'MY_SPAN'
    var line3coords = getXY(my_element,3);
    if (line3coords) {
       alert("The 3rd line of MY_SPAN is at " + line3coords.x + " by " + line3coords.y);
    }