一、react版本
二、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 };
}