Juan
Juan

Reputation: 15715

Get DOM text node from point?

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?

Upvotes: 15

Views: 3433

Answers (4)

NamiW
NamiW

Reputation: 1692

You can use document.caretPositionFromPoint(x, y) for this but note that you'll need to fall back to document.caretRangeFromPoint(x, y) if document.caretPositionFromPoint is not available (e.g. in Safari as of writing, and Chrome/Edge versions before v128).

caretRangeFromPoint is non-standard, and deprecated, but it won't be removed at this point since many sites rely on it. So between those two, you have full browser support.

If you're dealing with a huge number of nodes, this should be much more performant than iterating through all text nodes, creating ranges, and checking the bounds of those ranges.

Upvotes: 4

Tobias Buschor
Tobias Buschor

Reputation: 196

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;
};

Upvotes: 18

Ja͢ck
Ja͢ck

Reputation: 173532

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.

Upvotes: 0

Ben
Ben

Reputation: 57209

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

Upvotes: 0

Related Questions