@logicflow/extension 2.0.0-beta.0 → 2.0.0-beta.10

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 (235) hide show
  1. package/.turbo/turbo-build.log +146 -491
  2. package/dist/index.css +63 -0
  3. package/dist/index.min.js +42 -0
  4. package/dist/index.min.js.map +1 -0
  5. package/es/NodeResize/control/Control.d.ts +3 -3
  6. package/es/NodeResize/control/Control.js +13 -3
  7. package/es/NodeResize/control/Control.js.map +1 -1
  8. package/es/NodeResize/index.d.ts +4 -0
  9. package/es/NodeResize/index.js.map +1 -1
  10. package/es/NodeResize/node/DiamondResize.d.ts +1 -0
  11. package/es/NodeResize/node/DiamondResize.js +2 -1
  12. package/es/NodeResize/node/DiamondResize.js.map +1 -1
  13. package/es/NodeResize/node/EllipseResize.d.ts +1 -0
  14. package/es/NodeResize/node/EllipseResize.js +2 -1
  15. package/es/NodeResize/node/EllipseResize.js.map +1 -1
  16. package/es/NodeResize/node/HtmlResize.d.ts +1 -0
  17. package/es/NodeResize/node/HtmlResize.js +2 -1
  18. package/es/NodeResize/node/HtmlResize.js.map +1 -1
  19. package/es/bpmn/constant.d.ts +1 -1
  20. package/es/bpmn/constant.js +3 -0
  21. package/es/bpmn/constant.js.map +1 -1
  22. package/es/bpmn/index.d.ts +3 -6
  23. package/es/bpmn/index.js +5 -7
  24. package/es/bpmn/index.js.map +1 -1
  25. package/es/bpmn-elements/presets/Pool/Pool.d.ts +21 -1
  26. package/es/components/control/index.d.ts +4 -4
  27. package/es/components/control/index.js.map +1 -1
  28. package/es/components/highlight/index.d.ts +6 -4
  29. package/es/components/highlight/index.js +32 -5
  30. package/es/components/highlight/index.js.map +1 -1
  31. package/es/components/menu/index.d.ts +1 -1
  32. package/es/components/menu/index.js +9 -10
  33. package/es/components/menu/index.js.map +1 -1
  34. package/es/components/mini-map/index.d.ts +1 -1
  35. package/es/components/mini-map/index.js +2 -2
  36. package/es/components/mini-map/index.js.map +1 -1
  37. package/es/components/selection-select/index.d.ts +1 -1
  38. package/es/components/selection-select/index.js.map +1 -1
  39. package/es/dynamic-group/index.d.ts +106 -0
  40. package/es/dynamic-group/index.js +536 -0
  41. package/es/dynamic-group/index.js.map +1 -0
  42. package/es/dynamic-group/model.d.ts +135 -0
  43. package/es/dynamic-group/model.js +413 -0
  44. package/es/dynamic-group/model.js.map +1 -0
  45. package/es/dynamic-group/node.d.ts +16 -0
  46. package/es/dynamic-group/node.js +143 -0
  47. package/es/dynamic-group/node.js.map +1 -0
  48. package/es/dynamic-group/utils.d.ts +17 -0
  49. package/es/dynamic-group/utils.js +27 -0
  50. package/es/dynamic-group/utils.js.map +1 -0
  51. package/es/index.css +63 -0
  52. package/es/index.d.ts +16 -8
  53. package/es/index.js +24 -8
  54. package/es/index.js.map +1 -1
  55. package/es/insert-node-in-polyline/index.js +3 -3
  56. package/es/insert-node-in-polyline/index.js.map +1 -1
  57. package/es/materials/group/GroupNode.d.ts +6 -10
  58. package/es/materials/group/GroupNode.js +8 -6
  59. package/es/materials/group/GroupNode.js.map +1 -1
  60. package/es/materials/group/index.d.ts +5 -5
  61. package/es/materials/group/index.js +25 -26
  62. package/es/materials/group/index.js.map +1 -1
  63. package/es/materials/node-selection/index.d.ts +6 -1
  64. package/es/materials/node-selection/index.js +64 -56
  65. package/es/materials/node-selection/index.js.map +1 -1
  66. package/es/mindmap/index.d.ts +2 -2
  67. package/es/style/index.css +63 -0
  68. package/es/style/index.less +73 -0
  69. package/es/style/raw.d.ts +1 -1
  70. package/es/style/raw.js +1 -1
  71. package/es/style/raw.js.map +1 -1
  72. package/es/tools/flow-path/index.js +0 -1
  73. package/es/tools/flow-path/index.js.map +1 -1
  74. package/es/tools/label/Label.d.ts +30 -0
  75. package/es/tools/label/Label.js +241 -0
  76. package/es/tools/label/Label.js.map +1 -0
  77. package/es/tools/label/LabelModel.d.ts +26 -0
  78. package/es/tools/label/LabelModel.js +86 -0
  79. package/es/tools/label/LabelModel.js.map +1 -0
  80. package/es/tools/label/LabelOverlay.d.ts +28 -0
  81. package/es/tools/label/LabelOverlay.js +161 -0
  82. package/es/tools/label/LabelOverlay.js.map +1 -0
  83. package/es/tools/label/algorithm.d.ts +16 -0
  84. package/es/tools/label/algorithm.js +27 -0
  85. package/es/tools/label/algorithm.js.map +1 -0
  86. package/es/tools/label/index.d.ts +59 -0
  87. package/es/tools/label/index.js +292 -0
  88. package/es/tools/label/index.js.map +1 -0
  89. package/es/tools/label/mediumEditor.d.ts +17 -0
  90. package/es/tools/label/mediumEditor.js +92 -0
  91. package/es/tools/label/mediumEditor.js.map +1 -0
  92. package/es/tools/label/utils.d.ts +64 -0
  93. package/es/tools/label/utils.js +336 -0
  94. package/es/tools/label/utils.js.map +1 -0
  95. package/es/tools/snapshot/index.d.ts +107 -11
  96. package/es/tools/snapshot/index.js +366 -149
  97. package/es/tools/snapshot/index.js.map +1 -1
  98. package/es/tools/snapshot/utils.d.ts +35 -0
  99. package/es/tools/snapshot/utils.js +238 -0
  100. package/es/tools/snapshot/utils.js.map +1 -0
  101. package/lib/NodeResize/control/Control.d.ts +3 -3
  102. package/lib/NodeResize/control/Control.js +13 -3
  103. package/lib/NodeResize/control/Control.js.map +1 -1
  104. package/lib/NodeResize/index.d.ts +4 -0
  105. package/lib/NodeResize/index.js.map +1 -1
  106. package/lib/NodeResize/node/DiamondResize.d.ts +1 -0
  107. package/lib/NodeResize/node/DiamondResize.js +2 -1
  108. package/lib/NodeResize/node/DiamondResize.js.map +1 -1
  109. package/lib/NodeResize/node/EllipseResize.d.ts +1 -0
  110. package/lib/NodeResize/node/EllipseResize.js +2 -1
  111. package/lib/NodeResize/node/EllipseResize.js.map +1 -1
  112. package/lib/NodeResize/node/HtmlResize.d.ts +1 -0
  113. package/lib/NodeResize/node/HtmlResize.js +2 -1
  114. package/lib/NodeResize/node/HtmlResize.js.map +1 -1
  115. package/lib/bpmn/constant.d.ts +1 -1
  116. package/lib/bpmn/constant.js +3 -0
  117. package/lib/bpmn/constant.js.map +1 -1
  118. package/lib/bpmn/index.d.ts +3 -6
  119. package/lib/bpmn/index.js +5 -7
  120. package/lib/bpmn/index.js.map +1 -1
  121. package/lib/bpmn-elements/presets/Pool/Pool.d.ts +21 -1
  122. package/lib/components/control/index.d.ts +4 -4
  123. package/lib/components/control/index.js.map +1 -1
  124. package/lib/components/highlight/index.d.ts +6 -4
  125. package/lib/components/highlight/index.js +32 -5
  126. package/lib/components/highlight/index.js.map +1 -1
  127. package/lib/components/menu/index.d.ts +1 -1
  128. package/lib/components/menu/index.js +9 -10
  129. package/lib/components/menu/index.js.map +1 -1
  130. package/lib/components/mini-map/index.d.ts +1 -1
  131. package/lib/components/mini-map/index.js +2 -2
  132. package/lib/components/mini-map/index.js.map +1 -1
  133. package/lib/components/selection-select/index.d.ts +1 -1
  134. package/lib/components/selection-select/index.js.map +1 -1
  135. package/lib/dynamic-group/index.d.ts +106 -0
  136. package/lib/dynamic-group/index.js +553 -0
  137. package/lib/dynamic-group/index.js.map +1 -0
  138. package/lib/dynamic-group/model.d.ts +135 -0
  139. package/lib/dynamic-group/model.js +416 -0
  140. package/lib/dynamic-group/model.js.map +1 -0
  141. package/lib/dynamic-group/node.d.ts +16 -0
  142. package/lib/dynamic-group/node.js +146 -0
  143. package/lib/dynamic-group/node.js.map +1 -0
  144. package/lib/dynamic-group/utils.d.ts +17 -0
  145. package/lib/dynamic-group/utils.js +32 -0
  146. package/lib/dynamic-group/utils.js.map +1 -0
  147. package/lib/index.css +63 -0
  148. package/lib/index.d.ts +16 -8
  149. package/lib/index.js +24 -8
  150. package/lib/index.js.map +1 -1
  151. package/lib/insert-node-in-polyline/index.js +2 -2
  152. package/lib/insert-node-in-polyline/index.js.map +1 -1
  153. package/lib/materials/group/GroupNode.d.ts +6 -10
  154. package/lib/materials/group/GroupNode.js +8 -6
  155. package/lib/materials/group/GroupNode.js.map +1 -1
  156. package/lib/materials/group/index.d.ts +5 -5
  157. package/lib/materials/group/index.js +24 -25
  158. package/lib/materials/group/index.js.map +1 -1
  159. package/lib/materials/node-selection/index.d.ts +6 -1
  160. package/lib/materials/node-selection/index.js +63 -55
  161. package/lib/materials/node-selection/index.js.map +1 -1
  162. package/lib/mindmap/index.d.ts +2 -2
  163. package/lib/style/index.css +63 -0
  164. package/lib/style/index.less +73 -0
  165. package/lib/style/raw.d.ts +1 -1
  166. package/lib/style/raw.js +1 -1
  167. package/lib/style/raw.js.map +1 -1
  168. package/lib/tools/flow-path/index.js +0 -1
  169. package/lib/tools/flow-path/index.js.map +1 -1
  170. package/lib/tools/label/Label.d.ts +30 -0
  171. package/lib/tools/label/Label.js +247 -0
  172. package/lib/tools/label/Label.js.map +1 -0
  173. package/lib/tools/label/LabelModel.d.ts +26 -0
  174. package/lib/tools/label/LabelModel.js +89 -0
  175. package/lib/tools/label/LabelModel.js.map +1 -0
  176. package/lib/tools/label/LabelOverlay.d.ts +28 -0
  177. package/lib/tools/label/LabelOverlay.js +167 -0
  178. package/lib/tools/label/LabelOverlay.js.map +1 -0
  179. package/lib/tools/label/algorithm.d.ts +16 -0
  180. package/lib/tools/label/algorithm.js +32 -0
  181. package/lib/tools/label/algorithm.js.map +1 -0
  182. package/lib/tools/label/index.d.ts +59 -0
  183. package/lib/tools/label/index.js +298 -0
  184. package/lib/tools/label/index.js.map +1 -0
  185. package/lib/tools/label/mediumEditor.d.ts +17 -0
  186. package/lib/tools/label/mediumEditor.js +98 -0
  187. package/lib/tools/label/mediumEditor.js.map +1 -0
  188. package/lib/tools/label/utils.d.ts +64 -0
  189. package/lib/tools/label/utils.js +349 -0
  190. package/lib/tools/label/utils.js.map +1 -0
  191. package/lib/tools/snapshot/index.d.ts +107 -11
  192. package/lib/tools/snapshot/index.js +366 -149
  193. package/lib/tools/snapshot/index.js.map +1 -1
  194. package/lib/tools/snapshot/utils.d.ts +35 -0
  195. package/lib/tools/snapshot/utils.js +247 -0
  196. package/lib/tools/snapshot/utils.js.map +1 -0
  197. package/package.json +20 -3
  198. package/rollup.config.js +1 -1
  199. package/src/NodeResize/control/Control.tsx +13 -3
  200. package/src/NodeResize/index.ts +4 -0
  201. package/src/NodeResize/node/DiamondResize.tsx +2 -1
  202. package/src/NodeResize/node/EllipseResize.tsx +2 -1
  203. package/src/NodeResize/node/HtmlResize.tsx +2 -1
  204. package/src/bpmn/constant.ts +4 -1
  205. package/src/bpmn/index.ts +7 -4
  206. package/src/bpmn-elements-adapter/README.md +1 -3
  207. package/src/components/control/index.ts +4 -4
  208. package/src/components/highlight/index.ts +33 -6
  209. package/src/components/menu/index.ts +16 -13
  210. package/src/components/mini-map/index.ts +3 -3
  211. package/src/components/selection-select/index.ts +6 -2
  212. package/src/dynamic-group/index.ts +609 -0
  213. package/src/dynamic-group/model.ts +503 -0
  214. package/src/dynamic-group/node.ts +140 -0
  215. package/src/dynamic-group/utils.ts +33 -0
  216. package/src/index.ts +30 -8
  217. package/src/insert-node-in-polyline/index.ts +3 -3
  218. package/src/materials/group/GroupNode.ts +12 -12
  219. package/src/materials/group/index.ts +40 -40
  220. package/src/materials/node-selection/index.ts +78 -70
  221. package/src/style/index.less +73 -0
  222. package/src/style/raw.ts +64 -1
  223. package/src/tools/flow-path/index.ts +0 -1
  224. package/src/tools/label/Label.tsx +297 -0
  225. package/src/tools/label/LabelModel.ts +82 -0
  226. package/src/tools/label/LabelOverlay.tsx +159 -0
  227. package/src/tools/label/algorithm.ts +42 -0
  228. package/src/tools/label/index.ts +401 -0
  229. package/src/tools/label/mediumEditor.ts +94 -0
  230. package/src/tools/label/utils.ts +395 -0
  231. package/src/tools/snapshot/README.md +141 -5
  232. package/src/tools/snapshot/index.ts +288 -101
  233. package/src/tools/snapshot/utils.ts +163 -0
  234. package/dist/index.js +0 -26
  235. package/dist/index.js.map +0 -1
