以下分析均採用 Sigmajs 框架原始碼進行分析,有興趣的同學可以去檢視一下。 本文主要介紹下Canvas的事件機制,和一些設計思路。
圖形事件,設計思路及實現介紹。
圖形事件需要支援以下的內容:
- 支援各類事件型別
- 事件觸發機制
- 事件衝突問題
事件型別
mouse
- mousedown
- mousemove
- mouseup
- mouseenter
- mouseleave
- dblclick
- contextmenu
- click
- wheel
- drag 基於mousedown move leave做二次開發.
- dragstart
- dragend
touch
- touchstart
- touchend
- touchcancel
- touchmove
事件觸發機制
根據事件的觸發源不同可以分為兩種:
- 圖形上觸發
- Canvas上觸發
所有事件均在Canvas的DOM事件觸發基礎上實現。
以click為例:
滑鼠在畫布上點選 觸發Canvas DOM事件,然後與圖形進行碰撞 如果有就是圖形點選 沒有就是畫布點選。虛擬碼示例:
Canvas.addEventListener("click", function(){
// MouseCoords == CanvasCoords
// getShapeAtPoint(Shapes,CanvasCoords)
if(true){
// 如果碰撞到圖形
this.emit("clickGraph",false);
return
}
this.emit("clickCanvas",false);
//
}, false);
事件衝突問題
drag 和 click 的衝突
由於 canvas 是一個DOM節點, 不是每個圖元作為DOM 物件可以識別,所以無法通過 dragable 設定圖形是否可以拖拽,這時候使用觸控板時的點選和拖拽會衝突。
在使用 mousedown,mouseup 過程中進行模擬, 對於在兩者之間判定移動的距離和時間差進行一個判斷。
具體是Click還是drag事件。
click 和 dbclick的衝突
其實不算是衝突問題, 是對於dbclick的實現基於click那麼就需要對click事件有一個處理,方便識別。請看程式碼示例:
handleClick(e: MouseEvent): void {
if (!this.enabled) return;
this.clicks++;
if (this.clicks === 2) {
this.clicks = 0;
if (typeof this.doubleClickTimeout === "number") {
clearTimeout(this.doubleClickTimeout);
this.doubleClickTimeout = null;
}
return this.handleDoubleClick(e);
}
setTimeout(() => {
this.clicks = 0;
this.doubleClickTimeout = null;
}, DOUBLE_CLICK_TIMEOUT);
if (this.draggedEvents < DRAGGED_EVENTS_TOLERANCE) this.emit("click", getMouseCoords(e, this.container));
}
其他
關於事件的冒泡, 在Sigma中存在圖形和畫布,以及畫布做了分層。彼此存在事件先後(冒泡)順序。
最後
視覺化相關的架構設計,原始碼學習,日常開發。我會逐步進行深入分享。如果對你有幫助請關注我後續的內容。有需要的同學可以加一下我的聯絡方式(在我的主頁,拉你進群聊)。