将鼠标事件添加到svg <pattern>,检测网格悬停

时间:2018-08-11 01:01:17

标签: javascript reactjs svg

我有一个复杂的问题。我试图通过svg渲染网格,然后将事件侦听器添加到网格。目前,我正在通过<pattern>元素渲染网格。我对渲染网格的其他方法持开放态度,但是它需要可伸缩/高性能,因为此网格很容易是数千个正方形的十个。可以将其视为平面图或蓝图。

我想要的东西:我希望能够将事件监听器附加到网格的每个正方形

我所做的事情::我查阅了svg文档,尝试了一堆不同的东西(例如onclick处理程序,svg属性(例如指针事件等)等等,但是没有运气。我可能可以使其与鼠标客户端坐标一起使用,但是,如果可能的话,我想避免使用此方法,因为该svg具有缩放和平移功能。这会使坐标转换变得很麻烦。

基本svg代码(此问题的简化版):

<svg viewBox="0 0 100 100">
  <g className="view-control">
    <defs>
      <pattern id="grid" width="10" height="10" patternUnits="userSpaceOnUse">
        <path d="M 10 0 L 0 0 0 10" fill="none" stroke="gray" strokeWidth="0.5"/>
      </pattern>
    </defs>
    <rect width="100%" height="100%" fill="url(#grid)" />
  </g>
</svg>

Fiddle to play with

2 个答案:

答案 0 :(得分:1)

我不确定您对“鼠标客户端坐标”有何异议,但这很简单,是否可以满足您的要求。

  1. 将单击处理程序添加到网格矩形。我在此演示中使用了点击处理程序。但是,如果要基于悬停,则可以改用mousemove事件。

    <rect width="200%" height="200%" fill="url(#grid)" onClick={(e) => handleClick(e)}/>
    
    function handleClick(e) {
      var pos = getSVGPosition(e);
      createRectAt(pos);
    }
    
  2. 将鼠标坐标转换为svg坐标的功能如下:

    function getSVGPosition(e) {
      var svg = e.nativeEvent.target.ownerSVGElement;
      var pt = svg.createSVGPoint();
      pt.x = e.nativeEvent.clientX;
      pt.y = e.nativeEvent.clientY;
      pt = pt.matrixTransform(svg.getScreenCTM().inverse());
      return {svg: svg, x: pt.x, y: pt.y};
    }
    
  3. 然后出于演示目的,我在相关网格位置创建一个正方形

    function createRectAt(pos) {
      var rect = document.createElementNS(pos.svg.namespaceURI, "rect");
      rect.setAttribute("x", Math.floor(pos.x / 10) * 10);
      rect.setAttribute("y", Math.floor(pos.y / 10) * 10);
      rect.setAttribute("width", 10);
      rect.setAttribute("height", 10);
      rect.setAttribute("fill", "green");
      pos.svg.appendChild(rect);
    }
    

https://jsfiddle.net/tp530748/31/

答案 1 :(得分:0)

如果将网格设置为<pattern>,则将无法在模式上注册任何鼠标事件。模式命中框将覆盖整个<rect>

我建议您根据<svg>的大小,viewBox和网格的间距自己计算正方形的坐标。将任何鼠标事件附加到SVG元素