@logicflow/extension 2.2.0 → 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 (201) hide show
  1. package/README.md +16 -0
  2. package/dist/index.css +1 -1
  3. package/dist/index.min.js +1 -1
  4. package/dist/index.min.js.map +1 -1
  5. package/es/NodeResize/node/RectResize.d.ts +0 -6
  6. package/es/NodeResize/node/RectResize.js +2 -11
  7. package/es/bpmn-elements-adapter/json2xml.d.ts +2 -1
  8. package/es/bpmn-elements-adapter/json2xml.js +18 -4
  9. package/es/bpmn-elements-adapter/xml2json.js +2 -7
  10. package/es/components/control/index.d.ts +1 -0
  11. package/es/components/control/index.js +24 -11
  12. package/es/components/mini-map/index.js +1 -1
  13. package/es/dynamic-group/model.d.ts +2 -1
  14. package/es/dynamic-group/model.js +28 -11
  15. package/es/dynamic-group/node.js +1 -0
  16. package/es/index.css +1 -1
  17. package/es/index.d.ts +1 -0
  18. package/es/index.js +2 -0
  19. package/es/insert-node-in-polyline/index.js +11 -35
  20. package/es/materials/curved-edge/index.js +49 -21
  21. package/es/materials/group/GroupNode.d.ts +0 -6
  22. package/es/materials/group/GroupNode.js +1 -6
  23. package/es/pool/LaneModel.d.ts +90 -0
  24. package/es/pool/LaneModel.js +252 -0
  25. package/es/pool/LaneView.d.ts +40 -0
  26. package/es/pool/LaneView.js +202 -0
  27. package/es/pool/PoolModel.d.ts +120 -0
  28. package/es/pool/PoolModel.js +586 -0
  29. package/es/pool/PoolView.d.ts +17 -0
  30. package/es/pool/PoolView.js +76 -0
  31. package/es/pool/constant.d.ts +15 -0
  32. package/es/pool/constant.js +17 -0
  33. package/es/pool/index.d.ts +89 -0
  34. package/es/pool/index.js +524 -0
  35. package/es/pool/utils.d.ts +19 -0
  36. package/es/pool/utils.js +33 -0
  37. package/es/style/index.css +1 -1
  38. package/es/style/raw.d.ts +1 -1
  39. package/es/style/raw.js +1 -1
  40. package/es/tools/label/LabelOverlay.js +3 -3
  41. package/es/tools/label/mediumEditor.d.ts +1 -1
  42. package/es/tools/label/mediumEditor.js +89 -52
  43. package/es/tools/snapshot/index.d.ts +7 -3
  44. package/es/tools/snapshot/index.js +72 -77
  45. package/lib/NodeResize/node/RectResize.d.ts +0 -6
  46. package/lib/NodeResize/node/RectResize.js +1 -10
  47. package/lib/bpmn-elements-adapter/json2xml.d.ts +2 -1
  48. package/lib/bpmn-elements-adapter/json2xml.js +19 -4
  49. package/lib/bpmn-elements-adapter/xml2json.js +2 -7
  50. package/lib/components/control/index.d.ts +1 -0
  51. package/lib/components/control/index.js +24 -11
  52. package/lib/components/mini-map/index.js +1 -1
  53. package/lib/dynamic-group/model.d.ts +2 -1
  54. package/lib/dynamic-group/model.js +28 -11
  55. package/lib/dynamic-group/node.js +1 -0
  56. package/lib/index.css +1 -1
  57. package/lib/index.d.ts +1 -0
  58. package/lib/index.js +2 -0
  59. package/lib/insert-node-in-polyline/index.js +10 -34
  60. package/lib/materials/curved-edge/index.js +49 -21
  61. package/lib/materials/group/GroupNode.d.ts +0 -6
  62. package/lib/materials/group/GroupNode.js +1 -6
  63. package/lib/pool/LaneModel.d.ts +90 -0
  64. package/lib/pool/LaneModel.js +255 -0
  65. package/lib/pool/LaneView.d.ts +40 -0
  66. package/lib/pool/LaneView.js +205 -0
  67. package/lib/pool/PoolModel.d.ts +120 -0
  68. package/lib/pool/PoolModel.js +589 -0
  69. package/lib/pool/PoolView.d.ts +17 -0
  70. package/lib/pool/PoolView.js +79 -0
  71. package/lib/pool/constant.d.ts +15 -0
  72. package/lib/pool/constant.js +20 -0
  73. package/lib/pool/index.d.ts +89 -0
  74. package/lib/pool/index.js +527 -0
  75. package/lib/pool/utils.d.ts +19 -0
  76. package/lib/pool/utils.js +38 -0
  77. package/lib/style/index.css +1 -1
  78. package/lib/style/raw.d.ts +1 -1
  79. package/lib/style/raw.js +1 -1
  80. package/lib/tools/label/LabelOverlay.js +2 -2
  81. package/lib/tools/label/mediumEditor.d.ts +1 -1
  82. package/lib/tools/label/mediumEditor.js +91 -53
  83. package/lib/tools/snapshot/index.d.ts +7 -3
  84. package/lib/tools/snapshot/index.js +72 -77
  85. package/package.json +10 -7
  86. package/.turbo/turbo-build.log +0 -38
  87. package/CHANGELOG.md +0 -1766
  88. package/__test__/bpmn-adapter.test.js +0 -227
  89. package/es/materials/curved-edge/__test__/curved-edge.test.d.ts +0 -1
  90. package/es/materials/curved-edge/__test__/curved-edge.test.js +0 -18
  91. package/jest.config.js +0 -198
  92. package/lib/materials/curved-edge/__test__/curved-edge.test.d.ts +0 -1
  93. package/lib/materials/curved-edge/__test__/curved-edge.test.js +0 -20
  94. package/rollup.config.js +0 -52
  95. package/src/NodeResize/BasicShape/Ellipse.tsx +0 -22
  96. package/src/NodeResize/BasicShape/Polygon.tsx +0 -24
  97. package/src/NodeResize/BasicShape/Rect.tsx +0 -44
  98. package/src/NodeResize/control/Control.tsx +0 -537
  99. package/src/NodeResize/control/ControlGroup.tsx +0 -76
  100. package/src/NodeResize/control/Util.ts +0 -206
  101. package/src/NodeResize/index.ts +0 -26
  102. package/src/NodeResize/node/DiamondResize.tsx +0 -149
  103. package/src/NodeResize/node/EllipseResize.tsx +0 -140
  104. package/src/NodeResize/node/HtmlResize.tsx +0 -125
  105. package/src/NodeResize/node/RectResize.tsx +0 -146
  106. package/src/NodeResize/node/index.ts +0 -4
  107. package/src/bpmn/constant.ts +0 -56
  108. package/src/bpmn/events/EndEvent.ts +0 -73
  109. package/src/bpmn/events/StartEvent.ts +0 -52
  110. package/src/bpmn/events/index.ts +0 -2
  111. package/src/bpmn/flow/SequenceFlow.ts +0 -25
  112. package/src/bpmn/flow/index.ts +0 -1
  113. package/src/bpmn/gateways/ExclusiveGateway.ts +0 -71
  114. package/src/bpmn/gateways/index.ts +0 -1
  115. package/src/bpmn/getBpmnId.ts +0 -31
  116. package/src/bpmn/index.ts +0 -60
  117. package/src/bpmn/tasks/ServiceTask.ts +0 -63
  118. package/src/bpmn/tasks/UserTask.ts +0 -64
  119. package/src/bpmn/tasks/index.ts +0 -2
  120. package/src/bpmn-adapter/bpmnIds.ts +0 -31
  121. package/src/bpmn-adapter/index.ts +0 -835
  122. package/src/bpmn-adapter/json2xml.ts +0 -127
  123. package/src/bpmn-adapter/xml2json.ts +0 -544
  124. package/src/bpmn-elements/README.md +0 -223
  125. package/src/bpmn-elements/__tests__/definition.test.js +0 -72
  126. package/src/bpmn-elements/index.d.ts +0 -26
  127. package/src/bpmn-elements/index.ts +0 -107
  128. package/src/bpmn-elements/presets/Event/EndEventFactory.ts +0 -114
  129. package/src/bpmn-elements/presets/Event/IntermediateCatchEvent.ts +0 -108
  130. package/src/bpmn-elements/presets/Event/IntermediateThrowEvent.ts +0 -109
  131. package/src/bpmn-elements/presets/Event/StartEventFactory.ts +0 -114
  132. package/src/bpmn-elements/presets/Event/boundaryEventFactory.ts +0 -117
  133. package/src/bpmn-elements/presets/Event/index.ts +0 -14
  134. package/src/bpmn-elements/presets/Flow/flow.d.ts +0 -6
  135. package/src/bpmn-elements/presets/Flow/index.ts +0 -8
  136. package/src/bpmn-elements/presets/Flow/manhattan.ts +0 -691
  137. package/src/bpmn-elements/presets/Flow/sequenceFlow.ts +0 -65
  138. package/src/bpmn-elements/presets/Gateway/gateway.ts +0 -107
  139. package/src/bpmn-elements/presets/Gateway/index.ts +0 -23
  140. package/src/bpmn-elements/presets/Pool/Lane.ts +0 -211
  141. package/src/bpmn-elements/presets/Pool/Pool.ts +0 -284
  142. package/src/bpmn-elements/presets/Pool/index.ts +0 -89
  143. package/src/bpmn-elements/presets/Task/index.ts +0 -122
  144. package/src/bpmn-elements/presets/Task/subProcess.ts +0 -189
  145. package/src/bpmn-elements/presets/Task/task.ts +0 -193
  146. package/src/bpmn-elements/presets/icons.ts +0 -155
  147. package/src/bpmn-elements/utils.ts +0 -52
  148. package/src/bpmn-elements-adapter/README.md +0 -293
  149. package/src/bpmn-elements-adapter/__tests__/adapter_in.test.js +0 -528
  150. package/src/bpmn-elements-adapter/__tests__/adapter_out.test.js +0 -569
  151. package/src/bpmn-elements-adapter/constant.ts +0 -76
  152. package/src/bpmn-elements-adapter/index.ts +0 -1134
  153. package/src/bpmn-elements-adapter/json2xml.ts +0 -91
  154. package/src/bpmn-elements-adapter/xml2json.ts +0 -548
  155. package/src/components/context-menu/index.ts +0 -253
  156. package/src/components/control/index.ts +0 -141
  157. package/src/components/dnd-panel/index.ts +0 -137
  158. package/src/components/highlight/index.ts +0 -227
  159. package/src/components/menu/index.ts +0 -748
  160. package/src/components/mini-map/index.ts +0 -686
  161. package/src/components/selection-select/index.ts +0 -387
  162. package/src/dynamic-group/index.ts +0 -775
  163. package/src/dynamic-group/model.ts +0 -562
  164. package/src/dynamic-group/node.ts +0 -288
  165. package/src/dynamic-group/utils.ts +0 -46
  166. package/src/index.less +0 -1
  167. package/src/index.ts +0 -45
  168. package/src/insert-node-in-polyline/edge.ts +0 -175
  169. package/src/insert-node-in-polyline/index.ts +0 -187
  170. package/src/materials/curved-edge/__test__/curved-edge.test.ts +0 -46
  171. package/src/materials/curved-edge/index.ts +0 -185
  172. package/src/materials/group/GroupNode.ts +0 -442
  173. package/src/materials/group/index.ts +0 -542
  174. package/src/materials/node-selection/index.ts +0 -380
  175. package/src/mindmap/fakerRoot.ts +0 -19
  176. package/src/mindmap/index.ts +0 -328
  177. package/src/mindmap/markContent.ts +0 -81
  178. package/src/mindmap/markContentOption.ts +0 -81
  179. package/src/mindmap/markEntity.ts +0 -82
  180. package/src/mindmap/markRoot.ts +0 -83
  181. package/src/mindmap/theme.ts +0 -11
  182. package/src/rect-label-node/RectLabelNodeView.ts +0 -33
  183. package/src/rect-label-node/index.ts +0 -15
  184. package/src/style/index.less +0 -342
  185. package/src/style/raw.ts +0 -295
  186. package/src/tools/auto-layout/index.ts +0 -282
  187. package/src/tools/flow-path/index.ts +0 -233
  188. package/src/tools/label/Label.tsx +0 -357
  189. package/src/tools/label/LabelModel.ts +0 -83
  190. package/src/tools/label/LabelOverlay.tsx +0 -158
  191. package/src/tools/label/algorithm.ts +0 -42
  192. package/src/tools/label/index.ts +0 -479
  193. package/src/tools/label/mediumEditor.ts +0 -94
  194. package/src/tools/label/utils.ts +0 -395
  195. package/src/tools/proximity-connect/index.ts +0 -435
  196. package/src/tools/snapshot/README.md +0 -145
  197. package/src/tools/snapshot/index.ts +0 -718
  198. package/src/tools/snapshot/utils.ts +0 -163
  199. package/src/turbo-adapter/index.ts +0 -212
  200. package/stats.html +0 -4842
  201. package/tsconfig.json +0 -18
