circle.js 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. import { isArray } from '@antv/util';
  2. /**
  3. * 根据 edges 获取对应的 node 结构
  4. */
  5. export function getNodes(edges, sourceField, targetField) {
  6. var nodes = [];
  7. edges.forEach(function (e) {
  8. var source = e[sourceField];
  9. var target = e[targetField];
  10. if (!nodes.includes(source)) {
  11. nodes.push(source);
  12. }
  13. if (!nodes.includes(target)) {
  14. nodes.push(target);
  15. }
  16. });
  17. return nodes;
  18. }
  19. /**
  20. * 根据 edges 获取对应的 dfs 邻接矩阵
  21. */
  22. export function getMatrix(edges, nodes, sourceField, targetField) {
  23. var graphMatrix = {};
  24. nodes.forEach(function (pre) {
  25. graphMatrix[pre] = {};
  26. nodes.forEach(function (next) {
  27. graphMatrix[pre][next] = 0;
  28. });
  29. });
  30. edges.forEach(function (edge) {
  31. graphMatrix[edge[sourceField]][edge[targetField]] = 1;
  32. });
  33. return graphMatrix;
  34. }
  35. /**
  36. * 使用 DFS 思路切断桑基图数据中的环(会丢失数据),保证顺序
  37. * @param data
  38. * @param sourceField
  39. * @param targetField
  40. */
  41. export function cutoffCircle(edges, sourceField, targetField) {
  42. if (!isArray(edges))
  43. return [];
  44. // 待删除的环状结构
  45. var removedData = [];
  46. // 获取所有的节点
  47. var nodes = getNodes(edges, sourceField, targetField);
  48. // 获取节点与边的邻接矩阵
  49. var graphMatrix = getMatrix(edges, nodes, sourceField, targetField);
  50. // visited:标记节点访问状态, 0:未访问,1:访问中, -1:已访问
  51. var visited = {};
  52. // 初始化visited
  53. nodes.forEach(function (node) {
  54. visited[node] = 0;
  55. });
  56. // 图的深度遍历函数
  57. function DFS(dfsNode) {
  58. // 节点状态置为正在访问
  59. visited[dfsNode] = 1;
  60. nodes.forEach(function (node) {
  61. if (graphMatrix[dfsNode][node] != 0) {
  62. // 当前节点在访问中,再次被访问,证明有环,移动到 removeData
  63. if (visited[node] == 1) {
  64. // 拼接为字符串,方便最后过滤
  65. removedData.push("".concat(dfsNode, "_").concat(node));
  66. }
  67. else if (visited[node] == -1) {
  68. // 当前结点及后边的结点都被访问过,直接跳至下一个结点
  69. return;
  70. }
  71. else {
  72. DFS(node); // 否则递归访问
  73. }
  74. }
  75. });
  76. //遍历过所有相连的结点后,把本节点标记为-1
  77. visited[dfsNode] = -1;
  78. }
  79. // 对每个节点执行 dfs 操作
  80. nodes.forEach(function (node) {
  81. //该结点后边的结点都被访问过了,跳过它
  82. if (visited[node] == -1) {
  83. return;
  84. }
  85. DFS(node);
  86. });
  87. if (removedData.length !== 0) {
  88. console.warn("sankey data contains circle, ".concat(removedData.length, " records removed."), removedData);
  89. }
  90. // 过滤 remove 路径
  91. return edges.filter(function (edge) { return removedData.findIndex(function (i) { return i === "".concat(edge[sourceField], "_").concat(edge[targetField]); }) < 0; });
  92. }
  93. //# sourceMappingURL=circle.js.map