14

Just like I can get an element from a point with document.elementFromPoint or document.getElementFromPoint, is it possible to somehow get a text node if the point is at a text node? I guess if at least I could get the text node's position and size I could then figure out which of them contains the point. But then DOM nodes don't have position properties. Is it possible to do this at all?

Juan
  • 15,274
  • 23
  • 105
  • 187

4 Answers4

17

Here is an implementation that works in all current browsers: https://github.com/nuxodin/q1/blob/master/q1.dom.js

document.betaNodeFromPoint = function(x, y){
    var el = document.elementFromPoint(x, y);
    var nodes = el.childNodes;
    for ( var i = 0, n; n = nodes[i++];) {
        if (n.nodeType === 3) {
            var r = document.createRange();
            r.selectNode(n);
            var rects = r.getClientRects();
            for ( var j = 0, rect; rect = rects[j++];) {
                if (x > rect.left && x < rect.right && y > rect.top && y < rect.bottom) {
                    return n;
                }
            }
        }
    }
    return el;
};
2

For Firefox, you should use document.caretPositionFromPoint

Here's a greap demo: https://developer.mozilla.org/en-US/docs/Web/API/document.caretPositionFromPoint

For Chrome and Edge, try document.caretRangeFromPoint(x,y)

NamiW
  • 1,572
  • 4
  • 19
  • 33
  • 1
    alas, this is a Firefox specific function :-( – Michael Mar 26 '15 at 22:04
  • @Michael yah for other browsers, try document.caretRangeFromPoint(x,y) – NamiW Jan 02 '18 at 10:22
  • The support for Firefox was removed so the way is as per the top answer: https://stackoverflow.com/a/13789789/6664036 which goes from an outer `Element` that can be huge so the process might be slow. Alternatively, `elementFromPoint` can be used with an offset to pick up an `Element` nearby and then with `previousSibling`/`nextSibling` and comparing coordinates a text node in question can be found. However, while faster, this can be unreliable depending on the structure of the DOM which can overlay elements on top and have them displaced with `absolute` positioning or detached in other ways. – DDRRSS Feb 14 '22 at 15:04
0

You can use element.nodeName to see if it's a text node, and then element.nodeValue for its value.

Ben
  • 54,723
  • 49
  • 178
  • 224
  • 4
    I'd assume that `getElementFromPoint` only returns element nodes. – Felix Kling Nov 28 '12 at 03:18
  • Ahh, yes, you're right: https://developer.mozilla.org/en-US/docs/DOM/document.elementFromPoint states that `element must be an element object` (which is a different XML type than a text object) – Ben Nov 28 '12 at 03:25
0

Considering this document (fiddle):

<html>
<body>
    some text here 
    <p id="para1">lalala</p> 
    bla bla
</body>
</html>​

And this code:

$(document).on('click', function(evt) {
    var elem = document.elementFromPoint(evt.clientX, evt.clientY);
    console.log(elem);
});

When you click anywhere inside the <p> tag, the tag element itself is logged. However, when the surrounding text is clicked, the <body> is returned because text fragments are not considered elements.

Conclusion

It's not possible to accomplish what you want with elementFromPoint() and because text fragments don't receive click events, I don't think it's possible at all.

Ja͢ck
  • 170,779
  • 38
  • 263
  • 309