Coordinates of selected text in browser page
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
Getting selected text position
The easiest way is to insert a temporary marker element at the start or end of the selection and get its position. I've demonstrated how to do this before on Stack Overflow: How can I position an element next to user text selection?
selected text and xy coordinates
Just googled it:
var txt = "";
if (window.getSelection) {
txt = window.getSelection();
} else if (document.getSelection) {
// FireFox
txt = document.getSelection();
} else if (document.selection) {
// IE 6/7
txt = document.selection.createRange().text;
}
txt = txt.toString()
There is no simple way to get X/Y coordinates of the selected text. Because it dependes on its container position and size, text font, text layout, and many many other variables.
How to get the screen coordinates for the selected text within a textarea
First issue: startOffset
and endOffset
don't relate to the position of a selection on the screen. Instead they relate to the character or node position within the startContainer
or endContainer
where a selection begins an ends. This allows you to determine the starting and ending character or node index of a selection spanning multiple elements (imagine a selection starting in a bold region of a paragraph and ending outside of it, startOffset
would be the index of the within just the bold element's text, and endOffset
would be the index within the Text
range coming after the bold element).
Good news: there is an experimental function on the Range
object called getBoundingClientRect
that does get screen coordinates for a bounding box surrounding the current selection.
The rub: Unfortunately, at least in Google Chrome, getBoundingClientRect
does not return accurate coordinates when a selection is within a textarea
or input
. So unless you can avoid using textarea
, for example by using a content editable div (see: https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Editable_content) this solution may not work for you.
Crazy alternative: the Canvas
object has facilities for measuring the dimensions of text, so if you were really diehard, you could theoretically measure the dimensions of the text contained in the textarea
, including emulating the word wrapping behavior, in order to calculate independently where the selected text is within the textarea
(don't forget to account for scroll offset).
Here is a snippet that visually demonstrates the state of the selection Range
object as it changes.
var outline = document.getElementById('selection_outline');var start_container = document.getElementById('start_container');var end_container = document.getElementById('end_container');var start_offset = document.getElementById('start_offset');var end_offset = document.getElementById('end_offset');
document.addEventListener('selectionchange', function() { var selection = document.getSelection(); if (selection) { var range = selection.getRangeAt(0); if (range) { var bounds = range.getBoundingClientRect(); outline.style.top = `${bounds.top + window.scrollY}px`; outline.style.left = `${bounds.left + window.scrollX}px`; outline.style.width = `${bounds.width}px`; outline.style.height = `${bounds.height}px`; start_container.value = range.startContainer.tagName || range.startContainer.parentNode.tagName; end_container.value = range.endContainer.tagName || range.endContainer.parentNode.tagName; start_offset.value = range.startOffset; end_offset.value = range.endOffset; } }})
#selection_outline { position: absolute; border: 2px solid red; pointer-events: none;}
.flow-wrap-row { display: flex; flex-direction: row; flex-wrap: wrap;}
.flow-wrap-row > * { white-space: nowrap}
.flow-wrap-row > li { margin-right: 1.5em;}
ul { padding-left: 1.5em;}
input { width: 80px;}
<p>This is <b>a complex element</b> with lots of selectable text <i>and nested, <b> and double nested</b> elements</i>!!!</p><textarea cols="60" rows="5">Here is a text area with some simple content.</textarea><div contenteditable="true">Here is a contenteditable div with some simple content.</div><ul class="flow-wrap-row"> <li><label>startContainer: <input id="start_container" type="text" /></label></li> <li><label>endContainer: <input id="end_container" type="text" /></label></li> <li><label>startOffset: <input id="start_offset" type="text" /></label></li> <li><label>endOffset: <input id="end_offset" type="text" /></label></li></ul><div id="selection_outline"></div>
how do I get co-ordinates of selected text in an html using javascript document.getSelecttion()
Here is the basic idea. You insert dummy element in the beginning of the selection and get the coordinates of that dummy html element. Then you remove it.
var range = window.getSelection().getRangeAt(0);
var dummy = document.createElement("span");
range.insertNode(dummy);
var box = document.getBoxObjectFor(dummy);
var x = box.x, y = box.y;
dummy.parentNode.removeChild(dummy);
Get selected text position and place an element next to it
You could position a marker span at the end of the selection, get its coordinates using jQuery, place your button at those coordinates and remove the marker span.
The following should get you started:
var markSelection = (function() {
var markerTextChar = "\ufeff";
var markerTextCharEntity = "";
var markerEl, markerId = "sel_" + new Date().getTime() + "_" + Math.random().toString().substr(2);
var selectionEl;
return function(win) {
win = win || window;
var doc = win.document;
var sel, range;
// Branch for IE <= 8
if (doc.selection && doc.selection.createRange) {
// Clone the TextRange and collapse
range = doc.selection.createRange().duplicate();
range.collapse(false);
// Create the marker element containing a single invisible character by creating literal HTML and insert it
range.pasteHTML('<span id="' + markerId + '" style="position: relative;">' + markerTextCharEntity + '</span>');
markerEl = doc.getElementById(markerId);
} else if (win.getSelection) {
sel = win.getSelection();
range = sel.getRangeAt(0).cloneRange();
range.collapse(false);
// Create the marker element containing a single invisible character using DOM methods and insert it
markerEl = doc.createElement("span");
markerEl.id = markerId;
markerEl.appendChild( doc.createTextNode(markerTextChar) );
range.insertNode(markerEl);
}
if (markerEl) {
// Lazily create element to be placed next to the selection
if (!selectionEl) {
selectionEl = doc.createElement("div");
selectionEl.style.border = "solid darkblue 1px";
selectionEl.style.backgroundColor = "lightgoldenrodyellow";
selectionEl.innerHTML = "<- selection";
selectionEl.style.position = "absolute";
doc.body.appendChild(selectionEl);
}
// Find markerEl position http://www.quirksmode.org/js/findpos.html
var obj = markerEl;
var left = 0, top = 0;
do {
left += obj.offsetLeft;
top += obj.offsetTop;
} while (obj = obj.offsetParent);
// Move the button into place.
// Substitute your jQuery stuff in here
selectionEl.style.left = left + "px";
selectionEl.style.top = top + "px";
markerEl.parentNode.removeChild(markerEl);
}
};
})();
Related Topics
How to Start Automatic Download of a File in Internet Explorer
Want to Add "Addeventlistener" on Multiple Elements With Same Class
JavaScript - Shuffle HTML List Element Order
Best Way to Detect That Html5 ≪Canvas≫ Is Not Supported
How to Transform Black into Any Given Color Using Only CSS Filters
Remove All Classes That Begin With a Certain String
Styling ≪Input Type="File"≫
Using Async/Await With a Foreach Loop
How to Convert Base64 String to JavaScript File Object Like as from File Input Form
How to Write in File (User Directory) Using JavaScript
How to Use External ".Js" Files
Html5 Canvas Drawimage Ratio Bug Ios
Is It Possible For Flex Items to Align Tightly to the Items Above Them
Turn a Number into Star Rating Display Using Jquery and Css