如何使用AntV实现一个支持节点路径高亮的桑基图

背景

桑基图(如图1)作为一种流程可视化图表,广泛应用于展示不同节点之间的数据流动和转化关系。通过桑基图,用户可以直观地了解数据的来源、流向和相互关系。而路径高亮功能(如图2)则提供了进一步分析特定数据路径的能力,使用户能够更好地理解数据中的关键信息。然而默认情况下,G2Plot提供的桑基图并不支持节点路径高亮的交互效果。为了实现这一功能,我们可以借助G2Plot提供的内部API来进行定制和优化。接下来,让我们一步步来探索如何实现一个支持节点路径高亮的桑基图。

截图.png

图1

截图 (1).png

图2

方案调研

1. 事件捕获

首先,我们需要捕获鼠标进入和离开节点的事件,以实现节点悬浮时的路径高亮效果。G2Plot 提供了丰富的图表事件,我们可以通过监听这些事件来实现所需的功能。

// 监听鼠标进入节点事件
plot.on('element:mouseenter', (event) => {
  // 高亮节点以及节点关联的路径
})

// 监听鼠标离开节点事件
plot.on('element:mouseout', (event) => {

  // 取消高亮
})

2. 判断节点类型

在事件捕获的回调函数中,我们需要判断当前鼠标悬浮的元素是否为节点。通过观察事件回调参数的数据结构,我们发现isNode这个属性用来标记节点类型,当其值为true标记当前元素是节点元素。

plot.on('element:mouseenter', (event) => {



  const node = event.data.data;



  if (!node.isNode) return; // 判断是否为节点
  // 高亮节点以及节点关联的路径
})

3. 查找节点路径并高亮

一旦确定当前元素为节点,我们需要找到与该节点相关联的路径,并进行高亮显示。由于桑基图是一种关系图,数据结构中保存了每个节点的关系,我们可以根据当前节点的名称查找与之相关的源节点和目标节点,从而确定其路径。

plot.on('element:mouseenter', (event) => {



  const node = event.data.data;



  if (!node.isNode) return;


  // 查找与当前节点相关联的路径,并高亮显示
})


plot.on('element:mouseout', (event) => {

  // 取消路径的高亮显示
})

方案设计

在实现路径高亮的过程中,我们先后尝试了几种不同的方案。其间也踩了一些坑,我们把这个过程记录下来,供大家参考

方案一:使用图表实例的 setState 方法

在事件回调函数中,可以调用图表实例的 setState 方法来设置节点和路径的状态。通过条件判断,将满足高亮条件的节点和路径设置为激活状态,其他节点和路径设置为非激活状态。

plot.on('element:mouseenter', (event) => {



  const node = event.data.data;



  if (!node.isNode) return;


  
  plot.setState('active', (data) => {
    // 判断节点或路径是否需要高亮
    // 返回 true 表示需要高亮,false 表示不需要高亮
  });
});

plot.on('element:mouseout', (event) => {
  // 取消所有节点和路径的高亮状态
  //plot.setState('active', ()=>false); // 不生效,这里有坑
  plot.render()  // 必须重新渲染图表才能让图表恢复到默认状态
});

此方案由于调用setState去除路径高亮不生效,只有重新渲染图表才可以恢复图表初始状态,这样就会导致频繁地重新渲染图表,对于大规模的数据集或复杂的图表结构,会影响性能和用户体验。

方案二:使用图表元素的 setState 方法

通过查看事件回调参数的数据结构,我们可以获取到图表元素的集合,通过遍历元素集合,可以调用元素的 setState 方法来设置节点和路径的状态。

plot.on('element:mouseenter', (event) => {



  const node = event.data.data;



  if (!node.isNode) return;



  const elements = event.view.views[0].geometries[0].elements;
  elements.forEach((element) => {
    const { source, target } = element.data;
    if (/* 判断元素是否与当前节点相关 */) {
      element.setState('active', true); // 高亮
    } else {
      element.setState('active', false); // 取消高亮
    }
  });
});

plot.on('element:mouseout', (event) => {
  const elements = event.view.views[0].geometries[0].elements;
  elements.forEach((element) => {
    element.setState('active', false); // 取消高亮
  });
});

通过调用元素的 setState 方法,可以直接修改元素的状态,而无需重新渲染整个图表,从而提高性能和用户体验。

方案三:综合方案一和方案二

综合方案一和方案二,可以实现节点路径的高亮和恢复操作。在事件回调函数中,使用图表实例的 setState 方法来设置节点状态,同时采用元素的 setState 方法来重置路径状态。这样就无需通过重新渲染图表来恢复图表默认状态,解决了方案一中图表频繁重复渲染的问题。

plot.on("element:mouseenter", (event) => {
      const node = event.data.data;
      if (!node.isNode) return;
      plot.setState("active", (data: any) => {
        const { isNode, source, target, name } = data;
        if (!isNode) {
          if ([source, target].includes(node.name)) return true;
        } else if (name == node.name) return true;

        return false;
      });
    });
    
 plot.on("element:mouseout", (event) => {
      const elements = event.view.views[0].geometries[0].elements;
      elements.forEach((edge: any) => edge?.setState("active", false));
    });

通过综合方案一和方案二,我们可以在节点高亮时同时高亮相关路径,并在鼠标移出节点时取消高亮状态,而无需频繁重新渲染整个图表。完整代码见:codesandbox.io/s/practical…

总结

本文介绍了如何使用 AntV G2Plot 库实现支持节点路径高亮的桑基图。通过事件捕获、节点类型判断和路径查找,我们可以实现节点悬浮时路径高亮的效果。通过调用图表实例或元素的 setState 方法,我们可以修改节点和路径的状态,实现高亮和恢复操作。虽然过程中遇到了一些问题,好在G2Plot提供了较多的API可以实现图表灵活的功能定制。不过还是建议Antv团队可以考虑默认支持桑基图路径高亮的这种交互效果,这在真实的业务中是一个比较常见的交互场景。

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYtBKcAm' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片