@logicflow/extension 2.0.10 → 2.0.11

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.
@@ -3,6 +3,7 @@ import LogicFlow, {
3
3
  h,
4
4
  RectNode,
5
5
  handleResize,
6
+ CallbackArgs,
6
7
  } from '@logicflow/core'
7
8
  import { forEach } from 'lodash-es'
8
9
  import { DynamicGroupNodeModel } from './model'
@@ -18,101 +19,151 @@ export interface IDynamicGroupNodeProps {
18
19
  export class DynamicGroupNode<
19
20
  P extends IDynamicGroupNodeProps = IDynamicGroupNodeProps,
20
21
  > extends RectNode<P> {
21
- componentDidMount() {
22
- super.componentDidMount()
22
+ childrenPositionMap: Map<string, Position> = new Map()
23
23
 
24
+ onNodeRotate = ({
25
+ model,
26
+ }: Omit<CallbackArgs<'node:rotate'>, 'e' | 'position'>) => {
24
27
  const { model: curGroup, graphModel } = this.props
25
- const { eventCenter } = graphModel
26
-
27
- const childrenPositionMap: Map<string, Position> = new Map()
28
+ const { transformWithContainer, isRestrict } = curGroup
29
+ const childrenPositionMap = this.childrenPositionMap
30
+ if (!transformWithContainer || isRestrict) {
31
+ // isRestrict限制模式下,当前model resize时不能小于占地面积
32
+ // 由于parent:resize=>child:resize计算复杂,需要根据child:resize的判定结果来递归判断parent能否resize
33
+ // 不符合目前 parent:resize成功后emit事件 -> 触发child:resize 的代码交互模式
34
+ // 因此isRestrict限制模式下不支持联动(parent:resize=>child:resize)
35
+ // 由于transformWidthContainer是控制rotate+resize,为保持transformWidthContainer本来的含义
36
+ // parent:resize=>child:resize不支持,那么parent:rotate=>child:rotate也不支持
37
+ return
38
+ }
39
+ // DONE: 目前操作是对分组内节点以节点中心旋转节点本身,而按照正常逻辑,应该是以分组中心,旋转节点(跟 Label 旋转操作逻辑一致)
40
+ if (model.id === curGroup.id) {
41
+ const center = { x: curGroup.x, y: curGroup.y }
42
+ forEach(Array.from(curGroup.children), (childId) => {
43
+ const child = graphModel.getNodeModelById(childId)
28
44
 
29
- // group 旋转时,对组内的所有子节点也进行对应的旋转计算
30
- eventCenter.on('node:rotate', ({ model }) => {
31
- const { transformWithContainer, isRestrict } = this.props.model
32
- if (!transformWithContainer || isRestrict) {
33
- // isRestrict限制模式下,当前model resize时不能小于占地面积
34
- // 由于parent:resize=>child:resize计算复杂,需要根据child:resize的判定结果来递归判断parent能否resize
35
- // 不符合目前 parent:resize成功后emit事件 -> 触发child:resize 的代码交互模式
36
- // 因此isRestrict限制模式下不支持联动(parent:resize=>child:resize)
37
- // 由于transformWidthContainer是控制rotate+resize,为保持transformWidthContainer本来的含义
38
- // parent:resize=>child:resize不支持,那么parent:rotate=>child:rotate也不支持
39
- return
40
- }
41
- // DONE: 目前操作是对分组内节点以节点中心旋转节点本身,而按照正常逻辑,应该是以分组中心,旋转节点(跟 Label 旋转操作逻辑一致)
42
- if (model.id === curGroup.id) {
43
- const center = { x: curGroup.x, y: curGroup.y }
44
- forEach(Array.from(curGroup.children), (childId) => {
45
- const child = graphModel.getNodeModelById(childId)
46
-
47
- if (child) {
48
- let point: Position = { x: child.x, y: child.y }
49
- if (childrenPositionMap.has(child.id)) {
50
- point = childrenPositionMap.get(child.id)!
51
- } else {
52
- childrenPositionMap.set(child.id, point)
53
- }
54
-
55
- // 弧度转角度
56
- let theta = model.rotate * (180 / Math.PI)
57
- if (theta < 0) theta += 360
58
- const radian = theta * (Math.PI / 180)
59
-
60
- const newPoint = rotatePointAroundCenter(point, center, radian)
61
-
62
- child.moveTo(newPoint.x, newPoint.y)
63
- child.rotate = model.rotate
45
+ if (child) {
46
+ let point: Position = { x: child.x, y: child.y }
47
+ if (childrenPositionMap.has(child.id)) {
48
+ point = childrenPositionMap.get(child.id)!
49
+ } else {
50
+ childrenPositionMap.set(child.id, point)
64
51
  }
65
- })
66
- }
67
- })
68
52
 
69
- // 在 group 缩放时,对组内的所有子节点也进行对应的缩放计算
70
- eventCenter.on(
71
- 'node:resize',
72
- ({ deltaX, deltaY, index, model, preData }) => {
73
- const { transformWithContainer, isRestrict } = this.props.model
74
- if (!transformWithContainer || isRestrict) {
75
- // isRestrict限制模式下,当前model resize时不能小于占地面积
76
- // 由于parent:resize=>child:resize计算复杂,需要根据child:resize的判定结果来递归判断parent能否resize
77
- // 不符合目前 parent:resize成功后emit事件 -> 触发child:resize 的代码交互模式
78
- // 因此isRestrict限制模式下不支持联动(parent:resize=>child:resize)
79
- return
53
+ // 弧度转角度
54
+ let theta = model.rotate * (180 / Math.PI)
55
+ if (theta < 0) theta += 360
56
+ const radian = theta * (Math.PI / 180)
57
+
58
+ const newPoint = rotatePointAroundCenter(point, center, radian)
59
+
60
+ child.moveTo(newPoint.x, newPoint.y)
61
+ child.rotate = model.rotate
80
62
  }
81
- if (model.id === curGroup.id) {
82
- // node:resize是group已经改变width和height后的回调
83
- // 因此这里一定得用preData(没resize改变width之前的值),而不是data/model
84
- const { properties } = preData
85
- const { width: groupWidth, height: groupHeight } = properties || {}
86
- forEach(Array.from(curGroup.children), (childId) => {
87
- const child = graphModel.getNodeModelById(childId)
88
- if (child) {
89
- // 根据比例去控制缩放dx和dy
90
- const childDx = (child.width / groupWidth!) * deltaX
91
- const childDy = (child.height / groupHeight!) * deltaY
92
-
93
- // child.rotate = model.rotate
94
- handleResize({
95
- deltaX: childDx,
96
- deltaY: childDy,
97
- index,
98
- nodeModel: child,
99
- graphModel,
100
- cancelCallback: () => {},
101
- })
102
- }
63
+ })
64
+ }
65
+ }
66
+
67
+ onNodeResize = ({
68
+ deltaX,
69
+ deltaY,
70
+ index,
71
+ model,
72
+ preData,
73
+ }: Omit<CallbackArgs<'node:resize'>, 'e' | 'position'>) => {
74
+ const { model: curGroup, graphModel } = this.props
75
+ const { transformWithContainer, isRestrict } = curGroup
76
+ if (!transformWithContainer || isRestrict) {
77
+ // isRestrict限制模式下,当前model resize时不能小于占地面积
78
+ // 由于parent:resize=>child:resize计算复杂,需要根据child:resize的判定结果来递归判断parent能否resize
79
+ // 不符合目前 parent:resize成功后emit事件 -> 触发child:resize 的代码交互模式
80
+ // 因此isRestrict限制模式下不支持联动(parent:resize=>child:resize)
81
+ return
82
+ }
83
+ if (model.id === curGroup.id) {
84
+ // node:resize是group已经改变width和height后的回调
85
+ // 因此这里一定得用preData(没resize改变width之前的值),而不是data/model
86
+ const { properties } = preData
87
+ const { width: groupWidth, height: groupHeight } = properties || {}
88
+ forEach(Array.from(curGroup.children), (childId) => {
89
+ const child = graphModel.getNodeModelById(childId)
90
+ if (child) {
91
+ // 根据比例去控制缩放dx和dy
92
+ const childDx = (child.width / groupWidth!) * deltaX
93
+ const childDy = (child.height / groupHeight!) * deltaY
94
+
95
+ // child.rotate = model.rotate
96
+ handleResize({
97
+ deltaX: childDx,
98
+ deltaY: childDy,
99
+ index,
100
+ nodeModel: child,
101
+ graphModel,
102
+ cancelCallback: () => {},
103
103
  })
104
104
  }
105
- },
106
- )
105
+ })
106
+ }
107
+ }
107
108
 
109
+ onNodeMouseMove = ({
110
+ deltaX,
111
+ deltaY,
112
+ data,
113
+ }: Omit<CallbackArgs<'node:mousemove'>, 'e' | 'position'>) => {
114
+ const { model: curGroup, graphModel } = this.props
115
+ const { transformModel } = graphModel
116
+ const { SCALE_X, SCALE_Y } = transformModel
117
+ if (data.id === curGroup.id) {
118
+ const nodeIds = this.getNodesInGroup(curGroup, graphModel)
119
+ // https://github.com/didi/LogicFlow/issues/1914
120
+ // 当调用lf.fitView()时,会改变整体的SCALE_X和SCALE_Y
121
+ // 由于group的mousemove是在drag.ts的this.onDragging()处理的,在onDragging()里面进行SCALE的处理
122
+ // 而"node:mousemove"emit出来跟onDragging()是同时的,也就是emit出来的数据是没有经过SCALE处理的坐标
123
+ // 因此这里需要增加SCALE的处理
124
+ graphModel.moveNodes(nodeIds, deltaX / SCALE_X, deltaY / SCALE_Y, true)
125
+ }
126
+ }
127
+
128
+ graphRendered = () => {
129
+ const { model } = this.props
130
+ // 初始化时,如果 this.isCollapsed 为 true,则主动触发一次折叠操作
131
+ if (model.isCollapsed) {
132
+ // https://github.com/didi/LogicFlow/issues/1918
133
+ // 当lf.render({nodes:[{分组节点}, {普通节点}]})时,由于是顺序遍历
134
+ // 会先触发分组Group节点的new Model => toggleCollapse()
135
+ // => 此时在graphModel.elementsModelMap找不到它的children,因为还没初始化,因此无法正确折叠子元素
136
+ // --------------------
137
+ // 当lf.render({nodes:[{普通节点}, {分组节点}]})时,
138
+ // 会先触发普通节点的new Model => graphModel.elementsModelMap.set(id, new Model())
139
+ // 然后再触发分组Group节点的new Model => toggleCollapse() =>
140
+ // 此时在graphModel.elementsModelMap能找到它的children了,因此可以正确折叠子元素
141
+ // --------------------
142
+ // 因此将整个初始化判断是否【主动触发一次折叠操作】放在"graph:rendered"全部渲染完成后再执行
143
+ model.toggleCollapse(true)
144
+ }
145
+ }
146
+
147
+ componentDidMount() {
148
+ super.componentDidMount()
149
+ const { eventCenter } = this.props.graphModel
150
+ // 在 group 旋转时,对组内的所有子节点也进行对应的旋转计算
151
+ eventCenter.on('node:rotate', this.onNodeRotate)
152
+ // 在 group 缩放时,对组内的所有子节点也进行对应的缩放计算
153
+ eventCenter.on('node:resize', this.onNodeResize)
108
154
  // 在 group 移动时,对组内的所有子节点也进行对应的移动计算
109
- eventCenter.on('node:mousemove', ({ deltaX, deltaY, data }) => {
110
- if (data.id === curGroup.id) {
111
- const { model: curGroup, graphModel } = this.props
112
- const nodeIds = this.getNodesInGroup(curGroup, graphModel)
113
- graphModel.moveNodes(nodeIds, deltaX, deltaY, true)
114
- }
115
- })
155
+ eventCenter.on('node:mousemove', this.onNodeMouseMove)
156
+ // 全部渲染完成后,判断是否【主动触发一次折叠操作】
157
+ eventCenter.on('graph:rendered', this.graphRendered)
158
+ }
159
+
160
+ componentWillUnmount() {
161
+ super.componentWillUnmount()
162
+ const { eventCenter } = this.props.graphModel
163
+ eventCenter.off('node:rotate', this.onNodeRotate)
164
+ eventCenter.off('node:resize', this.onNodeResize)
165
+ eventCenter.off('node:mousemove', this.onNodeMouseMove)
166
+ eventCenter.off('graph:rendered', this.graphRendered)
116
167
  }
117
168
 
118
169
  /**