События мыши в SVG defs (маска) - PullRequest
1 голос
/ 05 апреля 2019

svg mouse events in defs

Имеется изображение поверх фонового изображения.SVG - это квадрат с круглым отверстием посередине (как пример).Фоновое изображение появляется через круг.

Я хочу перетащить этот круг с помощью мыши.Но как получить доступ из javascript к defs внутри svg, не ясно.Я могу изменить свойства, но события 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 ]

1 голос
/ 05 апреля 2019

Я предлагаю следующий вариант с помощью 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>
1 голос
/ 05 апреля 2019

При mousemove вы сбрасываете атрибуты cx и cy круга.Я надеюсь, что это то, что вы спрашивали.

//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>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...