package/src/style/raw.ts CHANGED
@@ -4,7 +4,10 @@
4
4
  * Auto generated file, do not modify it!
5
5
  */
6
6
 
7
- export const content = `.lf-control {
7
+ export const content = `@import url('medium-editor/dist/css/medium-editor.min.css');
8
+ @import url('medium-editor/dist/css/themes/beagle.min.css');
9
+ @import url('vanilla-picker/dist/vanilla-picker.csp.css');
10
+ .lf-control {
8
11
  position: absolute;
9
12
  top: 0;
10
13
  right: 10px;
@@ -219,4 +222,64 @@ export const content = `.lf-control {
219
222
  .lf-mindmap_addIcon {
220
223
  margin-top: 10px;
221
224
  }
225
+ /* label */
226
+ .lf-label-overlay {
227
+ width: 0;
228
+ height: 0;
229
+ overflow: visible;
230
+ }
231
+ .lf-label-overlay .lf-label-editor {
232
+ padding: 4px;
233
+ background: #fff;
234
+ border-radius: 5px;
235
+ }
236
+ .lf-label-overlay .lf-label-editor-container {
237
+ position: absolute;
238
+ display: flex;
239
+ align-items: center;
240
+ justify-content: center;
241
+ overflow: visible;
242
+ text-align: center;
243
+ }
244
+ .lf-label-overlay .lf-label-editor-container p {
245
+ margin: 0;
246
+ }
247
+ .lf-label-overlay .lf-label-editor-dragging {
248
+ cursor: move;
249
+ }
250
+ .lf-label-overlay .lf-label-editor-editing {
251
+ border: 2px solid #275dc5;
252
+ outline: none;
253
+ cursor: text;
254
+ }
255
+ .lf-label-overlay .lf-label-editor-hover {
256
+ border: 2px dashed #acacac;
257
+ }
258
+ .lf-label-overlay .lf-label-editor-clip {
259
+ width: 100px;
260
+ /* 根据需要调整宽度 */
261
+ overflow: hidden;
262
+ white-space: nowrap;
263
+ text-overflow: clip;
264
+ }
265
+ .lf-label-overlay .lf-label-editor-ellipsis {
266
+ width: 100px;
267
+ /* 根据需要调整宽度 */
268
+ overflow: hidden;
269
+ white-space: nowrap;
270
+ text-overflow: ellipsis;
271
+ }
272
+ .lf-label-overlay .lf-label-editor-wrap {
273
+ width: 100px;
274
+ /* 根据需要调整宽度 */
275
+ white-space: normal;
276
+ overflow-wrap: break-word;
277
+ /* 允许单词内换行 */
278
+ }
279
+ .lf-label-overlay .lf-label-editor-nowrap {
280
+ width: 100px;
281
+ /* 根据需要调整宽度 */
282
+ overflow: visible;
283
+ white-space: nowrap;
284
+ }
222
285
  `
@@ -136,7 +136,6 @@ export class FlowPath {
136
136
  // 由于循环路径不包括开始,所以存在重复的情况,此处去重。
137
137
  const LoopSet = new Set()
138
138
  pathElements.forEach((elements) => {
139
- console.log('elements', elements)
140
139
  const routeId = this.getNewId('path')
141
140
  const name = this.getNewId('路径')
142
141
  const isLoop = this.isLoopPath(elements)
@@ -0,0 +1,297 @@
1
+ import LogicFlow, {
2
+ BaseEdgeModel,
3
+ BaseNodeModel,
4
+ Component,
5
+ createRef,
6
+ ElementState,
7
+ GraphModel,
8
+ IDragParams,
9
+ observer,
10
+ StepDrag,
11
+ } from '@logicflow/core'
12
+ import classNames from 'classnames'
13
+ import LabelModel from './LabelModel'
14
+ import { findIndex } from 'lodash-es'
15
+
16
+ import LabelConfig = LogicFlow.LabelConfig
17
+
18
+ export interface ILabelProps {
19
+ label: LabelModel
20
+ element: BaseNodeModel | BaseEdgeModel
21
+ graphModel: GraphModel
22
+ }
23
+
24
+ export interface ILabelState {
25
+ isEditing: boolean
26
+ isHovered: boolean
27
+ isDragging: boolean
28
+ }
29
+
30
+ @observer
31
+ export class Label extends Component<ILabelProps, ILabelState> {
32
+ textRef = createRef<HTMLDivElement>()
33
+ stepDrag: StepDrag
34
+
35
+ constructor(props: ILabelProps) {
36
+ super(props)
37
+ const {
38
+ label,
39
+ graphModel: { gridSize, eventCenter },
40
+ } = props
41
+
42
+ this.stepDrag = new StepDrag({
43
+ onDragging: this.handleDragging,
44
+ onDragEnd: this.handleDragEnd,
45
+ step: gridSize,
46
+ eventType: 'LABEL',
47
+ model: label,
48
+ eventCenter,
49
+ })
50
+
51
+ this.state = {
52
+ isEditing: false,
53
+ isHovered: false,
54
+ isDragging: false,
55
+ }
56
+ }
57
+
58
+ setHoverOn = () => {
59
+ const { element } = this.props
60
+ if (element.isDragging || this.state.isHovered) return // 当节点或边在拖拽中时,不触发 hover 态
61
+
62
+ this.setState({ isHovered: true })
63
+ element.setHovered(true)
64
+ }
65
+ setHoverOff = () => {
66
+ const { element } = this.props
67
+ if (!this.state.isHovered) return
68
+
69
+ this.setState({ isHovered: false })
70
+ element.setHovered(false)
71
+ }
72
+
73
+ handleMouseDown = (e: MouseEvent) => {
74
+ const { label, graphModel } = this.props
75
+ const {
76
+ editConfigModel: { nodeTextDraggable },
77
+ } = graphModel
78
+
79
+ // 当 label 允许拖拽 且不处于拖拽状态时, StepDrag 开启拖拽
80
+ if ((label.draggable ?? nodeTextDraggable) && !this.state.isDragging) {
81
+ this.setState({ isDragging: true })
82
+ this.stepDrag.handleMouseDown(e)
83
+ }
84
+ }
85
+ handleDragging = ({ deltaX, deltaY }: IDragParams) => {
86
+ const { label, element, graphModel } = this.props
87
+
88
+ // DONE: 添加缩放时拖拽的逻辑,对 deltaX 和 deltaY 进行按比例缩放
89
+ const { transformModel } = graphModel
90
+ const [curDeltaX, curDeltaY] = transformModel.fixDeltaXY(deltaX, deltaY)
91
+
92
+ // DONE:更新 label 位置,触发 LABEL:DRAG 事件,并抛出相关的数据
93
+ const {
94
+ properties: { _label },
95
+ } = element
96
+ const elementLabel = _label as LabelConfig[]
97
+ const idx = findIndex(elementLabel, (cur) => cur.id === label.id)
98
+
99
+ const target = elementLabel[idx]
100
+ elementLabel[idx] = {
101
+ ...target,
102
+ x: target.x + curDeltaX,
103
+ y: target.y + curDeltaY,
104
+ }
105
+ const targetElem = graphModel.getElement(element.id)
106
+ targetElem?.setProperty('_label', elementLabel)
107
+
108
+ graphModel.eventCenter.emit('label:drag', {
109
+ data: label.getData(),
110
+ model: label,
111
+ })
112
+ }
113
+ handleDragEnd = () => {
114
+ this.setState({ isDragging: false })
115
+ }
116
+
117
+ handleDbClick = (e: MouseEvent) => {
118
+ const { label, element, graphModel } = this.props
119
+ graphModel.eventCenter.emit('label:dblclick', {
120
+ data: label.getData(),
121
+ e,
122
+ model: element,
123
+ })
124
+
125
+ if (!label.editable) {
126
+ element.setSelected(true)
127
+ return
128
+ }
129
+ element.setSelected()
130
+ element.setElementState(ElementState.TEXT_EDIT)
131
+
132
+ this.setState({ isEditing: true })
133
+
134
+ // DONE: 触发当前 label 的 focus 事件,设置内容可编辑,且在文本最后添加光标
135
+ if (this.textRef.current) {
136
+ this.textRef.current.contentEditable = 'true'
137
+ this.textRef.current.focus()
138
+
139
+ const range = document.createRange()
140
+ const selection = window.getSelection()
141
+ range.selectNodeContents(this.textRef.current)
142
+ range.collapse(false)
143
+ selection?.removeAllRanges()
144
+ selection?.addRange(range)
145
+ }
146
+ }
147
+ handleBlur = (e: FocusEvent) => {
148
+ const {
149
+ label,
150
+ element,
151
+ graphModel: { eventCenter },
152
+ } = this.props
153
+
154
+ // DONE: 触发 LABEL:BLUR 事件,并抛出相关的事件
155
+ eventCenter.emit('label:blur', {
156
+ e,
157
+ model: element,
158
+ data: label.getData(),
159
+ element: this.textRef.current,
160
+ })
161
+
162
+ this.setState({
163
+ isDragging: false,
164
+ isHovered: false,
165
+ })
166
+ }
167
+
168
+ // 重新计算 Label 大小
169
+ reCalcLabelSize = () => {}
170
+
171
+ // TODO:如何处理 Label zIndex 的问题, Label 永远会比节点层级高
172
+ // 当 Label 被元素遮盖时,隐藏它
173
+
174
+ componentDidMount() {
175
+ const { label, element, graphModel } = this.props
176
+
177
+ // 在点击元素、边或者画布 时,结束 Label 的编辑态
178
+ graphModel.eventCenter.on('blank:click,node:click,edge:click', () => {
179
+ // 如果当前 label 处于编辑态,则结束编辑态
180
+ if (this.state.isEditing) {
181
+ this.setState({ isEditing: false })
182
+
183
+ const value = this.textRef.current?.innerText ?? ''
184
+ const content = this.textRef.current?.innerHTML ?? ''
185
+
186
+ const {
187
+ properties: { _label },
188
+ } = element
189
+ const elementLabel = _label as LabelConfig[]
190
+ const idx = findIndex(elementLabel, (cur) => cur.id === label.id)
191
+
192
+ const target = elementLabel[idx]
193
+ elementLabel[idx] = {
194
+ ...target,
195
+ value,
196
+ content,
197
+ }
198
+
199
+ const targetElem = graphModel.getElement(element.id)
200
+ targetElem?.setProperty('_label', elementLabel)
201
+
202
+ element.setElementState(ElementState.DEFAULT)
203
+ }
204
+ if (this.textRef.current) {
205
+ this.textRef.current.contentEditable = 'false'
206
+ }
207
+ })
208
+
209
+ // TODO: 节点拖拽结束后,更新 Label 的位置
210
+ // eventCenter.on('node:drag', () => {})
211
+ // eventCenter.on('node:drop', () => {})
212
+ // eventCenter.on('node:mousemove', () => {})
213
+ //
214
+ // eventCenter.on('node:properties-change,node:properties-delete', () => {})
215
+ }
216
+
217
+ componentDidUpdate() {
218
+ // snapshot: any, // previousState: Readonly<ILabelState>, // previousProps: Readonly<ILabelProps>,
219
+ console.log('Label componentDidUpdate')
220
+ // console.log('previousProps', previousProps)
221
+ // console.log('previousState', previousState)
222
+ // console.log('snapshot', snapshot)
223
+ }
224
+
225
+ componentWillUnmount() {
226
+ const { graphModel } = this.props
227
+ graphModel.eventCenter.off('blank:click,node:click,edge:click')
228
+ }
229
+
230
+ // TODO: 当某一个标签更新时,如何避免其它标签的更新
231
+ // shouldComponentUpdate or memo
232
+
233
+ render() {
234
+ const { label, element, graphModel } = this.props
235
+ const { isDragging, isHovered, isEditing } = this.state
236
+ const { transformModel } = graphModel
237
+ const { transform } = transformModel.getTransformStyle()
238
+ const {
239
+ id,
240
+ x,
241
+ y,
242
+ zIndex,
243
+ vertical,
244
+ style,
245
+ rotate,
246
+ content,
247
+ labelWidth,
248
+ textOverflowMode,
249
+ } = label
250
+
251
+ const maxLabelWidth: number =
252
+ labelWidth ?? (element.BaseType === 'node' ? element.width - 20 : 80)
253
+ const containerStyle = {
254
+ left: `${x - maxLabelWidth / 2}px`,
255
+ top: `${y - 10}px`,
256
+ width: `${maxLabelWidth}px`,
257
+ height: '20px',
258
+ zIndex: zIndex ?? 1,
259
+ transform: rotate
260
+ ? `${transform} rotate(${rotate}deg)`
261
+ : `${transform} rotate(${vertical ? -0.25 : 0}turn)`,
262
+ }
263
+
264
+ return (
265
+ <div
266
+ id={`element-container-${id}`}
267
+ className={classNames('lf-label-editor-container')}
268
+ style={containerStyle}
269
+ onMouseDown={this.handleMouseDown}
270
+ onDblClick={this.handleDbClick}
271
+ onBlur={this.handleBlur}
272
+ onMouseEnter={this.setHoverOn}
273
+ onMouseOver={this.setHoverOn}
274
+ onMouseLeave={this.setHoverOff}
275
+ >
276
+ <div
277
+ ref={this.textRef}
278
+ id={`editor-container-${id}`}
279
+ className={classNames('lf-label-editor', {
280
+ 'lf-label-editor-dragging': isDragging,
281
+ 'lf-label-editor-editing': isEditing,
282
+ 'lf-label-editor-hover': !isEditing && isHovered,
283
+ [`lf-label-editor-${textOverflowMode}`]: !isEditing,
284
+ })}
285
+ style={{
286
+ maxWidth: `${maxLabelWidth}px`,
287
+ width: `${maxLabelWidth}px`,
288
+ ...style,
289
+ }}
290
+ dangerouslySetInnerHTML={{ __html: content }}
291
+ ></div>
292
+ </div>
293
+ )
294
+ }
295
+ }
296
+
297
+ export default Label
@@ -0,0 +1,82 @@
1
+ import LogicFlow, {
2
+ BaseEdgeModel,
3
+ BaseNodeModel,
4
+ GraphModel,
5
+ LogicFlowUtil,
6
+ h,
7
+ observable,
8
+ toJS,
9
+ } from '@logicflow/core'
10
+ import { assign } from 'lodash-es'
11
+
12
+ import LabelData = LogicFlow.LabelData
13
+ import LabelConfig = LogicFlow.LabelConfig
14
+ import GraphElement = LogicFlow.GraphElement
15
+
16
+ // export type ILabelConfig = {}
17
+ const { createUuid } = LogicFlowUtil
18
+
19
+ export class LabelModel {
20
+ id: string
21
+ type: string = 'label' // 目前写死,后续可以根据业务需求进行扩展
22
+
23
+ @observable x!: number
24
+ @observable y!: number
25
+ @observable content: string = ''
26
+ @observable value: string = ''
27
+ @observable rotate?: number
28
+ @observable style: h.JSX.CSSProperties = {}
29
+
30
+ @observable zIndex?: number
31
+ @observable vertical: boolean = false // 文字是否垂直显示
32
+ @observable editable: boolean = true // label 是否可编辑
33
+ @observable draggable: boolean = true // label 是否可拖拽
34
+ @observable labelWidth?: number
35
+ @observable textOverflowMode:
36
+ | 'ellipsis'
37
+ | 'wrap'
38
+ | 'clip'
39
+ | 'nowrap'
40
+ | 'default' = 'default' // Label 节点的文本溢出模式
41
+
42
+ // TODO: 后续看 label 是否可以独立存在,不依赖节点 or 边
43
+ element: BaseNodeModel | BaseEdgeModel // 当前节点关联的元素 Model
44
+ graphModel: GraphModel
45
+
46
+ constructor(
47
+ config: LabelConfig,
48
+ element: GraphElement,
49
+ graphModel: GraphModel,
50
+ ) {
51
+ this.element = element
52
+ this.graphModel = graphModel
53
+ this.id = config.id ?? createUuid()
54
+
55
+ this.initLabelData(config)
56
+ }
57
+
58
+ initLabelData(config: LabelConfig): void {
59
+ assign(this, config)
60
+ }
61
+
62
+ getData(): LabelData {
63
+ return {
64
+ id: this.id,
65
+ x: this.x,
66
+ y: this.y,
67
+ content: this.content,
68
+ value: this.value,
69
+ rotate: this.rotate,
70
+ style: toJS(this.style),
71
+
72
+ draggable: this.draggable,
73
+ editable: this.editable,
74
+ labelWidth: this.labelWidth,
75
+ textOverflowMode: this.textOverflowMode,
76
+
77
+ vertical: this.vertical,
78
+ }
79
+ }
80
+ }
81
+
82
+ export default LabelModel
@@ -0,0 +1,159 @@
1
+ import LogicFlow, { Component, GraphModel, h, observer } from '@logicflow/core'
2
+ import type { IToolProps } from '@logicflow/core'
3
+ import { forEach, merge } from 'lodash-es'
4
+ import LabelPlugin from '.'
5
+ import Label from './Label'
6
+ import LabelModel from './LabelModel'
7
+ import { MediumEditor, defaultOptions, ColorPickerButton } from './mediumEditor'
8
+
9
+ import LabelConfig = LogicFlow.LabelConfig
10
+
11
+ export type LabelConfigType = string | LabelConfig | LabelConfig[]
12
+
13
+ export interface ILabelOverlayState {
14
+ tick: number
15
+ }
16
+ // const { createUuid } = LogicFlowUtil
17
+
18
+ // DONE: 解决问题,如果 LabelOverlay 设置为 Observer,拖拽 Label 时会导致 LabelOverlay 组件重新渲染,不知道为何
19
+ // 目前解决了。流程是 拖动 -> 更新 label 的数据信息到 element model -> 重新渲染 LabelOverlay
20
+ // 这种目前存在的问题,会全量重新渲染,是否会影响性能 ❓❓❓
21
+ // 另一种解决方案是,在此组件中监听一些事件,当这些事件触发时,再重新渲染 LabelOverlay
22
+ // 讨论一下
23
+ @observer
24
+ export class LabelOverlay extends Component<IToolProps, ILabelOverlayState> {
25
+ static toolName = 'label-edit-tool'
26
+
27
+ lf: LogicFlow
28
+ editor?: MediumEditor
29
+ graphModel: GraphModel
30
+ labelMap: Map<string, LabelModel> = new Map()
31
+
32
+ constructor(props: IToolProps) {
33
+ super(props)
34
+
35
+ const { lf, graphModel } = props
36
+ this.lf = lf
37
+ this.graphModel = graphModel
38
+
39
+ this.state = { tick: 0 }
40
+ }
41
+
42
+ componentDidMount() {
43
+ const { graphModel } = this.props
44
+ // 1. 直接在此处初始化 RichTextEdit 工具
45
+ this.editor = new MediumEditor(
46
+ '.lf-label-editor',
47
+ merge(defaultOptions, {
48
+ autoLink: true,
49
+ extensions: {
50
+ colorPicker: new ColorPickerButton(),
51
+ },
52
+ }),
53
+ )
54
+
55
+ // TODO: 2. 在此处监听一些事件,当 node、edge 数据变化时,主动触发重新渲染,保证同步更新
56
+ // TODO: 3. 整理哪些事件应该触发 Label 的更新
57
+ // 不需要了,将当前组件设置成 @observer 后,graphModel 更新会自动触发更新
58
+ graphModel.eventCenter.on(
59
+ 'text:update,node:mousemove,node:resize,node:rotate,node:drag,label:drop,node:drop',
60
+ () => {
61
+ // this.setState({ tick: this.state.tick + 1 })
62
+ },
63
+ )
64
+
65
+ graphModel.eventCenter.on(
66
+ 'node:properties-change,node:properties-delete',
67
+ () => {
68
+ this.setState({ tick: this.state.tick + 1 })
69
+ },
70
+ )
71
+ }
72
+
73
+ componentDidUpdate() {
74
+ // 在组件更新后,将新增的 label 元素添加到富文本编辑器中
75
+ if (this.editor && this.editor.elements.length > 0) {
76
+ this.editor.addElements('.lf-label-editor')
77
+ } else {
78
+ // FIX: 如果初始化的数据中没有 properties._label,需要重新初始化富文本编辑器
79
+ this.editor?.destroy()
80
+ this.editor = new MediumEditor(
81
+ '.lf-label-editor',
82
+ merge(defaultOptions, {
83
+ autoLink: true,
84
+ extensions: {
85
+ colorPicker: new ColorPickerButton(),
86
+ },
87
+ }),
88
+ )
89
+ }
90
+ }
91
+
92
+ componentWillUnmount() {
93
+ // 组件销毁时,同时将富文本编辑器注销
94
+ this.editor?.destroy()
95
+ }
96
+
97
+ /**
98
+ * 获取当前画布上所有的 label
99
+ * 1. 第一步,先把当前所有的 text 转换为 label 进行展示
100
+ * 2. 数据同步,text 编辑后,同步更新 label,并重新渲染
101
+ */
102
+ getLabels(): h.JSX.Element[] | null {
103
+ // 1. 通过 graphModel 获取当前画布上所有的 label 配置数据
104
+ const {
105
+ lf: { extension },
106
+ graphModel,
107
+ } = this.props
108
+
109
+ const elements = [...graphModel.nodes, ...graphModel.edges]
110
+ const curExtension = extension['label'] as LabelPlugin
111
+
112
+ if (curExtension) {
113
+ const labels: h.JSX.Element[] = [] // 保存所有的 Label 元素
114
+
115
+ // TODO: 筛选出当前画布上,textMode 为 TextMode.LABEL 的元素(在支持元素级别的 textMode 时,需要做这个筛选)
116
+ // REMIND: 本期先只支持全局配置,所以判断全局的 textMode 即可
117
+ forEach(elements, (element) => {
118
+ const elementData = element.getData()
119
+ const labelConfig = elementData.properties?._label ?? []
120
+
121
+ forEach(labelConfig, (config) => {
122
+ const { labelMap } = this
123
+ // 查找 labelModel 实例,如果是实例化过的,直接复用;如果是新的,创建实例
124
+ // let label: LabelModel
125
+ // if (config.id && labelMap.has(config.id)) {
126
+ // label = labelMap.get(config.id)!
127
+ // } else {
128
+ // label = new LabelModel(config, element, graphModel)
129
+ // labelMap.set(label.id, label)
130
+ // }
131
+ const label = new LabelModel(config, element, graphModel)
132
+ labelMap.set(label.id, label)
133
+
134
+ labels.push(
135
+ <Label
136
+ key={label.id}
137
+ label={label}
138
+ element={element}
139
+ graphModel={graphModel}
140
+ />,
141
+ )
142
+ })
143
+ })
144
+
145
+ return labels
146
+ }
147
+ return null
148
+ }
149
+
150
+ render() {
151
+ return (
152
+ <foreignObject id="lf-label-overlay" class="lf-label-overlay">
153
+ {this.getLabels()}
154
+ </foreignObject>
155
+ )
156
+ }
157
+ }
158
+
159
+ export default LabelOverlay
@@ -0,0 +1,42 @@
1
+ import LogicFlow from '@logicflow/core'
2
+ import Point = LogicFlow.Point
3
+
4
+ /**
5
+ * 三次贝塞尔曲线公式
6
+ */
7
+ export const getPointOnBezier = (
8
+ t: number,
9
+ P0: Point,
10
+ P1: Point,
11
+ P2: Point,
12
+ P3: Point,
13
+ ) => {
14
+ const x =
15
+ (1 - t) ** 3 * P0.x +
16
+ 3 * (1 - t) ** 2 * t * P1.x +
17
+ 3 * (1 - t) * t ** 2 * P2.x +
18
+ t ** 3 * P3.x
19
+ const y =
20
+ (1 - t) ** 3 * P0.y +
21
+ 3 * (1 - t) ** 2 * t * P1.y +
22
+ 3 * (1 - t) * t ** 2 * P2.y +
23
+ t ** 3 * P3.y
24
+
25
+ return { x: x, y: y }
26
+ }
27
+
28
+ /**
29
+ * 计算两个节点间的距离
30
+ * @param point1
31
+ * @param point2
32
+ * @param gridSize
33
+ */
34
+ export const calcTwoPointsDistance = (
35
+ point1: Point,
36
+ point2: Point,
37
+ gridSize: number = 1,
38
+ ): number => {
39
+ const dx = (point1.x - point2.x) / gridSize
40
+ const dy = (point1.y - point2.y) / gridSize
41
+ return Math.sqrt(dx ** 2 + dy ** 2)
42
+ }