Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Coordinates of selected text in browser page

I need the coordinates in pixels of the beginning of the text selection (anywhere on the page, not in a textarea).

I tried using the cursor coordinates but this didn't work quite well because the cursor coordinates and the beginning of the selection are not always the same (for example when a user drags over a text).

I hope someone has the solution!

like image 917
Bouke Avatar asked Jul 27 '11 14:07

Bouke


People also ask

How do you find the coordinates of your browser?

In order to find the coordinates of the top left corner of the HTML page, you can use the web browser's instance properties DisplayRectangleX and DisplayRectangleY. For example, after storing a browser's instance into the variable %Browser%, then %Browser. DisplayRectangleX% will return the X dimension and %Browser.

What is window getSelection?

getSelection() The Window. getSelection() method returns a Selection object representing the range of text selected by the user or the current position of the caret.


2 Answers

In IE >= 9 and non-IE browsers (Firefox 4+, WebKit browsers released since early 2009, Opera 11, maybe earlier), you can use the getClientRects() method of Range. In IE 4 - 10, you can use the boundingLeft and boundingTop properties of the TextRange that can be extracted from the selection. Here's a function that will do what you want in recent browsers.

Note that there are some situations in which you may wrongly get co-ordinates 0, 0, as mentioned in the comments by @Louis. In that case you'll have to fall back to a workaround of temporarily inserting an element and getting its position.

jsFiddle: http://jsfiddle.net/NFJ9r/132/

Code:

function getSelectionCoords(win) {     win = win || window;     var doc = win.document;     var sel = doc.selection, range, rects, rect;     var x = 0, y = 0;     if (sel) {         if (sel.type != "Control") {             range = sel.createRange();             range.collapse(true);             x = range.boundingLeft;             y = range.boundingTop;         }     } else if (win.getSelection) {         sel = win.getSelection();         if (sel.rangeCount) {             range = sel.getRangeAt(0).cloneRange();             if (range.getClientRects) {                 range.collapse(true);                 rects = range.getClientRects();                 if (rects.length > 0) {                     rect = rects[0];                 }                 x = rect.left;                 y = rect.top;             }             // Fall back to inserting a temporary element             if (x == 0 && y == 0) {                 var span = doc.createElement("span");                 if (span.getClientRects) {                     // Ensure span has dimensions and position by                     // adding a zero-width space character                     span.appendChild( doc.createTextNode("\u200b") );                     range.insertNode(span);                     rect = span.getClientRects()[0];                     x = rect.left;                     y = rect.top;                     var spanParent = span.parentNode;                     spanParent.removeChild(span);                      // Glue any broken text nodes back together                     spanParent.normalize();                 }             }         }     }     return { x: x, y: y }; } 

UPDATE

I submitted a WebKit bug as a result of the comments, and it's now been fixed.

https://bugs.webkit.org/show_bug.cgi?id=65324

like image 125
Tim Down Avatar answered Oct 22 '22 04:10

Tim Down


The above answer by TimDown does not work if the caret is in an empty element.

The code below solves the problem. Note how it is almost identical to TimDown's solution except that this code checks the range.getClientRects() array has length>0 before calling range.getClientRects()[0]

function getSelectionCoords() {     var sel = document.selection, range, rect;     var x = 0, y = 0;     if (sel) {         if (sel.type != "Control") {             range = sel.createRange();             range.collapse(true);             x = range.boundingLeft;             y = range.boundingTop;         }     } else if (window.getSelection) {         sel = window.getSelection();         if (sel.rangeCount) {             range = sel.getRangeAt(0).cloneRange();             if (range.getClientRects) {                 range.collapse(true);                 if (range.getClientRects().length>0){                     rect = range.getClientRects()[0];                     x = rect.left;                     y = rect.top;                 }             }             // Fall back to inserting a temporary element             if (x == 0 && y == 0) {                 var span = document.createElement("span");                 if (span.getClientRects) {                     // Ensure span has dimensions and position by                     // adding a zero-width space character                     span.appendChild( document.createTextNode("\u200b") );                     range.insertNode(span);                     rect = span.getClientRects()[0];                     x = rect.left;                     y = rect.top;                     var spanParent = span.parentNode;                     spanParent.removeChild(span);                      // Glue any broken text nodes back together                     spanParent.normalize();                 }             }         }     }     return { x: x, y: y }; } 
like image 36
Jakobovski Avatar answered Oct 22 '22 02:10

Jakobovski