简体   繁体   中英

D3 zoom event firing on drag in Angular


Tldr; dragging the SVG causes it to rotate as well as translate.


I am trying to implement dragging and zooming events on an SVG group using D3 (v.4) as part of an Angular service.

this.unitGroup = this.svg.append('g')
  .attr('id', 'unitGroup')
  .call(this.drag)
  .call(this.zoom);

Dragging translates the SVG.

drag = d3.drag()
.on('start', () => {
  console.log('drag start');
  this.setClickOrigin(d3.event);
})
.on('drag', (d, i, n) => {
  const target = d3.select(n[i]).node() as any;
  const m = target.getCTM();
  const x = d3.event.x - this.clickOrigin.x;
  const y = d3.event.y - this.clickOrigin.y;
  this.setClickOrigin(d3.event);
  this.translate(target, x, y);
});

While zooming rotates the SVG.

zoom = d3.zoom()
.on('zoom', (d, i, n) => {
  const target = d3.select(n[i]).node() as any;
  const m = target.getCTM();
  const b = target.getBBox();
  const dir = (d3.event.sourceEvent.deltaY > 0) ? 1 : -1;
  this.rotate(target, dir);
});

My original code worked fine. However, integrating it into Angular has thrown up some problems.

The current problem is that when you drag the unitGroup it triggers the zoom event along with the drag event.

The expected behaviour is that:

  • 'click-and-drag' translates the small, dark-grey box in the x and y dimensions.
  • 'mouse-wheel-scroll' rotates the small, dark-grey box around its center.

Here is a Plunker: https://embed.plnkr.co/0GrGG7T79ubpjYa2ChYp/

Actually, what you are seeing here is the expected behaviour.

In D3, d3.zoom() handles not only the zoom but the panning as well. So, the mousemove is being handled by d3.drag() and by the zoom function as well.

As Bostock (D3 creator) once said:

combining these two behaviors* means that gesture interpretation is ambiguous and highly sensitive to position. (*zoom and drag)

Off the top of my head the simplest solution is just checking if you had a "real" zoom (mouse wheel) in the zoom function and, if you didn't (no mouse wheel), return:

if(!d3.event.sourceEvent.deltaY) return;

Here is your plunker with that change only: https://plnkr.co/edit/jz5X4Vm9wIzbKmTQLBAT?p=preview

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM