@antv/layout 0.2.0 → 0.2.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 (297) hide show
  1. package/dist/layout.min.js +1 -1
  2. package/dist/layout.min.js.LICENSE.txt +0 -9
  3. package/dist/layout.min.js.map +1 -1
  4. package/es/layout/circular.js.map +1 -1
  5. package/es/layout/comboCombined.js +3 -19
  6. package/es/layout/comboCombined.js.map +1 -1
  7. package/es/layout/concentric.js.map +1 -1
  8. package/es/layout/dagre/graph.d.ts +91 -0
  9. package/es/layout/dagre/graph.js +4 -0
  10. package/es/layout/dagre/graph.js.map +1 -0
  11. package/es/layout/dagre/index.d.ts +3 -4
  12. package/es/layout/dagre/index.js +0 -2
  13. package/es/layout/dagre/index.js.map +1 -1
  14. package/es/layout/dagre/src/acyclic.d.ts +1 -2
  15. package/es/layout/dagre/src/acyclic.js +7 -7
  16. package/es/layout/dagre/src/acyclic.js.map +1 -1
  17. package/es/layout/dagre/src/add-border-segments.d.ts +1 -2
  18. package/es/layout/dagre/src/add-border-segments.js +5 -5
  19. package/es/layout/dagre/src/add-border-segments.js.map +1 -1
  20. package/es/layout/dagre/src/coordinate-system.d.ts +1 -2
  21. package/es/layout/dagre/src/coordinate-system.js +15 -5
  22. package/es/layout/dagre/src/coordinate-system.js.map +1 -1
  23. package/es/layout/dagre/src/data/list.d.ts +9 -5
  24. package/es/layout/dagre/src/data/list.js +25 -27
  25. package/es/layout/dagre/src/data/list.js.map +1 -1
  26. package/es/layout/dagre/src/debug.d.ts +2 -3
  27. package/es/layout/dagre/src/debug.js +3 -5
  28. package/es/layout/dagre/src/debug.js.map +1 -1
  29. package/es/layout/dagre/src/greedy-fas.d.ts +2 -3
  30. package/es/layout/dagre/src/greedy-fas.js +16 -15
  31. package/es/layout/dagre/src/greedy-fas.js.map +1 -1
  32. package/es/layout/dagre/src/layout.d.ts +2 -3
  33. package/es/layout/dagre/src/layout.js +170 -91
  34. package/es/layout/dagre/src/layout.js.map +1 -1
  35. package/es/layout/dagre/src/nesting-graph.d.ts +1 -2
  36. package/es/layout/dagre/src/nesting-graph.js +15 -10
  37. package/es/layout/dagre/src/nesting-graph.js.map +1 -1
  38. package/es/layout/dagre/src/normalize.d.ts +1 -2
  39. package/es/layout/dagre/src/normalize.js +12 -11
  40. package/es/layout/dagre/src/normalize.js.map +1 -1
  41. package/es/layout/dagre/src/order/add-subgraph-constraints.d.ts +1 -2
  42. package/es/layout/dagre/src/order/add-subgraph-constraints.js.map +1 -1
  43. package/es/layout/dagre/src/order/barycenter.d.ts +1 -2
  44. package/es/layout/dagre/src/order/barycenter.js.map +1 -1
  45. package/es/layout/dagre/src/order/build-layer-graph.d.ts +2 -3
  46. package/es/layout/dagre/src/order/build-layer-graph.js +12 -8
  47. package/es/layout/dagre/src/order/build-layer-graph.js.map +1 -1
  48. package/es/layout/dagre/src/order/cross-count.d.ts +2 -3
  49. package/es/layout/dagre/src/order/cross-count.js +13 -12
  50. package/es/layout/dagre/src/order/cross-count.js.map +1 -1
  51. package/es/layout/dagre/src/order/index.d.ts +2 -3
  52. package/es/layout/dagre/src/order/index.js +17 -15
  53. package/es/layout/dagre/src/order/index.js.map +1 -1
  54. package/es/layout/dagre/src/order/init-data-order.d.ts +1 -2
  55. package/es/layout/dagre/src/order/init-data-order.js +3 -5
  56. package/es/layout/dagre/src/order/init-data-order.js.map +1 -1
  57. package/es/layout/dagre/src/order/init-order.d.ts +2 -3
  58. package/es/layout/dagre/src/order/init-order.js +1 -2
  59. package/es/layout/dagre/src/order/init-order.js.map +1 -1
  60. package/es/layout/dagre/src/order/resolve-conflicts.d.ts +18 -3
  61. package/es/layout/dagre/src/order/resolve-conflicts.js +9 -29
  62. package/es/layout/dagre/src/order/resolve-conflicts.js.map +1 -1
  63. package/es/layout/dagre/src/order/sort-subgraph.d.ts +6 -3
  64. package/es/layout/dagre/src/order/sort-subgraph.js +19 -14
  65. package/es/layout/dagre/src/order/sort-subgraph.js.map +1 -1
  66. package/es/layout/dagre/src/order/sort.d.ts +6 -1
  67. package/es/layout/dagre/src/order/sort.js +2 -2
  68. package/es/layout/dagre/src/order/sort.js.map +1 -1
  69. package/es/layout/dagre/src/parent-dummy-chains.d.ts +1 -2
  70. package/es/layout/dagre/src/parent-dummy-chains.js +47 -44
  71. package/es/layout/dagre/src/parent-dummy-chains.js.map +1 -1
  72. package/es/layout/dagre/src/position/bk.d.ts +22 -31
  73. package/es/layout/dagre/src/position/bk.js +49 -83
  74. package/es/layout/dagre/src/position/bk.js.map +1 -1
  75. package/es/layout/dagre/src/position/index.d.ts +1 -2
  76. package/es/layout/dagre/src/position/index.js +12 -14
  77. package/es/layout/dagre/src/position/index.js.map +1 -1
  78. package/es/layout/dagre/src/rank/feasible-tree.d.ts +5 -6
  79. package/es/layout/dagre/src/rank/feasible-tree.js +1 -2
  80. package/es/layout/dagre/src/rank/feasible-tree.js.map +1 -1
  81. package/es/layout/dagre/src/rank/index.d.ts +2 -3
  82. package/es/layout/dagre/src/rank/index.js.map +1 -1
  83. package/es/layout/dagre/src/rank/network-simplex.d.ts +8 -11
  84. package/es/layout/dagre/src/rank/network-simplex.js +18 -31
  85. package/es/layout/dagre/src/rank/network-simplex.js.map +1 -1
  86. package/es/layout/dagre/src/rank/util.d.ts +4 -5
  87. package/es/layout/dagre/src/rank/util.js +37 -20
  88. package/es/layout/dagre/src/rank/util.js.map +1 -1
  89. package/es/layout/dagre/src/util.d.ts +29 -48
  90. package/es/layout/dagre/src/util.js +91 -101
  91. package/es/layout/dagre/src/util.js.map +1 -1
  92. package/es/layout/dagre.d.ts +1 -1
  93. package/es/layout/dagre.js +28 -24
  94. package/es/layout/dagre.js.map +1 -1
  95. package/es/layout/fruchterman.js.map +1 -1
  96. package/es/layout/gForce.js +14 -6
  97. package/es/layout/gForce.js.map +1 -1
  98. package/lib/index.js +5 -1
  99. package/lib/index.js.map +1 -1
  100. package/lib/layout/circular.js.map +1 -1
  101. package/lib/layout/comboCombined.js +2 -18
  102. package/lib/layout/comboCombined.js.map +1 -1
  103. package/lib/layout/comboForce.js +5 -5
  104. package/lib/layout/comboForce.js.map +1 -1
  105. package/lib/layout/concentric.js.map +1 -1
  106. package/lib/layout/dagre/graph.d.ts +91 -0
  107. package/lib/layout/dagre/graph.js +28 -0
  108. package/lib/layout/dagre/graph.js.map +1 -0
  109. package/lib/layout/dagre/index.d.ts +3 -4
  110. package/lib/layout/dagre/index.js +0 -2
  111. package/lib/layout/dagre/index.js.map +1 -1
  112. package/lib/layout/dagre/src/acyclic.d.ts +1 -2
  113. package/lib/layout/dagre/src/acyclic.js +7 -7
  114. package/lib/layout/dagre/src/acyclic.js.map +1 -1
  115. package/lib/layout/dagre/src/add-border-segments.d.ts +1 -2
  116. package/lib/layout/dagre/src/add-border-segments.js +5 -8
  117. package/lib/layout/dagre/src/add-border-segments.js.map +1 -1
  118. package/lib/layout/dagre/src/coordinate-system.d.ts +1 -2
  119. package/lib/layout/dagre/src/coordinate-system.js +15 -5
  120. package/lib/layout/dagre/src/coordinate-system.js.map +1 -1
  121. package/lib/layout/dagre/src/data/list.d.ts +9 -5
  122. package/lib/layout/dagre/src/data/list.js +25 -26
  123. package/lib/layout/dagre/src/data/list.js.map +1 -1
  124. package/lib/layout/dagre/src/debug.d.ts +2 -3
  125. package/lib/layout/dagre/src/debug.js +6 -11
  126. package/lib/layout/dagre/src/debug.js.map +1 -1
  127. package/lib/layout/dagre/src/greedy-fas.d.ts +2 -3
  128. package/lib/layout/dagre/src/greedy-fas.js +41 -15
  129. package/lib/layout/dagre/src/greedy-fas.js.map +1 -1
  130. package/lib/layout/dagre/src/layout.d.ts +2 -3
  131. package/lib/layout/dagre/src/layout.js +171 -100
  132. package/lib/layout/dagre/src/layout.js.map +1 -1
  133. package/lib/layout/dagre/src/nesting-graph.d.ts +1 -2
  134. package/lib/layout/dagre/src/nesting-graph.js +15 -13
  135. package/lib/layout/dagre/src/nesting-graph.js.map +1 -1
  136. package/lib/layout/dagre/src/normalize.d.ts +1 -2
  137. package/lib/layout/dagre/src/normalize.js +12 -14
  138. package/lib/layout/dagre/src/normalize.js.map +1 -1
  139. package/lib/layout/dagre/src/order/add-subgraph-constraints.d.ts +1 -2
  140. package/lib/layout/dagre/src/order/add-subgraph-constraints.js.map +1 -1
  141. package/lib/layout/dagre/src/order/barycenter.d.ts +1 -2
  142. package/lib/layout/dagre/src/order/barycenter.js.map +1 -1
  143. package/lib/layout/dagre/src/order/build-layer-graph.d.ts +2 -3
  144. package/lib/layout/dagre/src/order/build-layer-graph.js +13 -12
  145. package/lib/layout/dagre/src/order/build-layer-graph.js.map +1 -1
  146. package/lib/layout/dagre/src/order/cross-count.d.ts +2 -3
  147. package/lib/layout/dagre/src/order/cross-count.js +14 -13
  148. package/lib/layout/dagre/src/order/cross-count.js.map +1 -1
  149. package/lib/layout/dagre/src/order/index.d.ts +2 -3
  150. package/lib/layout/dagre/src/order/index.js +15 -13
  151. package/lib/layout/dagre/src/order/index.js.map +1 -1
  152. package/lib/layout/dagre/src/order/init-data-order.d.ts +1 -2
  153. package/lib/layout/dagre/src/order/init-data-order.js +3 -5
  154. package/lib/layout/dagre/src/order/init-data-order.js.map +1 -1
  155. package/lib/layout/dagre/src/order/init-order.d.ts +2 -3
  156. package/lib/layout/dagre/src/order/init-order.js +1 -2
  157. package/lib/layout/dagre/src/order/init-order.js.map +1 -1
  158. package/lib/layout/dagre/src/order/resolve-conflicts.d.ts +18 -3
  159. package/lib/layout/dagre/src/order/resolve-conflicts.js +9 -29
  160. package/lib/layout/dagre/src/order/resolve-conflicts.js.map +1 -1
  161. package/lib/layout/dagre/src/order/sort-subgraph.d.ts +6 -3
  162. package/lib/layout/dagre/src/order/sort-subgraph.js +16 -11
  163. package/lib/layout/dagre/src/order/sort-subgraph.js.map +1 -1
  164. package/lib/layout/dagre/src/order/sort.d.ts +6 -1
  165. package/lib/layout/dagre/src/order/sort.js +2 -5
  166. package/lib/layout/dagre/src/order/sort.js.map +1 -1
  167. package/lib/layout/dagre/src/parent-dummy-chains.d.ts +1 -2
  168. package/lib/layout/dagre/src/parent-dummy-chains.js +47 -44
  169. package/lib/layout/dagre/src/parent-dummy-chains.js.map +1 -1
  170. package/lib/layout/dagre/src/position/bk.d.ts +22 -31
  171. package/lib/layout/dagre/src/position/bk.js +75 -85
  172. package/lib/layout/dagre/src/position/bk.js.map +1 -1
  173. package/lib/layout/dagre/src/position/index.d.ts +1 -2
  174. package/lib/layout/dagre/src/position/index.js +14 -17
  175. package/lib/layout/dagre/src/position/index.js.map +1 -1
  176. package/lib/layout/dagre/src/rank/feasible-tree.d.ts +5 -6
  177. package/lib/layout/dagre/src/rank/feasible-tree.js +3 -7
  178. package/lib/layout/dagre/src/rank/feasible-tree.js.map +1 -1
  179. package/lib/layout/dagre/src/rank/index.d.ts +2 -3
  180. package/lib/layout/dagre/src/rank/index.js.map +1 -1
  181. package/lib/layout/dagre/src/rank/network-simplex.d.ts +8 -11
  182. package/lib/layout/dagre/src/rank/network-simplex.js +27 -35
  183. package/lib/layout/dagre/src/rank/network-simplex.js.map +1 -1
  184. package/lib/layout/dagre/src/rank/util.d.ts +4 -5
  185. package/lib/layout/dagre/src/rank/util.js +36 -19
  186. package/lib/layout/dagre/src/rank/util.js.map +1 -1
  187. package/lib/layout/dagre/src/util.d.ts +29 -48
  188. package/lib/layout/dagre/src/util.js +80 -92
  189. package/lib/layout/dagre/src/util.js.map +1 -1
  190. package/lib/layout/dagre.d.ts +1 -1
  191. package/lib/layout/dagre.js +27 -23
  192. package/lib/layout/dagre.js.map +1 -1
  193. package/lib/layout/er/core.js +5 -1
  194. package/lib/layout/er/core.js.map +1 -1
  195. package/lib/layout/force/force-in-a-box.js +7 -3
  196. package/lib/layout/force/force-in-a-box.js.map +1 -1
  197. package/lib/layout/force/force.js +5 -1
  198. package/lib/layout/force/force.js.map +1 -1
  199. package/lib/layout/force/index.js +5 -1
  200. package/lib/layout/force/index.js.map +1 -1
  201. package/lib/layout/fruchterman.js.map +1 -1
  202. package/lib/layout/gForce.js +10 -2
  203. package/lib/layout/gForce.js.map +1 -1
  204. package/lib/layout/grid.js +2 -2
  205. package/lib/layout/grid.js.map +1 -1
  206. package/lib/layout/index.js +5 -1
  207. package/lib/layout/index.js.map +1 -1
  208. package/lib/layout/radial/index.js +5 -1
  209. package/lib/layout/radial/index.js.map +1 -1
  210. package/lib/registy/index.js +1 -1
  211. package/lib/registy/index.js.map +1 -1
  212. package/lib/util/index.js +5 -1
  213. package/lib/util/index.js.map +1 -1
  214. package/package.json +3 -2
  215. package/src/index.ts +7 -0
  216. package/src/layout/base.ts +54 -0
  217. package/src/layout/circular.ts +369 -0
  218. package/src/layout/comboCombined.ts +390 -0
  219. package/src/layout/comboForce.ts +873 -0
  220. package/src/layout/concentric.ts +289 -0
  221. package/src/layout/constants.ts +21 -0
  222. package/src/layout/dagre/graph.ts +104 -0
  223. package/src/layout/dagre/index.ts +31 -0
  224. package/src/layout/dagre/src/acyclic.ts +58 -0
  225. package/src/layout/dagre/src/add-border-segments.ts +47 -0
  226. package/src/layout/dagre/src/coordinate-system.ts +77 -0
  227. package/src/layout/dagre/src/data/list.ts +60 -0
  228. package/src/layout/dagre/src/debug.ts +30 -0
  229. package/src/layout/dagre/src/greedy-fas.ts +144 -0
  230. package/src/layout/dagre/src/layout.ts +580 -0
  231. package/src/layout/dagre/src/nesting-graph.ts +143 -0
  232. package/src/layout/dagre/src/normalize.ts +96 -0
  233. package/src/layout/dagre/src/order/add-subgraph-constraints.ts +29 -0
  234. package/src/layout/dagre/src/order/barycenter.ts +26 -0
  235. package/src/layout/dagre/src/order/build-layer-graph.ts +82 -0
  236. package/src/layout/dagre/src/order/cross-count.ts +77 -0
  237. package/src/layout/dagre/src/order/index.ts +105 -0
  238. package/src/layout/dagre/src/order/init-data-order.ts +27 -0
  239. package/src/layout/dagre/src/order/init-order.ts +56 -0
  240. package/src/layout/dagre/src/order/resolve-conflicts.ts +152 -0
  241. package/src/layout/dagre/src/order/sort-subgraph.ts +105 -0
  242. package/src/layout/dagre/src/order/sort.ts +76 -0
  243. package/src/layout/dagre/src/parent-dummy-chains.ts +102 -0
  244. package/src/layout/dagre/src/position/bk.ts +494 -0
  245. package/src/layout/dagre/src/position/index.ts +82 -0
  246. package/src/layout/dagre/src/rank/feasible-tree.ts +165 -0
  247. package/src/layout/dagre/src/rank/index.ts +54 -0
  248. package/src/layout/dagre/src/rank/network-simplex.ts +225 -0
  249. package/src/layout/dagre/src/rank/util.ts +157 -0
  250. package/src/layout/dagre/src/util.ts +308 -0
  251. package/src/layout/dagre.ts +423 -0
  252. package/src/layout/dagreCompound.ts +518 -0
  253. package/src/layout/er/core.ts +117 -0
  254. package/src/layout/er/forceGrid.ts +95 -0
  255. package/src/layout/er/grid.ts +185 -0
  256. package/src/layout/er/index.ts +68 -0
  257. package/src/layout/er/mysqlWorkbench.ts +345 -0
  258. package/src/layout/er/type.ts +39 -0
  259. package/src/layout/force/force-in-a-box.ts +400 -0
  260. package/src/layout/force/force.ts +391 -0
  261. package/src/layout/force/index.ts +1 -0
  262. package/src/layout/forceAtlas2/body.ts +115 -0
  263. package/src/layout/forceAtlas2/index.ts +556 -0
  264. package/src/layout/forceAtlas2/quad.ts +115 -0
  265. package/src/layout/forceAtlas2/quadTree.ts +107 -0
  266. package/src/layout/fruchterman.ts +361 -0
  267. package/src/layout/gForce.ts +487 -0
  268. package/src/layout/gpu/fruchterman.ts +314 -0
  269. package/src/layout/gpu/fruchtermanShader.ts +204 -0
  270. package/src/layout/gpu/gForce.ts +406 -0
  271. package/src/layout/gpu/gForceShader.ts +221 -0
  272. package/src/layout/grid.ts +391 -0
  273. package/src/layout/index.ts +45 -0
  274. package/src/layout/layout.ts +75 -0
  275. package/src/layout/mds.ts +140 -0
  276. package/src/layout/radial/index.ts +1 -0
  277. package/src/layout/radial/mds.ts +51 -0
  278. package/src/layout/radial/radial.ts +500 -0
  279. package/src/layout/radial/radialNonoverlapForce.ts +189 -0
  280. package/src/layout/random.ts +75 -0
  281. package/src/layout/types.ts +421 -0
  282. package/src/registy/index.ts +43 -0
  283. package/src/util/array.ts +1 -0
  284. package/src/util/function.ts +64 -0
  285. package/src/util/gpu.ts +254 -0
  286. package/src/util/index.ts +6 -0
  287. package/src/util/math.ts +158 -0
  288. package/src/util/number.ts +8 -0
  289. package/src/util/object.ts +28 -0
  290. package/src/util/string.ts +18 -0
  291. package/CHANGELOG.md +0 -78
  292. package/es/layout/dagre/src/graphlib.d.ts +0 -2
  293. package/es/layout/dagre/src/graphlib.js +0 -51
  294. package/es/layout/dagre/src/graphlib.js.map +0 -1
  295. package/lib/layout/dagre/src/graphlib.d.ts +0 -2
  296. package/lib/layout/dagre/src/graphlib.js +0 -56
  297. package/lib/layout/dagre/src/graphlib.js.map +0 -1
@@ -0,0 +1,487 @@
1
+ /**
2
+ * @fileOverview fruchterman layout
3
+ * @author shiwu.wyy@antfin.com
4
+ */
5
+
6
+ import {
7
+ OutNode,
8
+ Edge,
9
+ PointTuple,
10
+ IndexMap,
11
+ Point,
12
+ GForceLayoutOptions
13
+ } from "./types";
14
+ import { Base } from "./base";
15
+ import { isNumber, isFunction, isArray, getDegree, isObject, getEdgeTerminal } from "../util";
16
+
17
+ type INode = OutNode & {
18
+ size: number | PointTuple;
19
+ };
20
+
21
+ type NodeMap = {
22
+ [key: string]: INode;
23
+ };
24
+
25
+ const proccessToFunc = (
26
+ value: number | Function | undefined,
27
+ defaultV?: number
28
+ ): ((d: any) => number) => {
29
+ let func;
30
+ if (!value) {
31
+ func = (d: any): number => {
32
+ return defaultV || 1;
33
+ };
34
+ } else if (isNumber(value)) {
35
+ func = (d: any): number => {
36
+ return value;
37
+ };
38
+ } else {
39
+ func = value;
40
+ }
41
+ return func as any;
42
+ };
43
+
44
+ /**
45
+ * graphin 中的 force 布局
46
+ */
47
+ export class GForceLayout extends Base {
48
+ /** 布局中心 */
49
+ public center: PointTuple;
50
+
51
+ /** 停止迭代的最大迭代数 */
52
+ public maxIteration: number = 500;
53
+
54
+ /** 是否启动 worker */
55
+ public workerEnabled: boolean = false;
56
+
57
+ /** 弹簧引力系数 */
58
+ public edgeStrength: number | ((d?: any) => number) | undefined = 200;
59
+
60
+ /** 斥力系数 */
61
+ public nodeStrength: number | ((d?: any) => number) | undefined = 1000;
62
+
63
+ /** 库伦系数 */
64
+ public coulombDisScale: number = 0.005;
65
+
66
+ /** 阻尼系数 */
67
+ public damping: number = 0.9;
68
+
69
+ /** 最大速度 */
70
+ public maxSpeed: number = 1000;
71
+
72
+ /** 一次迭代的平均移动距离小于该值时停止迭代 */
73
+ public minMovement: number = 0.5;
74
+
75
+ /** 迭代中衰减 */
76
+ public interval: number = 0.02;
77
+
78
+ /** 斥力的一个系数 */
79
+ public factor: number = 1;
80
+
81
+ /** 每个节点质量的回调函数,若不指定,则默认使用度数作为节点质量 */
82
+ public getMass: ((d?: any) => number) | undefined;
83
+
84
+ /** 每个节点中心力的 x、y、强度的回调函数,若不指定,则没有额外中心力 */
85
+ public getCenter: ((d?: any, degree?: number) => number[]) | undefined;
86
+
87
+ /** 理想边长 */
88
+ public linkDistance: number | ((edge?: any, source?: any, target?: any) => number) | undefined = 1;
89
+
90
+ /** 重力大小 */
91
+ public gravity: number = 10;
92
+
93
+ /** 是否防止重叠 */
94
+ public preventOverlap: boolean = true;
95
+
96
+ /** 防止重叠时的节点大小,默认从节点数据中取 size */
97
+ public nodeSize: number | number[] | ((d?: any) => number) | undefined;
98
+
99
+ /** 防止重叠的力大小参数 */
100
+ public collideStrength: number = 1;
101
+
102
+ /** 防止重叠时的节点之间最小间距 */
103
+ public nodeSpacing: number | number[] | ((d?: any) => number) | undefined;
104
+
105
+ /** 每次迭代结束的回调函数 */
106
+ public tick: (() => void) | null = () => {};
107
+
108
+ /** 是否允许每次迭代结束调用回调函数 */
109
+ public enableTick: boolean;
110
+
111
+ public nodes: INode[] | null = [];
112
+
113
+ public edges: Edge[] | null = [];
114
+
115
+ public width: number = 300;
116
+
117
+ public height: number = 300;
118
+
119
+ public nodeMap: NodeMap = {};
120
+
121
+ public nodeIdxMap: IndexMap = {};
122
+
123
+ public canvasEl: HTMLCanvasElement;
124
+
125
+ public onLayoutEnd: () => void;
126
+
127
+ /** 是否使用 window.setInterval 运行迭代 */
128
+ public animate: Boolean = true;
129
+
130
+ /** 存储节点度数 */
131
+ private degrees: number[];
132
+
133
+ /** 迭代中的标识 */
134
+ private timeInterval: number;
135
+
136
+ constructor(options?: GForceLayoutOptions) {
137
+ super();
138
+ this.updateCfg(options);
139
+ }
140
+
141
+ public getDefaultCfg() {
142
+ return {
143
+ maxIteration: 500,
144
+ gravity: 10,
145
+ enableTick: true,
146
+ animate: true,
147
+ };
148
+ }
149
+
150
+ /**
151
+ * 执行布局
152
+ */
153
+ public execute() {
154
+ const self = this;
155
+ const nodes = self.nodes;
156
+
157
+ if (self.timeInterval !== undefined && typeof window !== "undefined") {
158
+ window.clearInterval(self.timeInterval);
159
+ }
160
+
161
+ if (!nodes || nodes.length === 0) {
162
+ self.onLayoutEnd?.();
163
+ return;
164
+ }
165
+
166
+ if (!self.width && typeof window !== "undefined") {
167
+ self.width = window.innerWidth;
168
+ }
169
+ if (!self.height && typeof window !== "undefined") {
170
+ self.height = window.innerHeight;
171
+ }
172
+ if (!self.center) {
173
+ self.center = [self.width / 2, self.height / 2];
174
+ }
175
+ const center = self.center;
176
+
177
+ if (nodes.length === 1) {
178
+ nodes[0].x = center[0];
179
+ nodes[0].y = center[1];
180
+ self.onLayoutEnd?.();
181
+ return;
182
+ }
183
+ const nodeMap: NodeMap = {};
184
+ const nodeIdxMap: IndexMap = {};
185
+ nodes.forEach((node, i) => {
186
+ if (!isNumber(node.x)) node.x = Math.random() * self.width;
187
+ if (!isNumber(node.y)) node.y = Math.random() * self.height;
188
+ nodeMap[node.id] = node;
189
+ nodeIdxMap[node.id] = i;
190
+ });
191
+ self.nodeMap = nodeMap;
192
+ self.nodeIdxMap = nodeIdxMap;
193
+
194
+ self.linkDistance = proccessToFunc(self.linkDistance, 1);
195
+ self.nodeStrength = proccessToFunc(self.nodeStrength, 1);
196
+ self.edgeStrength = proccessToFunc(self.edgeStrength, 1);
197
+
198
+ // node size function
199
+ const nodeSize = self.nodeSize;
200
+ let nodeSizeFunc;
201
+ if (self.preventOverlap) {
202
+ const nodeSpacing = self.nodeSpacing;
203
+ let nodeSpacingFunc: (d?: any) => number;
204
+ if (isNumber(nodeSpacing)) {
205
+ nodeSpacingFunc = () => nodeSpacing as number;
206
+ } else if (isFunction(nodeSpacing)) {
207
+ nodeSpacingFunc = nodeSpacing as (d?: any) => number;
208
+ } else {
209
+ nodeSpacingFunc = () => 0;
210
+ }
211
+ if (!nodeSize) {
212
+ nodeSizeFunc = (d: INode) => {
213
+ if (d.size) {
214
+ if (isArray(d.size)) {
215
+ return Math.max(d.size[0], d.size[1]) + nodeSpacingFunc(d);
216
+ } if(isObject(d.size)) {
217
+ return Math.max(d.size.width, d.size.height) + nodeSpacingFunc(d);
218
+ }
219
+ return (d.size as number) + nodeSpacingFunc(d);
220
+ }
221
+ return 10 + nodeSpacingFunc(d);
222
+ };
223
+ } else if (isArray(nodeSize)) {
224
+ nodeSizeFunc = (d: INode) => {
225
+ return Math.max(nodeSize[0], nodeSize[1]) + nodeSpacingFunc(d);
226
+ };
227
+ } else {
228
+ nodeSizeFunc = (d: INode) => (nodeSize as number) + nodeSpacingFunc(d);
229
+ }
230
+ }
231
+ self.nodeSize = nodeSizeFunc;
232
+
233
+ const edges = self.edges;
234
+ self.degrees = getDegree(nodes.length, self.nodeIdxMap, edges);
235
+ if (!self.getMass) {
236
+ self.getMass = (d) => {
237
+ const mass = d.mass || self.degrees[self.nodeIdxMap[d.id]] || 1;
238
+ return mass;
239
+ };
240
+ }
241
+
242
+ // layout
243
+ self.run();
244
+ }
245
+
246
+ public run() {
247
+ const self = this;
248
+ const { maxIteration, nodes, workerEnabled, minMovement, animate } = self;
249
+
250
+ if (!nodes) return;
251
+
252
+ if (workerEnabled || !animate) {
253
+ for (let i = 0; i < maxIteration; i++) {
254
+ const previousPos = self.runOneStep(i);
255
+ if (self.reachMoveThreshold(nodes, previousPos, minMovement)) {
256
+ break;
257
+ }
258
+ }
259
+ self.onLayoutEnd?.();
260
+ } else {
261
+ if (typeof window === "undefined") return;
262
+ let iter = 0;
263
+ // interval for render the result after each iteration
264
+ this.timeInterval = window.setInterval(() => {
265
+ if (!nodes) return;
266
+ const previousPos = self.runOneStep(iter) || [];
267
+ if (self.reachMoveThreshold(nodes, previousPos, minMovement)) {
268
+ self.onLayoutEnd?.();
269
+ window.clearInterval(self.timeInterval);
270
+ }
271
+ iter++;
272
+ if (iter >= maxIteration) {
273
+ self.onLayoutEnd?.();
274
+ window.clearInterval(self.timeInterval);
275
+ }
276
+ }, 0);
277
+ }
278
+ }
279
+
280
+ private reachMoveThreshold(nodes: any, previousPos: any, minMovement: number) {
281
+ // whether to stop the iteration
282
+ let movement = 0;
283
+ nodes.forEach((node: any, j: number) => {
284
+ const vx = node.x - previousPos[j].x;
285
+ const vy = node.y - previousPos[j].y;
286
+ movement += Math.sqrt(vx * vx + vy * vy);
287
+ });
288
+ movement /= nodes.length;
289
+ return movement < minMovement;
290
+ }
291
+
292
+ private runOneStep(iter: number) {
293
+ const self = this;
294
+ const { nodes, edges } = self;
295
+ const accArray: number[] = [];
296
+ const velArray: number[] = [];
297
+ if (!nodes) return;
298
+ nodes.forEach((_, i) => {
299
+ accArray[2 * i] = 0;
300
+ accArray[2 * i + 1] = 0;
301
+ velArray[2 * i] = 0;
302
+ velArray[2 * i + 1] = 0;
303
+ });
304
+ self.calRepulsive(accArray, nodes);
305
+ if (edges) self.calAttractive(accArray, edges);
306
+ self.calGravity(accArray, nodes);
307
+ const stepInterval = Math.max(0.02, self.interval - iter * 0.002);
308
+ self.updateVelocity(accArray, velArray, stepInterval, nodes);
309
+ const previousPos: Point[] = [];
310
+ nodes.forEach((node) => {
311
+ previousPos.push({
312
+ x: node.x,
313
+ y: node.y
314
+ });
315
+ });
316
+ self.updatePosition(velArray, stepInterval, nodes);
317
+ self.tick?.();
318
+ return previousPos;
319
+ }
320
+
321
+ public calRepulsive(accArray: number[], nodes: INode[]) {
322
+ const self = this;
323
+ const { getMass, factor, coulombDisScale, preventOverlap, collideStrength = 1 } = self;
324
+ const nodeStrength = self.nodeStrength as Function;
325
+ const nodeSize = self.nodeSize as Function;
326
+ nodes.forEach((ni: INode, i) => {
327
+ const massi = getMass ? getMass(ni) : 1;
328
+ nodes.forEach((nj, j) => {
329
+ if (i >= j) return;
330
+ // if (!accArray[j]) accArray[j] = 0;
331
+ let vecX = ni.x - nj.x;
332
+ let vecY = ni.y - nj.y;
333
+ if (vecX === 0 && vecY === 0) {
334
+ vecX = Math.random() * 0.01;
335
+ vecY = Math.random() * 0.01;
336
+ }
337
+ const lengthSqr = vecX * vecX + vecY * vecY;
338
+ const vecLength = Math.sqrt(lengthSqr);
339
+ const nVecLength = (vecLength + 0.1) * coulombDisScale;
340
+ const direX = vecX / vecLength;
341
+ const direY = vecY / vecLength;
342
+ const param =
343
+ (((nodeStrength(ni) + nodeStrength(nj)) * 0.5) * factor) /
344
+ (nVecLength * nVecLength);
345
+ const massj = getMass ? getMass(nj) : 1;
346
+ accArray[2 * i] += (direX * param);
347
+ accArray[2 * i + 1] += (direY * param);
348
+ accArray[2 * j] -= (direX * param);
349
+ accArray[2 * j + 1] -= (direY * param);
350
+ if (preventOverlap && (nodeSize(ni) + nodeSize(nj)) / 2 > vecLength) {
351
+ const paramOverlap =
352
+ collideStrength * (nodeStrength(ni) + nodeStrength(nj)) * 0.5 / lengthSqr;
353
+ accArray[2 * i] += (direX * paramOverlap) / massi;
354
+ accArray[2 * i + 1] += (direY * paramOverlap) / massi;
355
+ accArray[2 * j] -= (direX * paramOverlap) / massj;
356
+ accArray[2 * j + 1] -= (direY * paramOverlap) / massj;
357
+ }
358
+ });
359
+ });
360
+ }
361
+
362
+ public calAttractive(accArray: number[], edges: Edge[]) {
363
+ const self = this;
364
+ const { nodeMap, nodeIdxMap, linkDistance, edgeStrength } = self;
365
+ const nodeSize = self.nodeSize as Function;
366
+ const getMass = self.getMass;
367
+ edges.forEach((edge, i) => {
368
+ const source = getEdgeTerminal(edge, 'source');
369
+ const target = getEdgeTerminal(edge, 'target');
370
+ const sourceNode = nodeMap[source];
371
+ const targetNode = nodeMap[target];
372
+ let vecX = targetNode.x - sourceNode.x;
373
+ let vecY = targetNode.y - sourceNode.y;
374
+ if (vecX === 0 && vecY === 0) {
375
+ vecX = Math.random() * 0.01;
376
+ vecY = Math.random() * 0.01;
377
+ }
378
+ const vecLength = Math.sqrt(vecX * vecX + vecY * vecY);
379
+ const direX = vecX / vecLength;
380
+ const direY = vecY / vecLength;
381
+ const length = (linkDistance as Function)(edge, sourceNode, targetNode) || 1 + ((nodeSize(sourceNode) + nodeSize(sourceNode)) || 0) / 2;
382
+ const diff = length - vecLength;
383
+ const param = diff * (edgeStrength as Function)(edge);
384
+ const sourceIdx = nodeIdxMap[source];
385
+ const targetIdx = nodeIdxMap[target];
386
+ const massSource = getMass ? getMass(sourceNode) : 1;
387
+ const massTarget = getMass ? getMass(targetNode) : 1;
388
+ accArray[2 * sourceIdx] -= (direX * param) / massSource;
389
+ accArray[2 * sourceIdx + 1] -= (direY * param) / massSource;
390
+ accArray[2 * targetIdx] += (direX * param) / massTarget;
391
+ accArray[2 * targetIdx + 1] += (direY * param) / massTarget;
392
+ });
393
+ }
394
+
395
+ public calGravity(accArray: number[], nodes: INode[]) {
396
+ const self = this;
397
+ // const nodes = self.nodes;
398
+ const center = self.center;
399
+ const defaultGravity = self.gravity;
400
+ const degrees = self.degrees;
401
+ const nodeLength = nodes.length;
402
+ for (let i = 0; i < nodeLength; i++) {
403
+ const node = nodes[i];
404
+ let vecX = node.x - center[0];
405
+ let vecY = node.y - center[1];
406
+ let gravity = defaultGravity;
407
+
408
+ if (self.getCenter) {
409
+ const customCenterOpt = self.getCenter(node, degrees[i]);
410
+ if (
411
+ customCenterOpt &&
412
+ isNumber(customCenterOpt[0]) &&
413
+ isNumber(customCenterOpt[1]) &&
414
+ isNumber(customCenterOpt[2])
415
+ ) {
416
+ vecX = node.x - customCenterOpt[0];
417
+ vecY = node.y - customCenterOpt[1];
418
+ gravity = customCenterOpt[2];
419
+ }
420
+ }
421
+ if (!gravity) continue;
422
+
423
+ accArray[2 * i] -= gravity * vecX;
424
+ accArray[2 * i + 1] -= gravity * vecY;
425
+ }
426
+ }
427
+
428
+ public updateVelocity(
429
+ accArray: number[],
430
+ velArray: number[],
431
+ stepInterval: number,
432
+ nodes: INode[]
433
+ ) {
434
+ const self = this;
435
+ const param = stepInterval * self.damping;
436
+ // const nodes = self.nodes;
437
+ nodes.forEach((node, i) => {
438
+ let vx = accArray[2 * i] * param || 0.01;
439
+ let vy = accArray[2 * i + 1] * param || 0.01;
440
+ const vLength = Math.sqrt(vx * vx + vy * vy);
441
+ if (vLength > self.maxSpeed) {
442
+ const param2 = self.maxSpeed / vLength;
443
+ vx = param2 * vx;
444
+ vy = param2 * vy;
445
+ }
446
+ velArray[2 * i] = vx;
447
+ velArray[2 * i + 1] = vy;
448
+ });
449
+ }
450
+
451
+ public updatePosition(
452
+ velArray: number[],
453
+ stepInterval: number,
454
+ nodes: INode[]
455
+ ) {
456
+ nodes.forEach((node: any, i) => {
457
+ if (isNumber(node.fx) && isNumber(node.fy)) {
458
+ node.x = node.fx;
459
+ node.y = node.fy;
460
+ return;
461
+ }
462
+ const distX = velArray[2 * i] * stepInterval;
463
+ const distY = velArray[2 * i + 1] * stepInterval;
464
+ node.x += distX;
465
+ node.y += distY;
466
+ });
467
+ }
468
+
469
+ public stop() {
470
+ if (this.timeInterval && typeof window !== "undefined") {
471
+ window.clearInterval(this.timeInterval);
472
+ }
473
+ }
474
+
475
+ public destroy() {
476
+ const self = this;
477
+ self.stop();
478
+ self.tick = null;
479
+ self.nodes = null;
480
+ self.edges = null;
481
+ self.destroyed = true;
482
+ }
483
+
484
+ public getType() {
485
+ return "gForce";
486
+ }
487
+ }