簡體   English   中英

防止循環JavaScript事件

[英]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),但是我不知道該怎么做。 無論如何,函數或事件是否知道觸發它的事件然后停止自身?

如果translatescale不是模糊值,想到的第一個選項是使當前translatescale的調用adjustZoom成為無操作。 因此,如果chart1的值更改,它將引發事件,更改chart2的值,並且chart2引發事件,但是chart1中斷了循環,因為其translatescale已經是這些值。

另一個選擇是在事件中傳遞更改的源元素,然后如果是啟動該事件的圖表,則不在圖表上觸發它。

例如,觸發時:

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

注意,代碼示例假定chart1chart2是圍繞單個元件的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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM