admin管理员组

文章数量:1418437

I have an svg element I'd like to be able to click and drag separately. As far as I can tell in D3, clicking fires the "drag end" event (and possibly also drag start?). In the code below, simply clicking the circle gives it a red outline:

var svg = d3.select('body').append('svg');
var g = svg.append('g');

var c = g.append('circle').attr('r', 20).attr('cx', 25).attr('cy', 25)
         .call(d3.drag().on('drag', dragged).on('end', end))
         .on('click', clicked);

function dragged() {
    d3.select(this).attr('fill', 'green').attr('cx', d3.event.x).attr('cy', d3.event.y);
}

function end() {
    d3.select(this).attr('fill', 'red').attr('stroke', 'red').attr('stroke-width', 5);
}

function clicked() {
    if (d3.event.defaultPrevented) return;
    d3.select(this).attr('fill', 'blue');
}

fiddle

How do you register a click callback without triggering the drag.end callback?

It seems like most of the questions and blocks about clicking and dragging seem to want to suppress the click action on dragging, so are not relevant.


  • d3v5.7 (current)

I have an svg element I'd like to be able to click and drag separately. As far as I can tell in D3, clicking fires the "drag end" event (and possibly also drag start?). In the code below, simply clicking the circle gives it a red outline:

var svg = d3.select('body').append('svg');
var g = svg.append('g');

var c = g.append('circle').attr('r', 20).attr('cx', 25).attr('cy', 25)
         .call(d3.drag().on('drag', dragged).on('end', end))
         .on('click', clicked);

function dragged() {
    d3.select(this).attr('fill', 'green').attr('cx', d3.event.x).attr('cy', d3.event.y);
}

function end() {
    d3.select(this).attr('fill', 'red').attr('stroke', 'red').attr('stroke-width', 5);
}

function clicked() {
    if (d3.event.defaultPrevented) return;
    d3.select(this).attr('fill', 'blue');
}

fiddle

How do you register a click callback without triggering the drag.end callback?

It seems like most of the questions and blocks about clicking and dragging seem to want to suppress the click action on dragging, so are not relevant.


  • d3v5.7 (current)
Share Improve this question asked Oct 16, 2018 at 17:03 Alex LenailAlex Lenail 14.5k11 gold badges57 silver badges82 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 8

Since mouseup indicates a click's pletion and the end of a drag you could skip the click event and simply add some logic to determine if a drag occured:

// track action:
var wasMoved = false;

// Drag event:
function dragged() {
    d3.select(this).attr('fill', 'green').attr('cx', d3.event.x).attr('cy', d3.event.y);
    wasMoved = true; // or alternatively, measure the change in distance.
}

// Mouse up event: drag end & click:
function end() {
  if(wasMoved) {
  // It was a drag:
        d3.select(this).attr('fill', 'red').attr('stroke', 'red').attr('stroke-width', 5);
  }
  // Otherwise it was a click:
  else {
    d3.select(this).attr('fill', 'blue');
  }
  wasMoved = false; // reset for next drag.
}

Now we can only trigger one action on mouseup: drag end or what we wanted on click:

var svg = d3.select('body').append('svg');
var g = svg.append('g');

var drag = d3.drag().on("drag", dragged).on("end",end);

var c = g.append('circle')
  .attr('r', 20).attr('cx', 25).attr('cy', 25)
  .call(drag)

var wasMoved = false;

function dragged() {
	d3.select(this).attr('fill', 'green').attr('cx', d3.event.x).attr('cy', d3.event.y);
  wasMoved = true;
}

function end() {
  if(wasMoved) {
  // It was a drag:
		d3.select(this).attr('fill', 'red').attr('stroke', 'orange').attr('stroke-width', 5);
  }
  // It was a click:
  else {
    d3.select(this).attr('fill', 'blue');
  }
  wasMoved = false;
}
<script src="https://cdnjs.cloudflare./ajax/libs/d3/5.0.0/d3.min.js"></script>

本文标签: javascriptHow to prevent d3drag()on(39end39 from firing on(39click39Stack Overflow