聊聊Canvas事件机制相关 (非API层,偏框架设计方面)

903 阅读2分钟

image.png

以下分析均采用 Sigmajs 框架源码进行分析,有兴趣的同学可以去查看一下。 本文主要介绍下Canvas的事件机制,和一些设计思路。


图形事件,设计思路及实现介绍。

图形事件需要支持以下的内容:

  • 支持各类事件类型
  • 事件触发机制
  • 事件冲突问题

image.png

事件类型

image.png

  • mouse

    • mousedown
    • mousemove
    • mouseup
    • mouseenter
    • mouseleave
    • dblclick
    • contextmenu
    • click
    • wheel
      • drag 基于mousedown move leave做二次开发.
      • dragstart
      • dragend image.png
  • 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中存在图形和画布,以及画布做了分层。彼此存在事件先后(冒泡)顺序。

最后

可视化相关的架构设计,源码学习,日常开发。我会逐步进行深入分享。如果对你有帮助请关注我后续的内容。有需要的同学可以加一下我的联系方式(在我的主页,拉你进群聊)。