@logicflow/core 2.0.5 → 2.0.7

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 (76) hide show
  1. package/.turbo/turbo-build$colon$dev.log +10 -10
  2. package/.turbo/turbo-build.log +33 -33
  3. package/CHANGELOG.md +29 -0
  4. package/__tests__/algorithm/egde.test.ts +36 -23
  5. package/dist/index.min.js +1 -1
  6. package/dist/index.min.js.map +1 -1
  7. package/es/algorithm/rotate.d.ts +31 -0
  8. package/es/algorithm/rotate.js +43 -0
  9. package/es/event/eventArgs.d.ts +23 -29
  10. package/es/model/BaseModel.d.ts +9 -0
  11. package/es/model/GraphModel.d.ts +17 -1
  12. package/es/model/GraphModel.js +37 -2
  13. package/es/model/edge/BaseEdgeModel.d.ts +1 -0
  14. package/es/model/node/BaseNodeModel.d.ts +7 -0
  15. package/es/model/node/BaseNodeModel.js +55 -2
  16. package/es/util/drag.d.ts +1 -0
  17. package/es/util/drag.js +11 -0
  18. package/es/util/graph.d.ts +1 -1
  19. package/es/util/resize.d.ts +23 -9
  20. package/es/util/resize.js +139 -16
  21. package/es/view/Anchor.js +6 -8
  22. package/es/view/Control.d.ts +1 -0
  23. package/es/view/Control.js +6 -1
  24. package/es/view/Graph.js +3 -15
  25. package/es/view/behavior/dnd.js +1 -0
  26. package/es/view/edge/BaseEdge.d.ts +3 -1
  27. package/es/view/edge/BaseEdge.js +8 -5
  28. package/es/view/overlay/BackgroundOverlay.d.ts +4 -14
  29. package/es/view/overlay/BackgroundOverlay.js +11 -1
  30. package/es/view/overlay/Grid.d.ts +4 -3
  31. package/es/view/overlay/Grid.js +8 -31
  32. package/es/view/text/BaseText.js +1 -1
  33. package/lib/algorithm/rotate.d.ts +31 -0
  34. package/lib/algorithm/rotate.js +50 -0
  35. package/lib/event/eventArgs.d.ts +23 -29
  36. package/lib/model/BaseModel.d.ts +9 -0
  37. package/lib/model/GraphModel.d.ts +17 -1
  38. package/lib/model/GraphModel.js +36 -1
  39. package/lib/model/edge/BaseEdgeModel.d.ts +1 -0
  40. package/lib/model/node/BaseNodeModel.d.ts +7 -0
  41. package/lib/model/node/BaseNodeModel.js +55 -2
  42. package/lib/util/drag.d.ts +1 -0
  43. package/lib/util/drag.js +11 -0
  44. package/lib/util/graph.d.ts +1 -1
  45. package/lib/util/resize.d.ts +23 -9
  46. package/lib/util/resize.js +141 -17
  47. package/lib/view/Anchor.js +6 -8
  48. package/lib/view/Control.d.ts +1 -0
  49. package/lib/view/Control.js +6 -1
  50. package/lib/view/Graph.js +3 -15
  51. package/lib/view/behavior/dnd.js +1 -0
  52. package/lib/view/edge/BaseEdge.d.ts +3 -1
  53. package/lib/view/edge/BaseEdge.js +8 -5
  54. package/lib/view/overlay/BackgroundOverlay.d.ts +4 -14
  55. package/lib/view/overlay/BackgroundOverlay.js +11 -1
  56. package/lib/view/overlay/Grid.d.ts +4 -3
  57. package/lib/view/overlay/Grid.js +8 -31
  58. package/lib/view/text/BaseText.js +1 -1
  59. package/package.json +1 -1
  60. package/src/algorithm/edge.ts +2 -4
  61. package/src/event/eventArgs.ts +23 -29
  62. package/src/model/BaseModel.ts +16 -0
  63. package/src/model/GraphModel.ts +25 -3
  64. package/src/model/edge/BaseEdgeModel.ts +1 -0
  65. package/src/model/node/BaseNodeModel.ts +33 -1
  66. package/src/model/node/HtmlNodeModel.ts +1 -1
  67. package/src/util/drag.ts +12 -0
  68. package/src/util/resize.ts +7 -1
  69. package/src/view/Anchor.tsx +7 -8
  70. package/src/view/Control.tsx +1 -1
  71. package/src/view/Graph.tsx +2 -3
  72. package/src/view/behavior/dnd.ts +1 -0
  73. package/src/view/edge/BaseEdge.tsx +8 -3
  74. package/src/view/overlay/Grid.tsx +13 -9
  75. package/src/view/text/BaseText.tsx +1 -1
  76. package/stats.html +1 -1
