@logicflow/core 2.2.0 → 2.2.1

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 (236) hide show
  1. package/dist/index.css +3 -2
  2. package/dist/index.min.js +1 -1
  3. package/dist/index.min.js.map +1 -1
  4. package/es/LogicFlow.d.ts +9 -0
  5. package/es/LogicFlow.js +0 -1
  6. package/es/constant/index.d.ts +1 -1
  7. package/es/constant/index.js +1 -1
  8. package/es/constant/theme.d.ts +136 -0
  9. package/es/constant/theme.js +680 -0
  10. package/es/index.css +3 -2
  11. package/es/model/GraphModel.d.ts +10 -2
  12. package/es/model/GraphModel.js +48 -14
  13. package/es/model/TransformModel.js +9 -9
  14. package/es/model/edge/BaseEdgeModel.js +7 -2
  15. package/es/model/edge/PolylineEdgeModel.d.ts +7 -0
  16. package/es/model/edge/PolylineEdgeModel.js +136 -7
  17. package/es/model/node/BaseNodeModel.d.ts +12 -1
  18. package/es/model/node/BaseNodeModel.js +9 -2
  19. package/es/model/node/HtmlNodeModel.d.ts +12 -0
  20. package/es/model/node/HtmlNodeModel.js +19 -0
  21. package/es/model/node/PolygonNodeModel.js +3 -3
  22. package/es/options.d.ts +4 -2
  23. package/es/style/index.css +3 -2
  24. package/es/style/index.less +3 -2
  25. package/es/style/raw.d.ts +1 -1
  26. package/es/style/raw.js +1 -1
  27. package/es/tool/MultipleSelectTool.js +10 -5
  28. package/es/util/drag.js +0 -1
  29. package/es/util/edge.d.ts +40 -1
  30. package/es/util/edge.js +43 -9
  31. package/es/util/geometry.d.ts +8 -0
  32. package/es/util/geometry.js +79 -0
  33. package/es/util/theme.d.ts +2 -65
  34. package/es/util/theme.js +4 -281
  35. package/es/view/Anchor.d.ts +1 -0
  36. package/es/view/Anchor.js +24 -21
  37. package/es/view/Control.d.ts +5 -0
  38. package/es/view/Control.js +44 -57
  39. package/es/view/edge/BaseEdge.js +9 -0
  40. package/es/view/edge/PolylineEdge.js +13 -2
  41. package/es/view/node/BaseNode.d.ts +1 -0
  42. package/es/view/node/BaseNode.js +23 -11
  43. package/es/view/node/HtmlNode.js +2 -4
  44. package/es/view/overlay/CanvasOverlay.js +5 -2
  45. package/es/view/overlay/Grid.d.ts +12 -1
  46. package/es/view/overlay/Grid.js +85 -23
  47. package/es/view/overlay/OutlineOverlay.d.ts +1 -0
  48. package/es/view/overlay/OutlineOverlay.js +18 -17
  49. package/es/view/overlay/gridConfig.d.ts +46 -0
  50. package/es/view/overlay/gridConfig.js +99 -0
  51. package/es/view/shape/Polygon.d.ts +0 -7
  52. package/es/view/shape/Polygon.js +12 -43
  53. package/lib/LogicFlow.d.ts +9 -0
  54. package/lib/LogicFlow.js +0 -1
  55. package/lib/constant/index.d.ts +1 -1
  56. package/lib/constant/index.js +16 -2
  57. package/lib/constant/theme.d.ts +136 -0
  58. package/lib/constant/theme.js +683 -0
  59. package/lib/index.css +3 -2
  60. package/lib/model/GraphModel.d.ts +10 -2
  61. package/lib/model/GraphModel.js +49 -15
  62. package/lib/model/TransformModel.js +9 -9
  63. package/lib/model/edge/BaseEdgeModel.js +7 -2
  64. package/lib/model/edge/PolylineEdgeModel.d.ts +7 -0
  65. package/lib/model/edge/PolylineEdgeModel.js +136 -7
  66. package/lib/model/node/BaseNodeModel.d.ts +12 -1
  67. package/lib/model/node/BaseNodeModel.js +9 -2
  68. package/lib/model/node/HtmlNodeModel.d.ts +12 -0
  69. package/lib/model/node/HtmlNodeModel.js +19 -0
  70. package/lib/model/node/PolygonNodeModel.js +3 -3
  71. package/lib/options.d.ts +4 -2
  72. package/lib/style/index.css +3 -2
  73. package/lib/style/index.less +3 -2
  74. package/lib/style/raw.d.ts +1 -1
  75. package/lib/style/raw.js +1 -1
  76. package/lib/tool/MultipleSelectTool.js +10 -5
  77. package/lib/util/drag.js +0 -1
  78. package/lib/util/edge.d.ts +40 -1
  79. package/lib/util/edge.js +43 -9
  80. package/lib/util/geometry.d.ts +8 -0
  81. package/lib/util/geometry.js +81 -1
  82. package/lib/util/theme.d.ts +2 -65
  83. package/lib/util/theme.js +15 -292
  84. package/lib/view/Anchor.d.ts +1 -0
  85. package/lib/view/Anchor.js +24 -21
  86. package/lib/view/Control.d.ts +5 -0
  87. package/lib/view/Control.js +44 -57
  88. package/lib/view/edge/BaseEdge.js +9 -0
  89. package/lib/view/edge/PolylineEdge.js +13 -2
  90. package/lib/view/node/BaseNode.d.ts +1 -0
  91. package/lib/view/node/BaseNode.js +22 -10
  92. package/lib/view/node/HtmlNode.js +1 -3
  93. package/lib/view/overlay/CanvasOverlay.js +5 -2
  94. package/lib/view/overlay/Grid.d.ts +12 -1
  95. package/lib/view/overlay/Grid.js +83 -21
  96. package/lib/view/overlay/OutlineOverlay.d.ts +1 -0
  97. package/lib/view/overlay/OutlineOverlay.js +18 -17
  98. package/lib/view/overlay/gridConfig.d.ts +46 -0
  99. package/lib/view/overlay/gridConfig.js +104 -0
  100. package/lib/view/shape/Polygon.d.ts +0 -7
  101. package/lib/view/shape/Polygon.js +13 -45
  102. package/package.json +6 -1
  103. package/.turbo/turbo-build$colon$dev.log +0 -10
  104. package/.turbo/turbo-build.log +0 -33
  105. package/CHANGELOG.md +0 -1849
  106. package/__tests__/algorithm/egde.test.ts +0 -131
  107. package/__tests__/algorithm/index.test.ts +0 -74
  108. package/__tests__/algorithm/outline.test.ts +0 -43
  109. package/__tests__/bugs/1545-spec.test.ts +0 -42
  110. package/__tests__/event/event.test.ts +0 -22
  111. package/__tests__/history/history.test.ts +0 -28
  112. package/__tests__/logicflow.test.ts +0 -575
  113. package/__tests__/model/graphmodel.test.ts +0 -87
  114. package/__tests__/util/compatible.test.ts +0 -48
  115. package/__tests__/util/edge.test.ts +0 -224
  116. package/__tests__/util/geometry.test.ts +0 -14
  117. package/__tests__/util/graph.test.ts +0 -16
  118. package/__tests__/util/matrix.test.ts +0 -41
  119. package/__tests__/util/node.test.ts +0 -68
  120. package/__tests__/util/sampling.test.ts +0 -12
  121. package/__tests__/util/vector.test.ts +0 -50
  122. package/__tests__/util/zIndex.test.ts +0 -10
  123. package/src/LogicFlow.tsx +0 -2008
  124. package/src/algorithm/edge.ts +0 -67
  125. package/src/algorithm/index.ts +0 -70
  126. package/src/algorithm/outline.ts +0 -77
  127. package/src/algorithm/rotate.ts +0 -55
  128. package/src/common/drag.ts +0 -219
  129. package/src/common/history.ts +0 -108
  130. package/src/common/index.ts +0 -6
  131. package/src/common/keyboard.ts +0 -108
  132. package/src/common/matrix.ts +0 -122
  133. package/src/common/vector.ts +0 -93
  134. package/src/constant/index.ts +0 -179
  135. package/src/event/event.md +0 -66
  136. package/src/event/eventArgs.ts +0 -643
  137. package/src/event/eventEmitter.ts +0 -156
  138. package/src/history/index.ts +0 -119
  139. package/src/index.less +0 -1
  140. package/src/index.ts +0 -26
  141. package/src/keyboard/index.ts +0 -112
  142. package/src/keyboard/shortcut.ts +0 -200
  143. package/src/model/BaseModel.ts +0 -250
  144. package/src/model/EditConfigModel.ts +0 -334
  145. package/src/model/GraphModel.ts +0 -1788
  146. package/src/model/NestedTransformModel.ts +0 -121
  147. package/src/model/SnaplineModel.ts +0 -256
  148. package/src/model/TransformModel.ts +0 -258
  149. package/src/model/edge/BaseEdgeModel.ts +0 -777
  150. package/src/model/edge/BezierEdgeModel.ts +0 -197
  151. package/src/model/edge/LineEdgeModel.ts +0 -36
  152. package/src/model/edge/PolylineEdgeModel.ts +0 -672
  153. package/src/model/edge/index.ts +0 -4
  154. package/src/model/index.ts +0 -9
  155. package/src/model/node/BaseNodeModel.ts +0 -949
  156. package/src/model/node/CircleNodeModel.ts +0 -91
  157. package/src/model/node/DiamondNodeModel.ts +0 -132
  158. package/src/model/node/EllipseNodeModel.ts +0 -98
  159. package/src/model/node/HtmlNodeModel.ts +0 -50
  160. package/src/model/node/PolygonNodeModel.ts +0 -150
  161. package/src/model/node/RectNodeModel.ts +0 -69
  162. package/src/model/node/TextNodeModel.ts +0 -54
  163. package/src/model/node/index.ts +0 -8
  164. package/src/options.ts +0 -145
  165. package/src/style/index.less +0 -261
  166. package/src/style/raw.ts +0 -220
  167. package/src/tool/MultipleSelectTool.tsx +0 -132
  168. package/src/tool/TextEditTool.tsx +0 -193
  169. package/src/tool/index.ts +0 -101
  170. package/src/typings.d.ts +0 -5
  171. package/src/util/animation.ts +0 -29
  172. package/src/util/browser.ts +0 -4
  173. package/src/util/compatible.ts +0 -15
  174. package/src/util/drag.ts +0 -220
  175. package/src/util/edge.ts +0 -1060
  176. package/src/util/geometry.ts +0 -55
  177. package/src/util/graph.ts +0 -46
  178. package/src/util/index.ts +0 -17
  179. package/src/util/matrix.ts +0 -129
  180. package/src/util/mobx.ts +0 -23
  181. package/src/util/node.ts +0 -543
  182. package/src/util/raf.ts +0 -28
  183. package/src/util/resize.ts +0 -606
  184. package/src/util/sampling.ts +0 -85
  185. package/src/util/theme.ts +0 -375
  186. package/src/util/uuid.ts +0 -26
  187. package/src/util/vector.ts +0 -93
  188. package/src/util/zIndex.ts +0 -6
  189. package/src/view/Anchor.tsx +0 -445
  190. package/src/view/Control.tsx +0 -512
  191. package/src/view/Graph.tsx +0 -141
  192. package/src/view/Rotate.tsx +0 -113
  193. package/src/view/behavior/dnd.ts +0 -162
  194. package/src/view/behavior/index.ts +0 -2
  195. package/src/view/behavior/snapline.ts +0 -16
  196. package/src/view/edge/AdjustPoint.tsx +0 -425
  197. package/src/view/edge/Arrow.tsx +0 -54
  198. package/src/view/edge/BaseEdge.tsx +0 -650
  199. package/src/view/edge/BezierEdge.tsx +0 -101
  200. package/src/view/edge/LineEdge.tsx +0 -81
  201. package/src/view/edge/PolylineEdge.tsx +0 -299
  202. package/src/view/edge/index.ts +0 -6
  203. package/src/view/index.ts +0 -8
  204. package/src/view/node/BaseNode.tsx +0 -571
  205. package/src/view/node/CircleNode.tsx +0 -21
  206. package/src/view/node/DiamondNode.tsx +0 -24
  207. package/src/view/node/EllipseNode.tsx +0 -22
  208. package/src/view/node/HtmlNode.tsx +0 -95
  209. package/src/view/node/PolygonNode.tsx +0 -28
  210. package/src/view/node/RectNode.tsx +0 -30
  211. package/src/view/node/TextNode.tsx +0 -39
  212. package/src/view/node/index.ts +0 -8
  213. package/src/view/overlay/BackgroundOverlay.tsx +0 -34
  214. package/src/view/overlay/BezierAdjustOverlay.tsx +0 -150
  215. package/src/view/overlay/CanvasOverlay.tsx +0 -288
  216. package/src/view/overlay/Grid.tsx +0 -162
  217. package/src/view/overlay/ModificationOverlay.tsx +0 -31
  218. package/src/view/overlay/OutlineOverlay.tsx +0 -170
  219. package/src/view/overlay/SnaplineOverlay.tsx +0 -44
  220. package/src/view/overlay/ToolOverlay.tsx +0 -65
  221. package/src/view/overlay/getTransformHoc.tsx +0 -50
  222. package/src/view/overlay/index.ts +0 -8
  223. package/src/view/shape/Circle.tsx +0 -41
  224. package/src/view/shape/Ellipse.tsx +0 -42
  225. package/src/view/shape/Line.tsx +0 -39
  226. package/src/view/shape/Path.tsx +0 -22
  227. package/src/view/shape/Polygon.tsx +0 -91
  228. package/src/view/shape/Polyline.tsx +0 -31
  229. package/src/view/shape/Rect.tsx +0 -44
  230. package/src/view/shape/Text.tsx +0 -169
  231. package/src/view/shape/index.ts +0 -8
  232. package/src/view/text/BaseText.tsx +0 -134
  233. package/src/view/text/LineText.tsx +0 -168
  234. package/src/view/text/index.ts +0 -2
  235. package/stats.html +0 -4842
  236. package/tsconfig.json +0 -18
