简介

前一章节确定了 G6 的范围,本章对一些细节进行讨论,主要对下面几个领域进行设计:

  • 数据结构
  • 事件、行为和模式
  • 自定义节点和边
  • 动画机制
  • 类结构

其他的诸如数据流程、接口定义、具体支持哪些交互,在详细设计中阐述。

数据结构

node

默认提供的类型

  • G中提供的基础图形
  • 锚点机制
  1. {
  2. id: 'node1',
  3. color: '#333',
  4. className: '', // 标识符
  5. size: 10 || [10, 10], // [width, height]
  6. shape: 'circle', // node类型
  7. style: { // keyShape的绘图属性
  8. fill: 'red',
  9. stroke: 'blue'
  10. },
  11. x: 0, // x坐标
  12. y: 0, // y坐标
  13. label: '文本标签',
  14. labelStyle: {
  15. fill: 'green'
  16. },
  17. }
  • 必须有的字段 id, x, y

    edge

    默认提供类型

  • 直线line

  • 贝塞尔曲线
  • step curve
  • polyline
  • 平行边

    扩展机制

    edge cfg

    边的要素有:form, color, size, label。对应如下结构:

    1. {
    2. id: 'edge1',
    3. source: 'node1',
    4. target: 'node2',
    5. sourceAnchor: 1, // 可选
    6. targetAnchor: 0, //可选
    7. controlPoints: [{
    8. x: 10,
    9. y: 10
    10. }],
    11. color: 'red',
    12. size: 3,
    13. shape: 'line',
    14. style: {
    15. fill: 'red',
    16. stroke: 'blue',
    17. startArrow: boolean | fn,
    18. endArrow: boolean | fn
    19. },
    20. label: '文本标签',
    21. labelStyle: {
    22. fill: 'green'
    23. },
    24. }
  • 必须有的字段: id,source,target

    事件、行为和模式

    考虑到 G6 需要同时支持编辑器和分析场景,同样的用户行为会导致不同的结果,其出发点也不同,考虑几个典型场景:

  • 编辑器中拖拽节点位置,相邻的边重新计算;分析场景下拖拽单个节点,由于存在力导布局算法,所有的边和节点都会受到影响,进行移动。

  • 编辑器中框选选中多个节点,进行高亮,一些命令按钮高亮;分析场景下使用不规则图形框选多个节点,上面生成蒙层,可以拖动蒙层,其他图表与之进行联动。
  • 同样的拖拽,拖拽画布、拖拽节点、拖拽边、拖拽分组,都有不同的反馈和结果。
  • 相同的行为,例如拖拽,在编辑图的场景下和查看图的场景下,用户的目的也不一样,可以做的事情也不一样。

所以 G6 依然会使用事件、行为和模式的设计:

  • 事件:画布支持的事件,包括图形事件、组件事件、自定义的事件
  • 状态:画布、数据的状态,状态的改变会触发事件,有必要对这些状态进行细分。
  • 行为:用户在图表上的行为,例如鼠标在图表上移动、框选、拖拽、点击等整个的操作过程,每种行为都带有目的
  • 反馈:用户在图表上进行交互的反馈
  • 模式:查看视图、编辑视图、移动视图

概要设计 - 图1

事件

G6 层次的事件主要分为:

  • 图形事件:click、mousemove 等
  • 画布事件:resize、zoom 等
  • 节点、边等元素的事件:add、update、remove、drag 等
  • 各种自定义事件

    行为

    仅仅触发事件,没有任何意义,事件(包括状态改变) + 目的 = 行为,所以行为是带有目的的事件,行为往往是连贯的,用户框选元素时元素被选中(选中行为),用户按下删除键,元素被移除(删除行为)。行为的目的要同行为的结果一致,否则就是无效行为,甚至是 Bug。

    基本行为

    G6 层次支持的行为:

  • hover/active 元素

  • 点击选中节点,shift 多选
  • 框选节点
  • 画布拖拽
  • 画布缩放
  • 拖拽节点、拖拽边(不考虑改变链接)

