[英]Preventing cyclic JavaScript events
此問題碰巧涉及D3特定的功能,但不是D3特定的問題。 我已經創建了兩個D3圖表並將其附加到縮放功能,目的是使縮放比例和變換位置保持相等,以便在縮放一個圖表時,另一個圖表會自動縮放到相同的比例和位置。 為此,當一個圖表放大時,我會觸發一個自定義事件,以便我可以自動調整另一圖表:
// Within the chart definition:
var svg = ...; // The chart body definition
var zoom = d3.behavior.zoom()
.on("zoom", function(e){
// do stuff...
$("#chart-div").trigger({
type: "my.zoom",
translate: d3.event.translate,
scale: d3.event.scale
});
});
svg.call(zoom);
然后,我創建允許我手動調整每個圖表的縮放級別的方法,從而在此過程中觸發D3 zoom
事件:
var adjustZoom = function(t,s){
svg.transition().duration(500).call(zoom.scale(s).translate(t).event);
};
然后,我將事件偵聽器附加到每個圖表上,以便當我與其中一個進行交互並導致其縮放級別更改時,另一個會自動更新:
$("#chart-div1").on("my.zoom", function(e){
chart2.adjustZoom(e.translate, e.scale);
});
$("#chart-div2").on("my.zoom", function(e){
chart1.adjustZoom(e.translate, e.scale);
});
明顯的問題是,調用adjustZoom
方法會觸發D3 zoom
事件,因此在每個圖表上附加事件偵聽器都會創建周期性事件,因為每個圖表都試圖無限地調整另一個圖表。
1. chart1 [manual zoom] --> trigger d3.zoom --> triggers my.zoom
2. chart2 [my.zoom listener] --> trigger d3.zoom --> triggers my.zoom
3. chart1 [my.zoom listener] --> trigger d3.zoom --> triggers my.zoom
etc...
我想實現的是一種在決定觸發另一個my.zoom
事件時檢查my.zoom
事件是否已經被觸發的my.zoom
,以防止事件的周期性觸發(防止上述示例中的步驟3),但是我不知道該怎么做。 無論如何,函數或事件是否知道觸發它的事件然后停止自身?
如果translate
和scale
不是模糊值,想到的第一個選項是使當前translate
和scale
的調用adjustZoom
成為無操作。 因此,如果chart1的值更改,它將引發事件,更改chart2的值,並且chart2引發事件,但是chart1中斷了循環,因為其translate
和scale
已經是這些值。
另一個選擇是在事件中傳遞更改的源元素,然后如果是啟動該事件的圖表,則不在圖表上觸發它。
例如,觸發時:
$("#chart-div").trigger({
type: "my.zoom",
translate: d3.event.translate,
scale: d3.event.scale,
source: this // <=== The new bit
});
然后在處理時:
if (chart2[0] !== e.source) {
chart2.adjustZoom(e.translate, e.scale);
}
注意,代碼示例假定chart1
和chart2
是圍繞單個元件的jQuery包裝; 如果不是,請進行相應調整。
我找到了針對D3的解決方案:
D3事件對象d3.event
包含一個嵌套對象sourceEvent
,它表示觸發D3事件的先前事件的堆棧。 此嵌套對象中的底部事件是一個簡單的DOM事件。 例如,在縮放時,這可能是鼠標滾輪或單擊事件。 在我的示例中,自定義事件被表示為具有所有常規事件鍵和屬性的普通對象,因此我像下面這樣更改了縮放事件事件處理程序:
var zoom = d3.behavior.zoom()
.on("zoom", function(e){
// do stuff...
if (typeof d3.event.sourceEvent.sourceEvent != 'object'){
$("#chart-div").trigger({
type: "my.zoom",
translate: d3.event.translate,
scale: d3.event.scale
});
}
});
這項新測試的目的是檢查sourceEvent
是否具有父事件,如果有,請確保它不是普通對象(我的自定義事件)。 現在,當我縮放一個圖表時,它將觸發一個my.zoom
事件,該事件將觸發第二個圖表的縮放功能,但第二個圖表不會觸發其自己的my.zoom
事件。
很高興知道是否存在用於處理JavaScript事件的類似通用方法,但就我的用例而言,此解決方案可能會做得到。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.