package/src/util/edge.ts DELETED
@@ -1,1060 +0,0 @@
1
- import { pick, forEach } from 'lodash-es'
2
- import { getNodeBBox, isInNode, distance, sampleCubic } from '.'
3
- import LogicFlow from '../LogicFlow'
4
- import { Options } from '../options'
5
- import { SegmentDirection } from '../constant'
6
- import {
7
- getVerticalPointOfLine,
8
- getCrossPointOfLine,
9
- isInSegment,
10
- } from '../algorithm'
11
- import {
12
- Model,
13
- BaseNodeModel,
14
- BaseEdgeModel,
15
- LineEdgeModel,
16
- PolylineEdgeModel,
17
- GraphModel,
18
- } from '../model'
19
-
20
- import Point = LogicFlow.Point
21
- import Direction = LogicFlow.Direction
22
- import LineSegment = LogicFlow.LineSegment
23
- import NodeData = LogicFlow.NodeData
24
- import EdgeConfig = LogicFlow.EdgeConfig
25
- import Position = LogicFlow.Position
26
- import BoxBounds = Model.BoxBounds
27
-
28
- type PolyPointMap = Record<string, Point>
29
- type PolyPointLink = Record<string, string>
30
-
31
- /* 手动创建边时 edge -> edgeModel */
32
- export const setupEdgeModel = (edge: EdgeConfig, graphModel: GraphModel) => {
33
- let model: BaseEdgeModel
34
- switch (edge.type) {
35
- case 'line':
36
- model = new LineEdgeModel(edge, graphModel)
37
- break
38
- case 'polyline':
39
- model = new PolylineEdgeModel(edge, graphModel)
40
- break
41
- default:
42
- model = new LineEdgeModel(edge, graphModel)
43
- break
44
- }
45
- return model
46
- }
47
-
48
- /* 判断两个Bbox是否重合 */
49
- export const isBboxOverLapping = (b1: BoxBounds, b2: BoxBounds): boolean =>
50
- Math.abs(b1.centerX - b2.centerX) * 2 < b1.width + b2.width &&
51
- Math.abs(b1.centerY - b2.centerY) * 2 < b1.height + b2.height
52
-
53
- /* 连接点去重,去掉x,y位置重复的点 */
54
- export const filterRepeatPoints = (points: Point[]): Point[] => {
55
- const result: Point[] = []
56
- const pointsMap: Record<string, Point> = {}
57
- points.forEach((p) => {
58
- const id = `${p.x}-${p.y}`
59
- p.id = id
60
- pointsMap[id] = p
61
- })
62
- Object.keys(pointsMap).forEach((p) => {
63
- result.push(pointsMap[p])
64
- })
65
- return result
66
- }
67
-
68
- /* 获取简单边:边之间除了起始点,只有1个中间点 */
69
- export const getSimplePolyline = (sPoint: Point, tPoint: Point): Point[] => {
70
- const points = [
71
- sPoint,
72
- {
73
- x: sPoint.x,
74
- y: tPoint.y,
75
- },
76
- tPoint,
77
- ]
78
- return filterRepeatPoints(points)
79
- }
80
-
81
- /* 扩展的bbox,保证起始点的下一个点一定在node的垂直方向,不会与线重合, offset是点与线的垂直距离 */
82
- export const getExpandedBBox = (bbox: BoxBounds, offset: number): BoxBounds => {
83
- if (bbox.width === 0 && bbox.height === 0) {
84
- return bbox
85
- }
86
- return {
87
- x: bbox.x,
88
- y: bbox.y,
89
- centerX: bbox.centerX,
90
- centerY: bbox.centerY,
91
- minX: bbox.minX - offset,
92
- minY: bbox.minY - offset,
93
- maxX: bbox.maxX + offset,
94
- maxY: bbox.maxY + offset,
95
- height: bbox.height + 2 * offset,
96
- width: bbox.width + 2 * offset,
97
- }
98
- }
99
-
100
- /* 判断点与中心点边的方向:是否水平,true水平,false垂直 */
101
- export const pointDirection = (point: Point, bbox: BoxBounds): Direction => {
102
- const dx = Math.abs(point.x - bbox.centerX)
103
- const dy = Math.abs(point.y - bbox.centerY)
104
- return dx / bbox.width > dy / bbox.height
105
- ? SegmentDirection.HORIZONTAL
106
- : SegmentDirection.VERTICAL
107
- }
108
-
109
- /* 获取扩展图形上的点,即起始终点相邻的点,上一个或者下一个节点 */
110
- export const getExpandedBBoxPoint = (
111
- expendBBox: BoxBounds,
112
- bbox: BoxBounds,
113
- point: Point,
114
- ): Point => {
115
- // https://github.com/didi/LogicFlow/issues/817
116
- // 没有修复前传入的参数bbox实际是expendBBox
117
- // 由于pointDirection使用的是dx / bbox.width > dy / bbox.height判定方向
118
- // 此时的bbox.width是增加了offset后的宽度,bbox.height同理
119
- // 这导致了部分极端情况(宽度很大或者高度很小),计算出来的方向错误
120
- const direction = pointDirection(point, bbox)
121
- if (direction === SegmentDirection.HORIZONTAL) {
122
- return {
123
- x: point.x > expendBBox.centerX ? expendBBox.maxX : expendBBox.minX,
124
- y: point.y,
125
- }
126
- }
127
- return {
128
- x: point.x,
129
- y: point.y > expendBBox.centerY ? expendBBox.maxY : expendBBox.minY,
130
- }
131
- }
132
-
133
- /* 获取包含2个图形的外层box */
134
- export const mergeBBox = (b1: BoxBounds, b2: BoxBounds): BoxBounds => {
135
- const minX = Math.min(b1.minX, b2.minX)
136
- const minY = Math.min(b1.minY, b2.minY)
137
- const maxX = Math.max(b1.maxX, b2.maxX)
138
- const maxY = Math.max(b1.maxY, b2.maxY)
139
-
140
- return {
141
- x: (minX + maxX) / 2,
142
- y: (minY + maxY) / 2,
143
- centerX: (minX + maxX) / 2,
144
- centerY: (minY + maxY) / 2,
145
- minX,
146
- minY,
147
- maxX,
148
- maxY,
149
- height: maxY - minY,
150
- width: maxX - minX,
151
- }
152
- }
153
-
154
- /* 获取多个点的外层bbox
155
- * 这个函数的用处
156
- * 1、获取起始终点相邻点(expendBboxPoint)的bbox
157
- * 2、polylineEdge, bezierEdge,获取outline边框,这种情况传入offset
158
- */
159
- export const getBBoxOfPoints = (
160
- points: Point[] = [],
161
- offset?: number,
162
- ): BoxBounds => {
163
- const xList: number[] = []
164
- const yList: number[] = []
165
- points.forEach((p) => {
166
- xList.push(p.x)
167
- yList.push(p.y)
168
- })
169
- const minX = Math.min(...xList)
170
- const maxX = Math.max(...xList)
171
- const minY = Math.min(...yList)
172
- const maxY = Math.max(...yList)
173
- let width = maxX - minX
174
- let height = maxY - minY
175
- if (offset) {
176
- width += offset
177
- height += offset
178
- }
179
- return {
180
- centerX: (minX + maxX) / 2,
181
- centerY: (minY + maxY) / 2,
182
- maxX,
183
- maxY,
184
- minX,
185
- minY,
186
- x: (minX + maxX) / 2,
187
- y: (minY + maxY) / 2,
188
- height,
189
- width,
190
- }
191
- }
192
- /* 获取box四个角上的点 */
193
- export const getPointsFromBBox = (
194
- bbox: BoxBounds,
195
- ): [Point, Point, Point, Point] => {
196
- const { minX, minY, maxX, maxY } = bbox
197
- return [
198
- {
199
- x: minX,
200
- y: minY,
201
- },
202
- {
203
- x: maxX,
204
- y: minY,
205
- },
206
- {
207
- x: maxX,
208
- y: maxY,
209
- },
210
- {
211
- x: minX,
212
- y: maxY,
213
- },
214
- ]
215
- }
216
- /* 判断某一点是否在box中 */
217
- export const isPointOutsideBBox = (point: Point, bbox: BoxBounds): boolean => {
218
- const { x, y } = point
219
- return x < bbox.minX || x > bbox.maxX || y < bbox.minY || y > bbox.maxY
220
- }
221
-
222
- /* 获取点的x方向上与box的交点 */
223
- export const getBBoxXCrossPoints = (
224
- bbox: BoxBounds,
225
- x: number,
226
- ): [Point, Point] | [] => {
227
- if (x < bbox.minX || x > bbox.maxX) {
228
- return []
229
- }
230
- return [
231
- {
232
- x,
233
- y: bbox.minY,
234
- },
235
- {
236
- x,
237
- y: bbox.maxY,
238
- },
239
- ]
240
- }
241
-
242
- /* 获取点的y方向上与box的交点 */
243
- export const getBBoxYCrossPoints = (
244
- bbox: BoxBounds,
245
- y: number,
246
- ): [Point, Point] | [] => {
247
- if (y < bbox.minY || y > bbox.maxY) {
248
- return []
249
- }
250
- return [
251
- {
252
- x: bbox.minX,
253
- y,
254
- },
255
- {
256
- x: bbox.maxX,
257
- y,
258
- },
259
- ]
260
- }
261
-
262
- /* 获取点的x,y方向上与box的交点 */
263
- export const getBBoxCrossPointsByPoint = (
264
- bbox: BoxBounds,
265
- point: Point,
266
- ): [Point, Point, Point, Point] | [Point, Point] | [] => [
267
- ...getBBoxXCrossPoints(bbox, point.x),
268
- ...getBBoxYCrossPoints(bbox, point.y),
269
- ]
270
-
271
- /* 计算两点之间的预测距离(非直线距离) */
272
- export const estimateDistance = (p1: Point, p2: Point): number =>
273
- Math.abs(p1.x - p2.x) + Math.abs(p1.y - p2.y)
274
-
275
- /* 减少点别重复计算进距离的误差 */
276
- export const costByPoints = (p: Point, points: Point[]): number => {
277
- const offset = -2
278
- let result = 0
279
- points.forEach((point) => {
280
- if (point) {
281
- if (p.x === point.x) {
282
- result += offset
283
- }
284
- if (p.y === point.y) {
285
- result += offset
286
- }
287
- }
288
- })
289
- return result
290
- }
291
-
292
- /* 预估距离 */
293
- export const heuristicCostEstimate = (
294
- p: Point,
295
- ps: Point,
296
- pt: Point,
297
- source?: Point,
298
- target?: Point,
299
- ): number =>
300
- estimateDistance(p, ps) +
301
- estimateDistance(p, pt) +
302
- costByPoints(p, [ps, pt, source!, target!])
303
-
304
- /* 重建路径,根据cameFrom属性计算出从起始到结束的路径 */
305
- export const rebuildPath = (
306
- pathPoints: Point[],
307
- pointById: PolyPointMap,
308
- cameFrom: PolyPointLink,
309
- currentId: string,
310
- iterator?: number,
311
- ): void => {
312
- if (!iterator) {
313
- iterator = 0
314
- }
315
- pathPoints.unshift(pointById[currentId])
316
- if (
317
- cameFrom[currentId] &&
318
- cameFrom[currentId] !== currentId &&
319
- iterator <= 100
320
- ) {
321
- rebuildPath(
322
- pathPoints,
323
- pointById,
324
- cameFrom,
325
- cameFrom[currentId],
326
- iterator + 1,
327
- )
328
- }
329
- }
330
-
331
- /* 把计算完毕的点从开放列表中删除 */
332
- export const removeClosePointFromOpenList = (
333
- arr: Point[],
334
- item: Point,
335
- ): void => {
336
- const index = arr.indexOf(item)
337
- if (index > -1) {
338
- arr.splice(index, 1)
339
- }
340
- }
341
-
342
- /* 通过向量判断线段之间是否是相交的 */
343
- export const isSegmentsIntersected = (
344
- p0: Point,
345
- p1: Point,
346
- p2: Point,
347
- p3: Point,
348
- ): boolean => {
349
- const s1x = p1.x - p0.x
350
- const s1y = p1.y - p0.y
351
- const s2x = p3.x - p2.x
352
- const s2y = p3.y - p2.y
353
-
354
- const s =
355
- (-s1y * (p0.x - p2.x) + s1x * (p0.y - p2.y)) / (-s2x * s1y + s1x * s2y)
356
- const t =
357
- (s2x * (p0.y - p2.y) - s2y * (p0.x - p2.x)) / (-s2x * s1y + s1x * s2y)
358
-
359
- return s >= 0 && s <= 1 && t >= 0 && t <= 1
360
- }
361
-
362
- /* 判断线段与bbox是否是相交的,保证节点之间的边不会穿过节点自身 */
363
- export const isSegmentCrossingBBox = (
364
- p1: Point,
365
- p2: Point,
366
- bbox: BoxBounds,
367
- ): boolean => {
368
- if (bbox.width === 0 && bbox.height === 0) {
369
- return false
370
- }
371
- const [pa, pb, pc, pd] = getPointsFromBBox(bbox)
372
- return (
373
- isSegmentsIntersected(p1, p2, pa, pb) ||
374
- isSegmentsIntersected(p1, p2, pa, pd) ||
375
- isSegmentsIntersected(p1, p2, pb, pc) ||
376
- isSegmentsIntersected(p1, p2, pc, pd)
377
- )
378
- }
379
-
380
- /* 获取下一个相邻的点 */
381
- export const getNextNeighborPoints = (
382
- points: Point[],
383
- point: Point,
384
- bbox1: BoxBounds,
385
- bbox2: BoxBounds,
386
- ): Point[] => {
387
- const neighbors: Point[] = []
388
- points.forEach((p) => {
389
- if (p !== point) {
390
- if (p.x === point.x || p.y === point.y) {
391
- if (
392
- !isSegmentCrossingBBox(p, point, bbox1) &&
393
- !isSegmentCrossingBBox(p, point, bbox2)
394
- ) {
395
- neighbors.push(p)
396
- }
397
- }
398
- }
399
- })
400
- return filterRepeatPoints(neighbors)
401
- }
402
-
403
- /* 路径查找,AStar查找+曼哈顿距离
404
- * 算法wiki:https://zh.wikipedia.org/wiki/A*%E6%90%9C%E5%B0%8B%E6%BC%94%E7%AE%97%E6%B3%95
405
- * 方法无法复用,且调用了很多polyline相关的方法,暂不抽离到src/algorithm中
406
- */
407
- export const pathFinder = (
408
- points: Point[],
409
- start: Point,
410
- goal: Point,
411
- sBBox: BoxBounds,
412
- tBBox: BoxBounds,
413
- os: Point,
414
- ot: Point,
415
- ): Point[] => {
416
- // 定义已经遍历过的点
417
- const closedSet: Point[] = []
418
- // 定义需要遍历的店
419
- const openSet = [start]
420
- // 定义节点的上一个节点
421
- const cameFrom: PolyPointLink = {}
422
-
423
- const gScore: {
424
- [key: string]: number
425
- } = {}
426
-
427
- const fScore: {
428
- [key: string]: number
429
- } = {}
430
-
431
- if (start.id) {
432
- gScore[start.id] = 0
433
- fScore[start.id] = heuristicCostEstimate(start, goal, start)
434
- }
435
-
436
- const pointById: PolyPointMap = {}
437
-
438
- points.forEach((p) => {
439
- if (p.id) {
440
- pointById[p.id] = p
441
- }
442
- })
443
-
444
- while (openSet.length) {
445
- let current: Point | undefined
446
- let lowestFScore = Infinity
447
- openSet.forEach((p: Point) => {
448
- if (p.id && fScore[p.id] < lowestFScore) {
449
- lowestFScore = fScore[p.id]
450
- current = p
451
- }
452
- })
453
-
454
- if (current === goal && goal.id) {
455
- const pathPoints: Point[] = []
456
- rebuildPath(pathPoints, pointById, cameFrom, goal.id)
457
- return pathPoints
458
- }
459
-
460
- if (!current) {
461
- return [start, goal]
462
- }
463
-
464
- removeClosePointFromOpenList(openSet, current)
465
- closedSet.push(current)
466
-
467
- getNextNeighborPoints(points, current, sBBox, tBBox).forEach((neighbor) => {
468
- if (closedSet.indexOf(neighbor) !== -1) {
469
- return
470
- }
471
-
472
- if (openSet.indexOf(neighbor) === -1) {
473
- openSet.push(neighbor)
474
- }
475
-
476
- if (current?.id && neighbor?.id) {
477
- const tentativeGScore =
478
- fScore[current.id] + estimateDistance(current, neighbor)
479
- if (gScore[neighbor.id] && tentativeGScore >= gScore[neighbor.id]) {
480
- return
481
- }
482
-
483
- cameFrom[neighbor.id] = current.id
484
- gScore[neighbor.id] = tentativeGScore
485
- fScore[neighbor.id] =
486
- gScore[neighbor.id] +
487
- heuristicCostEstimate(neighbor, goal, start, os, ot)
488
- }
489
- })
490
- }
491
- return [start, goal]
492
- }
493
-
494
- export const getBoxByOriginNode = (node: BaseNodeModel): BoxBounds => {
495
- return getNodeBBox(node)
496
- }
497
- /* 保证一条直线上只有2个节点: 删除x/y相同的中间节点 */
498
- export const pointFilter = (points: Point[]): Point[] => {
499
- let i = 1
500
- while (i < points.length - 1) {
501
- const pre = points[i - 1]
502
- const current = points[i]
503
- const next = points[i + 1]
504
- if (
505
- (pre.x === current.x && current.x === next.x) ||
506
- (pre.y === current.y && current.y === next.y)
507
- ) {
508
- points.splice(i, 1)
509
- } else {
510
- i++
511
- }
512
- }
513
- return points
514
- }
515
-
516
- /* 计算折线点 */
517
- export const getPolylinePoints = (
518
- start: Point,
519
- end: Point,
520
- sNode: BaseNodeModel,
521
- tNode: BaseNodeModel,
522
- offset: number,
523
- ): Point[] => {
524
- const sBBox = getBoxByOriginNode(sNode)
525
- const tBBox = getBoxByOriginNode(tNode)
526
- const sxBBox = getExpandedBBox(sBBox, offset)
527
- const txBBox = getExpandedBBox(tBBox, offset)
528
- const sPoint = getExpandedBBoxPoint(sxBBox, sBBox, start)
529
- const tPoint = getExpandedBBoxPoint(txBBox, tBBox, end)
530
- // 当加上offset后的bbox有重合,直接简单计算节点
531
- if (isBboxOverLapping(sxBBox, txBBox)) {
532
- const points = getSimplePoints(start, end, sPoint, tPoint)
533
- return [start, sPoint, ...points, tPoint, end]
534
- }
535
- const lineBBox = getBBoxOfPoints([sPoint, tPoint])
536
- const sMixBBox = mergeBBox(sxBBox, lineBBox)
537
- const tMixBBox = mergeBBox(txBBox, lineBBox)
538
- let connectPoints: Point[] = []
539
- connectPoints = connectPoints.concat(getPointsFromBBox(sMixBBox))
540
- connectPoints = connectPoints.concat(getPointsFromBBox(tMixBBox))
541
- // 中心点
542
- const centerPoint = {
543
- x: (start.x + end.x) / 2,
544
- y: (start.y + end.y) / 2,
545
- }
546
- // 获取中心点与其他box的交点
547
- ;[lineBBox, sMixBBox, tMixBBox].forEach((bbox: BoxBounds) => {
548
- connectPoints = connectPoints.concat(
549
- getBBoxCrossPointsByPoint(bbox, centerPoint).filter(
550
- (p) => isPointOutsideBBox(p, sxBBox) && isPointOutsideBBox(p, txBBox),
551
- ),
552
- )
553
- })
554
- // 与起止终点相邻的两的,在x,y方向上的交点,这四个点组成了矩形 。。。解释图中在不中这两个点,
555
- ;[
556
- {
557
- x: sPoint.x,
558
- y: tPoint.y,
559
- },
560
- {
561
- x: tPoint.x,
562
- y: sPoint.y,
563
- },
564
- ].forEach((p) => {
565
- if (isPointOutsideBBox(p, sxBBox) && isPointOutsideBBox(p, txBBox)) {
566
- connectPoints.push(p)
567
- }
568
- })
569
- connectPoints.unshift(sPoint)
570
- connectPoints.push(tPoint)
571
- connectPoints = filterRepeatPoints(connectPoints)
572
- // 路径查找-最关键的步骤
573
- let pathPoints = pathFinder(
574
- connectPoints,
575
- sPoint,
576
- tPoint,
577
- sBBox,
578
- tBBox,
579
- start,
580
- end,
581
- )
582
- pathPoints.unshift(start)
583
- pathPoints.push(end)
584
- // 删除一条直线上的多余节点
585
- if (pathPoints.length > 2) {
586
- pathPoints = pointFilter(pathPoints)
587
- }
588
- return filterRepeatPoints(pathPoints)
589
- }
590
-
591
- /**
592
- * 获取折线中最长的一个线
593
- * @param pointsList 多个点组成的数组
594
- */
595
- export const getLongestEdge = (pointsList: Point[]): [Point, Point] => {
596
- if (pointsList.length === 1) {
597
- const [point] = pointsList
598
- return [point, point]
599
- } else {
600
- let point1 = pointsList[0]
601
- let point2 = pointsList[1]
602
- let edgeLength = distance(point1.x, point1.y, point2.x, point2.y)
603
- for (let i = 1; i < pointsList.length - 1; i++) {
604
- const newPoint1 = pointsList[i]
605
- const newPoint2 = pointsList[i + 1]
606
- const newEdgeLength = distance(
607
- newPoint1.x,
608
- newPoint1.y,
609
- newPoint2.x,
610
- newPoint2.y,
611
- )
612
- if (newEdgeLength > edgeLength) {
613
- edgeLength = newEdgeLength
614
- point1 = newPoint1
615
- point2 = newPoint2
616
- }
617
- }
618
- return [point1, point2]
619
- }
620
- }
621
-
622
- /* 线段是否在节点内部,被包含了 */
623
- export const isSegmentsInNode = (
624
- start: Point,
625
- end: Point,
626
- node: BaseNodeModel,
627
- ): boolean => {
628
- const startInNode = isInNode(start, node)
629
- const endInNode = isInNode(end, node)
630
- return startInNode && endInNode
631
- }
632
-
633
- /* 线段是否与节点相交 */
634
- export const isSegmentsCrossNode = (
635
- start: Point,
636
- end: Point,
637
- node: BaseNodeModel,
638
- ): boolean => {
639
- const startInNode = isInNode(start, node)
640
- const endInNode = isInNode(end, node)
641
- // bothInNode,线段两个端点都在节点内
642
- const bothInNode = startInNode && endInNode
643
- // cross,线段有端点在节点内
644
- const inNode = startInNode || endInNode
645
- // 有且只有一个点在节点内部
646
- return !bothInNode && inNode
647
- }
648
-
649
- /* 获取线段在矩形内部的交点
650
- */
651
- export const getCrossPointInRect = (
652
- start: Point,
653
- end: Point,
654
- node: BaseNodeModel,
655
- ): Point | false | undefined => {
656
- let crossSegments: [Point, Point] | undefined = undefined
657
- const nodeBox = getNodeBBox(node)
658
- const points = getPointsFromBBox(nodeBox)
659
- for (let i = 0; i < points.length; i++) {
660
- const isCross = isSegmentsIntersected(
661
- start,
662
- end,
663
- points[i],
664
- points[(i + 1) % points.length],
665
- )
666
- if (isCross) {
667
- crossSegments = [points[i], points[(i + 1) % points.length]]
668
- }
669
- }
670
- if (crossSegments) {
671
- return getCrossPointOfLine(start, end, crossSegments[0], crossSegments[1])
672
- }
673
- }
674
- /* 判断线段的方向 */
675
- export const segmentDirection = (
676
- start: Point,
677
- end: Point,
678
- ): Direction | undefined => {
679
- let direction: Direction | undefined = undefined
680
- if (start.x === end.x) {
681
- direction = SegmentDirection.VERTICAL
682
- } else if (start.y === end.y) {
683
- direction = SegmentDirection.HORIZONTAL
684
- }
685
- return direction
686
- }
687
-
688
- export const points2PointsList = (points: string): Point[] => {
689
- const currentPositionList = points.split(' ')
690
- const pointsList: LogicFlow.Position[] = []
691
- currentPositionList &&
692
- currentPositionList.forEach((item) => {
693
- const [x, y] = item.split(',')
694
- pointsList.push({
695
- x: Number(x),
696
- y: Number(y),
697
- })
698
- })
699
- return pointsList
700
- }
701
-
702
- export const getSimplePoints = (
703
- start: Point,
704
- end: Point,
705
- sPoint: Point,
706
- tPoint: Point,
707
- ): Point[] => {
708
- const points: LogicFlow.Position[] = []
709
- // start,sPoint的方向,水平或者垂直,即路径第一条线段的方向
710
- const startDirection = segmentDirection(start, sPoint)!
711
- // end,tPoint的方向,水平或者垂直,即路径最后一条条线段的方向
712
- const endDirection = segmentDirection(end, tPoint)!
713
- // 根据两条线段的方向作了计算,调整线段经验所得,非严格最优计算,能保证不出现折线
714
- // 方向相同,添加两个点,两条平行线垂直距离一半的两个端点
715
- if (startDirection === endDirection) {
716
- if (start.y === sPoint.y) {
717
- points.push({
718
- x: sPoint.x,
719
- y: (sPoint.y + tPoint.y) / 2,
720
- })
721
- points.push({
722
- x: tPoint.x,
723
- y: (sPoint.y + tPoint.y) / 2,
724
- })
725
- } else {
726
- points.push({
727
- x: (sPoint.x + tPoint.x) / 2,
728
- y: sPoint.y,
729
- })
730
- points.push({
731
- x: (sPoint.x + tPoint.x) / 2,
732
- y: tPoint.y,
733
- })
734
- }
735
- } else {
736
- // 方向不同,添加一个点,保证不在当前线段上(会出现重合),且不能有折线
737
- let point = {
738
- x: sPoint.x,
739
- y: tPoint.y,
740
- }
741
- const inStart = isInSegment(point, start, sPoint)
742
- const inEnd = isInSegment(point, end, tPoint)
743
- if (inStart || inEnd) {
744
- point = {
745
- x: tPoint.x,
746
- y: sPoint.y,
747
- }
748
- } else {
749
- const onStart = isOnLine(point, start, sPoint)
750
- const onEnd = isOnLine(point, end, tPoint)
751
- if (onStart && onEnd) {
752
- point = {
753
- x: tPoint.x,
754
- y: sPoint.y,
755
- }
756
- }
757
- }
758
- points.push(point)
759
- }
760
- return points
761
- }
762
-
763
- const isOnLine = (point: Point, start: Point, end: Point) =>
764
- (point.x === start.x && point.x === end.x) ||
765
- (point.y === start.y && point.y === end.y)
766
-
767
- /* 求字符串的字节长度 */
768
- export const getBytesLength = (word: string): number => {
769
- if (!word) {
770
- return 0
771
- }
772
- let totalLength = 0
773
- for (let i = 0; i < word.length; i++) {
774
- const c = word.charCodeAt(i)
775
- if (word.match(/[A-Z]/)) {
776
- totalLength += 1.5
777
- } else if ((c >= 0x0001 && c <= 0x007e) || (c >= 0xff60 && c <= 0xff9f)) {
778
- totalLength += 1
779
- } else {
780
- totalLength += 2
781
- }
782
- }
783
- return totalLength
784
- }
785
-
786
- /**
787
- * Uses canvas.measureText to compute
788
- * and return the width of the given text of given font in pixels.
789
- * @param {String} text The text to be rendered.
790
- * @param {String} font The css font descriptor
791
- * that text is to be rendered with (e.g. "bold 14px verdana").
792
- * @see https://stackoverflow.com/questions/118241/calculate-text-width-with-javascript/21015393#21015393
793
- */
794
- let canvas: HTMLCanvasElement | undefined = undefined
795
- export const getTextWidth = (text: string, font: string) => {
796
- if (!canvas) {
797
- canvas = document.createElement('canvas')
798
- }
799
- const context = canvas.getContext('2d')
800
- context!.font = font
801
- const metrics = context!.measureText(text)
802
- return metrics.width
803
- }
804
-
805
- type AppendAttributesType = {
806
- d: string
807
- fill: string
808
- stroke: string
809
- strokeWidth: number
810
- strokeDasharray: string
811
- }
812
- // 扩大边可点区域,获取边append的信息
813
- export const getAppendAttributes = (
814
- appendInfo: Record<'start' | 'end', Point>,
815
- ): AppendAttributesType => {
816
- const { start, end } = appendInfo
817
- let d: string
818
- if (start.x === end.x && start.y === end.y) {
819
- // 拖拽过程中会出现起终点重合的情况,这时候append无法计算
820
- d = ''
821
- } else {
822
- const config = {
823
- start,
824
- end,
825
- offset: 10,
826
- verticalLength: 5,
827
- }
828
- const startPosition = getVerticalPointOfLine({
829
- ...config,
830
- type: 'start',
831
- })
832
- const endPosition = getVerticalPointOfLine({
833
- ...config,
834
- type: 'end',
835
- })
836
- d = `M${startPosition.leftX} ${startPosition.leftY}
837
- L${startPosition.rightX} ${startPosition.rightY}
838
- L${endPosition.rightX} ${endPosition.rightY}
839
- L${endPosition.leftX} ${endPosition.leftY} z`
840
- }
841
- return {
842
- d,
843
- fill: 'transparent',
844
- stroke: 'transparent',
845
- strokeWidth: 1,
846
- strokeDasharray: '4, 4',
847
- }
848
- }
849
- export type IBezierControls = {
850
- sNext: Point
851
- ePre: Point
852
- }
853
-
854
- // bezier曲线
855
- export const getBezierControlPoints = ({
856
- start,
857
- end,
858
- sourceNode,
859
- targetNode,
860
- offset,
861
- }: {
862
- start: Point
863
- end: Point
864
- sourceNode: BaseNodeModel
865
- targetNode: BaseNodeModel
866
- offset: number
867
- }): IBezierControls => {
868
- const sBBox = getNodeBBox(sourceNode)
869
- const tBBox = getNodeBBox(targetNode)
870
- const sExpendBBox = getExpandedBBox(sBBox, offset)
871
- const tExpendBBox = getExpandedBBox(tBBox, offset)
872
- const sNext = getExpandedBBoxPoint(sExpendBBox, sBBox, start)
873
- const ePre = getExpandedBBoxPoint(tExpendBBox, tBBox, end)
874
- return {
875
- sNext,
876
- ePre,
877
- }
878
- }
879
-
880
- export type IBezierPoints = {
881
- start: Point
882
- sNext: Point
883
- ePre: Point
884
- end: Point
885
- }
886
- // 根据bezier曲线path求出Points
887
- export const getBezierPoints = (path: string): [Point, Point, Point, Point] => {
888
- const list = path.replace(/M/g, '').replace(/C/g, ',').split(',')
889
- const start = getBezierPoint(list[0])
890
- const sNext = getBezierPoint(list[1])
891
- const ePre = getBezierPoint(list[2])
892
- const end = getBezierPoint(list[3])
893
- return [start, sNext, ePre, end]
894
- }
895
- // 根据bezier曲线path求出Point坐标
896
- const getBezierPoint = (positionStr: string): Point => {
897
- const [x, y] = positionStr.replace(/(^\s*)/g, '').split(' ')
898
- return {
899
- x: +x,
900
- y: +y,
901
- }
902
- }
903
- // 根据bezier曲线path求出结束切线的两点坐标
904
- export const getEndTangent = (
905
- pointsList: Point[],
906
- offset: number,
907
- ): [Point, Point] => {
908
- // const bezierPoints = getBezierPoints(path)
909
- const [p1, cp1, cp2, p2] = pointsList
910
- const start = sampleCubic(p1, cp1, cp2, p2, offset)
911
- return [start, pointsList[3]]
912
- }
913
-
914
- /**
915
- * 获取移动边后,文本位置距离边上的最近的一点
916
- * @param point 边上文本的位置
917
- * @param points 边的各个拐点
918
- * TODO: Label实验没问题后统一改成新的计算方式,把这个方法废弃
919
- */
920
- export const getClosestPointOfPolyline = (
921
- point: Point,
922
- points: string,
923
- ): Point => {
924
- const { x, y } = point
925
- const pointsPosition = points2PointsList(points)
926
- let minDistance = Number.MAX_SAFE_INTEGER
927
- let crossPoint: Point
928
- const segments: LineSegment[] = []
929
- for (let i = 0; i < pointsPosition.length; i++) {
930
- segments.push({
931
- start: pointsPosition[i],
932
- end: pointsPosition[(i + 1) % pointsPosition.length],
933
- })
934
- }
935
- segments.forEach((item) => {
936
- const { start, end } = item
937
- // 若线段垂直,则crossPoint的横坐标与线段一致
938
- if (start.x === end.x) {
939
- const pointXY = {
940
- x: start.x,
941
- y,
942
- }
943
- const inSegment = isInSegment(pointXY, start, end)
944
- if (inSegment) {
945
- const currentDistance = Math.abs(start.x - x)
946
- if (currentDistance < minDistance) {
947
- minDistance = currentDistance
948
- crossPoint = pointXY
949
- }
950
- }
951
- } else if (start.y === end.y) {
952
- const pointXY = {
953
- x,
954
- y: start.y,
955
- }
956
- const inSegment = isInSegment(pointXY, start, end)
957
- if (inSegment) {
958
- const currentDistance = Math.abs(start.y - y)
959
- if (currentDistance < minDistance) {
960
- minDistance = currentDistance
961
- crossPoint = pointXY
962
- }
963
- }
964
- }
965
- })
966
- // 边界:只有一条线段时,沿线段移动节点,当文本超出边后,文本没有可供参考的线段
967
- if (!crossPoint!) {
968
- const { start, end } = segments[0]
969
- crossPoint = {
970
- x: start.x + (end.x - start.x) / 2,
971
- y: start.y + (end.y - start.y) / 2,
972
- }
973
- }
974
- return crossPoint
975
- }
976
-
977
- // 规范边初始化数据
978
- export const pickEdgeConfig = (data: EdgeConfig): EdgeConfig =>
979
- pick(data, [
980
- 'id',
981
- 'type',
982
- 'sourceNodeId',
983
- 'sourceAnchorId',
984
- 'targetNodeId',
985
- 'targetAnchorId',
986
- 'pointsList',
987
- 'startPoint',
988
- 'endPoint',
989
- 'properties',
990
- ])
991
-
992
- export const twoPointDistance = (source: Position, target: Position) => {
993
- // fix: 修复坐标存在负值时计算错误的问题。
994
- // const source = {
995
- // x: p1.x,
996
- // y: Math.abs(p1.y),
997
- // }
998
- // const target = {
999
- // x: Math.abs(p2.x),
1000
- // y: Math.abs(p2.y),
1001
- // }
1002
- return Math.sqrt((source.x - target.x) ** 2 + (source.y - target.y) ** 2)
1003
- }
1004
-
1005
- /**
1006
- * 包装边生成函数
1007
- * @param graphModel graph model
1008
- * @param generator 用户自定义的边生成函数
1009
- */
1010
- export function createEdgeGenerator(
1011
- graphModel: GraphModel,
1012
- generator?: Options.EdgeGeneratorType | unknown,
1013
- ): any {
1014
- // TODO: 定义返回值类型,保证 GraphModel 中类型的正确性
1015
- if (typeof generator !== 'function') {
1016
- return (
1017
- _sourceNode: NodeData,
1018
- _targetNode: NodeData,
1019
- currentEdge?: EdgeConfig,
1020
- ) => Object.assign({ type: graphModel.edgeType }, currentEdge)
1021
- }
1022
- return (
1023
- sourceNode: NodeData,
1024
- targetNode: NodeData,
1025
- currentEdge?: EdgeConfig,
1026
- ) => {
1027
- const result = generator(sourceNode, targetNode, currentEdge)
1028
- // 无结果使用默认类型
1029
- if (!result) return { type: graphModel.edgeType }
1030
- if (typeof result === 'string') {
1031
- return Object.assign({}, currentEdge, { type: result })
1032
- }
1033
- return Object.assign({ type: result }, currentEdge)
1034
- }
1035
- }
1036
-
1037
- // 获取 Svg 标签文案高度,自动换行
1038
- export type IGetSvgTextSizeParams = {
1039
- rows: string[]
1040
- rowsLength: number
1041
- fontSize: number
1042
- }
1043
- export const getSvgTextSize = ({
1044
- rows,
1045
- rowsLength,
1046
- fontSize,
1047
- }: IGetSvgTextSizeParams): LogicFlow.RectSize => {
1048
- let longestBytes = 0
1049
- forEach(rows, (row) => {
1050
- const rowBytesLength = getBytesLength(row)
1051
- longestBytes = rowBytesLength > longestBytes ? rowBytesLength : longestBytes
1052
- })
1053
-
1054
- // 背景框宽度,最长一行字节数/2 * fontsize + 2
1055
- // 背景框宽度, 行数 * fontsize + 2
1056
- return {
1057
- width: Math.ceil(longestBytes / 2) * fontSize + fontSize / 4,
1058
- height: rowsLength * (fontSize + 2) + fontSize / 4,
1059
- }
1060
- }