G6-Editor 和 G6-Analyzer 支持的行为不在这里列出。

反馈

行为过程中画布的响应:

  • 行为开始,伴随触发行为的事件的鼠标、画布、节点的变化,例如框选时,按下鼠标,鼠标的形状发生变化
  • 行为过程中,框选拖拽的过程中,出现虚框
  • 行为结束,用户释放鼠标,框选后的节点变成选中状态

    模式

    为什么要使用模式对用户的交互进行区分,考虑一下场景:

  • 用户在空白画布上拖拽鼠标,是进行拖拽画布还是框选?

  • 用户拖拽节点的边,是 resize 还是出现连接线?
  • 用户滚动鼠标滚轮,是放大还是滚动条移动?
  • 用户双击节点,是弹出 Dialog 还是编辑文本?

所以模式是为了区分相同事件(用户操作)产生不同反馈的行为而设计的,同一个模式下行为的结果是确定的,不能一个在画布空白处的拖拽既是框选又是拖动画布。
我们按照对 G6 的划分对模式进行梳理:

  • G6 通用的场景(编辑和分析都支持)
  • G6-Editor 编辑场景的模式
  • G6-Analyzer 分析场景的模式

通用场景

  • 查看模式:支持 hover 节点、画布拖拽、画布缩放
  • 选中模式:点击选中节点、框选、框选后的拖拽(拖拽节点、拖拽边)

    其他

    G6-Editor 和 G6-Analyzer 下有更多的模式,这里不展开讲解

注意点:

  • 一个模式下有多种行为,一种行为可以在多个模式下生效
  • 模式和行为不进行绑定,可以给任意模式增加任意行为,保证不冲突即可
  • 可以自定义模式和行为

自定义节点和边

G6 中对节点和边的定义最基本的类型,在数据结构中的 shape 字段类来确定使用什么类型的节点或者边。

默认的节点和边

默认的节点有:

  • 简单图形 + 文本, circle, rect
  • 图片 + 文本,image,需要传入图片地址
  • 列表:title + name + value 的列表

默认的边:

  • 直线(line),节点与节点的中心连接线,可能被节点的边框截断
  • 直角线(step),有垂直和水平方向的线段组成的连线
  • 折线(polyLine),多条线段组成的连线
  • 曲线(curve),贝塞尔曲线、平滑曲线

线上的文本比较复杂,有些文本在线上居中,有些文本分布在线的两端,而且线还要同线同向

自定义

节点和边的自定义主要是基于内置的节点和边进行扩充,两种元素的扩展有很大的差别:

  • 自定义节点,需要解决绘制节点和更新节点的问题
  • 自定义边,边如何同节点进行连接,边的更新,边控制点如何影响边的形状

节点和边的 active、selected 的效果也可以考虑在这时候实现

更新机制

节点和边的更新差异也比较大:

  • 节点在以下场景下会触发更新:
    • 移动
    • 数据更新
    • 刷新
  • 边的更新
    • 端点发生变化(端点变动、节点移动)
    • 控制点、锚点发生变化
    • 数据更新

在之前的版本中节点和边的更新都是直接删除重新绘制,需要重新思考这两种元素的更新方式。

动画机制

主要考虑两种情况下的动画:

  • 初始化时的动画:大多数力导布局都是渐进的,所以需要不断的调整节点位置,位置之间需要补间动画。
  • 交互过程中:树节点的展开、折叠,力导布局后的节点被拖拽

这两种动画都与布局算法相关,所以需要思考所有节点刷新时的操作接口和最佳实践。
还有其他的动画需要考虑

  • 节点激活时,出现光环效果
  • 边上的动画,表示数据流向
  • 节点上有些图标进行动画,表示节点的状态

这些动画都同图形相关,所以需要在定义节点时处理。

类结构

根据上面的讨论列出 G6 的类结构

概要设计 - 图2