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!
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
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
Method 2
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 }; }
Method 3
The code below is a simplified and modernized version of the solution given by Tim Down. It also uses a more browser compatible selection API (window.getSelection()
instead of window.document.selection
)
type Coord = {
x: number;
y: number;
};
// atStart: if true, returns coord of the beginning of the selection,
// if false, returns coord of the end of the selection
function getSelectionCoords(atStart: boolean): Coord | null {
const sel = window.getSelection();
// check if selection exists
if (!sel.rangeCount) return null;
// get range
let range = sel.getRangeAt(0).cloneRange();
if (!range.getClientRects) return null;
// get client rect
range.collapse(atStart);
let rects = range.getClientRects();
if (rects.length <= 0) return null;
// return coord
let rect = rects[0];
return { x: rect.x, y: rect.y };
}
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0