antv/G6图谱-节点共同邻居

一、react版本

https://github.com/antvis/G6VP/blob/master/packages/gi-assets-basic/src/components/CommonNeighbor/Component.tsx

二、vue版本-参考改编自react版本

1、依赖

import G6 from '@antv/g6';

import { intersectionWith, uniq, union } from 'lodash'; // 方法

2、共同邻居

// 查询所有选中的元素
export function selectAllActiveItem() {
  const nodes = graph.findAllByState('node', 'selected');
  return nodes;
}

// 共同邻居
export function sameneighbor() {
  let allSelectedNodes = selectAllActiveItem();
  if (allSelectedNodes.length < 2) {
    return;
  }
  const { edges } = findCommonNeighbors(allSelectedNodes); // 计算邻居

  const edgess = [...edges];
  if (edgess?.length) {
    // 先清除所有
    graph.getEdges().forEach((edge: any) => {
      graph.clearItemStates(edge);
    });
    // 高亮计算结果
    edgess.forEach(item => {
      graph.setItemState(item, 'hover', true);
    });
  } else {
    ElMessage.error('无共同邻居');
  }
}

3、计算邻居算法

/**
 * 发现共同邻居
 * @param beginNodes 起始节点数组
 * @param hop 跳数
 *
 * @return  { nodes: any[]; edges: any[] }
 */
function findCommonNeighbors(
  beginNodes: any[],
  hop: number = 1
): { nodes: any[]; edges: any[] } {
  // 存储从起点开始的每一分支在某一跳后到达的节点和访问过的节点
  const queue: any[][] = beginNodes.map(node => [
    {
      node,
      visited: new Set([node]),
    },
  ]);
  while (hop > 0) {
    const size = queue.length;
    for (let i = 0; i < size; i++) {
      const itemList = queue.shift()!.reduce((acc: any[], curr: any) => {
        uniq(
          curr.node.getNeighbors().filter((node: any) => {
            // 避免分支上出现环
            return !curr.visited.has(node);
          })
        ).forEach((node: any) => {
          acc.push({
            node,
            visited: new Set([...Array.from(curr.visited), node]),
          });
        });
        return acc;
      }, []);

      // 如果有分支不能达到hop指定的跳数,则不存在共同邻居, 提前返回
      if (itemList.length === 0) {
        return { nodes: [], edges: [] };
      }
      queue.push(itemList);
    }
    hop--;
  }

  // 将起点开始的每一分支在进行hop对应的跳数后到达的节点取交集
  const nodes: any = new Set(
    intersectionWith(
      ...queue,
      (itemA: any, itemB: any) => itemA.node === itemB.node
    ).map((item: any) => item.node)
  );
  // 收集起点到共同邻居节点之间的边
  const edges: any = new Set();
  union(...queue).map((item: any) => {
    if (nodes.has(item.node)) {
      let prevNode: any;
      item.visited.forEach((node: any) => {
        if (!prevNode) {
          prevNode = node;
          return;
        }
        prevNode.getEdges().forEach((edge: any) => {
          if (edge.getTarget() === node || edge.getSource() === node) {
            edges.add(edge);
          }
        });
        prevNode = node;
      });
    }
  });
  return { nodes, edges };
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值