前端可视化 - Antv G6 交互与事件

2,577 阅读6分钟

G6版本: 4.8.21

此部分主要包括以下4点:监听和事件绑定、交互行为Behavior、交互模式Mode、状态State

一、监听和事件绑定

除了 内置交互行为  Behavior 和 交互模式 Mode 搭配的事件管理方式外,G6 提供了直接的单个事件、时机的监听方法,可以监听画布、节点、边、以及各函数被调用的时机等

// 全局事件: 只要在画布上范围内发生均会被触发,如 `mousedown`,`mouseup`,`click`,`mouseenter`,`mouseleave` 等。

graph.on('click', (ev) => {
  const shape = ev.target;
  const item = ev.item;
  if (item) {
    const type = item.getType();
  }
});
//  canvas事件: 只在 canvas 空白处被触发,如 `canvas:mousedown`,`canvas:click` 等,以`canvas:eventName` 为事件名称
graph.on('canvas:click', (ev) => {
  const shape = ev.target;
  const item = ev.item;
  if (item) {
    const type = item.getType();
  }
});
// 节点/边/combo 上的事件: 例如 `node:mousedown`,`edge:click`, `combo:click` 等

graph.on('node:click', (ev) => {
  const node = ev.item; // 被点击的节点元素
  const shape = ev.target; // 被点击的图形,可根据该信息作出不同响应,以达到局部响应效果
  // ... do sth
});


graph.on('edge:click', (ev) => {
  const edge = ev.item; // 被点击的边元素
  const shape = ev.target; // 被点击的图形,可根据该信息作出不同响应,以达到局部响应效果
  // ... do sth
});


graph.on('combo:click', (ev) => {
  const combo = ev.item; // 被点击 combo 元素
  const shape = ev.target; // 被点击的图形,可根据该信息作出不同响应,以达到局部响应效果
  // ... do sth
});
// 图形上的事件: 指定图形上的事件

graph.on('circle-shape:click', (ev) => {
  const shape = ev.target; // 被点击的图形
  // ... do sth
});
// 时机事件: 时机事件指渲染、视口变换、元素增删改、数据变换等时机

graph.on('afterrender', (ev) => {
  // ... do sth
});
// 自定义事件: on 监听,emit触发
graph.on('some-custom-event-name', (ev) => {
  // ... do sth
});
graph.emit('some-custom-event-name', {
  // some params
})

二、Behavior

  1. 14个内置Behavior
drag-combo // 拖动 Combo
collapse-expand-combo // 收起和展开 Combo
drag-canvas // 拖拽画布
scroll-canvas //  滚轮滚动画布
zoom-canvas // 缩放画布
drag-node // 拖拽节点,或拖动 Combo 中的节点
click-select // 点击选中节点,再次点击节点或点击 Canvas 取消选中状态
tooltip // 节点文本提示
edge-tooltip // 边文本提示
activate-relations // 当鼠标移到某节点时,突出显示该节点以及与其直接关联的节点和连线

brush-select // 拖动框选节点
lasso-select // 自由圈选
collapse-expand // 只适用于树图,展开或收起子树
create-edge // 通过交互创建边
shortcuts-call // 允许终端用户使用键盘组合键调用 Graph 的函数,例如按下键盘上的               control 与 1,对图进行适应画布。

  1. 交互的声明周期
  • 绑定事件;
  • 触发事件;
  • 持续事件;
  • 结束事件;
  • 移除事件。
  1. 自定义Behavior
G6.registerBehavior('activate-node', {
  getDefaultCfg() {
    return {
      multiple: true
    };
  },
  getEvents() {
    return {
      'node:click': 'onNodeClick',
      'canvas:click': 'onCanvasClick'
    };
  }
  onNodeClick(e) {
    const graph = this.graph;
    const item = e.item;
    if (item.hasState('active')) {
      graph.setItemState(item, 'active', false);
      return;
    }
    // this 上即可取到配置,如果不允许多个 'active',先取消其他节点的 'active' 状态
    if (!this.multiple) {
      this.removeNodesState();
    }
    // 置点击的节点状态 'active' 为 true
    graph.setItemState(item, 'active', true);
  },
  onCanvasClick(e) {
    // shouldUpdate 可以由用户复写,返回 true 时取消所有节点的 'active' 状态,即将 'active' 状态置为 false
    if (this.shouldUpdate(e, self)) {
      removeNodesState();
    }
  },
  removeNodesState() {
    graph.findAllByState('node', 'active').forEach(node => {
        graph.setItemState(node, 'active', false);
      });
  }
});

三、Mode

交互模式 Mode,它是图上交互行为 Behavior 的管理机制。一个图上可以有存在多种交互模式,每个交互模式包含多种交互行为 Behavior

  1. 配置mode
const graph = new G6.Graph({
  container: 'mountNode',
  width: 500,
  height: 500,
  modes: {
    // 支持的 behavior
    default: ['drag-canvas', 'zoom-canvas'],
    edit: ['click-select'],
  },
});
  1. 切换mode
graph.setMode('edit'); // 默认graph会使用default模式
  1. 编辑已有的mode addBehaviors, removeBehaviors, updateBehavior
// 向 default 模式中添加名为 drag-canvas 的行为,并使用行为的默认配置
graph.addBehaviors('drag-canvas', 'default');


// 从 default 模式中移除名为 drag-canvas 的行为
graph.removeBehaviors('drag-canvas', 'default');


// 向 edit 模式中添加名为 drag-canvas 的行为,并定义个性化配置
graph.addBehaviors(
  {
    type: 'drag-canvas',
    direction: 'x',
  },
  'edit',
);

