@antv/layout 0.3.1 → 0.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/layout.min.js +1 -1
  2. package/dist/layout.min.js.map +1 -1
  3. package/es/layout/dagre/src/position/index.js +1 -1
  4. package/es/layout/dagre/src/position/index.js.map +1 -1
  5. package/es/layout/force2/ForceNBody.js +1 -1
  6. package/es/layout/force2/ForceNBody.js.map +1 -1
  7. package/es/layout/force2/index.js +9 -11
  8. package/es/layout/force2/index.js.map +1 -1
  9. package/es/layout/gForce.js +1 -1
  10. package/es/layout/gpu/gForce.js +1 -1
  11. package/es/layout/gpu/gForce.js.map +1 -1
  12. package/es/layout/layout.d.ts +12 -1
  13. package/es/layout/layout.js +30 -0
  14. package/es/layout/layout.js.map +1 -1
  15. package/es/util/gpu.js +0 -1
  16. package/es/util/gpu.js.map +1 -1
  17. package/es/util/math.js +25 -25
  18. package/es/util/math.js.map +1 -1
  19. package/es/util/object.js +1 -1
  20. package/es/util/object.js.map +1 -1
  21. package/lib/layout/dagre/src/position/index.js +10 -1
  22. package/lib/layout/dagre/src/position/index.js.map +1 -1
  23. package/lib/layout/force2/ForceNBody.js.map +1 -1
  24. package/lib/layout/force2/index.js +1 -3
  25. package/lib/layout/force2/index.js.map +1 -1
  26. package/lib/layout/gForce.js +1 -1
  27. package/lib/layout/gpu/gForce.js.map +1 -1
  28. package/lib/layout/layout.d.ts +12 -1
  29. package/lib/layout/layout.js +30 -0
  30. package/lib/layout/layout.js.map +1 -1
  31. package/lib/util/gpu.js +0 -1
  32. package/lib/util/gpu.js.map +1 -1
  33. package/lib/util/math.js +12 -12
  34. package/lib/util/math.js.map +1 -1
  35. package/lib/util/object.js +1 -1
  36. package/lib/util/object.js.map +1 -1
  37. package/package.json +2 -2
  38. package/src/layout/dagre/src/position/index.ts +1 -1
  39. package/src/layout/force2/ForceNBody.ts +2 -2
  40. package/src/layout/force2/index.ts +16 -16
  41. package/src/layout/gForce.ts +2 -2
  42. package/src/layout/gpu/gForce.ts +1 -1
  43. package/src/layout/layout.ts +34 -1
  44. package/src/layout/types.ts +1 -1
  45. package/src/util/gpu.ts +0 -1
  46. package/src/util/math.ts +30 -32
  47. package/src/util/object.ts +1 -1
