テキスト選択の先頭のピクセル単位の座標が必要です(テキストエリアではなく、ページ上の任意の場所)。
カーソル座標を使用してみましたが、カーソル座標と選択範囲の先頭が常に同じであるとは限らないため(たとえば、ユーザーがテキスト上をドラッグした場合)、これはうまく機能しませんでした。
私は誰かが解決策を持っていることを願っています!
テキスト選択の先頭のピクセル単位の座標が必要です(テキストエリアではなく、ページ上の任意の場所)。
カーソル座標を使用してみましたが、カーソル座標と選択範囲の先頭が常に同じであるとは限らないため(たとえば、ユーザーがテキスト上をドラッグした場合)、これはうまく機能しませんでした。
私は誰かが解決策を持っていることを願っています!
IE> = 9および非IEブラウザー(Firefox 4以降、2009年初頭以降にリリースされたWebKitブラウザー、Opera 11、おそらくそれ以前)では、のgetClientRects()
方法を使用できますRange
。IE 4-10では、選択範囲から抽出できるのプロパティboundingLeft
とboundingTop
プロパティを使用できます。TextRange
これが最近のブラウザでやりたいことをする関数です。
0, 0
@Louisのコメントに記載されているように、誤って座標を取得する場合があることに注意してください。その場合、要素を一時的に挿入してその位置を取得するという回避策にフォールバックする必要があります。
jsFiddle: http: //jsfiddle.net/NFJ9r/132/
コード:
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 };
}
アップデート
コメントの結果としてWebKitのバグを送信しましたが、修正されました。
キャレットが空の要素にある場合、TimDownによる上記の回答は機能しません。
以下のコードは問題を解決します。このコードが呼び出す前にrange.getClientRects()
配列が持っていることをチェックすることを除いて、TimDownのソリューションとほとんど同じであることに注意してくださいlength>0
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 };
}
以下のコードは、TimDownによって提供されたソリューションの簡略化された最新バージョンです。また、(の代わりに)よりブラウザ互換性のある選択APIを使用しますwindow.getSelection()
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 };
}