// 一次向 default 模式中添加多个行为
graph.addBehaviors(['drag-canvas', 'zoom-canvas'], 'default');


// 一次从 default 模式中移除多个行为
graph.removeBehaviors(['drag-canvas', 'zoom-canvas'], 'default');


// 更新 'default' 模式下的 behavior 'zoom-canvas'
graph.updateBehavior('zoom-canvas', { sensitivity: 1.5, enableOptimize: true}, 'default');


// 更新 'select' 模式下的 behavior 'click-select'
graph.updateBehavior('click-select', { trigger: 'ctrl' }, 'select');

四、状态 State

G6 中的 state,指的是节点或边的状态,包括交互状态业务状态两种。

何时使用 state

判断是否该使用 state 的原则很简单,从交互和业务两个层面来看:

  • 某个交互动作要改变节点或边的样式及属性;
  • 呈现给用户的内容会根据数据改变(如 1 代表成功,0 代表失败)。

满足上述条件其一,则应该使用 state。

状态的类型

状态可以是二值的,也可以是多值的

graph.setItemState(item, stateName, stateValue)
graph.setItemState(item, 'stateName', true);
调用的时机

可以在监听函数graph.on中被调用,也可以在自定义 Behavior 中调用,或在其他任意地方用于响应交互/业务的变化

// graph.on  在回调函数中使定义的交互状态 hover 生效
graph.on('node:mouseenter', (evt) => {
  const { item } = evt;
  graph.setItemState(item, 'hover', true);
});


graph.on('node:mouseleave', (evt) => {
  const { item } = evt;
  graph.setItemState(item, 'hover', false);
});
// 在自定义 Behavior 中使定义的交互状态 selected 生效。
G6.registerBehavior('nodeClick', {
  getEvents() {
    return {
      'node:click': 'onClick',
    };
  },
  onClick(e) {
    e.preventDefault();
    if (!this.shouldUpdate.call(this, e)) {
      return;
    }
    const { item } = e;
    const graph = this.graph;
    graph.setItemState(item, 'selected', true);
  },
});
配置state样式

graph.setItemState使某些状态在图元素(节点/边)上被激活/灭活,仅仅是为该元素做了某些状态的标识。我们还需要对不同状态设置不同样式。

有三种方式配置不同状态的样式

  • 在实例化 Graph 时,通过 nodeStateStyles 和 edgeStateStyles 对象定义;
  • 在节点/边数据中,在 stateStyles 对象中定义状态;
  • 在自定义节点/边时,在 options 配置项的 stateStyles 对象中定义状态。
// 实例化 Graph 时定义 state 样式

const graph = new G6.Graph({
  container: 'mountNode',
  width: 800,
  height: 600,
  defaultNode: {
    type: 'diamond',
    style: {
      // 默认状态样式
      fill: 'blue',
      // ... 其他样式
    },
  },
  nodeStateStyles: {
    
      // 二值状态 hover 为 true 时的样式
      hover: {
        // keyShape 的状态样式
        fill: '#d3adf7',
        // name 为 node-label 的子图形在该状态值下的样式
        'node-label': {
          fontSize: 15
        },
      },
      
      // 多值状态 bodyState 为 health 时的样式
      'bodyState:health': {
        // keyShape 该状态值下的样式
        fill: 'green',
        // ... 其他样式
        // name 为 shape-name1 的子图形在该状态值下的样式
        'shape-name1': {
          stroke: '#ccc'
          // ... 其他样式
        },
        // name 为 shape-name2 的子图形在该状态值下的样式
        'shape-name2': {
          fill: 'red'
          // ... 其他样式
        }
      },
      // 多值状态 bodyState 为 suspect 时的样式
      'bodyState:suspect': {
        // ...
      },
      // 多值状态 bodyState 为 ill 时的样式
      'bodyState:ill': {
        // ...
      }
  },
  
  defaultEdge: {
    // ...
  },
  edgeStateStyles: {
    // ...
  },
});
// 在节点/边数据中定义 state 样式

const data = {
  nodes: [
    {
      id: 'node1',
      stateStyles: {
      },
    },
    {
      id: 'node2',
      stateStyles: {
        //... 
      },
    },
  ],
  edges: [
    {
      source: 'node1',
      target: 'node2',
      styles: {
        // 默认样式
      },
      stateStyles: {
        //... 见上方例子
      },
    },
  ],
};
// 自定义节点和边时定义 state 样式
G6.registerNode('customShape', {
  // 自定义节点时的配置
  options: {
    size: 60,
    style: {
      lineWidth: 1
    },
    stateStyles: {
      // ... 见上方例子
    }
  }
}
更新状态配置

updateItem

更新状态样式配置是指更改在配置 state 样式中设置的某状态下的样式配置

graph.updateItem(item, {
  // 修改默认样式
  style: {
    stroke: 'green',
    // 修改 name 为 'node-label' 的子图形的默认样式
    'node-label': {
      stroke: 'yellow',
    },
  },
  stateStyles: {
    // 修改 hover 状态下的样式
    hover: {
      opacity: 0.1,
      // 修改 name 为 'node-label' 的子图形 hover 状态下的样式
      'node-text': {
        stroke: 'blue',
      },
    },
  },
});
取消状态
graph.setItemState(item, 'bodyState', 'health');

// 取消单个状态
graph.clearItemStates(item, 'selected');
graph.clearItemStates(item, ['selected']);

// 取消多个状态
graph.clearItemStates(item, ['bodyState:health', 'selected', 'active']);