I'm aware that starting with v4 d3-zoom swallows up certain events for some reasons I don't fully understand. I've read some discussions about this, and I know that if I stopPropagation()
on mousedown, then the zoom behavior won't get a chance to consume the event, and mouseup will consequently fire. The problem with that is that then the zoom doesnt work.
I haven't found a workaround for the case of needing to handle the mouseup event AND still have the zoom work. I'm particularly interested in the dragging case only. When the user does mousedown and starts to drag the canvas, I want to change the cursor to a clenched-hand, and when the user stops dragging and lets go of the mouse I want to change the cursor back.
How is this possible to do with the new d3-zoom behavior without resorting to a timeout? 'click' event is also not an option since that doesn't fire if there's a mousemove event in between.
I am concluding from your question that you are not able to track mouseup event after dragging the canvas. If that is the case then we can use events provided by "zoom" functionality - zoomstart and zoomend.
We can simply add that to zoom behavior and track when the user starts zoom and ends zoom. And in this way we can easily change cursor property.
Please find below code snippet and working code as well. Please let me know if i am missing anything.
var margin = {
top: -5,
right: -5,
bottom: -5,
left: -5
},
width = 460 - margin.left - margin.right,
height = 300 - margin.top - margin.bottom;
var zoom = d3.zoom()
.scaleExtent([1, 10])
.on("zoom", zoomed)
.on("start", function() {
document.getElementsByTagName("svg")[0].style.cursor = "grab";
})
.on("end", function() {
document.getElementsByTagName("svg")[0].style.cursor = "default";
})
console.log(zoom.scaleExtent()[0], zoom.scaleExtent()[1]);
var drag = d3.drag()
.subject(function(d) {
return d;
})
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended);
var slider = d3.select("body").append("p").append("input")
.datum({})
.attr("type", "range")
.attr("value", zoom.scaleExtent()[0])
.attr("min", zoom.scaleExtent()[0])
.attr("max", zoom.scaleExtent()[1])
.attr("step", (zoom.scaleExtent()[1] - zoom.scaleExtent()[0]) / 100)
.on("input", slided);
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.right + ")")
.call(zoom);
var rect = svg.append("rect")
.attr("width", width)
.attr("height", height)
.style("fill", "none")
.style("pointer-events", "all");
var container = svg.append("g");
container.append("g")
.attr("class", "x axis")
.selectAll("line")
.data(d3.range(0, width, 10))
.enter().append("line")
.attr("x1", function(d) {
return d;
})
.attr("y1", 0)
.attr("x2", function(d) {
return d;
})
.attr("y2", height);
container.append("g")
.attr("class", "y axis")
.selectAll("line")
.data(d3.range(0, height, 10))
.enter().append("line")
.attr("x1", 0)
.attr("y1", function(d) {
return d;
})
.attr("x2", width)
.attr("y2", function(d) {
return d;
});
dots = [{
x: 100,
y: 100,
}]
dot = container.append("g")
.attr("class", "dot")
.selectAll("circle")
.data(dots)
.enter().append("circle")
.attr("r", 5)
.attr("cx", function(d) {
return d.x;
})
.attr("cy", function(d) {
return d.y;
})
.call(drag);
function dottype(d) {
d.x = +d.x;
d.y = +d.y;
return d;
}
function zoomed(event) {
const currentTransform = d3.event.transform;
container.attr("transform", currentTransform);
slider.property("value", currentTransform.k);
}
function dragstarted(d) {
d3.event.sourceEvent.stopPropagation();
d3.select(this).classed("dragging", true);
}
function dragged(d) {
d3.select(this).attr("cx", d.x = d3.event.x).attr("cy", d.y = d3.event.y);
}
function dragended(d) {
d3.select(this).classed("dragging", false);
}
function slided(d) {
zoom.scaleTo(svg, d3.select(this).property("value"));
}
.dot circle {
fill: lightsteelblue;
stroke: steelblue;
stroke-width: 1.5px;
}
.dot circle.dragging {
fill: red;
stroke: brown;
}
.axis line {
fill: none;
stroke: #ddd;
shape-rendering: crispEdges;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<style>
</style>
<title></title>
</head>
<body>
<script src="https://d3js.org/d3.v4.min.js"></script>
</body>
</html>
var zoom = d3.zoom()
.scaleExtent([1, 10])
.on("zoom", zoomed)
.on("start", function() {
document.getElementsByTagName("svg")[0].style.cursor = "grab";
})
.on("end", function() {
document.getElementsByTagName("svg")[0].style.cursor = "default";
})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With