Диапазон от пикселей - PullRequest
       1

Диапазон от пикселей

2 голосов
/ 19 февраля 2012

Если у меня есть Range, я могу получить его ограничительный прямоугольник через getBoundingClientRect .Возможно ли обратное?То есть, учитывая прямоугольник пикселей, создайте Range.

Ответы [ 2 ]

1 голос
/ 07 марта 2012

Да и нет.

В общем случае это невозможно, если вы хотите создать только один диапазон, поскольку диапазон не может выделять текст в нескольких местах в большинстве браузеров (например,если высота вашего «прямоугольника пикселей» превышает одну строку текста).Обратите внимание, что упомянутый вами «прямоугольник пикселей» - это, точнее, ограничивающий прямоугольник.

Но это возможно, если вы согласны иметь кратные диапазоны.Основная идея состоит в том, чтобы создать один диапазон для каждой строки вашего прямоугольника отсечения.Выделение не будет отображаться на экране (поскольку большинство браузеров не поддерживают множественные выделения), но по крайней мере вы можете извлечь текст, который находится в прямоугольнике отсечения.Вот как я это реализовал:

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
0 голосов
/ 05 июля 2012

Я сделал это недавно для выбора. В браузерах, которые поддерживают Range, он создает диапазон и затем выбирает его, поэтому было бы тривиально убрать выделение.

Выберите из пиксельных координат для FF и Google Chrome

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...