@@ -56,6 +56,22 @@ export namespace Model {
56
56
  deltaY: number,
57
57
  ) => boolean | IsAllowMove
58
58
 
59
+ /**
60
+ * 限制节点resize规则
61
+ * model: 移动节点的 model
62
+ * deltaX: 中心点移动的 X 轴距离
63
+ * deltaY: 中心点移动的 Y 轴距离
64
+ * width: 中心点新的width
65
+ * height: 中心点新的height
66
+ */
67
+ export type NodeResizeRule = (
68
+ model: BaseNodeModel,
69
+ deltaX: number,
70
+ deltaY: number,
71
+ width: number,
72
+ height: number,
73
+ ) => boolean
74
+
59
75
  export type AdjustEdgeStartAndEndParams = {
60
76
  startPoint: LogicFlow.Point
61
77
  endPoint: LogicFlow.Point
@@ -1,4 +1,4 @@
1
- import { find, forEach, map } from 'lodash-es'
1
+ import { find, forEach, map, merge } from 'lodash-es'
2
2
  import { action, computed, observable } from 'mobx'
3
3
  import {
4
4
  BaseEdgeModel,
@@ -36,6 +36,7 @@ import {
36
36
  updateTheme,
37
37
  } from '../util'
38
38
  import EventEmitter from '../event/eventEmitter'
39
+ import { Grid } from '../view/overlay'
39
40
  import Position = LogicFlow.Position
40
41
  import PointTuple = LogicFlow.PointTuple
41
42
  import GraphData = LogicFlow.GraphData
@@ -55,6 +56,8 @@ export class GraphModel {
55
56
 
56
57
  // 流程图主题配置
57
58
  theme: LogicFlow.Theme
59
+ // 网格配置
60
+ @observable grid: Grid.GridOptions
58
61
  // 事件中心
59
62
  readonly eventCenter: EventEmitter
60
63
  // 维护所有节点和边类型对应的 model
@@ -81,10 +84,15 @@ export class GraphModel {
81
84
 
82
85
  /**
83
86
  * 节点移动规则判断
84
- * 在节点移动的时候,会出发此数组中的所有规则判断
87
+ * 在节点移动的时候,会触发此数组中的所有规则判断
85
88
  */
86
-
87
89
  nodeMoveRules: Model.NodeMoveRule[] = []
90
+ /**
91
+ * 节点resize规则判断
92
+ * 在节点resize的时候,会触发此数组中的所有规则判断
93
+ */
94
+ nodeResizeRules: Model.NodeResizeRule[] = []
95
+
88
96
  /**
89
97
  * 获取自定义连线轨迹
90
98
  */
@@ -137,6 +145,7 @@ export class GraphModel {
137
145
  this.gridSize = grid.size || 1 // 默认 gridSize 设置为 1
138
146
  }
139
147
  this.theme = setupTheme(options.style)
148
+ this.grid = Grid.getGridOptions(grid ?? false)
140
149
  this.edgeType = options.edgeType || 'polyline'
141
150
  this.animation = setupAnimation(animation)
142
151
  this.overlapMode = options.overlapMode || OverlapMode.DEFAULT
@@ -1230,6 +1239,12 @@ export class GraphModel {
1230
1239
  }
1231
1240
  }
1232
1241
 
1242
+ addNodeResizeRules(fn: Model.NodeResizeRule) {
1243
+ if (!this.nodeResizeRules.includes(fn)) {
1244
+ this.nodeResizeRules.push(fn)
1245
+ }
1246
+ }
1247
+
1233
1248
  /**
1234
1249
  * 设置默认的边类型
1235
1250
  * 也就是设置在节点直接有用户手动绘制的连线类型。
@@ -1396,6 +1411,13 @@ export class GraphModel {
1396
1411
  this.theme = updateTheme({ ...this.theme, ...style })
1397
1412
  }
1398
1413
 
1414
+ /**
1415
+ * 更新网格配置
1416
+ */
1417
+ updateGridOptions(options: Partial<Grid.GridOptions>) {
1418
+ merge(this.grid, options)
1419
+ }
1420
+
1399
1421
  /**
1400
1422
  * 重新设置画布的宽高
1401
1423
  */
@@ -87,6 +87,7 @@ export class BaseEdgeModel<P extends PropertiesType = PropertiesType>
87
87
  // 边特有属性,动画及调整点
88
88
  @observable isAnimation = false
89
89
  @observable isShowAdjustPoint = false // 是否显示边两端的调整点
90
+ isDragging?: boolean
90
91
  // 引用属性
91
92
  graphModel: GraphModel
92
93
  @observable zIndex: number = 0
@@ -148,6 +148,7 @@ export class BaseNodeModel<P extends PropertiesType = PropertiesType>
148
148
  targetRules: Model.ConnectRule[] = []
149
149
  sourceRules: Model.ConnectRule[] = []
150
150
  moveRules: Model.NodeMoveRule[] = [] // 节点移动之前的hook
151
+ resizeRules: Model.NodeResizeRule[] = [] // 节点resize之前的hook
151
152
  hasSetTargetRules = false // 用来限制rules的重复值
152
153
  hasSetSourceRules = false; // 用来限制rules的重复值
153
154
  [propName: string]: any // 支持用户自定义属性
@@ -281,6 +282,13 @@ export class BaseNodeModel<P extends PropertiesType = PropertiesType>
281
282
  */
282
283
  resize(resizeInfo: ResizeInfo): ResizeNodeData {
283
284
  const { width, height, deltaX, deltaY } = resizeInfo
285
+
286
+ const isAllowResize = this.isAllowResizeNode(deltaX, deltaY, width, height)
287
+
288
+ if (!isAllowResize) {
289
+ return this.getData()
290
+ }
291
+
284
292
  // 移动节点以及文本内容
285
293
  this.move(deltaX / 2, deltaY / 2)
286
294
 
@@ -761,6 +769,30 @@ export class BaseNodeModel<P extends PropertiesType = PropertiesType>
761
769
  }
762
770
  }
763
771
 
772
+ @action addNodeResizeRules(fn: Model.NodeResizeRule) {
773
+ if (!this.resizeRules.includes(fn)) {
774
+ this.resizeRules.push(fn)
775
+ }
776
+ }
777
+
778
+ /**
779
+ * 内部方法
780
+ * 是否允许resize节点到新的位置
781
+ */
782
+ isAllowResizeNode(
783
+ deltaX: number,
784
+ deltaY: number,
785
+ width: number,
786
+ height: number,
787
+ ): boolean {
788
+ const rules = this.resizeRules.concat(this.graphModel.nodeResizeRules)
789
+ for (const rule of rules) {
790
+ const r = rule(this, deltaX, deltaY, width, height)
791
+ if (!r) return false
792
+ }
793
+ return true
794
+ }
795
+
764
796
  @action setSelected(flag = true): void {
765
797
  this.isSelected = flag
766
798
  }
@@ -803,7 +835,7 @@ export class BaseNodeModel<P extends PropertiesType = PropertiesType>
803
835
  this.properties = nextProperties
804
836
  this.setAttributes()
805
837
 
806
- // 触发更新节点 properties:change 的事件
838
+ // 触发更新节点 node:properties-change 的事件
807
839
  this.graphModel.eventCenter.emit(EventType.NODE_PROPERTIES_CHANGE, {
808
840
  id: this.id,
809
841
  keys: updateKeys,
@@ -6,7 +6,7 @@ import AnchorConfig = Model.AnchorConfig
6
6
  import LogicFlow from '../../LogicFlow'
7
7
  import GraphModel from '../GraphModel'
8
8
 
9
- export type IHtmlNodeProperties = {
9
+ export interface IHtmlNodeProperties {
10
10
  width?: number
11
11
  height?: number
12
12
  style?: LogicFlow.CommonTheme
package/src/util/drag.ts CHANGED
@@ -201,4 +201,16 @@ export class StepDrag {
201
201
  this.onDragEnd({ event: undefined })
202
202
  this.isDragging = false
203
203
  }
204
+
205
+ destroy = () => {
206
+ if (this.isStartDragging) {
207
+ // https://github.com/didi/LogicFlow/issues/1934
208
+ // https://github.com/didi/LogicFlow/issues/1926
209
+ // cancelDrag()->onDragEnd()->updateEdgePointByAnchors()触发线的重新计算
210
+ // 我们的本意是为了防止mousemove和mouseup没有及时被移除
211
+ // 因此这里增加if(this.isStartDragging)的判断,isStartDragging=true代表没有触发handleMouseUp(),此时监听还没被移除
212
+ // 在拖拽情况下(isStartDragging=true),此时注册了监听,在组件突然销毁时,强制触发cancelDrag进行监听事件的移除
213
+ this.cancelDrag()
214
+ }
215
+ }
204
216
  }
@@ -386,6 +386,12 @@ export const handleResize = ({
386
386
  const preNodeData = nodeModel.getData()
387
387
  const curNodeData = nodeModel.resize(nextSize)
388
388
 
389
+ // 检测preNodeData和curNodeData是否没变化
390
+ if (preNodeData.x === curNodeData.x && preNodeData.y === curNodeData.y) {
391
+ // 中心点x和y都没有变化,说明无法resize,阻止下面边的更新以及resize事件的emit
392
+ return
393
+ }
394
+
389
395
  // 更新边
390
396
  updateEdgePointByAnchors(nodeModel, graphModel)
391
397
  // 触发 resize 事件
@@ -417,7 +423,7 @@ export function calculateWidthAndHeight(
417
423
  y: oldCenter.y - (startRotatedTouchControlPoint.y - oldCenter.y),
418
424
  }
419
425
  // 【touchEndPoint】右下角 + freezePoint左上角 计算出新的中心点
420
- let newCenter = getNewCenter(freezePoint, endRotatedTouchControlPoint)
426
+ const newCenter = getNewCenter(freezePoint, endRotatedTouchControlPoint)
421
427
 
422
428
  // 得到【touchEndPoint】右下角-没有transform的坐标
423
429
  let endZeroTouchControlPoint: SimplePoint = calculatePointAfterRotateAngle(
@@ -189,14 +189,13 @@ class Anchor extends Component<IProps, IState> {
189
189
  this.sourceRuleResults.clear()
190
190
  this.targetRuleResults.clear()
191
191
  const { graphModel, nodeModel, anchorData } = this.props
192
- if (edgeModel) {
193
- graphModel.eventCenter.emit(EventType.ANCHOR_DRAGEND, {
194
- data: anchorData,
195
- e: event!,
196
- nodeModel,
197
- edgeModel,
198
- })
199
- }
192
+
193
+ graphModel.eventCenter.emit(EventType.ANCHOR_DRAGEND, {
194
+ data: anchorData,
195
+ e: event!,
196
+ nodeModel,
197
+ edgeModel: edgeModel ?? undefined,
198
+ })
200
199
  }
201
200
 
202
201
  get customTrajectory() {
@@ -57,7 +57,7 @@ export class ResizeControl extends Component<
57
57
  }
58
58
 
59
59
  componentWillUnmount() {
60
- this.dragHandler.cancelDrag()
60
+ this.dragHandler.destroy()
61
61
  }
62
62
 
63
63
  updateEdgePointByAnchors = () => {
@@ -87,11 +87,10 @@ class Graph extends Component<IGraphProps> {
87
87
  if (options.height) {
88
88
  style.height = `${graphModel.height}px`
89
89
  }
90
- const grid = options.grid && Grid.getGridOptions(options.grid)
91
90
  const { fakeNode, editConfigModel } = graphModel
92
91
  const { adjustEdge } = editConfigModel
93
92
  return (
94
- <div className="lf-graph" flow-id={graphModel.flowId}>
93
+ <div className="lf-graph" flow-id={graphModel.flowId} style={style}>
95
94
  {/* 元素层 */}
96
95
  <CanvasOverlay graphModel={graphModel} dnd={dnd}>
97
96
  <g className="lf-base">
@@ -117,7 +116,7 @@ class Graph extends Component<IGraphProps> {
117
116
  <BackgroundOverlay background={options.background} />
118
117
  )}
119
118
  {/* 画布网格 */}
120
- {grid && <Grid {...grid} graphModel={graphModel} />}
119
+ <Grid graphModel={graphModel} />
121
120
  </div>
122
121
  )
123
122
  }
@@ -67,6 +67,7 @@ export class Dnd {
67
67
  this.lf.setNodeSnapLine(nodeData)
68
68
  this.lf.graphModel.eventCenter.emit(EventType.NODE_DND_DRAG, {
69
69
  data: nodeData,
70
+ e,
70
71
  })
71
72
  }
72
73
  return false
@@ -29,6 +29,7 @@ export abstract class BaseEdge<P extends IProps> extends Component<
29
29
  > {
30
30
  static isObserved: boolean = false
31
31
  static extendsKey?: string
32
+ mouseUpDrag?: boolean
32
33
 
33
34
  startTime?: number
34
35
  contextMenuTime?: number
@@ -385,13 +386,16 @@ export abstract class BaseEdge<P extends IProps> extends Component<
385
386
  e.stopPropagation()
386
387
  this.startTime = new Date().getTime()
387
388
  }
389
+ handleMouseUp = () => {
390
+ const { model } = this.props
391
+ this.mouseUpDrag = model.isDragging
392
+ }
388
393
  /**
389
394
  * 不支持重写
390
395
  */
391
- handleMouseUp = (e: MouseEvent) => {
396
+ handleClick = (e: MouseEvent) => {
392
397
  if (!this.startTime) return
393
- const time = new Date().getTime() - this.startTime
394
- if (time > 200) return // 事件大于200ms,认为是拖拽。
398
+ if (this.mouseUpDrag) return // 如果是拖拽,不触发click事件。
395
399
  const isRightClick = e.button === 2
396
400
  if (isRightClick) return
397
401
  // 这里 IE 11不能正确显示
@@ -490,6 +494,7 @@ export abstract class BaseEdge<P extends IProps> extends Component<
490
494
  .join(' ')}
491
495
  onMouseDown={this.handleMouseDown}
492
496
  onMouseUp={this.handleMouseUp}
497
+ onClick={this.handleClick}
493
498
  onContextMenu={this.handleContextMenu}
494
499
  onMouseOver={this.setHoverOn}
495
500
  onMouseEnter={this.setHoverOn}
@@ -5,19 +5,24 @@ import { createUuid } from '../../util'
5
5
  import { GraphModel } from '../../model'
6
6
  import { DEFAULT_GRID_SIZE } from '../../constant'
7
7
 
8
- import GridOptions = Grid.GridOptions
9
-
10
- type IProps = GridOptions & {
8
+ type IProps = {
11
9
  graphModel: GraphModel
12
10
  }
13
11
 
14
12
  @observer
15
13
  export class Grid extends Component<IProps> {
14
+ gridOptions: Grid.GridOptions
15
+
16
16
  readonly id = createUuid()
17
17
 
18
+ constructor(props: IProps) {
19
+ super(props)
20
+ this.gridOptions = this.props.graphModel.grid
21
+ }
22
+
18
23
  // 网格类型为点状
19
24
  renderDot() {
20
- const { config, size = 1, visible } = this.props
25
+ const { config, size = 1, visible } = this.gridOptions
21
26
 
22
27
  const { color, thickness = 2 } = config ?? {}
23
28
 
@@ -37,7 +42,7 @@ export class Grid extends Component<IProps> {
37
42
  // 网格类型为交叉线
38
43
  // todo: 采用背景缩放的方式,实现更好的体验
39
44
  renderMesh() {
40
- const { config, size = 1, visible } = this.props
45
+ const { config, size = 1, visible } = this.gridOptions
41
46
  const { color, thickness = 1 } = config ?? {}
42
47
 
43
48
  // 对于交叉线网格,线的宽度不能大于网格大小的一半
@@ -48,7 +53,7 @@ export class Grid extends Component<IProps> {
48
53
  <path
49
54
  d={d}
50
55
  stroke={color}
51
- strokeWidth={strokeWidth}
56
+ strokeWidth={strokeWidth / 2}
52
57
  opacity={opacity}
53
58
  fill="transparent"
54
59
  />
@@ -57,10 +62,9 @@ export class Grid extends Component<IProps> {
57
62
 
58
63
  render() {
59
64
  const {
60
- type,
61
- size = 1,
62
65
  graphModel: { transformModel },
63
66
  } = this.props
67
+ const { type, size = 1 } = this.gridOptions
64
68
  const { SCALE_X, SKEW_Y, SKEW_X, SCALE_Y, TRANSLATE_X, TRANSLATE_Y } =
65
69
  transformModel
66
70
  const matrixString = [
@@ -124,7 +128,7 @@ export namespace Grid {
124
128
  /**
125
129
  * 网格的颜色
126
130
  */
127
- color: string
131
+ color?: string
128
132
  /**
129
133
  * 网格的宽度
130
134
  * - 对于 `dot` 点状网格,表示点的大小
@@ -91,7 +91,7 @@ export class BaseText<
91
91
  graphModel: { transformModel },
92
92
  } = this.props
93
93
 
94
- if (deltaX && deltaY) {
94
+ if (deltaX || deltaY) {
95
95
  const [curDeltaX, curDeltaY] = transformModel.fixDeltaXY(deltaX, deltaY)
96
96
  model.moveText(curDeltaX, curDeltaY)
97
97
  }