SVG defs(遮罩)上的鼠标事件

时间:2019-04-05 14:26:13

标签: javascript svg

svg mouse events in defs

在背景图片上有svg。 SVG是一个在中间带有圆孔的正方形(例如)。通过圆圈显示背景图像。

我想用鼠标拖动该圆圈。但是如何从javascript访问svg中的defs还不清楚。我可以更改属性,但是onclick事件对它们不起作用。

这是我的SVG,我想使用id = my_mask访问元素上的鼠标事件:

<svg>
  <defs>
    <mask id="hole">
      <rect width="100%" height="100%" fill="#fff"/>
      <g id="my_mask">
        <circle r="50" cx="100" cy="100" fill="#000"/>
      </g>
    </mask>
  </defs>
<rect fill="#00f" width="100%" height="100%" mask="url(#hole)" />
</svg>

2 个答案:

答案 0 :(得分:1)

mousemove上,重置圆的cxcy属性。我希望这就是你的要求。

//on `mousemove` you reset the `cx` and `cy` attributes of the circle
svg.addEventListener("mousemove",(e)=>{
  let m = oMousePosSVG(e)
  c.setAttributeNS(null,"cx",m.x)
  c.setAttributeNS(null,"cy",m.y)
})

// a function to get the position of the mouse over the svg canvas
function oMousePosSVG(e) {
      var p = svg.createSVGPoint();
      p.x = e.clientX;
      p.y = e.clientY;
      var ctm = svg.getScreenCTM().inverse();
      var p =  p.matrixTransform(ctm);
      return p;
}
svg{background:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/222579/darwin300.jpg); background-size:cover}
<svg id="svg" viewBox="0 0 300 300">
<defs>
<mask id="hole">
<rect width="100%" height="100%" fill="#fff"/>
<g id="my_mask">
<circle id="c" r="50" cx="100" cy="100" fill="#000"/>
</g>
</mask>
</defs>
<rect fill="#00f" width="100%" height="100%" mask="url(#hole)" />
</svg>

更新

您不能将事件附加到蒙版上,但是您可以使用蒙版内的圆圈并将事件附加到使用上,如在下一个示例中一样:

在此示例中,我使用的是mousedown事件,但是您可以使用mouseover

let m,dx,dy;
let dragging = false;

theUse.addEventListener("mousedown",(e)=>{
  m = oMousePosSVG(e);
  dx = Number(c.getAttribute("cx")) - m.x;
  dy = Number(c.getAttribute("cy")) - m.y;
  dragging = true;
})

svg.addEventListener("mouseup",(e)=>{
  
  dragging = false;
})


svg.addEventListener("mousemove",(e)=>{
  if(dragging){
  m = oMousePosSVG(e)
  c.setAttributeNS(null,"cx",m.x + dx)
  c.setAttributeNS(null,"cy",m.y + dy)
  }
})


function oMousePosSVG(e) {
      var p = svg.createSVGPoint();
      p.x = e.clientX;
      p.y = e.clientY;
      var ctm = svg.getScreenCTM().inverse();
      var p =  p.matrixTransform(ctm);
      return p;
}
svg{background:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/222579/darwin300.jpg); background-size:cover}
<svg id="svg" viewBox="0 0 300 300">
<defs>
<mask id="hole">
<rect width="100%" height="100%" fill="#fff"/>
<g id="my_mask">
<circle id="c" r="50" cx="100" cy="100" />
</g>
</mask>
</defs>
<rect fill="#00f" width="100%" height="100%" mask="url(#hole)" />
  
  
<use id="theUse" xlink:href="#c" fill="none" pointer-events="all" />
</svg>

答案 1 :(得分:1)

我建议在d3.js的帮助下进行以下变体,但也可以在没有d3的情况下实现这种效果:

example

这是另一个具有拖动可能性的透明圆圈,并且在拖动时与遮罩圈保持位置同步,请尝试对其进行直播:

let d = [[100,100,50], [300,100,40], [500,100,30]]
         .map(d=>({x: d[0], y: d[1], r: d[2]}));
let mask = circles('mask').call(upd);
  
circles('g').style('fill','transparent')
  .style('cursor','pointer')
  .call(upd)
  .call(d3.drag().on("drag", function (d) {
    d3.select(this)
      .attr("cx", d.x = d3.event.x)
      .attr("cy", d.y = d3.event.y);
    mask.call(upd)  
  }));

function circles(selector) {
  return d3.select(selector)
           .selectAll('circle')
           .data(d)
           .enter()
           .append('circle')
}

function upd(selection) {
   selection.attr("cx", d => d.x)
            .attr("cy", d => d.y)
            .attr('r',  d => d.r);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg viewBox="0 0 600 600" style="background: center url(https://i.imgur.com/cdqfoqZ.png)">
<defs>
  <mask id="hole">
    <rect width="100%" height="100%" fill="#fff"/>
  </mask>
</defs>
<rect fill="#00f" width="100%" height="100%" mask="url(#hole)" />
<g></g>
</svg>