【问题标题】:How to test if a point is inside an SVG closed path如何测试一个点是否在 SVG 封闭路径内
【发布时间】:2019-06-02 05:52:01
【问题描述】:

我正在尝试组合一个拖放界面,该界面允许用户在页面上拖动一个 div,该页面被限制在不规则封闭 SVG 路径的内部。

这是一个例子 - 橙色方块是我的可拖动元素,灰色 SVG 路径是我想在放置时将其限制为:

<div class="drag-parent">

  <svg xmlns="http://www.w3.org/2000/svg" width="141.019" height="74.065" viewBox="0 0 141.019 74.065">
      <defs>
        <style>
          .target {
            fill: #333;
          }
        </style>
      </defs>
      <path id="Path_4569" data-name="Path 4569" class="target" d="M0,0H141.018V74.065h-24.27V37.033H10.88V12.971H0Z"/>
    </svg>


      <div class="draggable" style="width:20px;height:20px;background:orange;cursor:pointer;"></div>  
      </div>

我想做的是在拖动时检查可拖动的 div,以确保它完全位于我的 SVG 的封闭路径内。

我正在使用 GSAP Draggable 来处理实际拖动元素,但我不知道如何测试它是否在该路径内。

到目前为止,我已经尝试过isPointInFill,但是这似乎在我给它的 chrome nomatter 中返回了 true。

我还尝试在路径上使用 mouseenter / mouseleave 事件,这是一个很好的起点;但是当您拖动某些东西时,这些事件不会触发,因为鼠标指针位于拖动项目的“顶部”而不是 SVG 路径。

什么是强制 SVG 路径边界的好方法 - 或者,有没有更简单的方法来对拖动的项目强制不规则边界?

【问题讨论】:

  • @enxaneta 谢谢,当我检查鼠标位置是否在我想要的路径内时,我能够将它与将拖动元素的指针事件属性设置为“无”结合使用,这个有一些方法可以解决它。您会考虑对此进行扩展以获得完整答案吗?

标签: javascript svg drag-and-drop


【解决方案1】:

主要思想是检查橙色 div 的所有 4 个角是否都在路径上。也许我把事情过于简单化了,因为drag_parent 有`margin 0;填充:0;``

我希望这就是你要问的。

let D = false,// if D ids true you can drag
m = {},// the mouse position
thePath = document.querySelector("#Path_4569"),
draggable = document.querySelector("#draggable");

draggable.w = draggable.getBoundingClientRect().width;
draggable.h = draggable.getBoundingClientRect().height;

draggable.p0s = [[], [], [], []];//one array for every corner

draggable.delta = {};// distance between the click point and the left upper corner

draggable.addEventListener("mousedown", e => {
  D = true;
  draggable.delta = oMousePos(draggable, e);
});

drag_parent.addEventListener("mousemove", e => {
  if (D == true) {
    let counter = 0;// how many corners are in path
    m = oMousePos(drag_parent, e);
    draggablePoints(m);
    draggable.style.left = draggable.p0s[0][0] + 1 + "px";
    draggable.style.top = draggable.p0s[0][1] + 1 + "px";
    draggable.p0s.map(p => {
      if (document.elementFromPoint(p[0], p[1]) && document.elementFromPoint(p[0], p[1]).id == "Path_4569") {
        counter++;
      }
    });
  
    if (counter == 4) {// if all 4 corners are in path
      thePath.setAttributeNS(null, "fill", "#777");
    } else {
      thePath.setAttributeNS(null, "fill", "black");
    }
  }
});

drag_parent.addEventListener("mouseup", e => {
  D = false;
});

drag_parent.addEventListener("mouseleave", e => {
  D = false;
});

function oMousePos(elmt, evt) {
  var ClientRect = elmt.getBoundingClientRect();
  return {
    //objeto
    x: Math.round(evt.clientX - ClientRect.left),
    y: Math.round(evt.clientY - ClientRect.top)
  };
}

function draggablePoints(m) {
  //top left
  draggable.p0s[0][0] = m.x - draggable.delta.x - 1;
  draggable.p0s[0][1] = m.y - draggable.delta.y - 1;
  //top right
  draggable.p0s[1][0] = m.x - draggable.delta.x + draggable.w + 1;
  draggable.p0s[1][1] = m.y - draggable.delta.y + 1;
  //bottom right
  draggable.p0s[2][0] = m.x - draggable.delta.x + draggable.w + 1;
  draggable.p0s[2][1] = m.y - draggable.delta.y + draggable.h + 1;
  //bottom left
  draggable.p0s[3][0] = m.x - draggable.delta.x + 1;
  draggable.p0s[3][1] = m.y - draggable.delta.y + draggable.h + 1;
}
*{margin:0;padding:0}
svg {
  outline: 1px solid;
}
#drag_parent {
  outline: 1px solid;
  min-height: 100vh;
  position:relative;
}
#draggable {
  position: absolute;
  width: 20px;
  height: 20px;
  background: orange;
  cursor: pointer;
}
<div id="drag_parent">
  <svg xmlns="http://www.w3.org/2000/svg" width="141.019" height="74.065" viewBox="0 0 141.019 74.065">
      <path id="Path_4569" data-name="Path 4569" class="target" d="M0,0H141.018V74.065h-24.27V37.033H10.88V12.971H0Z"/>
  </svg>
      <div id="draggable"></div>
</div>

【讨论】:

  • 一个可能的简化可能是在您的draggablePoints 函数中使用可拖动的 div 边界框而不是进行计算。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-02-05
  • 1970-01-01
  • 2017-04-03
  • 1970-01-01
  • 1970-01-01
  • 2010-10-03
相关资源
最近更新 更多