首页 > 解决方案 > 按住 Ctrl 键拖动时出错

问题描述

我制作了两个片段,相同的代码,一个在JSFiddle中,一个作为堆栈片段(见下文)。出于某种原因,Ctrl键 + 拖动会产生不同的结果。

如果我按住Ctrl键,JSFiddle 不会触发我的拖动事件,但 Stack Snippet 会。有人可以尝试运行这些吗?我以为这是浏览器或计算机问题,但也许不是。

var svg = d3.select('svg');

var drag = d3
      .drag()
      .on("start", function() {
        console.log("start");
      })
      .on("drag", function() {
        console.log("dragging");
      })
      .on("end", function() {
        console.log("eneded");
      });

svg.append("g").call(drag).append("circle").attr("cx", 10).attr("cy", 10).attr("r", 8)
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.2.0/d3.min.js"></script>
<svg></svg>

标签: javascriptd3.js

解决方案


从 D3 版本5.10.0 开始(由 d3-drag 模块版本1.2.4引入,修复了 GitHub 问题#62Ctrl )按下键触发的事件被过滤掉,因为在某些情况下,<kbd>Ctrl+click 应该打开上下文菜单。上的文档drag.filter()涵盖了您:

拖动过滤器([过滤器])<>

如果指定了过滤器,则将过滤器设置为指定的函数并返回拖动行为。如果未指定过滤器,则返回当前过滤器,默认为:

function filter() {
  return !d3.event.ctrlKey && !d3.event.button;
}

如果过滤器返回 false,则忽略启动事件并且不启动拖动手势。因此,过滤器确定哪些输入事件被忽略;默认过滤器忽略辅助按钮上的 mousedown 事件,因为这些按钮通常用于其他目的,例如上下文菜单。

如您所见,这将忽略任何涉及Ctrl被按下的键的事件。但是,您问题中的代码段使用 D3 v5.2.0,它尚未实现上述更改,因此也确实使用Ctrl密钥侦听事件。

要包含这些事件,您可以轻松地提供自己的过滤器,该过滤器可能只是!d3.event.ctrlKey从原始过滤器中删除部分:

.filter(function() { 
  return !d3.event.button;
})

看看下面的工作演示:

const drag = d3
  .drag()
  .filter(() => !d3.event.button)   // Specify the filter
  .on("start", () => console.log("start"))
  .on("drag", () => console.log("dragging"))
  .on("end", () => console.log("ended"))

d3.select('body')
  .append("svg")
  .append("g")
  .call(drag)
  .append("circle")
    .attr("cx", 10)
    .attr("cy", 10)
    .attr("r", 8);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.12.0/d3.js"></script>


推荐阅读