可视化—AntV G6 高亮相邻节点的两种方式


目录
  • 内置的高亮节点
  • 自定义高亮
  • 自定义高亮时保持原始颜色
  • 总结
  • 案例完整代码

通过官方文档,可知高亮相邻节点分为两种方法,文档描述并不是很清楚,对刚接触这个库的小白并不是很友好,慢慢总结慢慢来吧

内置的高亮节点

是通过内置的Behavior activate-relations来实现,Behavior 是 G6 提供的定义图上交互事件的机制。与交互模式 Mode配合使用

activate-relations:当鼠标移到某节点时,突出显示该节点以及与其直接关联的节点和连线;

  • 参数:
    • trigger: 'mouseenter'。表示出发机制,可以是 mouseenterclick
    • activeState: 'active'。活跃节点状态,默认为 active,可以与 graph 实例的 xxxStateStyles 结合实现丰富的视觉效果。
    • inactiveState: 'inactive'。非活跃节点状态,默认值为 inactive。同样可以与 graph 实例的 xxxStateStyles 结合实现丰富的视觉效果。
    • 文档上还提到了另外两个参数,但是本案例中并未使用,暂不做说明 resetSelectedshouldUpdate(e)
  • 具体用法
let drawGraph = document.getElementById("drawGraph");
this.graphWidth = drawGraph.scrollWidth;
this.graphHeight = drawGraph.scrollHeight || 1200;

graphG = new this.G6.Graph({
  container: "drawGraph",
  width: this.graphWidth,
  height: this.graphHeight,
  modes: {
    default: [
      { type: "activate-relations", activeState: 'active', inactiveState: 'inactive' },
    ],
    // default: ['activate-relations']  // 由于活跃节点及非活跃节点状态均采用默认值,因此可以简写为这种形式
  },
  nodeStateStyles:{},    // 配置节点状态样式
  edgeStateStyles:{},    // 配置边状态样式
  comboStateStyles:{},   // 配置分组状态样式
}
graphG.data(data);
graphG.render(); 

如果仅采用内置的高亮节点,会采用默认的样式,最终的渲染效果为:

自定义高亮

这种方式是通过自定义状态,在通过实例提供的setItemState clearItemStates设置和清除目标的状态信息,同样需要与graph 实例的 xxxStateStyles 结合实现。

graphG = new this.G6.Graph({
  container: "drawGraph",
  width: this.graphWidth,
  height: this.graphHeight,
  nodeStateStyles:{  // 配置节点状态样式,此处就先写一个,后续会有完整的案例分享
    highlight: {
        fill: "#db4437",
        shadowColor: '#fff',
        stroke: "#db4437",
        cursor: "pointer",
        'text-shape': {
          lineWidth: 1,
          fill: "#db4437",
          stroke: "#db4437",
        },
      },
  },    
  edgeStateStyles:{},    // 配置边状态样式
  comboStateStyles:{},   // 配置分组状态样式
}
graphG.data(data);
graphG.render(); 
graphG.on("combo:mouseenter", (e) => {
  let edgeItem = e.item
  graphG.setItemState(edgeItem, 'highlight', true)
  edgeItem.getEdges().forEach(edge => {
    graphG.setItemState(edge.getTarget(), 'highlight', true)
    graphG.setItemState(edge.getSource(), 'highlight', true)
    graphG.setItemState(edge, 'highlight', true)
  })
  graphG.paint()
  graphG.setAutoPaint(true)
});

graphG.on('combo:mouseleave', (e) => {
  graphG.setAutoPaint(false)
  graphG.getNodes().forEach(node => {
    graphG.clearItemStates(node)
  })
  graphG.getEdges().forEach(edge => {
    graphG.clearItemStates(edge)
  })
  graphG.getCombos().forEach(combo => {
    graphG.clearItemStates(combo)
  })
  graphG.paint()
  graphG.setAutoPaint(true)
})

如果仅采用自定义高亮节点,最终的渲染效果为:

自定义高亮时保持原始颜色

通过上面的案例,可以看出,combo:mouseenter时相关联的边和点全部高亮,并且统一了连线的颜色,此时可能会与我们的需求相违背,可能连线还是想要保持原来的颜色,因为不同的颜色描述两点之间的不同类型的指向关系。那么此时在处理鼠标事件时,需要获取要节点和连线 原始样式。

graphG.on("combo:mouseenter", (e) => {
        let comboItem = e.item;
        const originStyle = comboItem._cfg.originStyle["circle-combo"].fill;
        comboItem._cfg.styles.highlight.fill = originStyle;
        graphG.setItemState(comboItem, "highlight", true);
        comboItem.getEdges().forEach((edge) => {
          const originStyle = edge._cfg.originStyle["edge-shape"].stroke; // 获取边edge 原始颜色
          edge._cfg.styles.highlight.stroke = originStyle;
          let edgeSource = edge.getSource();
          let edgeTarget = edge.getTarget();

          if ( edgeSource._cfg.type === "combo" && edgeSource._cfg.model.id =="100-600" ) {
            const originStyle = edgeSource._cfg.originStyle["circle-combo"].fill; // 获取分组combo 原始颜色
            edgeSource._cfg.styles.highlight.fill = originStyle;
          }
          if ( edgeTarget._cfg.type === "combo" && edgeTarget._cfg.model.id =="100-600" ) {
            const originStyle = edgeTarget._cfg.originStyle["circle-combo"].fill;
            edgeTarget._cfg.styles.highlight.fill = originStyle;
          }
          graphG.setItemState(edgeSource, "highlight", true);
          graphG.setItemState(edgeTarget, "highlight", true);
          graphG.setItemState(edge, "highlight", true);
        });
      });

      

那么此时最终的效果为:

总结

其实两种方法与异曲同工之妙,都是进行状态的处理,只不过一个是帮我们处理了一部分状态与样式,可以直接拿来用,但往往内置的样式与我们实际使用时不相符,因此可以使用两者结合的方式,最终效果及完整demo,采用随机数来模拟实体与关系。

案例完整代码