如何重用自定义事件
How to reuse custom events
我正在使用具有相当丰富的用户交互的 D3 构建可视化。目前我的背景 canvas 支持以下事件:
- 点击
- 双击
- 长按
- 拖动(用于平移)
- 缩放(捏+滚轮)
我正在尝试管理所有这些事件,但我已经到了开始为应用程序的不同部分重复我的代码的地步。例如,在应用程序中:
- 双击不应触发单击操作
- 双击也应该忽略用户可能不小心轻微拖动的事实
所以我设计了一种方法来做到这一点。我现在感兴趣的是,是否有一种技术允许我重新使用我创建的事件(有点像你创建一个 d3.behaviour.zoom
并使用 .call
)。
所以为了说明
单击 + 双击
我有一些行为可以在单击时启动计时器,这将在超时后触发单击行为。如果再次单击并且计时器仍然存在,则取消它并改为 运行 双击行为。我目前正在这样连接:
d3.select(target)
.append("circle")
.on("click", function (d) {
__onClick(d, this);
});
然后我这样定义 __onClick
:
var __onClick = function (d) {
var self = this;
if (d3.event.defaultPrevented) return; // ignore drag
d3.event.stopPropagation(); // prevent event bubbling
// If we already have a timer then we need to execute
// a double click behavior event
if (self.__timer) {
console.log("dblclick simulated");
clearTimeout(self.__timer);
self.__timer = null;
self.DoADoubleClickThingy();
return;
}
// Start a single click operation
self.__timer = setTimeout(function () {
console.log("click simulated");
self.__timer = null;
self.DoSingleClickThingy();
}, 250);
};
所以我想我想知道,是否可以创建如下所示的内容来注册新行为?我目前正在尝试查看 D3
代码,但不太了解它是否可行。
var clicks = d3.behaviours.customDoubleClick
.clickSpeed(250)
.on("click", function() { self.DoSingleClickThingy(); })
.on("dblclick", function() { self.DoADoubleClickThingy(); });
d3.select(target)
.append("circle")
.call(clicks);
您可以使用一个工厂函数,给定您想要的行为类型,returns一个安装适当处理程序的函数:
function mkClicks(type) {
// figure out what "self" should be depending on type
return function(sel) {
sel.on("click", function() { self.DoSingleClickThingy(); })
.on("dblclick", function() { self.DoADoubleClickThingy(); });
}
}
d3.select(target)
.append("circle")
.call(mkClicks(typeA));
再次阅读 github 上 D3
的 zoom 代码后,我意识到它并不像我想象的那么复杂 - 特别是当我意识到 call
实际上只是执行了 zoom
函数。这是我放在一起的解决方案,我希望放在 github 或类似的:
var custom = { };
custom.events = function () {
var clickTimeout = 3000; // The timeout that is used to distinguish between a single and double click
var clickTimer; // The timer that is used for a single click event
var dispatch = d3.dispatch("click", "dblclick");
function events(g) {
g.on("click", clicked)
.on("dblclick", doubleClicked);
};
function clicked(d, i) {
if (d3.event.defaultPrevented) return; // Ignore if a drag operation is taking place
d3.event.stopPropagation(); // Prevent the event going any further
// If we already have a timer then we need to execute
// a double click behaviour event
if (clickTimer) {
clearTimeout(clickTimer);
clickTimer = null;
dispatch.dblclick.call(this, d, i);
return;
}
// Setup the timer for single click
clickTimer = setTimeout(function () {
// Trigger a single click
clickTimer = null;
dispatch.click.call(this, d, i);
}, clickTimeout);
};
function doubleClicked(d, i) {
// Suppress the natural double click event
d3.event.stopPropagation();
};
// Return the bound events
return d3.rebind(events, dispatch, "on");
};
我正在使用具有相当丰富的用户交互的 D3 构建可视化。目前我的背景 canvas 支持以下事件:
- 点击
- 双击
- 长按
- 拖动(用于平移)
- 缩放(捏+滚轮)
我正在尝试管理所有这些事件,但我已经到了开始为应用程序的不同部分重复我的代码的地步。例如,在应用程序中:
- 双击不应触发单击操作
- 双击也应该忽略用户可能不小心轻微拖动的事实
所以我设计了一种方法来做到这一点。我现在感兴趣的是,是否有一种技术允许我重新使用我创建的事件(有点像你创建一个 d3.behaviour.zoom
并使用 .call
)。
所以为了说明
单击 + 双击
我有一些行为可以在单击时启动计时器,这将在超时后触发单击行为。如果再次单击并且计时器仍然存在,则取消它并改为 运行 双击行为。我目前正在这样连接:
d3.select(target)
.append("circle")
.on("click", function (d) {
__onClick(d, this);
});
然后我这样定义 __onClick
:
var __onClick = function (d) {
var self = this;
if (d3.event.defaultPrevented) return; // ignore drag
d3.event.stopPropagation(); // prevent event bubbling
// If we already have a timer then we need to execute
// a double click behavior event
if (self.__timer) {
console.log("dblclick simulated");
clearTimeout(self.__timer);
self.__timer = null;
self.DoADoubleClickThingy();
return;
}
// Start a single click operation
self.__timer = setTimeout(function () {
console.log("click simulated");
self.__timer = null;
self.DoSingleClickThingy();
}, 250);
};
所以我想我想知道,是否可以创建如下所示的内容来注册新行为?我目前正在尝试查看 D3
代码,但不太了解它是否可行。
var clicks = d3.behaviours.customDoubleClick
.clickSpeed(250)
.on("click", function() { self.DoSingleClickThingy(); })
.on("dblclick", function() { self.DoADoubleClickThingy(); });
d3.select(target)
.append("circle")
.call(clicks);
您可以使用一个工厂函数,给定您想要的行为类型,returns一个安装适当处理程序的函数:
function mkClicks(type) {
// figure out what "self" should be depending on type
return function(sel) {
sel.on("click", function() { self.DoSingleClickThingy(); })
.on("dblclick", function() { self.DoADoubleClickThingy(); });
}
}
d3.select(target)
.append("circle")
.call(mkClicks(typeA));
再次阅读 github 上 D3
的 zoom 代码后,我意识到它并不像我想象的那么复杂 - 特别是当我意识到 call
实际上只是执行了 zoom
函数。这是我放在一起的解决方案,我希望放在 github 或类似的:
var custom = { };
custom.events = function () {
var clickTimeout = 3000; // The timeout that is used to distinguish between a single and double click
var clickTimer; // The timer that is used for a single click event
var dispatch = d3.dispatch("click", "dblclick");
function events(g) {
g.on("click", clicked)
.on("dblclick", doubleClicked);
};
function clicked(d, i) {
if (d3.event.defaultPrevented) return; // Ignore if a drag operation is taking place
d3.event.stopPropagation(); // Prevent the event going any further
// If we already have a timer then we need to execute
// a double click behaviour event
if (clickTimer) {
clearTimeout(clickTimer);
clickTimer = null;
dispatch.dblclick.call(this, d, i);
return;
}
// Setup the timer for single click
clickTimer = setTimeout(function () {
// Trigger a single click
clickTimer = null;
dispatch.click.call(this, d, i);
}, clickTimeout);
};
function doubleClicked(d, i) {
// Suppress the natural double click event
d3.event.stopPropagation();
};
// Return the bound events
return d3.rebind(events, dispatch, "on");
};