@flowgram-vue/document 0.2.0
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.
- package/LICENSE +22 -0
- package/dist/index.cjs +3233 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +1728 -0
- package/dist/index.js +3199 -0
- package/dist/index.js.map +1 -0
- package/package.json +61 -0
- package/src/datas/flow-node-render-data.ts +227 -0
- package/src/datas/flow-node-transform-data.ts +337 -0
- package/src/datas/flow-node-transition-data.ts +182 -0
- package/src/datas/index.ts +8 -0
- package/src/entities/flow-document-transformer-entity.ts +125 -0
- package/src/entities/flow-node-entity.ts +415 -0
- package/src/entities/flow-renderer-state-entity.ts +127 -0
- package/src/entities/index.ts +8 -0
- package/src/flow-document-config.ts +42 -0
- package/src/flow-document-container-module.ts +33 -0
- package/src/flow-document-contribution.ts +22 -0
- package/src/flow-document-options.ts +79 -0
- package/src/flow-document.ts +766 -0
- package/src/flow-render-tree.ts +236 -0
- package/src/flow-virtual-tree.ts +244 -0
- package/src/index.ts +16 -0
- package/src/layout/horizontal-fixed-layout.ts +198 -0
- package/src/layout/index.ts +7 -0
- package/src/layout/vertical-fixed-layout.ts +198 -0
- package/src/services/flow-drag-service.ts +211 -0
- package/src/services/flow-group-service/flow-group-controller.ts +120 -0
- package/src/services/flow-group-service/flow-group-service.ts +107 -0
- package/src/services/flow-group-service/flow-group-utils.ts +104 -0
- package/src/services/flow-group-service/index.ts +7 -0
- package/src/services/flow-operation-base-service.ts +333 -0
- package/src/services/index.ts +8 -0
- package/src/typings/flow-group.ts +8 -0
- package/src/typings/flow-layout.ts +72 -0
- package/src/typings/flow-node-register.ts +356 -0
- package/src/typings/flow-operation.ts +312 -0
- package/src/typings/flow-transition.ts +104 -0
- package/src/typings/flow.ts +70 -0
- package/src/typings/index.ts +11 -0
- package/src/utils/get-default-spacing.ts +21 -0
- package/src/utils/index.ts +6 -0
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { Point } from '@flowgram-vue/utils';
|
|
7
|
+
import { EntityData } from '@flowgram-vue/core';
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
FlowNodeBaseType,
|
|
11
|
+
type FlowTransitionLabel,
|
|
12
|
+
FlowTransitionLabelEnum,
|
|
13
|
+
type FlowTransitionLine,
|
|
14
|
+
FlowTransitionLineEnum,
|
|
15
|
+
} from '../typings';
|
|
16
|
+
import { type FlowNodeEntity } from '../entities';
|
|
17
|
+
import { FlowNodeTransformData } from './flow-node-transform-data';
|
|
18
|
+
import { FlowNodeRenderData } from './flow-node-render-data';
|
|
19
|
+
|
|
20
|
+
export interface FlowNodeTransitionSchema {}
|
|
21
|
+
|
|
22
|
+
// 画线到下一个节点
|
|
23
|
+
export const drawLineToNext = (transition: FlowNodeTransitionData) => {
|
|
24
|
+
const { transform } = transition;
|
|
25
|
+
|
|
26
|
+
// 默认绘制一根连接到下一个节点的线条
|
|
27
|
+
const currentOutput = transform.outputPoint;
|
|
28
|
+
if (transform.next) {
|
|
29
|
+
return [
|
|
30
|
+
{
|
|
31
|
+
type: FlowTransitionLineEnum.STRAIGHT_LINE,
|
|
32
|
+
from: currentOutput,
|
|
33
|
+
to: transform.next.inputPoint,
|
|
34
|
+
},
|
|
35
|
+
];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return [];
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// 画线到父节点的结尾
|
|
42
|
+
export const drawLineToBottom = (transition: FlowNodeTransitionData) => {
|
|
43
|
+
const { transform } = transition;
|
|
44
|
+
|
|
45
|
+
const currentOutput = transform.outputPoint;
|
|
46
|
+
const isParentRoot = transform.parent?.entity.flowNodeType === FlowNodeBaseType.ROOT;
|
|
47
|
+
const parentOutput = transform.parent?.outputPoint;
|
|
48
|
+
if (
|
|
49
|
+
!isParentRoot &&
|
|
50
|
+
!transform.next &&
|
|
51
|
+
parentOutput &&
|
|
52
|
+
!new Point().copyFrom(currentOutput).equals(parentOutput) &&
|
|
53
|
+
!transition.isNodeEnd
|
|
54
|
+
) {
|
|
55
|
+
return [
|
|
56
|
+
{
|
|
57
|
+
type: FlowTransitionLineEnum.STRAIGHT_LINE,
|
|
58
|
+
from: currentOutput,
|
|
59
|
+
to: parentOutput,
|
|
60
|
+
},
|
|
61
|
+
];
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return [];
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export class FlowNodeTransitionData extends EntityData<FlowNodeTransitionSchema> {
|
|
68
|
+
static type = 'FlowNodeTransitionData';
|
|
69
|
+
|
|
70
|
+
declare entity: FlowNodeEntity;
|
|
71
|
+
|
|
72
|
+
// 当前节点的 transform
|
|
73
|
+
declare transform: FlowNodeTransformData;
|
|
74
|
+
|
|
75
|
+
declare renderData: FlowNodeRenderData;
|
|
76
|
+
|
|
77
|
+
getDefaultData(): FlowNodeTransitionSchema {
|
|
78
|
+
return {};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
formatLines(lines: FlowTransitionLine[]) {
|
|
82
|
+
if (this.entity.document.options?.formatNodeLines) {
|
|
83
|
+
return this.entity.document.options?.formatNodeLines?.(this.entity, lines);
|
|
84
|
+
}
|
|
85
|
+
return lines;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
formatLabels(labels: FlowTransitionLabel[]) {
|
|
89
|
+
if (this.entity.document.options.formatNodeLabels) {
|
|
90
|
+
return this.entity.document.options?.formatNodeLabels?.(this.entity, labels);
|
|
91
|
+
}
|
|
92
|
+
return labels;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
get lines(): FlowTransitionLine[] {
|
|
96
|
+
return this.entity.memoGlobal<FlowTransitionLine[]>('lines', () => {
|
|
97
|
+
const { getChildLines } = this.entity.parent?.getNodeRegistry() || {};
|
|
98
|
+
|
|
99
|
+
if (getChildLines) {
|
|
100
|
+
return this.formatLines(getChildLines(this, this.entity.document.layout));
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const { getLines } = this.entity.getNodeRegistry();
|
|
104
|
+
|
|
105
|
+
if (getLines) {
|
|
106
|
+
return this.formatLines(getLines(this, this.entity.document.layout));
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// 横向布局不画线
|
|
110
|
+
if (this.transform.entity.isInlineBlock) {
|
|
111
|
+
return [];
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return this.formatLines([...drawLineToNext(this), ...drawLineToBottom(this)]);
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
get labels() {
|
|
119
|
+
return this.entity.memoGlobal<FlowTransitionLabel[]>('labels', () => {
|
|
120
|
+
const { getChildLabels } = this.entity.parent?.getNodeRegistry() || {};
|
|
121
|
+
|
|
122
|
+
if (getChildLabels) {
|
|
123
|
+
return this.formatLabels(getChildLabels(this, this.entity.document.layout));
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const { getLabels } = this.entity.getNodeRegistry();
|
|
127
|
+
|
|
128
|
+
if (getLabels) {
|
|
129
|
+
return this.formatLabels(getLabels(this, this.entity.document.layout));
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// 横向布局不画加号
|
|
133
|
+
if (this.transform.entity.isInlineBlock) {
|
|
134
|
+
return [];
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// 默认在中间点添加一个加号
|
|
138
|
+
const currentOutput = this.transform.outputPoint;
|
|
139
|
+
if (this.transform.next) {
|
|
140
|
+
return this.formatLabels([
|
|
141
|
+
{
|
|
142
|
+
offset: Point.getMiddlePoint(currentOutput, this.transform.next.inputPoint),
|
|
143
|
+
type: FlowTransitionLabelEnum.ADDER_LABEL,
|
|
144
|
+
},
|
|
145
|
+
]);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const parentOutput = this.transform.parent?.outputPoint;
|
|
149
|
+
if (
|
|
150
|
+
parentOutput &&
|
|
151
|
+
!new Point().copyFrom(currentOutput).equals(parentOutput) &&
|
|
152
|
+
!this.isNodeEnd
|
|
153
|
+
) {
|
|
154
|
+
return this.formatLabels([
|
|
155
|
+
{
|
|
156
|
+
offset: parentOutput,
|
|
157
|
+
type: FlowTransitionLabelEnum.ADDER_LABEL,
|
|
158
|
+
},
|
|
159
|
+
]);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return [];
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
constructor(entity: FlowNodeEntity) {
|
|
167
|
+
super(entity);
|
|
168
|
+
this.transform = this.entity.addData<FlowNodeTransformData>(FlowNodeTransformData);
|
|
169
|
+
this.renderData = this.entity.addData<FlowNodeRenderData>(FlowNodeRenderData);
|
|
170
|
+
|
|
171
|
+
this.bindChange(this.transform);
|
|
172
|
+
this.bindChange(this.renderData);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
get collapsed() {
|
|
176
|
+
return this.entity.collapsed;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
get isNodeEnd(): boolean {
|
|
180
|
+
return this.entity.isNodeEnd;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { Emitter } from '@flowgram-vue/utils';
|
|
7
|
+
import { ConfigEntity, type EntityOpts } from '@flowgram-vue/core';
|
|
8
|
+
|
|
9
|
+
import type { FlowDocument } from '../flow-document';
|
|
10
|
+
import { FlowNodeTransformData } from '../datas';
|
|
11
|
+
|
|
12
|
+
interface FlowDocumentTransformerEntityConfig extends EntityOpts {
|
|
13
|
+
document: FlowDocument;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* 用于通知所有 layer 更新
|
|
18
|
+
*/
|
|
19
|
+
export class FlowDocumentTransformerEntity extends ConfigEntity<
|
|
20
|
+
{
|
|
21
|
+
loading: boolean;
|
|
22
|
+
treeVersion: number;
|
|
23
|
+
},
|
|
24
|
+
FlowDocumentTransformerEntityConfig
|
|
25
|
+
> {
|
|
26
|
+
static type = 'FlowDocumentTransformerEntity';
|
|
27
|
+
|
|
28
|
+
protected onRefreshEmitter = new Emitter<void>();
|
|
29
|
+
|
|
30
|
+
protected lastTransformVersion = -1;
|
|
31
|
+
|
|
32
|
+
protected lastTreeVersion = -1;
|
|
33
|
+
|
|
34
|
+
document: FlowDocument;
|
|
35
|
+
|
|
36
|
+
readonly onRefresh = this.onRefreshEmitter.event;
|
|
37
|
+
|
|
38
|
+
constructor(conf: FlowDocumentTransformerEntityConfig) {
|
|
39
|
+
super(conf);
|
|
40
|
+
this.document = conf.document;
|
|
41
|
+
this.toDispose.push(
|
|
42
|
+
this.document.originTree.onTreeChange(() => {
|
|
43
|
+
this.config.treeVersion += 1;
|
|
44
|
+
this.fireChange();
|
|
45
|
+
})
|
|
46
|
+
);
|
|
47
|
+
this.toDispose.push(this.onRefreshEmitter);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
getDefaultConfig(): { loading: boolean; treeVersion: number } {
|
|
51
|
+
return {
|
|
52
|
+
loading: true,
|
|
53
|
+
treeVersion: 0,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
get loading(): boolean {
|
|
58
|
+
return this.config.loading;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
set loading(loading) {
|
|
62
|
+
if (this.config.loading !== loading) {
|
|
63
|
+
this.config.loading = loading;
|
|
64
|
+
this.fireChange();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* 更新矩阵结构 (这个只有在树结构变化时候才会触发,如:添加节点、删除节点、改变位置节点)
|
|
70
|
+
*/
|
|
71
|
+
updateTransformsTree(): void {
|
|
72
|
+
// 更新 node 结构树
|
|
73
|
+
this.document.renderTree.traverse((node, depth, index) => {
|
|
74
|
+
const transform = node.getData<FlowNodeTransformData>(FlowNodeTransformData)!;
|
|
75
|
+
// 收起时清空子节点
|
|
76
|
+
if (transform.collapsed) {
|
|
77
|
+
transform.transform.clearChildren();
|
|
78
|
+
}
|
|
79
|
+
if (node.parent) {
|
|
80
|
+
transform.setParentTransform(node.parent!.getData(FlowNodeTransformData));
|
|
81
|
+
}
|
|
82
|
+
// 更新 index
|
|
83
|
+
node.index = index;
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
clear(): void {
|
|
88
|
+
this.lastTreeVersion = -1;
|
|
89
|
+
this.lastTransformVersion = -1;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
isTreeDirty(): boolean {
|
|
93
|
+
const transformVersion = this.entityManager.getEntityDataVersion(FlowNodeTransformData);
|
|
94
|
+
const isTreeVersionChanged = this.lastTreeVersion !== this.config.treeVersion;
|
|
95
|
+
const isTransformVersionChanged = this.lastTransformVersion !== transformVersion;
|
|
96
|
+
return isTreeVersionChanged || isTransformVersionChanged;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* 刷新节点的相对偏移
|
|
101
|
+
*/
|
|
102
|
+
refresh(): void {
|
|
103
|
+
const transformVersion = this.entityManager.getEntityDataVersion(FlowNodeTransformData);
|
|
104
|
+
|
|
105
|
+
const isTreeVersionChanged = this.lastTreeVersion !== this.config.treeVersion;
|
|
106
|
+
const isTransformVersionChanged = this.lastTransformVersion !== transformVersion;
|
|
107
|
+
|
|
108
|
+
this.entityManager.changeEntityLocked = true;
|
|
109
|
+
if (isTreeVersionChanged) {
|
|
110
|
+
this.document.renderTree.updateRenderStruct(); // 重新调整 renderTree 结构
|
|
111
|
+
this.updateTransformsTree(); // 更新树结构
|
|
112
|
+
this.lastTreeVersion = this.config.treeVersion;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (isTreeVersionChanged || isTransformVersionChanged) {
|
|
116
|
+
// 位置计算不需要重新触发 Layer 刷新
|
|
117
|
+
this.document.layout.update(); // 更新布局
|
|
118
|
+
this.lastTransformVersion = this.entityManager.getEntityDataVersion(FlowNodeTransformData);
|
|
119
|
+
this.lastTreeVersion = this.config.treeVersion;
|
|
120
|
+
this.onRefreshEmitter.fire();
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
this.entityManager.changeEntityLocked = false;
|
|
124
|
+
}
|
|
125
|
+
}
|