@logicflow/core 2.2.0-alpha.7 → 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 (137) hide show
  1. package/package.json +6 -1
  2. package/.turbo/turbo-build$colon$dev.log +0 -10
  3. package/.turbo/turbo-build.log +0 -33
  4. package/CHANGELOG.md +0 -1901
  5. package/__tests__/algorithm/egde.test.ts +0 -131
  6. package/__tests__/algorithm/index.test.ts +0 -74
  7. package/__tests__/algorithm/outline.test.ts +0 -43
  8. package/__tests__/bugs/1545-spec.test.ts +0 -42
  9. package/__tests__/event/event.test.ts +0 -22
  10. package/__tests__/history/history.test.ts +0 -28
  11. package/__tests__/logicflow.test.ts +0 -575
  12. package/__tests__/model/graphmodel.test.ts +0 -87
  13. package/__tests__/util/compatible.test.ts +0 -48
  14. package/__tests__/util/edge.test.ts +0 -224
  15. package/__tests__/util/geometry.test.ts +0 -14
  16. package/__tests__/util/graph.test.ts +0 -16
  17. package/__tests__/util/matrix.test.ts +0 -41
  18. package/__tests__/util/node.test.ts +0 -68
  19. package/__tests__/util/sampling.test.ts +0 -12
  20. package/__tests__/util/vector.test.ts +0 -50
  21. package/__tests__/util/zIndex.test.ts +0 -10
  22. package/src/LogicFlow.tsx +0 -2017
  23. package/src/algorithm/edge.ts +0 -67
  24. package/src/algorithm/index.ts +0 -70
  25. package/src/algorithm/outline.ts +0 -77
  26. package/src/algorithm/rotate.ts +0 -55
  27. package/src/common/drag.ts +0 -219
  28. package/src/common/history.ts +0 -108
  29. package/src/common/index.ts +0 -6
  30. package/src/common/keyboard.ts +0 -108
  31. package/src/common/matrix.ts +0 -122
  32. package/src/common/vector.ts +0 -93
  33. package/src/constant/index.ts +0 -179
  34. package/src/constant/theme.ts +0 -708
  35. package/src/event/event.md +0 -66
  36. package/src/event/eventArgs.ts +0 -643
  37. package/src/event/eventEmitter.ts +0 -156
  38. package/src/history/index.ts +0 -119
  39. package/src/index.less +0 -1
  40. package/src/index.ts +0 -26
  41. package/src/keyboard/index.ts +0 -112
  42. package/src/keyboard/shortcut.ts +0 -200
  43. package/src/model/BaseModel.ts +0 -250
  44. package/src/model/EditConfigModel.ts +0 -334
  45. package/src/model/GraphModel.ts +0 -1824
  46. package/src/model/NestedTransformModel.ts +0 -121
  47. package/src/model/SnaplineModel.ts +0 -256
  48. package/src/model/TransformModel.ts +0 -258
  49. package/src/model/edge/BaseEdgeModel.ts +0 -785
  50. package/src/model/edge/BezierEdgeModel.ts +0 -197
  51. package/src/model/edge/LineEdgeModel.ts +0 -36
  52. package/src/model/edge/PolylineEdgeModel.ts +0 -817
  53. package/src/model/edge/index.ts +0 -4
  54. package/src/model/index.ts +0 -9
  55. package/src/model/node/BaseNodeModel.ts +0 -959
  56. package/src/model/node/CircleNodeModel.ts +0 -91
  57. package/src/model/node/DiamondNodeModel.ts +0 -132
  58. package/src/model/node/EllipseNodeModel.ts +0 -98
  59. package/src/model/node/HtmlNodeModel.ts +0 -64
  60. package/src/model/node/PolygonNodeModel.ts +0 -152
  61. package/src/model/node/RectNodeModel.ts +0 -69
  62. package/src/model/node/TextNodeModel.ts +0 -54
  63. package/src/model/node/index.ts +0 -8
  64. package/src/options.ts +0 -150
  65. package/src/style/index.less +0 -262
  66. package/src/style/raw.ts +0 -221
  67. package/src/tool/MultipleSelectTool.tsx +0 -140
  68. package/src/tool/TextEditTool.tsx +0 -193
  69. package/src/tool/index.ts +0 -101
  70. package/src/typings.d.ts +0 -5
  71. package/src/util/animation.ts +0 -29
  72. package/src/util/browser.ts +0 -4
  73. package/src/util/compatible.ts +0 -15
  74. package/src/util/drag.ts +0 -219
  75. package/src/util/edge.ts +0 -1094
  76. package/src/util/geometry.ts +0 -154
  77. package/src/util/graph.ts +0 -46
  78. package/src/util/index.ts +0 -17
  79. package/src/util/matrix.ts +0 -129
  80. package/src/util/mobx.ts +0 -23
  81. package/src/util/node.ts +0 -543
  82. package/src/util/raf.ts +0 -28
  83. package/src/util/resize.ts +0 -606
  84. package/src/util/sampling.ts +0 -85
  85. package/src/util/theme.ts +0 -84
  86. package/src/util/uuid.ts +0 -26
  87. package/src/util/vector.ts +0 -93
  88. package/src/util/zIndex.ts +0 -6
  89. package/src/view/Anchor.tsx +0 -462
  90. package/src/view/Control.tsx +0 -510
  91. package/src/view/Graph.tsx +0 -141
  92. package/src/view/Rotate.tsx +0 -113
  93. package/src/view/behavior/dnd.ts +0 -162
  94. package/src/view/behavior/index.ts +0 -2
  95. package/src/view/behavior/snapline.ts +0 -16
  96. package/src/view/edge/AdjustPoint.tsx +0 -425
  97. package/src/view/edge/Arrow.tsx +0 -54
  98. package/src/view/edge/BaseEdge.tsx +0 -660
  99. package/src/view/edge/BezierEdge.tsx +0 -101
  100. package/src/view/edge/LineEdge.tsx +0 -81
  101. package/src/view/edge/PolylineEdge.tsx +0 -311
  102. package/src/view/edge/index.ts +0 -6
  103. package/src/view/index.ts +0 -8
  104. package/src/view/node/BaseNode.tsx +0 -585
  105. package/src/view/node/CircleNode.tsx +0 -21
  106. package/src/view/node/DiamondNode.tsx +0 -24
  107. package/src/view/node/EllipseNode.tsx +0 -22
  108. package/src/view/node/HtmlNode.tsx +0 -112
  109. package/src/view/node/PolygonNode.tsx +0 -28
  110. package/src/view/node/RectNode.tsx +0 -30
  111. package/src/view/node/TextNode.tsx +0 -39
  112. package/src/view/node/index.ts +0 -8
  113. package/src/view/overlay/BackgroundOverlay.tsx +0 -34
  114. package/src/view/overlay/BezierAdjustOverlay.tsx +0 -150
  115. package/src/view/overlay/CanvasOverlay.tsx +0 -290
  116. package/src/view/overlay/Grid.tsx +0 -319
  117. package/src/view/overlay/ModificationOverlay.tsx +0 -31
  118. package/src/view/overlay/OutlineOverlay.tsx +0 -158
  119. package/src/view/overlay/SnaplineOverlay.tsx +0 -44
  120. package/src/view/overlay/ToolOverlay.tsx +0 -65
  121. package/src/view/overlay/getTransformHoc.tsx +0 -50
  122. package/src/view/overlay/gridConfig.ts +0 -103
  123. package/src/view/overlay/index.ts +0 -8
  124. package/src/view/shape/Circle.tsx +0 -41
  125. package/src/view/shape/Ellipse.tsx +0 -42
  126. package/src/view/shape/Line.tsx +0 -39
  127. package/src/view/shape/Path.tsx +0 -22
  128. package/src/view/shape/Polygon.tsx +0 -54
  129. package/src/view/shape/Polyline.tsx +0 -31
  130. package/src/view/shape/Rect.tsx +0 -44
  131. package/src/view/shape/Text.tsx +0 -168
  132. package/src/view/shape/index.ts +0 -8
  133. package/src/view/text/BaseText.tsx +0 -134
  134. package/src/view/text/LineText.tsx +0 -168
  135. package/src/view/text/index.ts +0 -2
  136. package/stats.html +0 -4842
  137. package/tsconfig.json +0 -18
