Да и нет.
В общем случае это невозможно, если вы хотите создать только один диапазон, поскольку диапазон не может выделять текст в нескольких местах в большинстве браузеров (например,если высота вашего «прямоугольника пикселей» превышает одну строку текста).Обратите внимание, что упомянутый вами «прямоугольник пикселей» - это, точнее, ограничивающий прямоугольник.
Но это возможно, если вы согласны иметь кратные диапазоны.Основная идея состоит в том, чтобы создать один диапазон для каждой строки вашего прямоугольника отсечения.Выделение не будет отображаться на экране (поскольку большинство браузеров не поддерживают множественные выделения), но по крайней мере вы можете извлечь текст, который находится в прямоугольнике отсечения.Вот как я это реализовал:
var columnModeSelection = {
startX:10,
startY:10,
endX:20,
endY:30,
selectedTextRanges:null // an Array of Range
};
createColumnModeSelection();
/**
Emulates MSIE function range.moveToPoint(x,y) by returning the selection node info which corresponds to the given x/y location.
@param x the point X coordinate
@param y the point Y coordinate
@return the node and offset in characters as {node,offsetInsideNode} (e.g. can be passed to range.setStart)
*/
function getSelectionNodeInfo(x, y) {
var startRange = document.createRange();
window.getSelection().removeAllRanges();
window.getSelection().addRange(startRange);
// Implementation note: range.setStart offset is
// counted in number of child elements if any or
// in characters if there is no childs. Since we
// want to compute in number of chars, we need to
// get the node which has no child.
var elem = document.elementFromPoint(x, y);
var startNode = (elem.childNodes.length>0?elem.childNodes[0]:elem);
var startCharIndexCharacter = -1;
do {
startCharIndexCharacter++;
startRange.setStart(startNode, startCharIndexCharacter);
startRange.setEnd(startNode, startCharIndexCharacter+1);
var rangeRect = startRange.getBoundingClientRect();
} while (rangeRect.left<x && startCharIndexCharacter<startNode.length-1);
return {node:startNode, offsetInsideNode:startCharIndexCharacter};
}
/**
Copy user selection to clipboard in plain text.
Multibrowser: supported under MSIE and WebKit
*/
function createColumnModeSelection() {
// build a TextRange for each line to select
var startY = columnModeSelection.startY;
columnModeSelection.selectedTextRanges=new Array();
while (startY<columnModeSelection.endY) {
// select the line
var range = null;
if (document.selection) {
// MSIE
// Implementation note: the TextRange cannot be created from pixel
// coordinates, only the start point can. Thus, we are creating two
// TextRanges with a start point and set the end point of the first
// range to the start point of the end range.
// set the start point
range = document.selection.createRange();
range.moveToPoint(columnModeSelection.startX, startY);
// set the end point
var endRange = document.selection.createRange();
endRange.moveToPoint(columnModeSelection.endX, startY); // set the first line end
range.setEndPoint("EndToStart", endRange);
// create the selection
range.select();
} else {
// other browsers
var lineStartNodeInfo = getSelectionNodeInfo(columnModeSelection.startX, startY);
var lineEndNodeInfo = getSelectionNodeInfo(columnModeSelection.endX, startY);
range = document.createRange();
range.setStart(lineStartNodeInfo.node, lineStartNodeInfo.offsetInsideNode);
range.setEnd(lineEndNodeInfo.node, lineEndNodeInfo.offsetInsideNode+1);
}
// keep the selection for later usage
if (range!=null) {
columnModeSelection.selectedTextRanges.push(range);
}
// go to the next line
var elem = document.elementFromPoint(columnModeSelection.startX, startY);
var lineHeight = elem.clientHeight;
startY += lineHeight;
}
// clear the last selected range
if (document.selection) {
// MSIE
document.selection.empty();
} else {
// Safari, Firefox
window.getSelection().removeAllRanges();
}
}
Это было протестировано в следующих браузерах:
- MSIE 7, MSIE 9
- Firefox 5, Firefox 10
- Chrome 9
- Safari 5