Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/hibernate/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 从FF/Webkit中的像素位置创建折叠范围_Javascript_Range_Position - Fatal编程技术网

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

Javascript 从FF/Webkit中的像素位置创建折叠范围,javascript,range,position,Javascript,Range,Position,使用JavaScript,我想从像素位置创建一个折叠的范围,以便在文档流中插入新节点,位于该位置标识的范围之后 这可以通过Internet Exporer中的TextRange对象(moveToPoint(x,y)方法)完成 如何在FireFox和Webkit中做到这一点? 我可以从document.elementFromPoint(x,y)的位置获取容器元素。但是,当位置恰好位于文本节点内时,如何获取有关构建范围所需的文本偏移量的更多信息?以下是我从像素位置获取文本节点内字符位置的调查结果:

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

这可以通过Internet Exporer中的TextRange对象(moveToPoint(x,y)方法)完成

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


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

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

  • 标准化方法:使用document.caretRangeFromPoint(x,y)从位置获取范围 . 这正是我想要的。问题在于,截至本文撰写之日(2010年7月),Chrome是唯一一款实现这种方法的web浏览器
  • 带有专有textRange.moveToPoint(x,y)的MS IE方式
  • Firefox方法:如果像素位置(x,y)是从鼠标事件中获取的,那么Firefox将向事件对象添加两个有用的属性:rangParent和rangeOffset
  • 对于Safari&Opera(实际上是唯一的跨浏览器方法)来说,是重新构造文本节点的包含框,然后使用包含框内的像素位置推断字符位置。为此,您必须:
  • 将所有文本节点包装到元素中(标注信息仅适用于元素,不适用于文本节点)
  • 调用span.getClientRects()获取每个textNode的包含框(包装成一个文本)。如果文本节点跨越多行,您将得到多个框
  • 找到包含(x,y)像素位置的框,并根据总像素宽度和文本长度,使用简单的“三个规则”推断字符位置
    • 在MSIE下,您写道:

      var range = document.selection.createRange();
      range.moveToPoint(x, y); 
      
      对于其他浏览器,其想法是确定x/y位置的HTML元素,并在其上创建一个单字符选择。根据
      range.getBoundingClientRect()
      ,您可以确定单字符选择是在x/y位置之前还是之后。然后,我们可以选择下一个字符,直到选择位置到达x/y位置。我为Firefox、Safari和Chrome编写了以下实现:

      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};
      }
      
      var nodeInfo=getSelectionNodeInfo(x,y);
      var range=document.createRange();
      range.setStart(nodeInfo.node、nodeInfo.offsetInsideNode);
      range.setEnd(nodeInfo.node,nodeInfo.offsetInsideNode);
      /**
      模拟MSIE函数范围。移动点(x,y)b
      返回相应的选择节点信息
      到给定的x/y位置。
      @参数x点x坐标
      @参数y点y坐标
      @以字符形式返回节点和偏移量,如下所示
      {node,offsetInsideNode}(例如,可以传递到range.setStart)
      */
      函数getSelectionNodeInfo(x,y){
      var startRange=document.createRange();
      getSelection().removeAllRanges();
      window.getSelection().addRange(startRange);
      //实施说明:range.setStart偏移量为
      //计入子元素的数量(如果有或
      //如果没有孩子,在角色中。因为我们
      //要计算字符数,我们需要
      //获取没有子节点的节点。
      var elem=document.elementFromPoint(x,y);
      var startNode=(elem.childNodes.length>0?elem.childNodes[0]:elem);
      var startCharIndexCharacter=-1;
      做{
      startCharIndexCharacter++;
      setStart(startNode,startCharIndexCharacter);
      startRange.setEnd(startNode,startCharIndexCharacter+1);
      var rangeRect=startRange.getBoundingClientRect();
      
      }while(rangeRect.left这是我为旧浏览器实现的
      caretRangeFromPoint

      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;
          };
      }
      
      if(!document.caretRangeFromPoint){
      document.caretRangeFromPoint=函数(x,y){
      var log=“”;
      函数inRect(x,y,rect){
      
      return x>=rect.left&&x=rect.top&&y是上面Julien答案的扩展。这可以处理多行。需要稍微调整一下,但似乎有效。它通过获取从开始到结束的选择的高度和单个字母选择的高度,除以两个字母并取整来查找行数。可能存在以下情况:在这里这不起作用,但在大多数情况下

      function getLineCount(node, range) {
          if ((node) && (range)) {
              range.setStart(node, 0);
              range.setEnd(node, 1);
              var r = range.getBoundingClientRect();
              var h1 = r.bottom - r.top;
              range.setEnd(node, node.length);
              r = range.getBoundingClientRect();
              return Math.round((r.bottom - r.top) / h1);
          }
      };
      
      这是上面代码的一个调整版本,使用上面的行计数例程。它还可以更好地处理节点内的选择,但位于实际文本的右侧。所有这些都没有优化,但我们在用户时间内,因此毫秒可能不太重要

      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);
          console.log("ElementFromPoint: " + $(elem).attr('class'));
          var startNode = (elem.childNodes.length>0?elem.childNodes[0]:elem);
      
          var lines = getLineCount(startNode, startRange);
          console.log("Lines: " + lines);
      
          var startCharIndexCharacter = 0;
          startRange.setStart(startNode, 0);
          startRange.setEnd(startNode, 1);
          var letterCount = startNode.length;
          var rangeRect = startRange.getBoundingClientRect();
          var rangeWidth = 0
      
          if (lines>1) {
              while ((rangeRect.bottom < y) && (startCharIndexCharacter < (letterCount-1))) {
                  startCharIndexCharacter++;
                  startRange.setStart(startNode, startCharIndexCharacter);
                  startRange.setEnd(startNode, startCharIndexCharacter + 1);
                  rangeRect = startRange.getBoundingClientRect();
                  rangeWidth = rangeRect.right - rangeRect.left
              }
          }
          while (rangeRect.left < (x-(rangeWidth/2)) && (startCharIndexCharacter < (letterCount))) {
              startCharIndexCharacter++;
              startRange.setStart(startNode, startCharIndexCharacter);
              startRange.setEnd(startNode, startCharIndexCharacter + ((startCharIndexCharacter<letterCount) ? 1 : 0));
              rangeRect = startRange.getBoundingClientRect();
              rangeWidth = rangeRect.right - rangeRect.left
          }
      
          return {node:startNode, offsetInsideNode:startCharIndexCharacter};
      }
      
      函数getSelectionNodeInfo(x,y){ var startRange=document.createRange(); getSelection().removeAllRanges(); window.getSelection().addRange(startRange); //实施说明:range.setStart偏移量为 //计入子元素的数量(如果有或 //如果没有孩子,在角色中。因为我们 //要计算字符数,我们需要 //获取没有子节点的节点。 var elem=document.elementFromPoint(x,y); log(“ElementFromPoint:”+$(elem.attr('class')); var startNode=(elem.childNodes.length>0?elem.childNodes[0]:elem); 变量行=getLineCount(startNode,startRange); 控制台日志(“行:+行); var startCharIndexCharacter=0; startRange.setStart(startNode,0); startRange.setEnd(startNode,1); var letterCount=起始节点长度; var rangeRect=startRange.getBoundingClientRect(); var rangeWidth=0 如果(行数>1){ 而((rangeRect.bottomtextRange.select(); var range = window.getSelection().getRangeAt(0);
      function createCollapsedRangeFromPoint(x, y) {
          var doc = document;
          var position, range = null;
          if (typeof doc.caretPositionFromPoint != "undefined") {
              position = doc.caretPositionFromPoint(x, y);
              range = doc.createRange();
              range.setStart(position.offsetNode, position.offset);
              range.collapse(true);
          } else if (typeof doc.caretRangeFromPoint != "undefined") {
              range = doc.caretRangeFromPoint(x, y);
          } else if (typeof doc.body.createTextRange != "undefined") {
              range = doc.body.createTextRange();
              range.moveToPoint(x, y);
          }
          return range;
      }