@@ -1,817 +0,0 @@
1
- import { get, assign, cloneDeep } from 'lodash-es'
2
- import { observable, action } from 'mobx'
3
- import { BaseEdgeModel } from '.'
4
- import { BaseNodeModel, RectNodeModel, CircleNodeModel, Model } from '..'
5
- import LogicFlow from '../../LogicFlow'
6
- import { ModelType, SegmentDirection } from '../../constant'
7
- import {
8
- isInNode,
9
- distance,
10
- getClosestRadiusCenter,
11
- inStraightLineOfRect,
12
- getCrossPointWithCircle,
13
- getCrossPointWithEllipse,
14
- getCrossPointWithPolygon,
15
- getPolylinePoints,
16
- getLongestEdge,
17
- getCrossPointInRect,
18
- isSegmentsInNode,
19
- isSegmentsCrossNode,
20
- segmentDirection,
21
- points2PointsList,
22
- pointFilter,
23
- } from '../../util'
24
-
25
- import Point = LogicFlow.Point
26
- import Position = LogicFlow.Position
27
- import AppendConfig = LogicFlow.AppendConfig
28
- import AnchorConfig = Model.AnchorConfig
29
-
30
- export class PolylineEdgeModel extends BaseEdgeModel {
31
- modelType = ModelType.POLYLINE_EDGE
32
- draggingPointList: Point[] = []
33
- @observable offset?: number
34
- @observable dbClickPosition?: Point
35
-
36
- initEdgeData(data: LogicFlow.EdgeConfig): void {
37
- const providedOffset = get(data, 'properties.offset')
38
- // 当用户未传入 offset 时,按“箭头与折线重叠长度 + 5”作为默认值
39
- // 其中“重叠长度”采用箭头样式中的 offset(沿边方向的长度)
40
- this.offset =
41
- typeof providedOffset === 'number'
42
- ? providedOffset
43
- : this.getDefaultOffset()
44
- if (data.pointsList) {
45
- const corrected = this.orthogonalizePath(data.pointsList)
46
- ;(data as any).pointsList = corrected
47
- this.pointsList = corrected
48
- }
49
- super.initEdgeData(data)
50
- }
51
-
52
- setAttributes() {
53
- const { offset: newOffset } = this.properties
54
- if (newOffset && newOffset !== this.offset) {
55
- this.offset = newOffset
56
- this.updatePoints()
57
- }
58
- }
59
-
60
- orthogonalizePath(points: Point[]): Point[] {
61
- // 输入非法或不足两点时直接返回副本
62
- if (!Array.isArray(points) || points.length < 2) {
63
- return points
64
- }
65
- // pushUnique: 向数组中添加唯一点,避免重复
66
- const pushUnique = (arr: Point[], p: Point) => {
67
- const last = arr[arr.length - 1]
68
- if (!last || last.x !== p.x || last.y !== p.y) {
69
- arr.push({ x: p.x, y: p.y })
70
- }
71
- }
72
- // isAxisAligned: 检查两点是否在同一条轴上
73
- const isAxisAligned = (a: Point, b: Point) => a.x === b.x || a.y === b.y
74
- // manhattanDistance: 计算两点在曼哈顿距离上的距离
75
- const manhattanDistance = (a: Point, b: Point) =>
76
- Math.abs(a.x - b.x) + Math.abs(a.y - b.y)
77
-
78
- // 1) 生成严格正交路径,尽量延续前一段方向以减少折点
79
- const orthogonal: Point[] = []
80
- pushUnique(orthogonal, points[0])
81
- // previousDirection: 记录前一段的方向,用于判断当前段的PreferredCorner
82
- let previousDirection: SegmentDirection | undefined
83
- // 遍历所有点对,生成正交路径
84
- for (let i = 0; i < points.length - 1; i++) {
85
- const current = orthogonal[orthogonal.length - 1]
86
- const next = points[i + 1]
87
- if (!current || !next) continue
88
-
89
- if (isAxisAligned(current, next)) {
90
- pushUnique(orthogonal, next)
91
- previousDirection =
92
- current.x === next.x
93
- ? SegmentDirection.VERTICAL
94
- : SegmentDirection.HORIZONTAL
95
- continue
96
- }
97
-
98
- const cornerHV: Point = { x: next.x, y: current.y }
99
- const cornerVH: Point = { x: current.x, y: next.y }
100
-
101
- // 根据前一段的方向,优先选择能延续该方向的拐角点,以减少折点数量;
102
- // 若前一段为垂直方向,则优先选择垂直-水平拐角(cornerVH);
103
- // 若前一段为水平方向,则优先选择水平-垂直拐角(cornerHV);
104
- // 若前一段无方向(初始情况),则比较两个拐角的曼哈顿距离,选更近者。
105
- const preferredCorner =
106
- previousDirection === SegmentDirection.VERTICAL
107
- ? cornerVH
108
- : previousDirection === SegmentDirection.HORIZONTAL
109
- ? cornerHV
110
- : manhattanDistance(current, cornerHV) <=
111
- manhattanDistance(current, cornerVH)
112
- ? cornerHV
113
- : cornerVH
114
-
115
- if (preferredCorner.x !== current.x || preferredCorner.y !== current.y) {
116
- pushUnique(orthogonal, preferredCorner)
117
- }
118
- pushUnique(orthogonal, next)
119
-
120
- const a = orthogonal[orthogonal.length - 2]
121
- const b = orthogonal[orthogonal.length - 1]
122
- previousDirection =
123
- a && b
124
- ? a.x === b.x
125
- ? SegmentDirection.VERTICAL
126
- : SegmentDirection.HORIZONTAL
127
- : previousDirection
128
- }
129
-
130
- // 2) 去除冗余共线中间点
131
- const simplified: Point[] = []
132
- for (let i = 0; i < orthogonal.length; i++) {
133
- const prev = orthogonal[i - 1]
134
- const curr = orthogonal[i]
135
- const next = orthogonal[i + 1]
136
- // 如果当前点与前一个点和后一个点在同一条水平线或垂直线上,则跳过该点,去除冗余的共线中间点
137
- if (
138
- prev &&
139
- curr &&
140
- next &&
141
- ((prev.x === curr.x && curr.x === next.x) || // 水平共线
142
- (prev.y === curr.y && curr.y === next.y)) // 垂直共线
143
- ) {
144
- continue
145
- }
146
- pushUnique(simplified, curr)
147
- }
148
-
149
- // 3) 保留原始起点与终点位置
150
- if (simplified.length >= 2) {
151
- simplified[0] = { x: points[0].x, y: points[0].y }
152
- simplified[simplified.length - 1] = {
153
- x: points[points.length - 1].x,
154
- y: points[points.length - 1].y,
155
- }
156
- }
157
-
158
- // 4) 结果校验:任意相邻段都必须为水平/垂直;失败则退化为起止两点
159
- const isOrthogonal =
160
- simplified.length < 2 ||
161
- simplified.every((_, idx, arr) => {
162
- if (idx === 0) return true
163
- return isAxisAligned(arr[idx - 1], arr[idx])
164
- })
165
-
166
- return isOrthogonal
167
- ? simplified
168
- : [
169
- { x: points[0].x, y: points[0].y },
170
- { x: points[points.length - 1].x, y: points[points.length - 1].y },
171
- ]
172
- }
173
-
174
- /**
175
- * 计算默认 offset:箭头与折线重叠长度 + 5
176
- * 重叠长度采用箭头样式中的 offset(沿边方向的长度)
177
- */
178
- private getDefaultOffset(): number {
179
- const arrowStyle = this.getArrowStyle()
180
- const arrowOverlap =
181
- typeof arrowStyle.offset === 'number' ? arrowStyle.offset : 0
182
- return arrowOverlap + 5
183
- }
184
-
185
- getEdgeStyle() {
186
- const { polyline } = this.graphModel.theme
187
- const style = super.getEdgeStyle()
188
- const { style: customStyle = {} } = this.properties
189
- return {
190
- ...style,
191
- ...cloneDeep(polyline),
192
- ...cloneDeep(customStyle),
193
- }
194
- }
195
-
196
- getTextPosition() {
197
- // 在文本为空的情况下,文本位置为双击位置
198
- const textValue = this.text?.value
199
- if (this.dbClickPosition && !textValue) {
200
- const { x, y } = this.dbClickPosition
201
- return { x, y }
202
- }
203
- // 文本不为空或者没有双击位置时,取最长边的中点作为文本位置
204
- const currentPositionList = points2PointsList(this.points)
205
- const [p1, p2] = getLongestEdge(currentPositionList)
206
- return {
207
- x: (p1.x + p2.x) / 2,
208
- y: (p1.y + p2.y) / 2,
209
- }
210
- }
211
-
212
- // 获取下一个锚点
213
- getAfterAnchor(
214
- direction: SegmentDirection,
215
- position: Position,
216
- anchorList: AnchorConfig[],
217
- ) {
218
- let anchor: AnchorConfig
219
- let minDistance: number
220
- anchorList.forEach((item) => {
221
- let distanceX: number
222
- if (direction === SegmentDirection.HORIZONTAL) {
223
- distanceX = Math.abs(position.y - item.y)
224
- } else if (direction === SegmentDirection.VERTICAL) {
225
- distanceX = Math.abs(position.x - item.x)
226
- }
227
- if (!minDistance || minDistance > distanceX!) {
228
- minDistance = distanceX!
229
- anchor = item
230
- }
231
- })
232
- return anchor!
233
- }
234
-
235
- /* 获取拖拽过程中产生的交点 */
236
- getCrossPoint(direction: SegmentDirection, start: Position, end: Position) {
237
- let position: Point
238
- if (direction === SegmentDirection.HORIZONTAL) {
239
- position = {
240
- x: end.x,
241
- y: start.y,
242
- }
243
- } else if (direction === SegmentDirection.VERTICAL) {
244
- position = {
245
- x: start.x,
246
- y: end.y,
247
- }
248
- }
249
- return position!
250
- }
251
-
252
- // 删除在图形内的过个交点
253
- removeCrossPoints(startIndex: number, endIndex: number, pointList: Point[]) {
254
- const list = pointList.map((i) => i)
255
- if (startIndex === 1) {
256
- const start = list[startIndex]
257
- const end = list[endIndex]
258
- const pre = list[startIndex - 1]
259
- const isInStartNode = isSegmentsInNode(pre, start, this.sourceNode)
260
- if (isInStartNode) {
261
- const isSegmentsCrossStartNode = isSegmentsCrossNode(
262
- start,
263
- end,
264
- this.sourceNode,
265
- )
266
- if (isSegmentsCrossStartNode) {
267
- const point = getCrossPointInRect(start, end, this.sourceNode)
268
- if (point) {
269
- list[startIndex] = point
270
- list.splice(startIndex - 1, 1)
271
- startIndex--
272
- endIndex--
273
- }
274
- }
275
- } else {
276
- const anchorList = this.sourceNode.anchors
277
- anchorList.forEach((item) => {
278
- if (
279
- (item.x === pre.x && item.x === start.x) ||
280
- (item.y === pre.y && item.y === start.y)
281
- ) {
282
- const distance1 = distance(item.x, item.y, start.x, start.y)
283
- const distance2 = distance(pre.x, pre.y, start.x, start.y)
284
- if (distance1 < distance2) {
285
- list[startIndex - 1] = item
286
- }
287
- }
288
- })
289
- }
290
- }
291
- if (endIndex === pointList.length - 2) {
292
- const start = list[startIndex]
293
- const end = list[endIndex]
294
- const next = list[endIndex + 1]
295
- const isInEndNode = isSegmentsInNode(end, next, this.targetNode)
296
- if (isInEndNode) {
297
- const isSegmentsCrossStartNode = isSegmentsCrossNode(
298
- start,
299
- end,
300
- this.targetNode,
301
- )
302
- if (isSegmentsCrossStartNode) {
303
- const point = getCrossPointInRect(start, end, this.targetNode)
304
- if (point) {
305
- list[endIndex] = point
306
- list.splice(endIndex + 1, 1)
307
- }
308
- }
309
- } else {
310
- const anchorList = this.targetNode.anchors
311
- anchorList.forEach((item) => {
312
- if (
313
- (item.x === next.x && item.x === end.x) ||
314
- (item.y === next.y && item.y === end.y)
315
- ) {
316
- const distance1 = distance(item.x, item.y, end.x, end.y)
317
- const distance2 = distance(next.x, next.y, end.x, end.y)
318
- if (distance1 < distance2) {
319
- list[endIndex + 1] = item
320
- }
321
- }
322
- })
323
- }
324
- }
325
- return list
326
- }
327
-
328
- // 获取在拖拽过程中可能产生的点
329
- getDraggingPoints(
330
- direction: SegmentDirection,
331
- positionType: string,
332
- position: Position,
333
- anchorList: AnchorConfig[],
334
- draggingPointList: Point[],
335
- ) {
336
- const pointList = draggingPointList.map((i) => i)
337
- const anchor = this.getAfterAnchor(direction, position, anchorList)
338
- const crossPoint = this.getCrossPoint(direction, position, anchor)
339
- if (positionType === 'start') {
340
- pointList.unshift(crossPoint)
341
- pointList.unshift(anchor)
342
- } else {
343
- pointList.push(crossPoint)
344
- pointList.push(anchor)
345
- }
346
- return pointList
347
- }
348
-
349
- // 更新相交点[起点,终点],更加贴近图形, 未修改observable不作为action
350
- updateCrossPoints(pointList: Point[]) {
351
- const list = pointList.map((i) => i)
352
- const start = pointList[0]
353
- const next = pointList[1]
354
- const pre = pointList[list.length - 2]
355
- const end = pointList[list.length - 1]
356
- const { sourceNode, targetNode } = this
357
- const sourceModelType = sourceNode.modelType
358
- const targetModelType = targetNode.modelType
359
- const startPointDirection = segmentDirection(start, next)!
360
- let startCrossPoint = list[0]
361
- switch (sourceModelType) {
362
- case ModelType.RECT_NODE:
363
- if ((sourceNode as RectNodeModel).radius !== 0) {
364
- const inInnerNode = inStraightLineOfRect(start, sourceNode)
365
- if (!inInnerNode) {
366
- startCrossPoint = getClosestRadiusCenter(
367
- start,
368
- startPointDirection,
369
- sourceNode,
370
- )
371
- }
372
- }
373
- break
374
- case ModelType.CIRCLE_NODE:
375
- startCrossPoint = getCrossPointWithCircle(
376
- start,
377
- startPointDirection,
378
- sourceNode as CircleNodeModel,
379
- )
380
- break
381
- case ModelType.ELLIPSE_NODE:
382
- startCrossPoint = getCrossPointWithEllipse(
383
- start,
384
- startPointDirection,
385
- sourceNode,
386
- )
387
- break
388
- case ModelType.DIAMOND_NODE:
389
- startCrossPoint = getCrossPointWithPolygon(
390
- start,
391
- startPointDirection,
392
- sourceNode,
393
- )
394
- break
395
- case ModelType.POLYGON_NODE:
396
- startCrossPoint = getCrossPointWithPolygon(
397
- start,
398
- startPointDirection,
399
- sourceNode,
400
- )
401
- break
402
- default:
403
- break
404
- }
405
- // 如果线段和形状没有交点时startCrossPoint会为undefined导致后续计算报错
406
- if (startCrossPoint) {
407
- list[0] = startCrossPoint
408
- }
409
- const endPointDirection = segmentDirection(pre, end)!
410
- let endCrossPoint = list[list.length - 1]
411
- switch (targetModelType) {
412
- case ModelType.RECT_NODE:
413
- if ((targetNode as RectNodeModel).radius !== 0) {
414
- const inInnerNode = inStraightLineOfRect(end, targetNode)
415
- if (!inInnerNode) {
416
- endCrossPoint = getClosestRadiusCenter(
417
- end,
418
- endPointDirection,
419
- targetNode,
420
- )
421
- }
422
- }
423
- break
424
- case ModelType.CIRCLE_NODE:
425
- endCrossPoint = getCrossPointWithCircle(
426
- end,
427
- endPointDirection,
428
- targetNode as CircleNodeModel,
429
- )
430
- break
431
- case ModelType.ELLIPSE_NODE:
432
- endCrossPoint = getCrossPointWithEllipse(
433
- end,
434
- endPointDirection,
435
- targetNode,
436
- )
437
- break
438
- case ModelType.DIAMOND_NODE:
439
- endCrossPoint = getCrossPointWithPolygon(
440
- end,
441
- endPointDirection,
442
- targetNode,
443
- )
444
- break
445
- case ModelType.POLYGON_NODE:
446
- endCrossPoint = getCrossPointWithPolygon(
447
- end,
448
- endPointDirection,
449
- targetNode,
450
- )
451
- break
452
- default:
453
- break
454
- }
455
- // 如果线段和形状没有交点时startCrossPoint会为undefined导致后续计算报错
456
- if (endCrossPoint) {
457
- list[list.length - 1] = endCrossPoint
458
- }
459
- return list
460
- }
461
-
462
- updatePath(pointList: Point[]) {
463
- this.pointsList = this.orthogonalizePath(pointList)
464
- this.points = this.getPath(this.pointsList)
465
- }
466
-
467
- getData() {
468
- const data = super.getData()
469
- const pointsList = this.pointsList.map(({ x, y }) => ({
470
- x,
471
- y,
472
- }))
473
- return Object.assign({}, data, {
474
- pointsList,
475
- })
476
- }
477
-
478
- getPath(points: Point[]): string {
479
- return points.map((point) => `${point.x},${point.y}`).join(' ')
480
- }
481
-
482
- @action
483
- initPoints() {
484
- if (this.pointsList.length > 0) {
485
- this.points = this.getPath(this.pointsList)
486
- } else {
487
- this.updatePoints()
488
- }
489
- }
490
-
491
- @action
492
- updatePoints() {
493
- const pointsList = getPolylinePoints(
494
- {
495
- x: this.startPoint.x,
496
- y: this.startPoint.y,
497
- },
498
- {
499
- x: this.endPoint.x,
500
- y: this.endPoint.y,
501
- },
502
- this.sourceNode,
503
- this.targetNode,
504
- this.offset || 0,
505
- )
506
- this.pointsList = this.orthogonalizePath(pointsList)
507
- this.points = this.pointsList
508
- .map((point) => `${point.x},${point.y}`)
509
- .join(' ')
510
- }
511
-
512
- @action
513
- updateStartPoint(anchor: Point) {
514
- this.startPoint = Object.assign({}, anchor)
515
- this.updatePoints()
516
- }
517
-
518
- @action
519
- moveStartPoint(deltaX: number, deltaY: number): void {
520
- this.startPoint.x += deltaX
521
- this.startPoint.y += deltaY
522
- this.updatePoints()
523
- // todo: 尽量保持边的整体轮廓, 通过deltaX和deltaY更新pointsList,而不是重新计算。
524
- }
525
-
526
- @action
527
- updateEndPoint(anchor: Point) {
528
- this.endPoint = Object.assign({}, anchor)
529
- this.updatePoints()
530
- }
531
-
532
- @action
533
- moveEndPoint(deltaX: number, deltaY: number): void {
534
- this.endPoint.x += deltaX
535
- this.endPoint.y += deltaY
536
- this.updatePoints()
537
- }
538
-
539
- @action
540
- updatePointsList(deltaX: number, deltaY: number): void {
541
- this.pointsList.forEach((item) => {
542
- item.x += deltaX
543
- item.y += deltaY
544
- })
545
- const startPoint = this.pointsList[0]
546
- this.startPoint = Object.assign({}, startPoint)
547
- const endPoint = this.pointsList[this.pointsList.length - 1]
548
- this.endPoint = Object.assign({}, endPoint)
549
- this.initPoints()
550
- }
551
-
552
- @action
553
- dragAppendStart() {
554
- // mobx observer 对象被iterator处理会有问题
555
- this.draggingPointList = this.pointsList.map((i) => i)
556
- }
557
-
558
- @action
559
- dragAppendSimple(
560
- appendInfo: AppendConfig,
561
- dragInfo: Record<'x' | 'y', number>,
562
- ) {
563
- // 因为drag事件是mouseDown事件触发的,因此当真实拖拽之后再设置isDragging
564
- // 避免因为点击事件造成,在dragStart触发之后,没有触发dragEnd错误设置了isDragging状态,对history计算造成错误
565
- this.isDragging = true
566
- const { start, end, startIndex, endIndex, direction } = appendInfo
567
- const { pointsList } = this
568
- let draggingPointList = pointsList
569
- if (direction === SegmentDirection.HORIZONTAL) {
570
- // 水平,仅调整y坐标,拿到当前线段两个端点移动后的坐标
571
- pointsList[startIndex] = {
572
- x: start.x,
573
- y: start.y + dragInfo.y,
574
- }
575
- pointsList[endIndex] = {
576
- x: end.x,
577
- y: end.y + dragInfo.y,
578
- }
579
- draggingPointList = this.pointsList.map((i) => i)
580
- } else if (direction === SegmentDirection.VERTICAL) {
581
- // 垂直,仅调整x坐标, 与水平调整同理
582
- pointsList[startIndex] = {
583
- x: start.x + dragInfo.x,
584
- y: start.y,
585
- }
586
- pointsList[endIndex] = {
587
- x: end.x + dragInfo.x,
588
- y: end.y,
589
- }
590
- draggingPointList = this.pointsList.map((i) => i)
591
- }
592
- this.updatePointsAfterDrag(draggingPointList)
593
- this.draggingPointList = draggingPointList
594
- // TODO: 判断该逻辑是否需要
595
- if (this.text?.value) {
596
- this.setText(assign({}, this.text, this.textPosition))
597
- }
598
- return {
599
- start: assign({}, pointsList[startIndex]),
600
- end: assign({}, pointsList[endIndex]),
601
- startIndex,
602
- endIndex,
603
- direction,
604
- }
605
- }
606
-
607
- @action
608
- dragAppend(appendInfo: AppendConfig, dragInfo: Record<'x' | 'y', number>) {
609
- this.isDragging = true
610
- const { start, end, startIndex, endIndex, direction } = appendInfo
611
- const { pointsList } = this
612
- if (direction === SegmentDirection.HORIZONTAL) {
613
- // 水平,仅调整y坐标
614
- // step1: 拿到当前线段两个端点移动后的坐标
615
- pointsList[startIndex] = {
616
- x: start.x,
617
- y: start.y + dragInfo.y,
618
- }
619
- pointsList[endIndex] = {
620
- x: end.x,
621
- y: end.y + dragInfo.y,
622
- }
623
- // step2: 计算拖拽后,两个端点与节点外框的交点
624
- // 定义一个拖住中节点list
625
- let draggingPointList = this.pointsList.map((i) => i)
626
- if (startIndex !== 0 && endIndex !== this.pointsList.length - 1) {
627
- // 2.1)如果线段没有连接起终点,过滤会穿插在图形内部的线段,取整个图形离线段最近的点
628
- draggingPointList = this.removeCrossPoints(
629
- startIndex,
630
- endIndex,
631
- draggingPointList,
632
- )
633
- }
634
- if (startIndex === 0) {
635
- // 2.2)如果线段连接了起点, 判断起点是否在节点内部
636
- const startPosition = {
637
- x: start.x,
638
- y: start.y + dragInfo.y,
639
- }
640
- const inNode = isInNode(startPosition, this.sourceNode)
641
- if (!inNode) {
642
- // 如果不在节点内部,更换起点为线段与节点的交点
643
- const anchorList = this.sourceNode.anchors
644
- draggingPointList = this.getDraggingPoints(
645
- direction,
646
- 'start',
647
- startPosition,
648
- anchorList,
649
- draggingPointList,
650
- )
651
- }
652
- }
653
- if (endIndex === this.pointsList.length - 1) {
654
- // 2.2)如果线段连接了终点, 判断起点是否在节点内部
655
- const endPosition = {
656
- x: end.x,
657
- y: end.y + dragInfo.y,
658
- }
659
- const inNode = isInNode(endPosition, this.targetNode)
660
- if (!inNode) {
661
- // 如果不在节点内部,更换终点为线段与节点的交点
662
- const anchorList = this.targetNode.anchors
663
- draggingPointList = this.getDraggingPoints(
664
- direction,
665
- 'end',
666
- endPosition,
667
- anchorList,
668
- draggingPointList,
669
- )
670
- }
671
- }
672
- this.updatePointsAfterDrag(draggingPointList)
673
- // step3: 调整到对应外框的位置后,执行updatePointsAfterDrag,找到当前线段和图形的准确交点
674
- this.draggingPointList = draggingPointList
675
- } else if (direction === SegmentDirection.VERTICAL) {
676
- // 垂直,仅调整x坐标, 与水平调整同理
677
- pointsList[startIndex] = {
678
- x: start.x + dragInfo.x,
679
- y: start.y,
680
- }
681
- pointsList[endIndex] = {
682
- x: end.x + dragInfo.x,
683
- y: end.y,
684
- }
685
- let draggingPointList = this.pointsList.map((i) => i)
686
- if (startIndex !== 0 && endIndex !== this.pointsList.length - 1) {
687
- draggingPointList = this.removeCrossPoints(
688
- startIndex,
689
- endIndex,
690
- draggingPointList,
691
- )
692
- }
693
- if (startIndex === 0) {
694
- const startPosition = {
695
- x: start.x + dragInfo.x,
696
- y: start.y,
697
- }
698
- const inNode = isInNode(startPosition, this.sourceNode)
699
- if (!inNode) {
700
- const anchorList = this.sourceNode.anchors
701
- draggingPointList = this.getDraggingPoints(
702
- direction,
703
- 'start',
704
- startPosition,
705
- anchorList,
706
- draggingPointList,
707
- )
708
- }
709
- }
710
- if (endIndex === this.pointsList.length - 1) {
711
- const endPosition = {
712
- x: end.x + dragInfo.x,
713
- y: end.y,
714
- }
715
- const inNode = isInNode(endPosition, this.targetNode)
716
- if (!inNode) {
717
- const anchorList = this.targetNode.anchors
718
- draggingPointList = this.getDraggingPoints(
719
- direction,
720
- 'end',
721
- endPosition,
722
- anchorList,
723
- draggingPointList,
724
- )
725
- }
726
- }
727
- this.updatePointsAfterDrag(draggingPointList)
728
- this.draggingPointList = draggingPointList
729
- }
730
- // TODO: 确认该判断逻辑是否需要
731
- if (this.text?.value) {
732
- this.setText(assign({}, this.text, this.textPosition))
733
- }
734
- return {
735
- start: assign({}, pointsList[startIndex]),
736
- end: assign({}, pointsList[endIndex]),
737
- startIndex,
738
- endIndex,
739
- direction,
740
- }
741
- }
742
-
743
- @action
744
- dragAppendEnd() {
745
- if (this.draggingPointList) {
746
- const pointsList = pointFilter(points2PointsList(this.points))
747
- // 更新pointsList,重新渲染appendWidth
748
- this.pointsList = pointsList.map((i) => i)
749
- // draggingPointList清空
750
- this.draggingPointList = []
751
- // 更新起终点
752
- const startPoint = pointsList[0]
753
- this.startPoint = assign({}, startPoint)
754
- const endPoint = pointsList[pointsList.length - 1]
755
- this.endPoint = assign({}, endPoint)
756
- }
757
- this.isDragging = false
758
- }
759
-
760
- /* 拖拽之后个更新points,仅更新边,不更新pointsList,
761
- appendWidth会依赖pointsList,更新pointsList会重新渲染appendWidth,从而导致不能继续拖拽
762
- 在拖拽结束后再进行pointsList的更新
763
- */
764
- @action
765
- updatePointsAfterDrag(pointsList: Point[]) {
766
- // 找到准确的连接点后,更新points, 更新边,同时更新依赖points的箭头
767
- const list = this.updateCrossPoints(pointsList)
768
- this.points = list.map((point) => `${point.x},${point.y}`).join(' ')
769
- }
770
-
771
- // 获取边调整的起点
772
- @action
773
- getAdjustStart() {
774
- return this.pointsList[0] || this.startPoint
775
- }
776
-
777
- // 获取边调整的终点
778
- @action
779
- getAdjustEnd() {
780
- const { pointsList } = this
781
- return pointsList[pointsList.length - 1] || this.endPoint
782
- }
783
-
784
- // 起终点拖拽调整过程中,进行折线路径更新
785
- @action
786
- updateAfterAdjustStartAndEnd({
787
- startPoint,
788
- endPoint,
789
- sourceNode,
790
- targetNode,
791
- }: {
792
- startPoint: Point
793
- endPoint: Point
794
- sourceNode: BaseNodeModel
795
- targetNode: BaseNodeModel
796
- }) {
797
- this.pointsList = this.orthogonalizePath(
798
- getPolylinePoints(
799
- {
800
- x: startPoint.x,
801
- y: startPoint.y,
802
- },
803
- {
804
- x: endPoint.x,
805
- y: endPoint.y,
806
- },
807
- sourceNode,
808
- targetNode,
809
- this.offset || 0,
810
- ),
811
- )
812
-
813
- this.initPoints()
814
- }
815
- }
816
-
817
- export default PolylineEdgeModel