@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,959 +0,0 @@
1
- import { action, computed, isObservable, observable, toJS } from 'mobx'
2
- import {
3
- assign,
4
- cloneDeep,
5
- has,
6
- isNil,
7
- mapKeys,
8
- isUndefined,
9
- set,
10
- } from 'lodash-es'
11
- import { GraphModel, Model } from '..'
12
- import LogicFlow from '../../LogicFlow'
13
- import {
14
- createUuid,
15
- formatData,
16
- getClosestAnchor,
17
- getZIndex,
18
- Matrix,
19
- pickNodeConfig,
20
- TranslateMatrix,
21
- } from '../../util'
22
- import {
23
- ElementState,
24
- ElementType,
25
- EventType,
26
- ModelType,
27
- OverlapMode,
28
- TextMode,
29
- } from '../../constant'
30
- import { ResizeControl } from '../../view/Control'
31
- import AnchorConfig = Model.AnchorConfig
32
- import GraphElements = LogicFlow.GraphElements
33
- import TextConfig = LogicFlow.TextConfig
34
- import NodeConfig = LogicFlow.NodeConfig
35
- import NodeData = LogicFlow.NodeData
36
- import Point = LogicFlow.Point
37
- import CommonTheme = LogicFlow.CommonTheme
38
- import PropertiesType = LogicFlow.PropertiesType
39
-
40
- import ResizeInfo = ResizeControl.ResizeInfo
41
- import ResizeNodeData = ResizeControl.ResizeNodeData
42
- import PCTResizeParams = ResizeControl.PCTResizeParams
43
-
44
- export interface IBaseNodeModel<P extends PropertiesType>
45
- extends Model.BaseModel<P> {
46
- /**
47
- * model基础类型,固定为node
48
- */
49
- readonly BaseType: ElementType.NODE
50
- properties: P
51
-
52
- isDragging: boolean
53
- isShowAnchor: boolean
54
- getNodeStyle: () => CommonTheme
55
- getTextStyle: () => LogicFlow.TextNodeTheme
56
- setIsShowAnchor: (isShowAnchor: boolean) => void
57
- }
58
-
59
- export class BaseNodeModel<P extends PropertiesType = PropertiesType>
60
- implements IBaseNodeModel<P> {
61
- readonly BaseType = ElementType.NODE
62
- static BaseType: ElementType = ElementType.NODE
63
-
64
- // 数据属性
65
- public id = ''
66
- @observable readonly type = ''
67
- @observable x = 0
68
- @observable y = 0
69
- @observable textMode = TextMode.TEXT
70
- @observable text: TextConfig = {
71
- value: '',
72
- x: 0,
73
- y: 0,
74
- draggable: false,
75
- editable: true,
76
- }
77
- @observable properties: P
78
- // 形状属性
79
- @observable private _width = 100
80
- public get width() {
81
- return this._width
82
- }
83
-
84
- public set width(value: number) {
85
- this._width = value
86
- }
87
-
88
- @observable private _height = 80
89
- public get height() {
90
- return this._height
91
- }
92
-
93
- public set height(value: number) {
94
- this._height = value
95
- }
96
-
97
- minWidth: number = 30
98
- minHeight: number = 30
99
- maxWidth: number = 2000
100
- maxHeight: number = 2000
101
- PCTResizeInfo?: PCTResizeParams
102
-
103
- // 根据与 (x, y) 的偏移量计算 anchors 的坐标
104
- @observable anchorsOffset: BaseNodeModel.AnchorsOffsetItem[] = []
105
-
106
- // 状态属性
107
- readonly virtual: boolean = false
108
- @observable isSelected = false
109
- @observable isHovered = false
110
- @observable isShowAnchor = false
111
- @observable isDragging = false
112
- @observable isHitable = true // TODO: 兼容拼写错误的情况 Remove
113
- @observable isHittable = true // 细粒度控制节点是否对用户操作进行反应
114
- @observable draggable = true
115
- @observable visible = true
116
-
117
- @observable rotatable = true // 节点可旋转
118
- @observable resizable = true // 节点可缩放
119
-
120
- // 其它属性
121
- graphModel: GraphModel
122
- @observable zIndex = 1
123
- @observable state = ElementState.DEFAULT
124
- @observable autoToFront = true // 节点选中时是否自动置顶,默认为true.
125
- @observable style: CommonTheme = {} // 每个节点自己的样式,动态修改
126
-
127
- // TODO: 利用向量计算实现 平移、旋转、缩放 等操作,利用 svg 的 transform 属性
128
- @observable transform!: string // 节点的transform属性
129
- @observable private _rotate = 0
130
- get rotate() {
131
- return this._rotate
132
- }
133
-
134
- set rotate(value: number) {
135
- this._rotate = value
136
- const { x = 0, y = 0 } = this
137
- this.transform = new TranslateMatrix(-x, -y)
138
- .rotate(value)
139
- .translate(x, y)
140
- .toString()
141
- }
142
-
143
- modelType = ModelType.NODE
144
- additionStateData?: Model.AdditionStateDataType = {}
145
-
146
- // 节点连入、练出、移动等规则
147
- targetRules: Model.ConnectRule[] = []
148
- sourceRules: Model.ConnectRule[] = []
149
- moveRules: Model.NodeMoveRule[] = [] // 节点移动之前的hook
150
- resizeRules: Model.NodeResizeRule[] = [] // 节点resize之前的hook
151
- hasSetTargetRules = false // 用来限制rules的重复值
152
- hasSetSourceRules = false; // 用来限制rules的重复值
153
- [propName: string]: any // 支持用户自定义属性
154
-
155
- constructor(data: NodeConfig<P>, graphModel: GraphModel) {
156
- this.graphModel = graphModel
157
- this.properties = data.properties ?? ({} as P)
158
-
159
- this.initNodeData(data)
160
- this.setAttributes()
161
- }
162
-
163
- /**
164
- * 获取进入当前节点的边和节点
165
- */
166
- @computed get incoming(): GraphElements {
167
- return {
168
- nodes: this.graphModel.getNodeIncomingNode(this.id),
169
- edges: this.graphModel.getNodeIncomingEdge(this.id),
170
- }
171
- }
172
-
173
- /*
174
- * 获取离开当前节点的边和节点
175
- */
176
- @computed get outgoing(): GraphElements {
177
- return {
178
- nodes: this.graphModel.getNodeOutgoingNode(this.id),
179
- edges: this.graphModel.getNodeOutgoingEdge(this.id),
180
- }
181
- }
182
-
183
- /**
184
- * @overridable 可以重写
185
- * 初始化节点数据
186
- * initNodeData 和 setAttributes 的区别在于
187
- * initNodeData 只在节点初始化的时候调用,用于初始化节点的所有属性。
188
- * setAttributes 除了初始化调用外,还会在 properties 发生变化了调用。
189
- */
190
- public initNodeData(data: NodeConfig) {
191
- if (!data.properties) {
192
- data.properties = {}
193
- }
194
-
195
- if (!data.id) {
196
- // 自定义节点id > 全局定义id > 内置
197
- const { idGenerator } = this.graphModel
198
- const globalId = idGenerator && idGenerator(data.type)
199
- const nodeId = this.createId()
200
- data.id = nodeId || globalId || createUuid()
201
- }
202
-
203
- this.formatText(data)
204
- // 在下面又将 NodeConfig 中的数据赋值给了 this,应该会触发 setAttributes,确认是否符合预期
205
- // TODO: 确认 constructor 中赋值 properties 是否必要,此处将 NodeConfig 中所有属性赋值给 this,包括 rotate、rotatable,resizable 等
206
- assign(this, pickNodeConfig(data))
207
-
208
- const { overlapMode, eventCenter } = this.graphModel
209
- this.updateZIndexByOverlap(overlapMode, data.zIndex || getZIndex())
210
- eventCenter.on('overlap:change', (data) => {
211
- const { overlapMode: newMode } = data
212
- this.updateZIndexByOverlap(newMode, this.zIndex || getZIndex())
213
- })
214
- }
215
-
216
- /**
217
- * 设置model属性,每次properties发生变化会触发
218
- * 例如设置节点的宽度
219
- * @example
220
- *
221
- * setAttributes () {
222
- * this.width = 300
223
- * this.height = 200
224
- * }
225
- *
226
- * @overridable 支持重写
227
- */
228
- public setAttributes() { }
229
-
230
- /**
231
- * @overridable 支持重写,自定义此类型节点默认生成方式
232
- * @returns string | null
233
- */
234
- public createId(): string | null {
235
- return null
236
- }
237
-
238
- /**
239
- * 设置当前元素的文本模式
240
- * @param mode
241
- */
242
- @action setTextMode(mode: TextMode) {
243
- this.textMode = mode
244
- }
245
-
246
- /**
247
- * 始化文本属性
248
- */
249
- private formatText(data: NodeConfig): void {
250
- const {
251
- editConfigModel: { nodeTextDraggable, nodeTextEdit },
252
- } = this.graphModel
253
- const { x, y, text } = data
254
- let textConfig: TextConfig = {
255
- value: '',
256
- x,
257
- y,
258
- draggable: nodeTextDraggable,
259
- editable: nodeTextEdit,
260
- }
261
- if (text) {
262
- if (typeof text === 'string') {
263
- textConfig.value = text
264
- } else {
265
- textConfig = {
266
- ...textConfig,
267
- x: text.x ?? x,
268
- y: text.y ?? y,
269
- value: text.value ?? '',
270
- }
271
- if (!isUndefined(text.draggable)) {
272
- textConfig.draggable = text.draggable
273
- }
274
- if (!isUndefined(text.editable)) {
275
- textConfig.editable = text.editable
276
- }
277
- }
278
- }
279
-
280
- data.text = textConfig
281
- }
282
-
283
- /**
284
- * @overridable 支持重写
285
- * 计算节点 resize 时
286
- */
287
- resize(resizeInfo: ResizeInfo): ResizeNodeData {
288
- const { width, height, deltaX, deltaY } = resizeInfo
289
-
290
- const isAllowResize = this.isAllowResizeNode(deltaX, deltaY, width, height)
291
-
292
- if (!isAllowResize) {
293
- return this.getData()
294
- }
295
-
296
- // 移动节点以及文本内容
297
- this.move(deltaX / 2, deltaY / 2)
298
-
299
- this.width = width
300
- this.height = height
301
- this.setProperties({
302
- width,
303
- height,
304
- })
305
- return this.getData()
306
- }
307
-
308
- // TODO: 等比例缩放
309
- proportionalResize() { }
310
-
311
- /**
312
- * 获取被保存时返回的数据
313
- * @overridable 支持重写
314
- */
315
- getData(): NodeData {
316
- const { x, y, value } = this.text
317
- let { properties } = this
318
- if (isObservable(properties)) {
319
- properties = toJS(properties)
320
- }
321
- if (isNil(properties.width)) {
322
- // resize()的时候会触发this.setProperties({width,height})
323
- // 然后返回getData(),可以从properties拿到width
324
- // 但是初始化如果没有在properties传入width,那么getData()就一直无法从properties拿到width
325
- properties.width = this.width
326
- }
327
- if (isNil(properties.height)) {
328
- // resize()的时候会触发this.setProperties({width,height})
329
- // 然后返回getData(),可以从properties拿到height
330
- // 但是初始化如果没有在properties传入height,那么getData()就一直无法从properties拿到width
331
- properties.height = this.height
332
- }
333
- const data: NodeData = {
334
- id: this.id,
335
- type: this.type,
336
- x: this.x,
337
- y: this.y,
338
- properties,
339
- }
340
- if (this.rotate) {
341
- data.rotate = this.rotate
342
- }
343
- // 因为默认模式和节点在上模式下,对边的zIndex要求不高(因为渲染的时候会按照模式对所有元素进行排序)
344
- // 所以只在递增模式和静态模式下设置zIndex
345
- if (
346
- [OverlapMode.INCREASE, OverlapMode.STATIC].includes(
347
- this.graphModel.overlapMode,
348
- )
349
- ) {
350
- data.zIndex = this.zIndex
351
- }
352
- if (value) {
353
- data.text = {
354
- x,
355
- y,
356
- value,
357
- }
358
- }
359
- return data
360
- }
361
-
362
- /**
363
- * 用于在历史记录时获取节点数据,
364
- * 在某些情况下,如果希望某个属性变化不引起history的变化,
365
- * 可以重写此方法。
366
- */
367
- getHistoryData(): NodeData {
368
- return this.getData()
369
- }
370
-
371
- /**
372
- * 获取当前节点的properties
373
- */
374
- getProperties() {
375
- return toJS(this.properties)
376
- }
377
-
378
- /**
379
- * @overridable 支持重写
380
- * 获取当前节点最外层g标签Attributes, 例如 className
381
- * @returns 自定义节点样式
382
- */
383
- getOuterGAttributes(): LogicFlow.DomAttributes {
384
- return {
385
- className: '',
386
- }
387
- }
388
-
389
- /**
390
- * @overridable 支持重写
391
- * 获取当前节点样式
392
- * @returns 自定义节点样式
393
- */
394
- getNodeStyle(): CommonTheme {
395
- return {
396
- ...this.graphModel.theme.baseNode,
397
- ...this.style,
398
- }
399
- }
400
-
401
- /**
402
- * @overridable 支持重写
403
- * 获取当前节点文本样式
404
- */
405
- getTextStyle() {
406
- // 透传 nodeText
407
- const { nodeText } = this.graphModel.theme
408
- const { textStyle = {} } = this.properties
409
- return {
410
- ...cloneDeep(nodeText),
411
- ...cloneDeep(textStyle),
412
- }
413
- }
414
-
415
- /**
416
- * @overridable 支持重写
417
- * 获取当前节点旋转控制点的样式
418
- */
419
- getRotateControlStyle(): CommonTheme {
420
- const { rotateControl } = this.graphModel.theme
421
- return cloneDeep(rotateControl)
422
- }
423
-
424
- /**
425
- * @overrideable 支持重写
426
- * 获取当前节点缩放控制节点的样式
427
- */
428
- getResizeControlStyle() {
429
- const { resizeControl } = this.graphModel.theme
430
- return cloneDeep(resizeControl)
431
- }
432
-
433
- getResizeOutlineStyle() {
434
- const { resizeOutline } = this.graphModel.theme
435
- let attributes = { ...resizeOutline }
436
- if (this.isHovered) {
437
- const hoverStyle = resizeOutline.hover || {}
438
- attributes = {
439
- ...attributes,
440
- ...hoverStyle,
441
- }
442
- }
443
- return cloneDeep(attributes)
444
- }
445
-
446
- /**
447
- * @overridable 支持重写
448
- * 获取当前节点锚点样式
449
- * @returns 自定义样式
450
- */
451
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
452
- getAnchorStyle(_anchorInfo?: Point): LogicFlow.AnchorTheme {
453
- const { anchor } = this.graphModel.theme
454
- // 防止被重写覆盖主题。
455
- return cloneDeep(anchor)
456
- }
457
-
458
- /**
459
- * @overridable 支持重写
460
- * 获取当前节点锚点拖出连线样式
461
- * @returns 自定义锚点拖出样式
462
- */
463
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
464
- getAnchorLineStyle(_anchorInfo?: Point): LogicFlow.AnchorLineTheme {
465
- const { anchorLine } = this.graphModel.theme
466
- return cloneDeep(anchorLine)
467
- }
468
-
469
- /**
470
- * @overridable 支持重写
471
- * 获取outline样式,重写可以定义此类型节点outline样式, 默认使用主题样式
472
- * @returns 自定义outline样式
473
- */
474
- getOutlineStyle(): LogicFlow.OutlineTheme {
475
- const { outline } = this.graphModel.theme
476
- return cloneDeep(outline)
477
- }
478
-
479
- /**
480
- * @overridable 在连接边时,是否允许这个节点为 source 节点,边到 target 节点
481
- * @param target 目标节点
482
- * @param sourceAnchor 源锚点
483
- * @param targetAnchor 目标锚点
484
- * @param edgeId 调整后边的 id,在开启 adjustEdgeStartAndEnd 后调整边连接的节点时会传入
485
- * 详见:https://github.com/didi/LogicFlow/issues/926#issuecomment-1371823306
486
- */
487
- isAllowConnectedAsSource(
488
- target: BaseNodeModel,
489
- sourceAnchor?: Model.AnchorConfig,
490
- targetAnchor?: Model.AnchorConfig,
491
- edgeId?: string,
492
- ): Model.ConnectRuleResult {
493
- const rules = !this.hasSetSourceRules
494
- ? this.getConnectedSourceRules()
495
- : this.sourceRules
496
- this.hasSetSourceRules = true
497
- let isAllPass = true
498
- let msg: string = ''
499
- for (let i = 0; i < rules.length; i++) {
500
- const rule = rules[i]
501
- if (
502
- !rule.validate.call(
503
- this,
504
- this,
505
- target,
506
- sourceAnchor,
507
- targetAnchor,
508
- edgeId,
509
- )
510
- ) {
511
- isAllPass = false
512
- msg = rule.message
513
- break
514
- }
515
- }
516
- return {
517
- isAllPass,
518
- msg,
519
- }
520
- }
521
-
522
- /**
523
- * 获取当前节点作为连接的起始节点规则。
524
- */
525
- getConnectedSourceRules(): Model.ConnectRule[] {
526
- return this.sourceRules
527
- }
528
-
529
- /**
530
- * @overridable 在连线时,判断是否允许这个节点为 target 节点
531
- * @param source 源节点
532
- * @param sourceAnchor 源锚点
533
- * @param targetAnchor 目标锚点
534
- * @param edgeId 调整后边的 id,在开启 adjustEdgeStartAndEnd 后调整边连接的节点时会传入
535
- * 详见:https://github.com/didi/LogicFlow/issues/926#issuecomment-1371823306
536
- */
537
- isAllowConnectedAsTarget(
538
- source: BaseNodeModel,
539
- sourceAnchor?: Model.AnchorConfig,
540
- targetAnchor?: Model.AnchorConfig,
541
- edgeId?: string,
542
- ): Model.ConnectRuleResult {
543
- const rules = !this.hasSetTargetRules
544
- ? this.getConnectedTargetRules()
545
- : this.targetRules
546
- this.hasSetTargetRules = true
547
- let isAllPass = true
548
- let msg: string = ''
549
- for (let i = 0; i < rules.length; i++) {
550
- const rule = rules[i]
551
- if (
552
- !rule.validate.call(
553
- this,
554
- source,
555
- this,
556
- sourceAnchor,
557
- targetAnchor,
558
- edgeId,
559
- )
560
- ) {
561
- isAllPass = false
562
- msg = rule.message
563
- break
564
- }
565
- }
566
- return {
567
- isAllPass,
568
- msg,
569
- }
570
- }
571
-
572
- /**
573
- * 内部方法
574
- * 是否允许移动节点到新的位置
575
- */
576
- isAllowMoveNode(deltaX: number, deltaY: number): boolean | Model.IsAllowMove {
577
- let isAllowMoveX = true
578
- let isAllowMoveY = true
579
- const rules = this.moveRules.concat(this.graphModel.nodeMoveRules)
580
- for (const rule of rules) {
581
- const r = rule(this, deltaX, deltaY)
582
- if (!r) return false
583
- if (typeof r === 'object') {
584
- const r1 = r as Model.IsAllowMove
585
- if (!r1.x && !r1.y) {
586
- return false
587
- }
588
- isAllowMoveX = isAllowMoveX && r1.x
589
- isAllowMoveY = isAllowMoveY && r1.y
590
- }
591
- }
592
- return {
593
- x: isAllowMoveX,
594
- y: isAllowMoveY,
595
- }
596
- }
597
-
598
- /**
599
- * 获取作为连线终点时的所有规则。
600
- */
601
- getConnectedTargetRules(): Model.ConnectRule[] {
602
- return this.targetRules
603
- }
604
-
605
- /**
606
- * @returns Point[] 锚点坐标构成的数组
607
- */
608
- getAnchorsByOffset(): Model.AnchorConfig[] {
609
- const { anchorsOffset, id, x, y } = this
610
- if (anchorsOffset && anchorsOffset.length > 0) {
611
- return anchorsOffset.map((el, idx) => {
612
- if (el.length) {
613
- el = el as LogicFlow.PointTuple // 历史数据格式
614
- return {
615
- id: `${id}_${idx}`,
616
- x: x + el[0],
617
- y: y + el[1],
618
- }
619
- }
620
- el = el as Model.AnchorConfig
621
- return {
622
- ...el,
623
- x: x + el.x,
624
- y: y + el.y,
625
- id: el.id || `${id}_${idx}`,
626
- }
627
- })
628
- }
629
- return this.getDefaultAnchor()
630
- }
631
-
632
- /**
633
- * @overridable 子类重写此方法设置默认锚点
634
- * 获取节点默认情况下的锚点
635
- */
636
- public getDefaultAnchor(): Model.AnchorConfig[] {
637
- return []
638
- }
639
-
640
- /**
641
- * @overridable 子类重写此方法获取手动连接边到节点时,需要连接的锚点
642
- * 手动连接边到节点时,需要连接的锚点
643
- */
644
- public getTargetAnchor(position: Point): Model.AnchorInfo {
645
- const { customTargetAnchor } = this.graphModel
646
- return (
647
- customTargetAnchor?.(this, position) ?? getClosestAnchor(position, this)
648
- )
649
- }
650
-
651
- /**
652
- * 获取节点BBox
653
- */
654
- public getBounds(): Model.BoxBoundsPoint {
655
- return {
656
- minX: this.x - this.width / 2,
657
- minY: this.y - this.height / 2,
658
- maxX: this.x + this.width / 2,
659
- maxY: this.y + this.height / 2,
660
- }
661
- }
662
-
663
- get anchors(): Model.AnchorConfig[] {
664
- const anchors = this.getAnchorsByOffset()
665
- const { x, y, rotate } = this
666
- anchors.forEach((anchor) => {
667
- const { x: anchorX, y: anchorY } = anchor
668
- const [e, f] = new Matrix([anchorX, anchorY, 1])
669
- .translate(-x, -y)
670
- .rotate(rotate)
671
- .translate(x, y)[0]
672
- anchor.x = e
673
- anchor.y = f
674
- })
675
- return anchors
676
- }
677
-
678
- getAnchorInfo(anchorId: string | undefined): AnchorConfig | undefined {
679
- if (isNil(anchorId)) return undefined
680
-
681
- for (let i = 0; i < this.anchors.length; i++) {
682
- const anchor = this.anchors[i]
683
- if (anchor.id === anchorId) {
684
- return anchor
685
- }
686
- }
687
- }
688
-
689
- @action addNodeMoveRules(fn: Model.NodeMoveRule) {
690
- if (!this.moveRules.includes(fn)) {
691
- this.moveRules.push(fn)
692
- }
693
- }
694
-
695
- isAllowMoveByXORY(deltaX: number, deltaY: number, isIgnoreRule: boolean) {
696
- let isAllowMoveX: boolean
697
- let isAllowMoveY: boolean
698
- if (isIgnoreRule) {
699
- isAllowMoveX = true
700
- isAllowMoveY = true
701
- } else {
702
- const r = this.isAllowMoveNode(deltaX, deltaY)
703
- if (typeof r === 'boolean') {
704
- isAllowMoveX = r
705
- isAllowMoveY = r
706
- } else {
707
- isAllowMoveX = r.x
708
- isAllowMoveY = r.y
709
- }
710
- }
711
- return {
712
- isAllowMoveX,
713
- isAllowMoveY,
714
- }
715
- }
716
-
717
- @action move(deltaX: number, deltaY: number, isIgnoreRule = false): boolean {
718
- const { isAllowMoveX, isAllowMoveY } = this.isAllowMoveByXORY(
719
- deltaX,
720
- deltaY,
721
- isIgnoreRule,
722
- )
723
- if (isAllowMoveX) {
724
- this.x = this.x + deltaX
725
- this.text && this.moveText(deltaX, 0)
726
- }
727
- if (isAllowMoveY) {
728
- this.y = this.y + deltaY
729
- this.text && this.moveText(0, deltaY)
730
- }
731
- if (isAllowMoveX || isAllowMoveY) {
732
- // 更新x和y的同时也要更新对应的transform旋转矩阵(依赖x、y)
733
- this.rotate = this._rotate
734
- }
735
- return isAllowMoveX || isAllowMoveY
736
- }
737
-
738
- @action getMoveDistance(
739
- deltaX: number,
740
- deltaY: number,
741
- isIgnoreRule = false,
742
- ): [number, number] {
743
- const { isAllowMoveX, isAllowMoveY } = this.isAllowMoveByXORY(
744
- deltaX,
745
- deltaY,
746
- isIgnoreRule,
747
- )
748
- let moveX = 0
749
- let moveY = 0
750
-
751
- if (isAllowMoveX && deltaX) {
752
- this.x = this.x + deltaX
753
- this.text && this.moveText(deltaX, 0)
754
- moveX = deltaX
755
- }
756
- if (isAllowMoveY && deltaY) {
757
- this.y = this.y + deltaY
758
- this.text && this.moveText(0, deltaY)
759
- moveY = deltaY
760
- }
761
- this.transform = new TranslateMatrix(-this.x, -this.y)
762
- .rotate(this.rotate)
763
- .translate(this.x, this.y)
764
- .toString()
765
- return [moveX, moveY]
766
- }
767
-
768
- @action moveTo(x: number, y: number, isIgnoreRule = false): boolean {
769
- const deltaX = x - this.x
770
- const deltaY = y - this.y
771
- if (!isIgnoreRule && !this.isAllowMoveNode(deltaX, deltaY)) return false
772
-
773
- this.text && this.moveText(deltaX, deltaY)
774
- this.x = x
775
- this.y = y
776
- return true
777
- }
778
-
779
- @action moveText(deltaX: number, deltaY: number): void {
780
- const { x, y, value, draggable, editable } = this.text
781
- this.text = {
782
- value,
783
- editable,
784
- draggable,
785
- x: x + deltaX,
786
- y: y + deltaY,
787
- }
788
- }
789
-
790
- @action updateText(value: string): void {
791
- this.text = {
792
- ...toJS(this.text),
793
- value,
794
- }
795
- }
796
-
797
- @action addNodeResizeRules(fn: Model.NodeResizeRule) {
798
- if (!this.resizeRules.includes(fn)) {
799
- this.resizeRules.push(fn)
800
- }
801
- }
802
-
803
- /**
804
- * 内部方法
805
- * 是否允许resize节点到新的位置
806
- */
807
- isAllowResizeNode(
808
- deltaX: number,
809
- deltaY: number,
810
- width: number,
811
- height: number,
812
- ): boolean {
813
- const rules = this.resizeRules.concat(this.graphModel.nodeResizeRules)
814
- for (const rule of rules) {
815
- const r = rule(this, deltaX, deltaY, width, height)
816
- if (!r) return false
817
- }
818
- return true
819
- }
820
-
821
- @action setSelected(flag = true): void {
822
- this.isSelected = flag
823
- }
824
-
825
- @action setHovered(flag = true): void {
826
- this.isHovered = flag
827
- this.setIsShowAnchor(flag)
828
- }
829
-
830
- @action setIsShowAnchor(flag = true): void {
831
- this.isShowAnchor = flag
832
- }
833
-
834
- @action setRotatable(flag = true): void {
835
- this.rotatable = flag
836
- }
837
-
838
- @action setResizable(flag = true): void {
839
- this.resizable = flag
840
- }
841
-
842
- @action setHitable(flag = true): void {
843
- this.isHitable = flag
844
- }
845
-
846
- @action setHittable(flag = true): void {
847
- this.isHittable = flag
848
- }
849
-
850
- @action setElementState(
851
- state: number,
852
- additionStateData?: Model.AdditionStateDataType,
853
- ): void {
854
- this.state = state
855
- this.additionStateData = additionStateData
856
- }
857
-
858
- private updateProperties(nextProperties: P, updateKeys: string[]): void {
859
- const preProperties = toJS(this.properties)
860
- this.properties = nextProperties
861
- this.setAttributes()
862
-
863
- // 触发更新节点 node:properties-change 的事件
864
- this.graphModel.eventCenter.emit(EventType.NODE_PROPERTIES_CHANGE, {
865
- id: this.id,
866
- keys: updateKeys,
867
- preProperties,
868
- properties: nextProperties,
869
- })
870
- }
871
-
872
- @action setProperty(key: string, val: any): void {
873
- const preProperties = toJS(this.properties)
874
- const nextProperties = cloneDeep(preProperties)
875
- // https://lodash.com/docs/4.17.15#set
876
- // 使用 lodash 的 set 方法更新某个属性,可以支持 key 为 'a.b.c' 的情况
877
- set(nextProperties, key, formatData(val))
878
-
879
- this.updateProperties(nextProperties, [key])
880
- }
881
-
882
- @action setProperties(properties: Record<string, any>): void {
883
- const preProperties = toJS(this.properties)
884
- const nextProperties = {
885
- ...preProperties,
886
- ...formatData(properties),
887
- }
888
-
889
- const updateKeys: string[] = []
890
- mapKeys(properties, (val, key) => {
891
- // key 存在于上一个 properties 并且与传入的值不相等 或者 key 不存在于上一个 properties
892
- if (
893
- (has(preProperties, key) && preProperties[key] !== val) ||
894
- !has(preProperties, key)
895
- ) {
896
- updateKeys.push(key)
897
- }
898
- })
899
-
900
- this.updateProperties(nextProperties, updateKeys)
901
- }
902
-
903
- @action deleteProperty(key: string): void {
904
- delete this.properties[key]
905
- this.setAttributes()
906
- }
907
-
908
- @action setStyle(key: string, val: any): void {
909
- this.style = {
910
- ...this.style,
911
- [key]: formatData(val),
912
- }
913
- }
914
-
915
- @action setStyles(styles: Record<string, any>): void {
916
- this.style = {
917
- ...this.style,
918
- ...formatData(styles),
919
- }
920
- }
921
-
922
- @action updateStyles(styles: Record<string, any>): void {
923
- this.style = {
924
- ...formatData(styles),
925
- }
926
- }
927
-
928
- @action setZIndex(zIndex = 1): void {
929
- this.zIndex = zIndex
930
- }
931
-
932
- @action updateAttributes(attributes: any) {
933
- assign(this, attributes)
934
- }
935
- // 堆叠模式变化时,更新zIndex
936
- @action
937
- updateZIndexByOverlap(overlapMode: OverlapMode, defaultZIndex) {
938
- switch (overlapMode) {
939
- case OverlapMode.DEFAULT:
940
- this.zIndex = 1
941
- break
942
- case OverlapMode.EDGE_TOP:
943
- this.zIndex = 0
944
- break
945
- case OverlapMode.INCREASE:
946
- this.zIndex = defaultZIndex
947
- break
948
- default:
949
- break
950
- }
951
- }
952
- }
953
-
954
- export namespace BaseNodeModel {
955
- export type PointTuple = [number, number]
956
- export type AnchorsOffsetItem = PointTuple | Point
957
- }
958
-
959
- export default BaseNodeModel