【问题标题】:d3-zoom mouseup event workaroundd3-zoom mouseup 事件解决方法
【发布时间】:2020-05-28 16:33:42
【问题描述】:

我知道从 v4 开始 d3-zoom 会因为某些我不完全理解的原因而吞噬某些事件。我已经阅读了一些关于此的discussions,并且我知道如果我在 mousedown 上stopPropagation(),那么缩放行为将没有机会消耗该事件,并且 mouseup 将因此触发。这样做的问题是缩放不起作用。

对于需要处理 mouseup 事件 并且 仍然可以进行缩放的情况,我还没有找到解决方法。我只对拖动案例特别感兴趣。当用户执行 mousedown 并开始拖动画布时,我想将光标更改为握紧的手,当用户停止拖动并放开鼠标时,我想将光标改回。

如何在不使用超时的情况下使用新的 d3-zoom 行为? 'click' 事件也不是一个选项,因为如果中间有 mousemove 事件,它不会触发。

【问题讨论】:

  • @pariament 我已经为您的问题添加了答案,请您检查它是否回答了您的问题。如果我遗漏了什么,请告诉我。
  • 为什么不使用 d3 v5? v5 可以做到this.
  • @tatsuyakanemoto 我使用的是 v5,我已经看到该链接并没有真正回答问题。最终,我只是忽略了缩放的“结束”事件。我错误地认为它只是在拖动行为。

标签: d3.js


【解决方案1】:

我从您的问题中得出结论,您在拖动画布后无法跟踪 mouseup 事件。如果是这种情况,那么我们可以使用“缩放”功能提供的事件 - zoomstart 和 zoomend。

我们可以简单地将其添加到缩放行为并跟踪用户何时开始缩放和结束缩放。通过这种方式,我们可以轻松更改光标属性。

请在下面找到代码 sn-p 和工作代码。如果我遗漏任何东西,请告诉我。

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";
        })

【讨论】:

  • 谢谢。这是相当直截了当的,我不知道我是如何忽略 startend 事件(facepalm)的。
  • 没问题,伙计,这发生在我们所有人身上。有时我们会错过一些小事。感谢您的赏金:)
猜你喜欢
  • 2019-04-23
  • 1970-01-01
  • 1970-01-01
  • 2011-02-16
  • 1970-01-01
  • 1970-01-01
  • 2012-11-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多