@@ -69,7 +69,7 @@ export class Force2Layout extends Base {
69
69
  public damping: number = 0.9;
70
70
 
71
71
  /** 最大速度 */
72
- public maxSpeed: number = 1000;
72
+ public maxSpeed: number = 100;
73
73
 
74
74
  /** 一次迭代的平均移动距离小于该值时停止迭代 */
75
75
  public minMovement: number = 0.4;
@@ -93,7 +93,7 @@ export class Force2Layout extends Base {
93
93
  public linkDistance: number | ((edge?: any, source?: any, target?: any) => number) | undefined = 200;
94
94
 
95
95
  /** 理想边长,兼容 graphin-force */
96
- public defSpringLen: number | ((edge?: any, source?: any, target?: any) => number) | undefined
96
+ public defSpringLen: number | ((edge?: any, source?: any, target?: any) => number) | undefined;
97
97
 
98
98
  /** 重力大小 */
99
99
  public gravity: number = 0;
@@ -194,7 +194,7 @@ export class Force2Layout extends Base {
194
194
  // 如果传入了需要叶子节点聚类
195
195
  if (leafCluster) {
196
196
  sameTypeLeafMap = this.getSameTypeLeafMap() || {};
197
- const relativeNodesType = Array.from(new Set(nodes?.map(node => node[nodeClusterBy]))) || [];
197
+ const relativeNodesType = Array.from(new Set(nodes?.map((node) => node[nodeClusterBy]))) || [];
198
198
  centripetalOptions = {
199
199
  single: 100,
200
200
  leaf: (node, nodes, edges) => {
@@ -245,18 +245,18 @@ export class Force2Layout extends Base {
245
245
  const clusters: string[] = Array.from(new Set(nodes.map((node, i) => {
246
246
  return node[nodeClusterBy];
247
247
  }))).filter(
248
- item => item !== undefined,
248
+ (item) => item !== undefined,
249
249
  );
250
250
  const centerNodeInfo: { [key: string]: { x: number; y: number } } = {};
251
- clusters.forEach(cluster => {
252
- const sameTypeNodes = nodes.filter(item => item[nodeClusterBy] === cluster).map(node => nodeMap[node.id]);
251
+ clusters.forEach((cluster) => {
252
+ const sameTypeNodes = nodes.filter((item) => item[nodeClusterBy] === cluster).map((node) => nodeMap[node.id]);
253
253
  // 找出同类型节点平均位置节点的距离最近的节点作为中心节点
254
254
  centerNodeInfo[cluster] = getAvgNodePosition(sameTypeNodes);
255
255
  });
256
256
  centripetalOptions = {
257
- single: node => getClusterNodeStrength(node),
258
- leaf: node => getClusterNodeStrength(node),
259
- others: node => getClusterNodeStrength(node),
257
+ single: (node) => getClusterNodeStrength(node),
258
+ leaf: (node) => getClusterNodeStrength(node),
259
+ others: (node) => getClusterNodeStrength(node),
260
260
  center: (node, nodes, edges) => {
261
261
  // 找出同类型节点平均位置节点的距离最近的节点作为中心节点
262
262
  const centerNode = centerNodeInfo[node[nodeClusterBy]];
@@ -407,7 +407,7 @@ export class Force2Layout extends Base {
407
407
 
408
408
 
409
409
  self.edgeInfos = [];
410
- edges?.forEach(edge => {
410
+ edges?.forEach((edge) => {
411
411
  const sourceNode = nodeMap[edge.source];
412
412
  const targetNode = nodeMap[edge.target];
413
413
  if (!sourceNode || !targetNode) {
@@ -424,9 +424,9 @@ export class Force2Layout extends Base {
424
424
  sourceNode,
425
425
  targetNode
426
426
  ) : self.linkDistance(edge, sourceNode, targetNode) || 1 + ((nodeSize(sourceNode) + nodeSize(sourceNode)) || 0) / 2
427
- })
427
+ });
428
428
  }
429
- })
429
+ });
430
430
 
431
431
  this.getCentripetalOptions();
432
432
 
@@ -506,7 +506,7 @@ export class Force2Layout extends Base {
506
506
  });
507
507
 
508
508
  return energy;
509
- };
509
+ }
510
510
 
511
511
  // coulombs law
512
512
  public calRepulsive(accArray: number[]) {
@@ -617,7 +617,7 @@ export class Force2Layout extends Base {
617
617
  }
618
618
 
619
619
  /** others */
620
- const othersStrength = others(node)
620
+ const othersStrength = others(node);
621
621
  if (!othersStrength) continue;
622
622
  accArray[idx] -= othersStrength * vx;
623
623
  accArray[idx + 1] -= othersStrength * vy;
@@ -731,11 +731,11 @@ export class Force2Layout extends Base {
731
731
  // eslint-disable-next-line
732
732
  const sameTypeLeafMap: { [nodeId: string]: any } = {};
733
733
  nodes.forEach((node, i) => {
734
- const degree = degreesMap[node.id].all
734
+ const degree = degreesMap[node.id].all;
735
735
  if (degree === 1) {
736
736
  sameTypeLeafMap[node.id] = getCoreNodeAndRelativeLeafNodes('leaf', node, edges, nodeClusterBy, degreesMap, nodeMap);
737
737
  }
738
738
  });
739
739
  return sameTypeLeafMap;
740
- };
740
+ }
741
741
  }
@@ -379,7 +379,7 @@ export class GForceLayout extends Base {
379
379
  const vecLength = Math.sqrt(vecX * vecX + vecY * vecY);
380
380
  const direX = vecX / vecLength;
381
381
  const direY = vecY / vecLength;
382
- const length = (linkDistance as Function)(edge, sourceNode, targetNode) || 1 + ((nodeSize(sourceNode) + nodeSize(sourceNode)) || 0) / 2;
382
+ const length = (linkDistance as Function)(edge, sourceNode, targetNode) || 1 + ((nodeSize(sourceNode) + nodeSize(targetNode)) || 0) / 2;
383
383
  const diff = length - vecLength;
384
384
  const param = diff * (edgeStrength as Function)(edge);
385
385
  const sourceIdx = nodeIdxMap[source];
@@ -485,4 +485,4 @@ export class GForceLayout extends Base {
485
485
  public getType() {
486
486
  return "gForce";
487
487
  }
488
- }
488
+ }
@@ -221,7 +221,7 @@ export class GForceGPULayout extends Base {
221
221
  );
222
222
 
223
223
  // init degree for mass
224
- self.degrees = getDegree(nodes.length, self.nodeIdxMap, edges).map(degree => degree.all);
224
+ self.degrees = getDegree(nodes.length, self.nodeIdxMap, edges).map((degree) => degree.all);
225
225
  const masses: number[] = [];
226
226
  const nodeStrengths: number[] = [];
227
227
  const centerXs: number[] = [];
@@ -1,5 +1,5 @@
1
1
  import { Base } from "./base";
2
- import { Model, ILayout } from "./types";
2
+ import { Model, ILayout, Node } from "./types";
3
3
  import { getLayoutByName } from "../registy";
4
4
  import { GridLayout } from "./grid";
5
5
  import { RandomLayout } from "./random";
@@ -19,6 +19,12 @@ import { ComboCombinedLayout } from "./comboCombined";
19
19
  import { ForceAtlas2Layout } from "./forceAtlas2";
20
20
  import { ERLayout } from "./er";
21
21
  import { DagreCompoundLayout } from "./dagreCompound";
22
+ import { isString } from "../util";
23
+
24
+ interface DagreNodeData extends Node {
25
+ layer?: number;
26
+ }
27
+
22
28
  export class Layout {
23
29
  public readonly layoutInstance: Base;
24
30
 
@@ -36,9 +42,36 @@ export class Layout {
36
42
  }
37
43
 
38
44
  init(data: Model) {
45
+ this.correctLayers(data.nodes);
39
46
  this.layoutInstance.init(data);
40
47
  }
41
48
 
49
+ /**
50
+ * correcting the layers on the node data
51
+ * if min(layer) <= 0, layers should begin from abs(min(layer)) + 1
52
+ * @param nodes
53
+ * @returns
54
+ */
55
+ correctLayers(nodes: DagreNodeData[] | undefined) {
56
+ if (!nodes?.length) return;
57
+ let minLayer = Infinity;
58
+ const hasLayerNodes: DagreNodeData[] = [];
59
+ nodes.forEach((node) => {
60
+ if (isString(node.layer)) {
61
+ node.layer = parseInt(node.layer, 10);
62
+ }
63
+ // keep node.layer === undefined for TS problem
64
+ if (node.layer === undefined || isNaN(node.layer)) return;
65
+ hasLayerNodes.push(node);
66
+ if (node.layer < minLayer) minLayer = node.layer;
67
+ });
68
+ if (minLayer <= 0) {
69
+ const layerOffset = Math.abs(minLayer) + 1;
70
+ // @ts-ignore
71
+ hasLayerNodes.forEach((node) => node.layer += layerOffset);
72
+ }
73
+ }
74
+
42
75
  execute() {
43
76
  this.layoutInstance.execute();
44
77
  }
@@ -268,7 +268,7 @@ export interface Force2LayoutOptions {
268
268
  gravity?: number;
269
269
  factor?: number;
270
270
  workerEnabled?: boolean;
271
- centripetalOptions?: CentripetalOptions
271
+ centripetalOptions?: CentripetalOptions;
272
272
  leafCluster?: boolean;
273
273
  clustering?: boolean;
274
274
  nodeClusterBy?: string;
package/src/util/gpu.ts CHANGED
@@ -63,7 +63,6 @@ export const buildTextureData = (nodes: OutNode[], edges: Edge[]): {
63
63
  const offset: number = dataArray.length;
64
64
  const dests = nodeDict[i];
65
65
  const len = dests.length;
66
- console.log('dests', dests, len)
67
66
  dataArray[i * 4 + 2] = offset;
68
67
  dataArray[i * 4 + 3] = len;
69
68
  maxEdgePerVetex = Math.max(maxEdgePerVetex, len);
package/src/util/math.ts CHANGED
@@ -35,14 +35,14 @@ export const getDegree = (n: number, nodeIdxMap: IndexMap, edges: Edge[] | null)
35
35
  };
36
36
 
37
37
  export const getDegreeMap = (nodes: Node[], edges: Edge[] | null) => {
38
- const degreesMap: { [id: string]: Degree } = {}
39
- nodes.forEach(node => {
38
+ const degreesMap: { [id: string]: Degree } = {};
39
+ nodes.forEach((node) => {
40
40
  degreesMap[node.id] = {
41
41
  in: 0,
42
42
  out: 0,
43
43
  all: 0
44
- }
45
- })
44
+ };
45
+ });
46
46
 
47
47
  if (!edges) return degreesMap;
48
48
  edges.forEach((e) => {
@@ -111,19 +111,17 @@ export const getAdjMatrix = (data: Model, directed: boolean): Matrix[] => {
111
111
  });
112
112
  }
113
113
 
114
- if (edges) {
115
- edges.forEach((e) => {
116
- const source = getEdgeTerminal(e, 'source');
117
- const target = getEdgeTerminal(e, 'target');
118
- const sIndex = nodeMap[source as string];
119
- const tIndex = nodeMap[target as string];
120
- matrix[sIndex][tIndex] = 1;
121
- if (!directed) {
122
- matrix[tIndex][sIndex] = 1;
123
- }
124
- });
125
- }
126
-
114
+ edges?.forEach((e) => {
115
+ const source = getEdgeTerminal(e, 'source');
116
+ const target = getEdgeTerminal(e, 'target');
117
+ const sIndex = nodeMap[source as string];
118
+ const tIndex = nodeMap[target as string];
119
+ if (sIndex === undefined || tIndex === undefined) return;
120
+ matrix[sIndex][tIndex] = 1;
121
+ if (!directed) {
122
+ matrix[tIndex][sIndex] = 1;
123
+ }
124
+ });
127
125
  return matrix;
128
126
  };
129
127
 
@@ -195,8 +193,8 @@ export const findMinMaxNodeXY = (nodes: OutNode[]) => {
195
193
  * @returns 平局内置
196
194
  */
197
195
  export const getAvgNodePosition = (nodes: OutNode[]) => {
198
- let totalNodes = { x: 0, y: 0 };
199
- nodes.forEach(node => {
196
+ const totalNodes = { x: 0, y: 0 };
197
+ nodes.forEach((node) => {
200
198
  totalNodes.x += node.x || 0;
201
199
  totalNodes.y += node.y || 0;
202
200
  });
@@ -211,26 +209,26 @@ export const getAvgNodePosition = (nodes: OutNode[]) => {
211
209
  // 找出指定节点关联的边的起点或终点
212
210
  const getCoreNode = (type: 'source' | 'target', node: Node, edges: Edge[]) => {
213
211
  if (type === 'source') {
214
- return (edges?.find(edge => edge.target === node.id)?.source || {}) as Node;
212
+ return (edges?.find((edge) => edge.target === node.id)?.source || {}) as Node;
215
213
  }
216
- return (edges?.find(edge => edge.source === node.id)?.target || {}) as Node;
214
+ return (edges?.find((edge) => edge.source === node.id)?.target || {}) as Node;
217
215
  };
218
216
 
219
217
  // 找出指定节点为起点或终点的所有一度叶子节点
220
218
  const getRelativeNodeIds = (type: 'source' | 'target' | 'both', coreNode: Node, edges: Edge[]) => {
221
- let relativeNodes: string[] = []
219
+ let relativeNodes: string[] = [];
222
220
  switch (type) {
223
221
  case 'source':
224
- relativeNodes = edges?.filter(edge => edge.source === coreNode.id).map(edge => edge.target);
222
+ relativeNodes = edges?.filter((edge) => edge.source === coreNode.id).map((edge) => edge.target);
225
223
  break;
226
224
  case 'target':
227
- relativeNodes = edges?.filter(edge => edge.target === coreNode.id).map(edge => edge.source);
225
+ relativeNodes = edges?.filter((edge) => edge.target === coreNode.id).map((edge) => edge.source);
228
226
  break;
229
227
  case 'both':
230
228
  relativeNodes = edges
231
- ?.filter(edge => edge.source === coreNode.id)
232
- .map(edge => edge.target)
233
- .concat(edges?.filter(edge => edge.target === coreNode.id).map(edge => edge.source));
229
+ ?.filter((edge) => edge.source === coreNode.id)
230
+ .map((edge) => edge.target)
231
+ .concat(edges?.filter((edge) => edge.target === coreNode.id).map((edge) => edge.source));
234
232
  break;
235
233
  default:
236
234
  break;
@@ -244,9 +242,9 @@ const getSameTypeNodes = (type: 'leaf' | 'all', nodeClusterBy: string, node: Nod
244
242
  // @ts-ignore
245
243
  const typeName = node[nodeClusterBy] || '';
246
244
  // @ts-ignore
247
- let sameTypeNodes = relativeNodes?.filter(item => item[nodeClusterBy] === typeName) || [];
245
+ let sameTypeNodes = relativeNodes?.filter((item) => item[nodeClusterBy] === typeName) || [];
248
246
  if (type === 'leaf') {
249
- sameTypeNodes = sameTypeNodes.filter(node => degreesMap[node.id]?.in === 0 ||degreesMap[node.id]?.out === 0);
247
+ sameTypeNodes = sameTypeNodes.filter((node) => degreesMap[node.id]?.in === 0 ||degreesMap[node.id]?.out === 0);
250
248
  }
251
249
  return sameTypeNodes;
252
250
  };
@@ -260,14 +258,14 @@ export const getCoreNodeAndRelativeLeafNodes = (type: 'leaf' | 'all', node: Node
260
258
  if (inDegree === 0) {
261
259
  // 如果为没有出边的叶子节点,则找出与它关联的边的起点出发的所有一度节点
262
260
  coreNode = getCoreNode('source', node, edges);
263
- relativeLeafNodes = getRelativeNodeIds('both', coreNode, edges).map(nodeId => nodeMap[nodeId]);
261
+ relativeLeafNodes = getRelativeNodeIds('both', coreNode, edges).map((nodeId) => nodeMap[nodeId]);
264
262
  } else if (outDegree === 0) {
265
263
  // 如果为没有入边边的叶子节点,则找出与它关联的边的起点出发的所有一度节点
266
264
  coreNode = getCoreNode('target', node, edges);
267
- relativeLeafNodes = getRelativeNodeIds('both', coreNode, edges).map(nodeId => nodeMap[nodeId]);
265
+ relativeLeafNodes = getRelativeNodeIds('both', coreNode, edges).map((nodeId) => nodeMap[nodeId]);
268
266
  }
269
267
  relativeLeafNodes = relativeLeafNodes.filter(
270
- node => degreesMap[node.id] && (degreesMap[node.id].in === 0 || degreesMap[node.id].out === 0),
268
+ (node) => degreesMap[node.id] && (degreesMap[node.id].in === 0 || degreesMap[node.id].out === 0),
271
269
  );
272
270
  const sameTypeLeafNodes = getSameTypeNodes(type, nodeClusterBy, node, relativeLeafNodes, degreesMap);
273
271
  return { coreNode, relativeLeafNodes, sameTypeLeafNodes };
@@ -15,7 +15,7 @@ export const clone = <T>(target: T): T => {
15
15
  });
16
16
  return cp.map((n: any) => clone<any>(n)) as any;
17
17
  }
18
- if (typeof target === 'object' && target !== {}) {
18
+ if (typeof target === 'object' && Object.keys(target).length) {
19
19
  const cp = { ...(target as { [key: string]: any }) } as {
20
20
  [key: string]: any
21
21
  };