我知道,由于某些我不完全理解的原因,从 v4 d3-zoom 开始会吞掉某些事件。我读过一些关于此的讨论,并且我知道如果我stopPropagation()使用 mousedown,则缩放行为将没有机会消耗该事件,并且 mouseup 将因此触发。问题是缩放功能不起作用。
对于需要处理 mouseup 事件并且仍然可以进行缩放工作的情况,我还没有找到解决方法。我只对拖动的情况特别感兴趣。当用户按下鼠标并开始拖动画布时,我想将光标更改为紧握的手,当用户停止拖动并放开鼠标时,我想将光标更改回来。
如何在不诉诸超时的情况下使用新的 d3-zoom 行为来实现这一点?“click”事件也不是一个选项,因为如果中间有 mousemove 事件,则不会触发该事件。
我从您的问题得出的结论是,您在拖动画布后无法跟踪 mouseup 事件。如果是这种情况,那么我们可以使用“缩放”功能提供的事件 - Zoomstart 和 Zoomend。
我们可以简单地将其添加到缩放行为并跟踪用户何时开始缩放和结束缩放。这样我们就可以轻松地改变光标属性。
请找到下面的代码片段和工作代码。如果我遗漏了什么,请告诉我。
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"));
}Run Code Online (Sandbox Code Playgroud)
.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;
}Run Code Online (Sandbox Code Playgroud)
<!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>Run Code Online (Sandbox Code Playgroud)
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";
})
Run Code Online (Sandbox Code Playgroud)