@logicflow/extension 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 (125) hide show
  1. package/README.md +16 -0
  2. package/package.json +10 -7
  3. package/.turbo/turbo-build.log +0 -38
  4. package/CHANGELOG.md +0 -1829
  5. package/__test__/bpmn-adapter.test.js +0 -227
  6. package/es/materials/curved-edge/__test__/curved-edge.test.d.ts +0 -1
  7. package/es/materials/curved-edge/__test__/curved-edge.test.js +0 -18
  8. package/jest.config.js +0 -198
  9. package/lib/materials/curved-edge/__test__/curved-edge.test.d.ts +0 -1
  10. package/lib/materials/curved-edge/__test__/curved-edge.test.js +0 -20
  11. package/rollup.config.js +0 -52
  12. package/src/NodeResize/BasicShape/Ellipse.tsx +0 -22
  13. package/src/NodeResize/BasicShape/Polygon.tsx +0 -24
  14. package/src/NodeResize/BasicShape/Rect.tsx +0 -44
  15. package/src/NodeResize/control/Control.tsx +0 -537
  16. package/src/NodeResize/control/ControlGroup.tsx +0 -76
  17. package/src/NodeResize/control/Util.ts +0 -206
  18. package/src/NodeResize/index.ts +0 -26
  19. package/src/NodeResize/node/DiamondResize.tsx +0 -149
  20. package/src/NodeResize/node/EllipseResize.tsx +0 -140
  21. package/src/NodeResize/node/HtmlResize.tsx +0 -125
  22. package/src/NodeResize/node/RectResize.tsx +0 -126
  23. package/src/NodeResize/node/index.ts +0 -4
  24. package/src/bpmn/constant.ts +0 -56
  25. package/src/bpmn/events/EndEvent.ts +0 -73
  26. package/src/bpmn/events/StartEvent.ts +0 -52
  27. package/src/bpmn/events/index.ts +0 -2
  28. package/src/bpmn/flow/SequenceFlow.ts +0 -25
  29. package/src/bpmn/flow/index.ts +0 -1
  30. package/src/bpmn/gateways/ExclusiveGateway.ts +0 -71
  31. package/src/bpmn/gateways/index.ts +0 -1
  32. package/src/bpmn/getBpmnId.ts +0 -31
  33. package/src/bpmn/index.ts +0 -60
  34. package/src/bpmn/tasks/ServiceTask.ts +0 -63
  35. package/src/bpmn/tasks/UserTask.ts +0 -64
  36. package/src/bpmn/tasks/index.ts +0 -2
  37. package/src/bpmn-adapter/bpmnIds.ts +0 -31
  38. package/src/bpmn-adapter/index.ts +0 -835
  39. package/src/bpmn-adapter/json2xml.ts +0 -127
  40. package/src/bpmn-adapter/xml2json.ts +0 -544
  41. package/src/bpmn-elements/README.md +0 -223
  42. package/src/bpmn-elements/__tests__/definition.test.js +0 -72
  43. package/src/bpmn-elements/index.d.ts +0 -26
  44. package/src/bpmn-elements/index.ts +0 -107
  45. package/src/bpmn-elements/presets/Event/EndEventFactory.ts +0 -114
  46. package/src/bpmn-elements/presets/Event/IntermediateCatchEvent.ts +0 -108
  47. package/src/bpmn-elements/presets/Event/IntermediateThrowEvent.ts +0 -109
  48. package/src/bpmn-elements/presets/Event/StartEventFactory.ts +0 -114
  49. package/src/bpmn-elements/presets/Event/boundaryEventFactory.ts +0 -117
  50. package/src/bpmn-elements/presets/Event/index.ts +0 -14
  51. package/src/bpmn-elements/presets/Flow/flow.d.ts +0 -6
  52. package/src/bpmn-elements/presets/Flow/index.ts +0 -8
  53. package/src/bpmn-elements/presets/Flow/manhattan.ts +0 -691
  54. package/src/bpmn-elements/presets/Flow/sequenceFlow.ts +0 -65
  55. package/src/bpmn-elements/presets/Gateway/gateway.ts +0 -107
  56. package/src/bpmn-elements/presets/Gateway/index.ts +0 -23
  57. package/src/bpmn-elements/presets/Pool/Lane.ts +0 -211
  58. package/src/bpmn-elements/presets/Pool/Pool.ts +0 -284
  59. package/src/bpmn-elements/presets/Pool/index.ts +0 -89
  60. package/src/bpmn-elements/presets/Task/index.ts +0 -122
  61. package/src/bpmn-elements/presets/Task/subProcess.ts +0 -189
  62. package/src/bpmn-elements/presets/Task/task.ts +0 -193
  63. package/src/bpmn-elements/presets/icons.ts +0 -155
  64. package/src/bpmn-elements/utils.ts +0 -52
  65. package/src/bpmn-elements-adapter/README.md +0 -293
  66. package/src/bpmn-elements-adapter/__tests__/adapter_in.test.js +0 -528
  67. package/src/bpmn-elements-adapter/__tests__/adapter_out.test.js +0 -569
  68. package/src/bpmn-elements-adapter/constant.ts +0 -76
  69. package/src/bpmn-elements-adapter/index.ts +0 -1134
  70. package/src/bpmn-elements-adapter/json2xml.ts +0 -105
  71. package/src/bpmn-elements-adapter/xml2json.ts +0 -542
  72. package/src/components/context-menu/index.ts +0 -253
  73. package/src/components/control/index.ts +0 -155
  74. package/src/components/dnd-panel/index.ts +0 -137
  75. package/src/components/highlight/index.ts +0 -227
  76. package/src/components/menu/index.ts +0 -748
  77. package/src/components/mini-map/index.ts +0 -686
  78. package/src/components/selection-select/index.ts +0 -387
  79. package/src/dynamic-group/index.ts +0 -774
  80. package/src/dynamic-group/model.ts +0 -580
  81. package/src/dynamic-group/node.ts +0 -288
  82. package/src/dynamic-group/utils.ts +0 -46
  83. package/src/index.less +0 -1
  84. package/src/index.ts +0 -47
  85. package/src/insert-node-in-polyline/edge.ts +0 -175
  86. package/src/insert-node-in-polyline/index.ts +0 -193
  87. package/src/materials/curved-edge/__test__/curved-edge.test.ts +0 -46
  88. package/src/materials/curved-edge/index.ts +0 -217
  89. package/src/materials/group/GroupNode.ts +0 -437
  90. package/src/materials/group/index.ts +0 -542
  91. package/src/materials/node-selection/index.ts +0 -380
  92. package/src/mindmap/fakerRoot.ts +0 -19
  93. package/src/mindmap/index.ts +0 -328
  94. package/src/mindmap/markContent.ts +0 -81
  95. package/src/mindmap/markContentOption.ts +0 -81
  96. package/src/mindmap/markEntity.ts +0 -82
  97. package/src/mindmap/markRoot.ts +0 -83
  98. package/src/mindmap/theme.ts +0 -11
  99. package/src/pool/LaneModel.ts +0 -226
  100. package/src/pool/LaneView.ts +0 -220
  101. package/src/pool/PoolModel.ts +0 -631
  102. package/src/pool/PoolView.ts +0 -75
  103. package/src/pool/constant.ts +0 -19
  104. package/src/pool/index.ts +0 -621
  105. package/src/pool/utils.ts +0 -46
  106. package/src/rect-label-node/RectLabelNodeView.ts +0 -33
  107. package/src/rect-label-node/index.ts +0 -15
  108. package/src/style/index.less +0 -381
  109. package/src/style/raw.ts +0 -328
  110. package/src/tools/auto-layout/index.ts +0 -282
  111. package/src/tools/flow-path/index.ts +0 -233
  112. package/src/tools/label/Label.tsx +0 -357
  113. package/src/tools/label/LabelModel.ts +0 -83
  114. package/src/tools/label/LabelOverlay.tsx +0 -162
  115. package/src/tools/label/algorithm.ts +0 -42
  116. package/src/tools/label/index.ts +0 -479
  117. package/src/tools/label/mediumEditor.ts +0 -121
  118. package/src/tools/label/utils.ts +0 -395
  119. package/src/tools/proximity-connect/index.ts +0 -435
  120. package/src/tools/snapshot/README.md +0 -145
  121. package/src/tools/snapshot/index.ts +0 -701
  122. package/src/tools/snapshot/utils.ts +0 -163
  123. package/src/turbo-adapter/index.ts +0 -212
  124. package/stats.html +0 -4842
  125. package/tsconfig.json +0 -18
