问题
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)
回答1:
Since mouseup indicates a click's completion 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.com/ajax/libs/d3/5.0.0/d3.min.js"></script>
来源:https://stackoverflow.com/questions/52840597/how-to-prevent-d3-drag-onend-from-firing-onclick