假如我有一个知识图谱(如下图),我希望单击节点的时候触发事件1,双击节点的时候触发事件2,(比如单击我希望看到节点的详细信息,双击我希望获得节点的子图)。
实现的比较简单,是使用d3提供的节点监听事件,但是浏览器在判断是否是 dblclick 时,往往会先触发 click 事件,再触发 dblclick 事件。这就导致触发双击事件的时候一定会有 单击事件。我的解决方法是定时器。
首先补充一个错误做法,mouseup失效
这个应该是d3的drag事件(不太确定,但反正是d3中的其他事件)覆盖了mouseup
, mouseup无法触发(console.log没有打印),区分失败。
const nodeGroup = svg
.append("g")
.selectAll("g")
.data(nodes)
.join("g")
.attr("class", "node-group")
.on("mousedown", (event, d) => {
isDoubleClick = false;
})
.on("mouseup", (event, d) => {
if (isDoubleClick) return; // 如果是双击,忽略单击逻辑
nodeClick(d); // 单击逻辑
setSelectedElement({ type: "node", data: d });
})
.on("dblclick", (event, d) => {
isDoubleClick = true; // 标记为双击
handleNodeDoubleClick(d); // 执行双击逻辑
})
定时器区分
通过设置一个短暂的定时器,延迟处理单击事件。如果在延迟期间检测到双击,就取消单击逻辑。
let clickTimer = null;
// 绘制节点分组,支持叠加圆形和图标
const nodeGroup = svg
.append("g")
.selectAll("g")
.data(nodes)
.join("g")
.attr("class", "node-group")
.on("click", (event, d) => {
// 如果已经触发双击,则忽略单击
if (clickTimer) {
clearTimeout(clickTimer);
clickTimer = null;
}
// 设置定时器,延迟执行单击逻辑
clickTimer = setTimeout(() => {
nodeClick(d); // 单击逻辑
setSelectedElement({ type: "node", data: d });
clickTimer = null; // 清空定时器
}, 300); // 300ms 是浏览器区分单击和双击的常见延迟
})
.on("dblclick", (event, d) => {
// 清空单击定时器
if (clickTimer) {
clearTimeout(clickTimer);
clickTimer = null;
}
// 执行双击逻辑
handleNodeDoubleClick(d);
})
这个方法个人感受不太优秀的点在,延迟太长了。
当然不一定要使用单击和双击触发节点的筛选/信息, 可以用其他方法触发两个事件
这些理论上都可以:
右键操作
键盘快捷键
按钮或图标
长按操作