@@ -1,158 +0,0 @@
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
- labels.push(
134
- <Label
135
- key={label.id}
136
- label={label}
137
- element={element}
138
- graphModel={graphModel}
139
- />,
140
- )
141
- })
142
- })
143
-
144
- return labels
145
- }
146
- return null
147
- }
148
-
149
- render() {
150
- return (
151
- <foreignObject id="lf-label-overlay" class="lf-label-overlay">
152
- {this.getLabels()}
153
- </foreignObject>
154
- )
155
- }
156
- }
157
-
158
- export default LabelOverlay
@@ -1,42 +0,0 @@
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
- }
@@ -1,479 +0,0 @@
1
- import LogicFlow, { createUuid, GraphModel, TextMode } from '@logicflow/core'
2
- import {
3
- cloneDeep,
4
- forEach,
5
- isArray,
6
- isEmpty,
7
- isEqual,
8
- isObject,
9
- map,
10
- } from 'lodash-es'
11
- import LabelOverlay, { LabelConfigType } from './LabelOverlay'
12
- import {
13
- BBoxInfo,
14
- calcPointAfterResize,
15
- rotatePointAroundCenter,
16
- } from './utils'
17
-
18
- import Position = LogicFlow.Position
19
- import NodeData = LogicFlow.NodeData
20
- import EdgeData = LogicFlow.EdgeData
21
- import Extension = LogicFlow.Extension
22
- import LabelConfig = LogicFlow.LabelConfig
23
- import GraphElement = LogicFlow.GraphElement
24
-
25
- // 类型定义,如果 isMultiple 为 true 的话,maxCount 为数值且大于 1
26
- export type ILabelOptions = {
27
- isMultiple?: boolean
28
- maxCount?: number
29
- labelWidth?: number
30
- textOverflowMode?: 'ellipsis' | 'wrap' | 'clip' | 'nowrap' | 'default'
31
- }
32
-
33
- export class Label implements Extension {
34
- static pluginName = 'label'
35
-
36
- lf: LogicFlow
37
- options: ILabelOptions
38
-
39
- textOverflowMode: 'ellipsis' | 'wrap' | 'clip' | 'nowrap' | 'default'
40
- isMultiple: boolean
41
- labelWidth?: number
42
- maxCount: number // 默认值给无限大数值
43
-
44
- labelInitPositionMap: Map<string, Position> = new Map()
45
-
46
- constructor({ lf, options }: { lf: LogicFlow; options: ILabelOptions }) {
47
- this.lf = lf
48
- // DONE: 根据 options 初始化一些插件配置,比如是否支持多个 label 等,生效在所有 label 中
49
- this.options = options ?? {}
50
-
51
- this.textOverflowMode = options.textOverflowMode ?? 'default'
52
- this.isMultiple = options.isMultiple ?? true
53
- this.labelWidth = options.labelWidth
54
- this.maxCount = options.maxCount ?? Infinity
55
-
56
- // DONE: 1. 启用插件时,将当前画布的 textMode 更新为 TextMode.LABEL。
57
- // 如果将其又重新设置为 TextModel.TEXT,则需要 disable 掉 Label 工具,enable TextEditTool
58
- lf.graphModel.editConfigModel.updateTextMode(TextMode.LABEL)
59
-
60
- // TODO: 2. 做一些插件需要的事件监听
61
- this.addEventListeners()
62
-
63
- // TODO: 3. 自定义快捷键,比如 delete,选中 label 时,移除 label
64
- this.rewriteShortcut()
65
-
66
- // 插件中注册 LabelOverlay 工具,用于 label 的编辑
67
- lf.tool.registerTool(LabelOverlay.toolName, LabelOverlay)
68
- // LabelOverlay 和 TextEditTool 互斥,所以将它 disable 掉
69
- lf.tool.disableTool('text-edit-tool')
70
- }
71
-
72
- /**
73
- * 格式化元素的 Label 配置,后续初始化 Label 用统一的数据格式
74
- * 主要是将 _label 类型 string | LabelConfig | LabelConfig[] 统一转换为 LabelConfig[]
75
- * @param graphModel 当前图的 model
76
- * @param element 当前元素 model
77
- * @return LabelConfig[]
78
- */
79
- private formatConfig(
80
- graphModel: GraphModel,
81
- element: GraphElement,
82
- ): LabelConfig[] {
83
- const {
84
- editConfigModel: {
85
- nodeTextEdit,
86
- edgeTextEdit,
87
- nodeTextDraggable,
88
- edgeTextDraggable,
89
- },
90
- } = graphModel
91
- const { textOverflowMode, isMultiple, maxCount, labelWidth } = this
92
- const {
93
- text,
94
- zIndex,
95
- properties: { _label, _labelOption = {} },
96
- } = element
97
-
98
- // 当前元素的 Label 相关配置
99
- const curLabelConfig = _label as LabelConfigType
100
- const { isMultiple: curIsMultiple, maxCount: curMaxCount }: ILabelOptions =
101
- _labelOption as ILabelOptions
102
-
103
- // REMIND: 对 3 种可能得数据类型进行处理
104
- let formatConfig: LabelConfig[] = [] // 保存格式化后的 LabelConfig
105
- if (isArray(curLabelConfig)) {
106
- // 1. 数组的话就是 LabelConfig[] 类型
107
- // 判断是否开启 isMultiple, 如果开启了,判断是否超过最大数量。超出就截取
108
- const size = curMaxCount ?? maxCount // 优先级,当设置 multiple 时,元素的 maxCount 优先级高于插件的 maxCount
109
- if (isMultiple && curIsMultiple) {
110
- if (curLabelConfig.length > size) {
111
- formatConfig = curLabelConfig.slice(0, size)
112
- } else {
113
- formatConfig = curLabelConfig
114
- }
115
- } else {
116
- formatConfig = [curLabelConfig[0]]
117
- }
118
- } else if (isObject(curLabelConfig)) {
119
- // 2. 对象的话就是 LabelConfig 类型
120
- formatConfig = [curLabelConfig]
121
- } else if (typeof curLabelConfig === 'string' || !curLabelConfig) {
122
- // 3. 字符串或者为空的话就是 string 类型,基于 text 的数据合成 LabelConfig 信息(主要复用 text 的 x,y 信息)
123
- const config: LabelConfig = {
124
- ...text,
125
- content: curLabelConfig || text?.value,
126
- draggable:
127
- element.BaseType === 'edge' ? edgeTextDraggable : nodeTextDraggable,
128
- }
129
- formatConfig = config.value ? [config] : []
130
- }
131
-
132
- // TODO: 针对 Edge,在 edge 更新时 重新计算 Label 的位置
133
- if (element.BaseType === 'edge') {
134
- // 判断当前 label,是否在 edge 的路径上,如果不在,就重新计算位置
135
- formatConfig = map(formatConfig, (config) => {
136
- return config
137
- })
138
- }
139
-
140
- // DONE: 再根据一些全局配置,比如是否支持垂直显示等,对 LabelConfig 进行二次处理
141
- // 优先级:全局配置 > 元素配置。比如全局设置 isMultiple 为 true 时,才可以使用 局部的 isMultiple 设置才生效
142
- // 当全局 isMultiple 为 false 时,局部的 isMultiple 不生效
143
- return map(formatConfig, (config) => {
144
- if (!config.id) {
145
- config.id = createUuid()
146
- }
147
-
148
- const {
149
- value,
150
- content,
151
- vertical,
152
- editable,
153
- draggable,
154
- textOverflowMode: labelTextOverflowMode,
155
- } = config
156
-
157
- const textEdit = element.BaseType === 'node' ? nodeTextEdit : edgeTextEdit
158
- const textDraggable =
159
- element.BaseType === 'node' ? nodeTextDraggable : edgeTextDraggable
160
- return {
161
- ...config,
162
- zIndex,
163
- labelWidth,
164
- content: content ?? value,
165
- vertical: vertical ?? false,
166
- editable: Boolean(textEdit) && editable,
167
- draggable: Boolean(textDraggable) && draggable,
168
- textOverflowMode: labelTextOverflowMode ?? textOverflowMode,
169
- }
170
- })
171
- }
172
-
173
- /**
174
- * 根据初始化的数据,格式化 Label 的数据格式后,统一更新到元素的 properties._label 中,保证后续的渲染以这个数据格式进行
175
- * @param graphModel
176
- */
177
- private setupLabels(graphModel: GraphModel) {
178
- // const elements = [...graphModel.nodes, ...graphModel.edges]
179
- const elements = graphModel.sortElements
180
-
181
- // TODO: 1. 筛选出当前画布上,textMode 为 TextMode.LABEL 的元素(在支持元素级别的 textMode 时,需要做这个筛选)
182
- // REMIND: 本期先只支持全局配置,所以判断全局的 textMode 即可
183
- forEach(elements, (element) => {
184
- // DONE: 2. 在此处做数据的转换
185
- // 输入:NodeConfig.properties._label: string | LabelConfig | LabelConfig[]
186
- // 输出:NodeData.properties._label: LabelData | LabelData[]
187
- // 是否需要根据 isMultiple 控制是否返回数组或对象 or 直接全部返回数组 ❓❓❓ -> 目前直接全部返回数组
188
-
189
- this.rewriteInnerMethods(element)
190
-
191
- const formatLabelConfig = this.formatConfig(graphModel, element)
192
- // FIX: BUG Here: 格式化后的 labelConfig 没有同步到 element 上,导致每次重新渲染时,都会重新格式化,且重新生成 id
193
- // 但如果在此处通过 setProperty 更新元素的 _label 时,又会导致死循环
194
- element.setProperty('_label', formatLabelConfig)
195
- })
196
- }
197
-
198
- /**
199
- * 给元素添加一个 label
200
- * @param element
201
- * @param position
202
- */
203
- private addLabel(element: GraphElement, position: Position) {
204
- const { isMultiple, maxCount } = this
205
- const {
206
- properties: { _label, _labelOption },
207
- } = element
208
- const curLabelConfig = (_label as LabelConfig[]) ?? []
209
- const curLabelOption = (_labelOption as ILabelOptions) ?? {}
210
-
211
- const len = curLabelConfig.length
212
- const newLabel = {
213
- id: createUuid(),
214
- x: position.x,
215
- y: position.y,
216
- content: `Label${len + 1}`,
217
- value: `Label${len + 1}`,
218
- style: {},
219
- draggable: true,
220
- editable: true,
221
- vertical: false,
222
- }
223
- // 全局的isMultiple为false,或全局isMultiple为true但局部isMultiple指明是false,或当前label长度已经达到上线时,不允许添加多个 label
224
- if (
225
- !isMultiple ||
226
- (isMultiple && curLabelOption.isMultiple === false) ||
227
- len >= (curLabelOption?.maxCount ?? maxCount)
228
- ) {
229
- return
230
- }
231
-
232
- curLabelConfig.push(newLabel)
233
- element.setProperty('_label', curLabelConfig)
234
- }
235
-
236
- /**
237
- * 移除元素的某个 label
238
- * @private
239
- */
240
- // private removeLabel() {}
241
-
242
- private addEventListeners() {
243
- const { graphModel } = this.lf
244
- const { eventCenter, editConfigModel } = graphModel
245
-
246
- eventCenter.on('graph:rendered', ({ graphModel }) => {
247
- this.setupLabels(graphModel)
248
- })
249
-
250
- // 监听元素双击事件,给元素增加 Label
251
- eventCenter.on(
252
- 'node:dbclick,edge:dbclick',
253
- ({ e, data }: { e: MouseEvent; data: NodeData | EdgeData }) => {
254
- // DONE: 增加 label 的数据信息到 element model
255
- const target: GraphElement | undefined = graphModel.getElement(data.id)
256
- // DONE: 将 clientX 和 clientY 转换为画布坐标
257
- const {
258
- canvasOverlayPosition: { x: x1, y: y1 },
259
- } = graphModel.getPointByClient({
260
- x: e.clientX,
261
- y: e.clientY,
262
- })
263
-
264
- const point: Position = {
265
- x: x1,
266
- y: y1,
267
- }
268
- if (target && editConfigModel.textMode === TextMode.LABEL) {
269
- this.addLabel(target, point)
270
- }
271
- },
272
- )
273
-
274
- // 监听 node:resize 事件,在 resize 时,重新计算 label 的位置信息
275
- eventCenter.on('node:resize', ({ preData, data, model }) => {
276
- const {
277
- width: preWidth,
278
- height: preHeight,
279
- _label = [],
280
- } = preData.properties ?? {}
281
- const { width: curWidth, height: curHeight } = data.properties ?? {}
282
-
283
- if (preWidth && preHeight && curWidth && curHeight) {
284
- const origin: BBoxInfo = {
285
- x: preData.x,
286
- y: preData.y,
287
- width: preWidth,
288
- height: preHeight,
289
- }
290
- const scaled: BBoxInfo = {
291
- x: data.x,
292
- y: data.y,
293
- width: curWidth,
294
- height: curHeight,
295
- }
296
- const newLabelConfig = map(_label as LabelConfig[], (label) => {
297
- const { x, y } = label
298
- const newPoint = calcPointAfterResize(origin, scaled, { x, y })
299
- return {
300
- ...label,
301
- ...newPoint,
302
- }
303
- })
304
-
305
- model.setProperty('_label', newLabelConfig)
306
- }
307
- })
308
-
309
- // 监听 node:rotate 事件,在 rotate 时,重新计算 Label 的位置信息
310
- eventCenter.on('node:rotate', ({ model }) => {
311
- const {
312
- x,
313
- y,
314
- rotate,
315
- properties: { _label = [] },
316
- } = model
317
- const center: Position = { x, y }
318
-
319
- const newLabelConfig = map(_label as LabelConfig[], (label) => {
320
- if (!label.id) return label
321
-
322
- let point: Position = { x: label.x, y: label.y }
323
- if (this.labelInitPositionMap.has(label.id)) {
324
- point = this.labelInitPositionMap.get(label.id)!
325
- } else {
326
- this.labelInitPositionMap.set(label.id, point)
327
- }
328
-
329
- // 弧度转角度
330
- let theta = rotate * (180 / Math.PI)
331
- if (theta < 0) theta += 360
332
- const radian = theta * (Math.PI / 180)
333
-
334
- const newPoint = rotatePointAroundCenter(point, center, radian)
335
- return {
336
- ...label,
337
- ...newPoint,
338
- rotate: theta,
339
- }
340
- })
341
-
342
- model.setProperty('_label', newLabelConfig)
343
- })
344
- // 监听元素新增事件,元素label格式化
345
- eventCenter.on('node:dnd-add,node:add,edge:add', ({ data }) => {
346
- const element = graphModel.getElement(data.id)
347
- if (element) {
348
- this.rewriteInnerMethods(element)
349
- // 检查_label是否已经是格式化后的数组格式,如果是则跳过格式化
350
- // 这样可以避免在复制粘贴时重复处理已经格式化好的label数据
351
- const currentLabel = element.properties._label
352
- if (
353
- !isArray(currentLabel) ||
354
- currentLabel.length === 0 ||
355
- !currentLabel[0].id
356
- ) {
357
- const formatedLabel = this.formatConfig(graphModel, data)
358
- element.setProperty('_label', formatedLabel)
359
- }
360
- }
361
- })
362
- }
363
-
364
- /**
365
- * 重写元素的一些方法,以支持 Label 的拖拽、编辑等
366
- * @param element
367
- */
368
- private rewriteInnerMethods(element: GraphElement) {
369
- // 重写 edgeModel/nodeModel moveText 方法,在 move text 时,以相同的逻辑移动 label
370
- element.moveText = (deltaX: number, deltaY: number) => {
371
- if (!element.text) return
372
- const {
373
- text: { x, y, value, draggable, editable },
374
- } = element
375
-
376
- element.text = {
377
- value,
378
- editable,
379
- draggable,
380
- x: x + deltaX,
381
- y: y + deltaY,
382
- }
383
- const properties = cloneDeep(element.getProperties())
384
- // 重新计算新的 label 位置信息
385
- if (isArray(properties._label)) {
386
- const nextLabel = map(properties._label as LabelConfig[], (label) => {
387
- return {
388
- ...label,
389
- x: label.x + deltaX,
390
- y: label.y + deltaY,
391
- }
392
- })
393
- element?.setProperty('_label', nextLabel)
394
- }
395
- }
396
-
397
- // TODO: others methods ???
398
- }
399
-
400
- private rewriteShortcut() {
401
- const { keyboard, graphModel } = this.lf
402
- const {
403
- options: { keyboard: keyboardOptions },
404
- } = keyboard
405
- keyboard.off(['backspace'])
406
- keyboard.on(['backspace'], () => {
407
- if (!keyboardOptions?.enabled) return true
408
- if (graphModel.textEditElement) return true
409
- const elements = graphModel.getSelectElements(true)
410
- this.lf.clearSelectElements()
411
- const {
412
- graphModel: { editConfigModel },
413
- } = this.lf
414
- elements.edges.forEach((edge) => {
415
- const { properties } = edge
416
- if (
417
- properties &&
418
- !isEmpty(properties._label) &&
419
- editConfigModel.textMode === TextMode.LABEL
420
- ) {
421
- const newLabelList = properties._label.filter(
422
- (label) => !label.isSelected,
423
- )
424
- // 如果两个labelList长度不一致,说明有选中的元素,此时backspace做的动作是删除label
425
- if (!isEqual(newLabelList.length, properties._label.length)) {
426
- const edgeModel = graphModel.getEdgeModelById(edge.id)
427
- edgeModel?.setProperty('_label', newLabelList)
428
- return
429
- }
430
- }
431
- edge.id && this.lf.deleteEdge(edge.id)
432
- })
433
- elements.nodes.forEach((node) => {
434
- const { properties } = node
435
- if (
436
- properties &&
437
- !isEmpty(properties._label) &&
438
- editConfigModel.textMode === TextMode.LABEL
439
- ) {
440
- const newLabelList = properties._label.filter(
441
- (label) => !label.isSelected,
442
- )
443
- if (!isEqual(newLabelList.length, properties._label.length)) {
444
- const nodeModel = graphModel.getNodeModelById(node.id)
445
- nodeModel?.setProperty('_label', newLabelList)
446
- return
447
- }
448
- }
449
- node.id && this.lf.deleteNode(node.id)
450
- })
451
- return false
452
- })
453
- }
454
-
455
- /**
456
- * 更新当前渲染使用的 Text or Label 模式
457
- */
458
- updateTextMode(textMode: TextMode) {
459
- const {
460
- graphModel: { editConfigModel },
461
- } = this.lf
462
- if (textMode === editConfigModel.textMode) return
463
-
464
- editConfigModel.updateTextMode(textMode)
465
- if (textMode === TextMode.LABEL) {
466
- this.lf.tool.enableTool(LabelOverlay.toolName)
467
- this.lf.tool.disableTool('text-edit-tool')
468
- } else if (textMode === TextMode.TEXT) {
469
- this.lf.tool.enableTool('text-edit-tool')
470
- this.lf.tool.disableTool(LabelOverlay.toolName)
471
- }
472
- }
473
-
474
- render() {}
475
-
476
- destroy() {}
477
- }
478
-
479
- export default Label