首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从FF/Webkit中的像素位置创建折叠范围

从FF/Webkit中的像素位置创建折叠范围
EN

Stack Overflow用户
提问于 2010-07-06 20:07:48
回答 5查看 6.2K关注 0票数 10

使用JavaScript,我想从像素位置创建一个折叠的范围,以便在文档流中插入新的节点,在这个位置标识的范围之后。

这可以使用Internet中的TextRange对象(moveToPoint(x,y)方法)来完成。

如何在FireFox &Webkit中做到这一点?

我可以从document.elementFromPoint(x,y)的位置得到容器元素。但是,当位置恰好位于文本节点中时,如何获得构建范围所需的文本偏移量的更多信息?

EN

回答 5

Stack Overflow用户

发布于 2012-11-23 10:49:02

下面是我为旧浏览器实现的caretRangeFromPoint

代码语言:javascript
复制
if (!document.caretRangeFromPoint) {
    document.caretRangeFromPoint = function(x, y) {
        var log = "";

        function inRect(x, y, rect) {
            return x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom;
        }

        function inObject(x, y, object) {
            var rects = object.getClientRects();
            for (var i = rects.length; i--;)
                if (inRect(x, y, rects[i]))
                    return true;
            return false;
        }

        function getTextNodes(node, x, y) {
            if (!inObject(x, y, node))
                return [];

            var result = [];
            node = node.firstChild;
            while (node) {
                if (node.nodeType == 3)
                    result.push(node);
                if (node.nodeType == 1)
                    result = result.concat(getTextNodes(node, x, y));

                node = node.nextSibling;
            }

            return result;
        }

        var element = document.elementFromPoint(x, y);
        var nodes = getTextNodes(element, x, y);
        if (!nodes.length)
            return null;
        var node = nodes[0];

        var range = document.createRange();
        range.setStart(node, 0);
        range.setEnd(node, 1);

        for (var i = nodes.length; i--;) {
            var node = nodes[i],
                text = node.nodeValue;


            range = document.createRange();
            range.setStart(node, 0);
            range.setEnd(node, text.length);

            if (!inObject(x, y, range))
                continue;

            for (var j = text.length; j--;) {
                if (text.charCodeAt(j) <= 32)
                    continue;

                range = document.createRange();
                range.setStart(node, j);
                range.setEnd(node, j + 1);

                if (inObject(x, y, range)) {
                    range.setEnd(node, j);
                    return range;
                }
            }
        }

        return range;
    };
}
票数 20
EN

Stack Overflow用户

发布于 2010-07-08 21:39:44

下面是我从像素位置获取文本节点内字符位置的调查结果:

  • 标准化的方法:从document.caretRangeFromPoint(x,y) 参见W3c的规范的位置得到一个范围。这正是我要找的。问题是Chrome是实现此方法的唯一web浏览器(2010年7月)。
  • 使用专有的textRange.moveToPoint(x,y)的MS方式。
  • 火狐方式:如果从鼠标事件中检索像素位置(x,y),火狐将向事件对象添加两个有用的属性: rangParent和rangeOffset
  • 对于Safari & Opera (实际上,唯一的跨浏览器方法)是重新构造文本节点的包含框,然后使用包含框内的像素位置来推断字符位置。要做到这一点,您必须:
    1. 将所有文本节点包装为元素(维度信息仅适用于元素,而不适用于文本节点)
    2. 调用span.getClientRects()来获取每个textNode的包含框(包装为a )。如果文本节点跨越几行,您将得到几个框。
    3. 找到包含(x,y)像素位置的框,并根据总像素宽度和文本长度,用简单的“三条规则”推断字符位置。

票数 12
EN

Stack Overflow用户

发布于 2012-03-07 14:27:29

在MSIE下,您写道:

代码语言:javascript
复制
var range = document.selection.createRange();
range.moveToPoint(x, y); 

对于其他浏览器,其思想是在x/y位置确定HTML元素,并在其上创建一个字符选择。基于range.getBoundingClientRect(),您可以确定一个字符选择是在x/y位置之前还是之后。然后我们可以选择下一个字符,直到选择位置raich x/y位置。我为Firefox、Safari和Chrome编写了以下实现:

代码语言:javascript
复制
var nodeInfo = getSelectionNodeInfo(x, y);
var range = document.createRange();
range.setStart(nodeInfo.node, nodeInfo.offsetInsideNode);
range.setEnd(nodeInfo.node, nodeInfo.offsetInsideNode);

/**
Emulates MSIE function range.moveToPoint(x,y) b
returning the selection node info corresponding
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};
}

对这两段代码进行了以下测试:

  • MSIE 7,MSIE 9
  • Firefox 5,Firefox 10
  • 铬9
  • 狩猎5

未对下列情况进行测试:

  • 缩放因子问题
  • 具有多个文本行的HTML元素
票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3189812

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档