@@ -1,162 +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 {
8
- MediumEditor,
9
- defaultOptions,
10
- createColorPickerButtonClass,
11
- } from './mediumEditor'
12
-
13
- import LabelConfig = LogicFlow.LabelConfig
14
-
15
- export type LabelConfigType = string | LabelConfig | LabelConfig[]
16
-
17
- export interface ILabelOverlayState {
18
- tick: number
19
- }
20
- // const { createUuid } = LogicFlowUtil
21
-
22
- // DONE: 解决问题,如果 LabelOverlay 设置为 Observer,拖拽 Label 时会导致 LabelOverlay 组件重新渲染,不知道为何
23
- // 目前解决了。流程是 拖动 -> 更新 label 的数据信息到 element model -> 重新渲染 LabelOverlay
24
- // 这种目前存在的问题,会全量重新渲染,是否会影响性能 ❓❓❓
25
- // 另一种解决方案是,在此组件中监听一些事件,当这些事件触发时,再重新渲染 LabelOverlay
26
- // 讨论一下
27
- @observer
28
- export class LabelOverlay extends Component<IToolProps, ILabelOverlayState> {
29
- static toolName = 'label-edit-tool'
30
-
31
- lf: LogicFlow
32
- editor?: MediumEditor
33
- graphModel: GraphModel
34
- labelMap: Map<string, LabelModel> = new Map()
35
-
36
- constructor(props: IToolProps) {
37
- super(props)
38
-
39
- const { lf, graphModel } = props
40
- this.lf = lf
41
- this.graphModel = graphModel
42
-
43
- this.state = { tick: 0 }
44
- }
45
-
46
- componentDidMount() {
47
- const { graphModel } = this.props
48
- // 1. 直接在此处初始化 RichTextEdit 工具
49
- this.editor = new MediumEditor(
50
- '.lf-label-editor',
51
- merge(defaultOptions, {
52
- autoLink: true,
53
- extensions: {
54
- colorPicker: new (createColorPickerButtonClass(MediumEditor))(),
55
- },
56
- }),
57
- )
58
-
59
- // TODO: 2. 在此处监听一些事件,当 node、edge 数据变化时,主动触发重新渲染,保证同步更新
60
- // TODO: 3. 整理哪些事件应该触发 Label 的更新
61
- // 不需要了,将当前组件设置成 @observer 后,graphModel 更新会自动触发更新
62
- graphModel.eventCenter.on(
63
- 'text:update,node:mousemove,node:resize,node:rotate,node:drag,label:drop,node:drop',
64
- () => {
65
- // this.setState({ tick: this.state.tick + 1 })
66
- },
67
- )
68
-
69
- graphModel.eventCenter.on(
70
- 'node:properties-change,node:properties-delete',
71
- () => {
72
- this.setState({ tick: this.state.tick + 1 })
73
- },
74
- )
75
- }
76
-
77
- componentDidUpdate() {
78
- // 在组件更新后,将新增的 label 元素添加到富文本编辑器中
79
- if (this.editor && this.editor.elements.length > 0) {
80
- this.editor.addElements('.lf-label-editor')
81
- } else {
82
- // FIX: 如果初始化的数据中没有 properties._label,需要重新初始化富文本编辑器
83
- this.editor?.destroy()
84
- this.editor = new MediumEditor(
85
- '.lf-label-editor',
86
- merge(defaultOptions, {
87
- autoLink: true,
88
- extensions: {
89
- colorPicker: new (createColorPickerButtonClass(MediumEditor))(),
90
- },
91
- }),
92
- )
93
- }
94
- }
95
-
96
- componentWillUnmount() {
97
- // 组件销毁时,同时将富文本编辑器注销
98
- this.editor?.destroy()
99
- }
100
-
101
- /**
102
- * 获取当前画布上所有的 label
103
- * 1. 第一步,先把当前所有的 text 转换为 label 进行展示
104
- * 2. 数据同步,text 编辑后,同步更新 label,并重新渲染
105
- */
106
- getLabels(): h.JSX.Element[] | null {
107
- // 1. 通过 graphModel 获取当前画布上所有的 label 配置数据
108
- const {
109
- lf: { extension },
110
- graphModel,
111
- } = this.props
112
-
113
- const elements = [...graphModel.nodes, ...graphModel.edges]
114
- const curExtension = extension['label'] as LabelPlugin
115
-
116
- if (curExtension) {
117
- const labels: h.JSX.Element[] = [] // 保存所有的 Label 元素
118
-
119
- // TODO: 筛选出当前画布上,textMode 为 TextMode.LABEL 的元素(在支持元素级别的 textMode 时,需要做这个筛选)
120
- // REMIND: 本期先只支持全局配置,所以判断全局的 textMode 即可
121
- forEach(elements, (element) => {
122
- const elementData = element.getData()
123
- const labelConfig = elementData.properties?._label ?? []
124
-
125
- forEach(labelConfig, (config) => {
126
- const { labelMap } = this
127
- // 查找 labelModel 实例,如果是实例化过的,直接复用;如果是新的,创建实例
128
- // let label: LabelModel
129
- // if (config.id && labelMap.has(config.id)) {
130
- // label = labelMap.get(config.id)!
131
- // } else {
132
- // label = new LabelModel(config, element, graphModel)
133
- // labelMap.set(label.id, label)
134
- // }
135
- const label = new LabelModel(config, element, graphModel)
136
- labelMap.set(label.id, label)
137
- labels.push(
138
- <Label
139
- key={label.id}
140
- label={label}
141
- element={element}
142
- graphModel={graphModel}
143
- />,
144
- )
145
- })
146
- })
147
-
148
- return labels
149
- }
150
- return null
151
- }
152
-
153
- render() {
154
- return (
155
- <foreignObject id="lf-label-overlay" class="lf-label-overlay">
156
- {this.getLabels()}
157
- </foreignObject>
158
- )
159
- }
160
- }
161
-
162
- 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