aldehyde 0.2.473 → 0.2.474
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/lib/controls/entry-control.js +2 -2
- package/lib/controls/entry-control.js.map +1 -1
- package/lib/controls/icon-selector/icon/phonenode-menu-icon/iconfont.css +47 -3
- package/lib/controls/icon-selector/icon/phonenode-menu-icon/iconfont.js +12 -12
- package/lib/controls/icon-selector/icon/phonenode-menu-icon/iconfont.js.map +1 -1
- package/lib/controls/icon-selector/icon/phonenode-menu-icon/iconfont.json +77 -0
- package/lib/controls/icon-selector/icon/phonenode-menu-icon/iconfont.ttf +0 -0
- package/lib/controls/icon-selector/icon/phonenode-menu-icon/iconfont.woff +0 -0
- package/lib/controls/icon-selector/icon/phonenode-menu-icon/iconfont.woff2 +0 -0
- package/lib/draw-canvas/edit/components/asset-bar/index.d.ts +5 -0
- package/lib/draw-canvas/edit/components/asset-bar/index.d.ts.map +1 -0
- package/lib/draw-canvas/edit/components/asset-bar/index.js +78 -0
- package/lib/draw-canvas/edit/components/asset-bar/index.js.map +1 -0
- package/lib/draw-canvas/edit/components/asset-bar/index.less +36 -0
- package/lib/draw-canvas/edit/components/main-header/index.d.ts +14 -0
- package/lib/draw-canvas/edit/components/main-header/index.d.ts.map +1 -0
- package/lib/draw-canvas/edit/components/main-header/index.js +163 -0
- package/lib/draw-canvas/edit/components/main-header/index.js.map +1 -0
- package/lib/draw-canvas/edit/components/main-header/index.less +21 -0
- package/lib/draw-canvas/edit/components/render/index.d.ts +86 -0
- package/lib/draw-canvas/edit/components/render/index.d.ts.map +1 -0
- package/lib/draw-canvas/edit/components/render/index.js +686 -0
- package/lib/draw-canvas/edit/components/render/index.js.map +1 -0
- package/lib/draw-canvas/edit/components/render/types.d.ts +243 -0
- package/lib/draw-canvas/edit/components/render/types.d.ts.map +1 -0
- package/lib/draw-canvas/edit/components/render/types.js +66 -0
- package/lib/draw-canvas/edit/components/render/types.js.map +1 -0
- package/lib/draw-canvas/edit/components/setting-form/index.d.ts +19 -0
- package/lib/draw-canvas/edit/components/setting-form/index.d.ts.map +1 -0
- package/lib/draw-canvas/edit/components/setting-form/index.js +164 -0
- package/lib/draw-canvas/edit/components/setting-form/index.js.map +1 -0
- package/lib/draw-canvas/edit/index.d.ts +5 -0
- package/lib/draw-canvas/edit/index.d.ts.map +1 -0
- package/lib/draw-canvas/edit/index.js +112 -0
- package/lib/draw-canvas/edit/index.js.map +1 -0
- package/lib/draw-canvas/edit/index.less +34 -0
- package/lib/form/form-Item-group.d.ts.map +1 -1
- package/lib/form/form-Item-group.js +1 -1
- package/lib/form/form-Item-group.js.map +1 -1
- package/lib/icon/local-aliIcon/iconfont.js +5 -5
- package/lib/icon/local-aliIcon/iconfont.js.map +1 -1
- package/lib/table/relation-table.d.ts +4 -0
- package/lib/table/relation-table.d.ts.map +1 -1
- package/lib/tmpl/hcservice-v3.d.ts +1 -0
- package/lib/tmpl/hcservice-v3.d.ts.map +1 -1
- package/lib/tmpl/hcservice-v3.js +27 -0
- package/lib/tmpl/hcservice-v3.js.map +1 -1
- package/lib/tmpl/interface.d.ts +4 -0
- package/lib/tmpl/interface.d.ts.map +1 -1
- package/lib/tmpl/interface.js.map +1 -1
- package/lib/units/index.d.ts +1 -0
- package/lib/units/index.d.ts.map +1 -1
- package/lib/units/index.js +16 -0
- package/lib/units/index.js.map +1 -1
- package/package.json +1 -1
- package/src/aldehyde/controls/entry-control.tsx +2 -2
- package/src/aldehyde/controls/icon-selector/icon/phonenode-menu-icon/iconfont.css +47 -3
- package/src/aldehyde/controls/icon-selector/icon/phonenode-menu-icon/iconfont.js +1 -1
- package/src/aldehyde/controls/icon-selector/icon/phonenode-menu-icon/iconfont.json +77 -0
- package/src/aldehyde/controls/icon-selector/icon/phonenode-menu-icon/iconfont.ttf +0 -0
- package/src/aldehyde/controls/icon-selector/icon/phonenode-menu-icon/iconfont.woff +0 -0
- package/src/aldehyde/controls/icon-selector/icon/phonenode-menu-icon/iconfont.woff2 +0 -0
- package/src/aldehyde/draw-canvas/edit/components/asset-bar/index.less +36 -0
- package/src/aldehyde/draw-canvas/edit/components/asset-bar/index.tsx +93 -0
- package/src/aldehyde/draw-canvas/edit/components/main-header/index.less +21 -0
- package/src/aldehyde/draw-canvas/edit/components/main-header/index.tsx +187 -0
- package/src/aldehyde/draw-canvas/edit/components/render/draws/bg-draw.ts +98 -0
- package/src/aldehyde/draw-canvas/edit/components/render/draws/contextmenu-draw.ts +307 -0
- package/src/aldehyde/draw-canvas/edit/components/render/draws/graph-draw.ts +251 -0
- package/src/aldehyde/draw-canvas/edit/components/render/draws/index.ts +7 -0
- package/src/aldehyde/draw-canvas/edit/components/render/draws/link-draw.ts +1416 -0
- package/src/aldehyde/draw-canvas/edit/components/render/draws/preview-draw.ts +257 -0
- package/src/aldehyde/draw-canvas/edit/components/render/draws/ref-line-draw.ts +72 -0
- package/src/aldehyde/draw-canvas/edit/components/render/draws/ruler-draw.ts +167 -0
- package/src/aldehyde/draw-canvas/edit/components/render/graphs/base-graph.ts +241 -0
- package/src/aldehyde/draw-canvas/edit/components/render/graphs/bezier.ts +542 -0
- package/src/aldehyde/draw-canvas/edit/components/render/graphs/circle.ts +700 -0
- package/src/aldehyde/draw-canvas/edit/components/render/graphs/curve.ts +501 -0
- package/src/aldehyde/draw-canvas/edit/components/render/graphs/index.ts +6 -0
- package/src/aldehyde/draw-canvas/edit/components/render/graphs/line.ts +494 -0
- package/src/aldehyde/draw-canvas/edit/components/render/graphs/rect.ts +681 -0
- package/src/aldehyde/draw-canvas/edit/components/render/handlers/drag-handlers.ts +69 -0
- package/src/aldehyde/draw-canvas/edit/components/render/handlers/drag-outside-handlers.ts +162 -0
- package/src/aldehyde/draw-canvas/edit/components/render/handlers/graph-handlers.ts +108 -0
- package/src/aldehyde/draw-canvas/edit/components/render/handlers/index.ts +9 -0
- package/src/aldehyde/draw-canvas/edit/components/render/handlers/key-move-handlers.ts +50 -0
- package/src/aldehyde/draw-canvas/edit/components/render/handlers/link-handlers.ts +46 -0
- package/src/aldehyde/draw-canvas/edit/components/render/handlers/selection-handlers.ts +385 -0
- package/src/aldehyde/draw-canvas/edit/components/render/handlers/shutcut-handlers.ts +46 -0
- package/src/aldehyde/draw-canvas/edit/components/render/handlers/text-handlers.ts +82 -0
- package/src/aldehyde/draw-canvas/edit/components/render/handlers/zoom-handlers.ts +60 -0
- package/src/aldehyde/draw-canvas/edit/components/render/index.ts +768 -0
- package/src/aldehyde/draw-canvas/edit/components/render/tools/align-tool.ts +91 -0
- package/src/aldehyde/draw-canvas/edit/components/render/tools/asset-tool.ts +142 -0
- package/src/aldehyde/draw-canvas/edit/components/render/tools/attract-tool.ts +440 -0
- package/src/aldehyde/draw-canvas/edit/components/render/tools/copy-tool.ts +269 -0
- package/src/aldehyde/draw-canvas/edit/components/render/tools/import-export-tool.ts +603 -0
- package/src/aldehyde/draw-canvas/edit/components/render/tools/index.ts +9 -0
- package/src/aldehyde/draw-canvas/edit/components/render/tools/link-tool.ts +225 -0
- package/src/aldehyde/draw-canvas/edit/components/render/tools/position-tool.ts +212 -0
- package/src/aldehyde/draw-canvas/edit/components/render/tools/selection-tool.ts +132 -0
- package/src/aldehyde/draw-canvas/edit/components/render/tools/z-index-tool.ts +227 -0
- package/src/aldehyde/draw-canvas/edit/components/render/types.ts +287 -0
- package/src/aldehyde/draw-canvas/edit/components/render/utils/a-star.ts +116 -0
- package/src/aldehyde/draw-canvas/edit/components/render/utils/bezier-scene-func.ts +73 -0
- package/src/aldehyde/draw-canvas/edit/components/setting-form/index.tsx +200 -0
- package/src/aldehyde/draw-canvas/edit/index.less +34 -0
- package/src/aldehyde/draw-canvas/edit/index.tsx +138 -0
- package/src/aldehyde/form/form-Item-group.tsx +1 -0
- package/src/aldehyde/icon/local-aliIcon/iconfont.js +1 -1
- package/src/aldehyde/tmpl/hcservice-v3.tsx +14 -0
- package/src/aldehyde/tmpl/interface.tsx +2 -0
- package/src/aldehyde/units/index.tsx +15 -0
|
@@ -0,0 +1,603 @@
|
|
|
1
|
+
import Konva from 'konva';
|
|
2
|
+
import { nanoid } from 'nanoid';
|
|
3
|
+
import { Render } from '../index';
|
|
4
|
+
import { LinkDraw, GraphDraw, RulerDraw, PreviewDraw } from '../draws';
|
|
5
|
+
import { AssetSettings, AssetType } from '../types';
|
|
6
|
+
import { BezierSceneFunc } from '../utils/bezier-scene-func';
|
|
7
|
+
|
|
8
|
+
// 导入导出
|
|
9
|
+
|
|
10
|
+
export class ImportExportTool {
|
|
11
|
+
// @ts-ignore
|
|
12
|
+
static readonly name = 'ImportExportTool';
|
|
13
|
+
|
|
14
|
+
private render: Render;
|
|
15
|
+
constructor(render: Render) {
|
|
16
|
+
this.render = render;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* 获得显示内容
|
|
21
|
+
* @param withLink 是否包含线条
|
|
22
|
+
* @returns
|
|
23
|
+
*/
|
|
24
|
+
getView(withLink: boolean = false) {
|
|
25
|
+
// 复制画布
|
|
26
|
+
const copy = this.render.stage.clone();
|
|
27
|
+
// 提取 main layer 备用
|
|
28
|
+
const main = copy.find('#main')[0] as Konva.Layer;
|
|
29
|
+
const cover = copy.find('#cover')[0] as Konva.Layer;
|
|
30
|
+
// 暂时清空所有 layer
|
|
31
|
+
const copyChildren = copy.getChildren();
|
|
32
|
+
copy.removeChildren();
|
|
33
|
+
if (main && cover) {
|
|
34
|
+
// 提取节点
|
|
35
|
+
let nodes = main.getChildren((node) => !this.render.ignore(node));
|
|
36
|
+
// 移除多余结构
|
|
37
|
+
for (const node of nodes) {
|
|
38
|
+
// 如果当前被选中,listening 会是 false,需恢复
|
|
39
|
+
node.listening(true);
|
|
40
|
+
// 恢复 draggable(因为,绘制 Graph 的时候,不允许直接拖动其他素材)
|
|
41
|
+
node.draggable(!this.render.config.readonly);
|
|
42
|
+
for (const child of (node as Konva.Group).children) {
|
|
43
|
+
if (this.render.ignoreSelect(child)) {
|
|
44
|
+
child.remove();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (withLink) {
|
|
50
|
+
// 从 Link group 中提取 连接线
|
|
51
|
+
const linkDraw = cover.children.find((o) => o.attrs.name === LinkDraw.name) as Konva.Group;
|
|
52
|
+
if (linkDraw) {
|
|
53
|
+
nodes = nodes.concat(linkDraw.children.filter((o) => o.attrs.name === 'link-line'));
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// 重新装载节点
|
|
58
|
+
const layer = new Konva.Layer();
|
|
59
|
+
layer.add(...nodes);
|
|
60
|
+
nodes = layer.getChildren();
|
|
61
|
+
|
|
62
|
+
for (const node of nodes) {
|
|
63
|
+
if (node.attrs.nodeMousedownPos) {
|
|
64
|
+
// 修正正在选中的节点透明度
|
|
65
|
+
node.setAttrs({ opacity: copy.attrs.lastOpacity ?? 1 });
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// 重新装载 layer
|
|
70
|
+
copy.add(layer);
|
|
71
|
+
main.removeChildren();
|
|
72
|
+
cover.removeChildren();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
copyChildren.forEach((o) => o.destroy());
|
|
76
|
+
// 返回可视节点和 layer
|
|
77
|
+
return copy;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// 保存
|
|
81
|
+
save() {
|
|
82
|
+
const copy = this.getView();
|
|
83
|
+
const json = copy.toJSON();
|
|
84
|
+
copy.destroy();
|
|
85
|
+
// 通过 stage api 导出 json
|
|
86
|
+
return json;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// 加载 image(用于导入)
|
|
90
|
+
loadImage(src: string) {
|
|
91
|
+
return new Promise<HTMLImageElement | null>((resolve) => {
|
|
92
|
+
const img = new Image();
|
|
93
|
+
img.onload = () => {
|
|
94
|
+
// 返回加载完成的图片 element
|
|
95
|
+
resolve(img);
|
|
96
|
+
};
|
|
97
|
+
img.onerror = () => {
|
|
98
|
+
resolve(null);
|
|
99
|
+
};
|
|
100
|
+
img.src = src;
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// 恢复图片(用于导入)
|
|
105
|
+
async restoreImage(nodes: Konva.Node[] = []) {
|
|
106
|
+
for (const node of nodes) {
|
|
107
|
+
if (node instanceof Konva.Group) {
|
|
108
|
+
// 递归
|
|
109
|
+
await this.restoreImage(node.getChildren());
|
|
110
|
+
} else if (node instanceof Konva.Image) {
|
|
111
|
+
// 处理图片
|
|
112
|
+
if (node.attrs.svgXML) {
|
|
113
|
+
// svg 素材
|
|
114
|
+
const blob = new Blob([node.attrs.svgXML], { type: 'image/svg+xml' });
|
|
115
|
+
// dataurl
|
|
116
|
+
const url = URL.createObjectURL(blob);
|
|
117
|
+
// 加载为图片 element
|
|
118
|
+
const image = await this.loadImage(url);
|
|
119
|
+
if (image) {
|
|
120
|
+
// 设置图片
|
|
121
|
+
node.image(image);
|
|
122
|
+
}
|
|
123
|
+
} else if (node.attrs.gif) {
|
|
124
|
+
// gif 素材
|
|
125
|
+
const imageNode = await this.render.assetTool.loadGif(node.attrs.gif);
|
|
126
|
+
if (imageNode) {
|
|
127
|
+
// 设置图片
|
|
128
|
+
node.image(imageNode.image());
|
|
129
|
+
}
|
|
130
|
+
} else if (node.attrs.src) {
|
|
131
|
+
// 其他图片素材
|
|
132
|
+
const image = await this.loadImage(node.attrs.src);
|
|
133
|
+
if (image) {
|
|
134
|
+
// 设置图片
|
|
135
|
+
node.image(image);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// 恢复图形
|
|
143
|
+
restoreGraph(nodes: Konva.Node[] = []) {
|
|
144
|
+
for (const node of nodes) {
|
|
145
|
+
if (node instanceof Konva.Group && node.attrs.assetType === AssetType.Graph) {
|
|
146
|
+
if (node.attrs.graphType === "Bezier") {
|
|
147
|
+
const graph = node.findOne('.graph');
|
|
148
|
+
if (graph instanceof Konva.Arrow) {
|
|
149
|
+
graph.sceneFunc(BezierSceneFunc);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
const hoverRect = node.findOne('.hoverRect');
|
|
153
|
+
if (hoverRect instanceof Konva.Rect) {
|
|
154
|
+
hoverRect.on('mouseenter', () => {
|
|
155
|
+
// 防止进入调整点,重复处理
|
|
156
|
+
if (!node.attrs.hoverAnchor) {
|
|
157
|
+
node.setAttr('hover', true);
|
|
158
|
+
this.render.redraw([GraphDraw.name]);
|
|
159
|
+
}
|
|
160
|
+
setTimeout(() => {
|
|
161
|
+
// 调整产生 redraw,导致离开调整点不触发其 mouseleave(进入其他元素区域除外)
|
|
162
|
+
// 在此静态补充"离开调整点"
|
|
163
|
+
// 不影响正常处理(调整点会不停 hoverAnchor = true)
|
|
164
|
+
node.setAttr('hoverAnchor', false);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
// 显示 连接点
|
|
168
|
+
this.render.linkTool.pointsVisible(true, node);
|
|
169
|
+
});
|
|
170
|
+
hoverRect.on('mouseleave', () => {
|
|
171
|
+
// 延迟事件,使调整点的 mouseleave 优先
|
|
172
|
+
setTimeout(() => {
|
|
173
|
+
// 防止进入调整点,重复处理
|
|
174
|
+
// 补充 2,快速调整会漏掉
|
|
175
|
+
if (!node.attrs.hoverAnchor) {
|
|
176
|
+
node.setAttr('hover', false);
|
|
177
|
+
node.setAttr('hoverAnchor', false);
|
|
178
|
+
this.render.redraw([GraphDraw.name]);
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
// 隐藏 连接点
|
|
182
|
+
this.render.linkTool.pointsVisible(false, node);
|
|
183
|
+
// 隐藏 hover 框
|
|
184
|
+
node.findOne('#hoverRect')?.visible(false);
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// 恢复
|
|
192
|
+
async restore(json: string, silent = false) {
|
|
193
|
+
|
|
194
|
+
try {
|
|
195
|
+
this.render.emit('loading', true);
|
|
196
|
+
// 清空选择
|
|
197
|
+
this.render.selectionTool.selectingClear();
|
|
198
|
+
this.render.linkTool.selectingClear();
|
|
199
|
+
// 清空 main layer 节点
|
|
200
|
+
this.render.layer.getChildren().forEach((o) => o.destroy());
|
|
201
|
+
this.render.layer.removeChildren();
|
|
202
|
+
|
|
203
|
+
// 加载 json,提取节点
|
|
204
|
+
const container = document.createElement('div');
|
|
205
|
+
const stage = Konva.Node.create(json, container);
|
|
206
|
+
const main = stage.getChildren()[0];
|
|
207
|
+
const nodes = main.getChildren();
|
|
208
|
+
// 恢复节点图片素材
|
|
209
|
+
await this.restoreImage(nodes);
|
|
210
|
+
await this.restoreGraph(nodes);
|
|
211
|
+
for (const node of nodes) {
|
|
212
|
+
// 重置旧数据节点为可 draggable
|
|
213
|
+
// 为了使旧数据和新节点一样
|
|
214
|
+
// 可以直接被拖动
|
|
215
|
+
node.draggable(!this.render.config.readonly);
|
|
216
|
+
node.off('mouseenter');
|
|
217
|
+
node.on('mouseenter', () => {
|
|
218
|
+
// 显示 连接点
|
|
219
|
+
this.render.linkTool.pointsVisible(true, node);
|
|
220
|
+
});
|
|
221
|
+
// 恢复的时候,恢复 hoverRect
|
|
222
|
+
node.add(
|
|
223
|
+
new Konva.Rect({
|
|
224
|
+
id: 'hoverRect',
|
|
225
|
+
width: node.width(),
|
|
226
|
+
height: node.height(),
|
|
227
|
+
fill: 'rgba(0,255,0,0.3)',
|
|
228
|
+
visible: false
|
|
229
|
+
})
|
|
230
|
+
);
|
|
231
|
+
node.off('mouseleave');
|
|
232
|
+
node.on('mouseleave', () => {
|
|
233
|
+
// 隐藏 连接点
|
|
234
|
+
this.render.linkTool.pointsVisible(false, node);
|
|
235
|
+
// 隐藏 hover 框
|
|
236
|
+
node.findOne('#hoverRect')?.visible(false);
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
// 往 main layer 插入新节点
|
|
240
|
+
this.render.layer.add(...nodes);
|
|
241
|
+
// 同步页面设置
|
|
242
|
+
this.render.stage.setAttr('pageSettings', stage.attrs.pageSettings);
|
|
243
|
+
this.render.emit('page-settings-change', this.render.getPageSettings());
|
|
244
|
+
// 更新背景
|
|
245
|
+
this.render.updateBackground();
|
|
246
|
+
// 上一步、下一步 无需更新 history 记录
|
|
247
|
+
if (!silent) {
|
|
248
|
+
// 更新历史
|
|
249
|
+
this.render.updateHistory();
|
|
250
|
+
}
|
|
251
|
+
// 隐藏 连接点
|
|
252
|
+
this.render.linkTool.pointsVisible(false);
|
|
253
|
+
// 重绘
|
|
254
|
+
this.render.redraw([
|
|
255
|
+
GraphDraw.name,
|
|
256
|
+
LinkDraw.name,
|
|
257
|
+
RulerDraw.name,
|
|
258
|
+
PreviewDraw.name
|
|
259
|
+
]);
|
|
260
|
+
stage.destroy();
|
|
261
|
+
} catch (e) {
|
|
262
|
+
console.error(e);
|
|
263
|
+
} finally {
|
|
264
|
+
this.render.emit('loading', false);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// 获取图片
|
|
269
|
+
getImage(pixelRatio = 1, bgColor?: string) {
|
|
270
|
+
// 在 getAssetView 的基础上,增加背景即可
|
|
271
|
+
const copy = this.getAssetView();
|
|
272
|
+
// 背景层
|
|
273
|
+
const bgLayer = new Konva.Layer();
|
|
274
|
+
// 背景矩形
|
|
275
|
+
const bg = new Konva.Rect({ listening: false });
|
|
276
|
+
|
|
277
|
+
bg.setAttrs({
|
|
278
|
+
x: 0,
|
|
279
|
+
y: 0,
|
|
280
|
+
width: copy.width(),
|
|
281
|
+
height: copy.height(),
|
|
282
|
+
fill: bgColor ?? this.render.getPageSettings().background
|
|
283
|
+
});
|
|
284
|
+
// 添加背景
|
|
285
|
+
bgLayer.add(bg);
|
|
286
|
+
const children = copy.getChildren() as Konva.Layer[];
|
|
287
|
+
copy.removeChildren();
|
|
288
|
+
copy.add(bgLayer);
|
|
289
|
+
copy.add(children[0], ...children.slice(1));
|
|
290
|
+
const url = copy.toDataURL({ pixelRatio });
|
|
291
|
+
copy.destroy();
|
|
292
|
+
// 通过 stage api 导出图片
|
|
293
|
+
return url;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// 获取元素图片
|
|
297
|
+
getAssetImage(pixelRatio = 1, bgColor?: string) {
|
|
298
|
+
// 获取可视节点和 layer
|
|
299
|
+
const copy = this.getAssetView();
|
|
300
|
+
// 背景层
|
|
301
|
+
const bgLayer = new Konva.Layer();
|
|
302
|
+
// 背景矩形
|
|
303
|
+
const bg = new Konva.Rect({ listening: false });
|
|
304
|
+
bg.setAttrs({
|
|
305
|
+
x: -copy.x(),
|
|
306
|
+
y: -copy.y(),
|
|
307
|
+
width: copy.width(),
|
|
308
|
+
height: copy.height(),
|
|
309
|
+
fill: bgColor ?? this.render.getPageSettings().background
|
|
310
|
+
});
|
|
311
|
+
// 添加背景
|
|
312
|
+
bgLayer.add(bg);
|
|
313
|
+
// 插入背景
|
|
314
|
+
const children = copy.getChildren();
|
|
315
|
+
copy.removeChildren();
|
|
316
|
+
copy.add(bgLayer);
|
|
317
|
+
copy.add(children[0], ...children.slice(1));
|
|
318
|
+
const url = copy.toDataURL({ pixelRatio });
|
|
319
|
+
copy.destroy();
|
|
320
|
+
// 通过 stage api 导出图片
|
|
321
|
+
return url;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// blob to base64 url
|
|
325
|
+
blobToBase64(blob: Blob, type: string): Promise<string> {
|
|
326
|
+
return new Promise((resolve) => {
|
|
327
|
+
const file = new File([blob], 'image', { type });
|
|
328
|
+
const fileReader = new FileReader();
|
|
329
|
+
fileReader.readAsDataURL(file);
|
|
330
|
+
fileReader.onload = function () {
|
|
331
|
+
resolve((this.result as string) ?? '');
|
|
332
|
+
};
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// 替换 svg blob: 链接
|
|
337
|
+
parseSvgImage(urls: string[]): Promise<string[]> {
|
|
338
|
+
return new Promise((resolve) => {
|
|
339
|
+
if (urls.length > 0) {
|
|
340
|
+
Promise.all(urls.map((o) => fetch(o))).then((rs: Response[]) => {
|
|
341
|
+
// fetch
|
|
342
|
+
// 替换为 svg 嵌套
|
|
343
|
+
Promise.all(rs.map((o) => o.text())).then((xmls: string[]) => {
|
|
344
|
+
// svg xml
|
|
345
|
+
resolve(xmls);
|
|
346
|
+
});
|
|
347
|
+
});
|
|
348
|
+
} else {
|
|
349
|
+
resolve([]);
|
|
350
|
+
}
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// 替换其他 image 链接
|
|
355
|
+
parseOtherImage(urls: string[]): Promise<string[]> {
|
|
356
|
+
return new Promise((resolve) => {
|
|
357
|
+
if (urls.length > 0) {
|
|
358
|
+
Promise.all(urls.map((o) => fetch(o))).then((rs: Response[]) => {
|
|
359
|
+
// fetch
|
|
360
|
+
// 替换为 base64 url image
|
|
361
|
+
Promise.all(rs.map((o) => o.blob())).then((bs: Blob[]) => {
|
|
362
|
+
// blob
|
|
363
|
+
Promise.all(bs.map((o) => this.blobToBase64(o, 'image/*'))).then((urls: string[]) => {
|
|
364
|
+
// base64
|
|
365
|
+
resolve(urls);
|
|
366
|
+
});
|
|
367
|
+
});
|
|
368
|
+
});
|
|
369
|
+
} else {
|
|
370
|
+
resolve([]);
|
|
371
|
+
}
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// 替换 image 链接
|
|
376
|
+
parseImage(xml: string): Promise<string> {
|
|
377
|
+
return new Promise((resolve) => {
|
|
378
|
+
// 找出 blob:http 图片链接(目前发现只有 svg 是)
|
|
379
|
+
const svgs = xml.match(/(?<=xlink:href=")blob:https?:\/\/[^"]+(?=")/g) ?? [];
|
|
380
|
+
// 其他图片转为 base64
|
|
381
|
+
const imgs = xml.match(/(?<=xlink:href=")(?<!blob:)[^"]+(?=")/g) ?? [];
|
|
382
|
+
Promise.all([this.parseSvgImage(svgs), this.parseOtherImage(imgs)]).then(
|
|
383
|
+
([svgXmls, imgUrls]) => {
|
|
384
|
+
// svg xml
|
|
385
|
+
svgs.forEach((svg, idx) => {
|
|
386
|
+
// 替换
|
|
387
|
+
xml = xml.replace(
|
|
388
|
+
new RegExp(`<image[^><]* xlink:href="${svg}"[^><]*/>`),
|
|
389
|
+
svgXmls[idx].match(/<svg[^><]*>.*<\/svg>/)?.[0] ?? '' // 仅保留 svg 结构
|
|
390
|
+
);
|
|
391
|
+
});
|
|
392
|
+
// base64
|
|
393
|
+
imgs.forEach((img, idx) => {
|
|
394
|
+
// 替换
|
|
395
|
+
xml = xml.replace(`"${img}"`, `"${imgUrls[idx]}"`);
|
|
396
|
+
});
|
|
397
|
+
// 替换完成
|
|
398
|
+
resolve(xml);
|
|
399
|
+
}
|
|
400
|
+
);
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* 获得显示内容(用于另存为元素)
|
|
406
|
+
* @returns Konva.Stage
|
|
407
|
+
*/
|
|
408
|
+
getAssetView() {
|
|
409
|
+
const copy = this.getView(true);
|
|
410
|
+
const children = copy.getChildren()[0].getChildren();
|
|
411
|
+
const nodes: Konva.Stage | Konva.Layer | Konva.Group | Konva.Node[] = [...children];
|
|
412
|
+
|
|
413
|
+
let minX = Infinity,
|
|
414
|
+
maxX = -Infinity,
|
|
415
|
+
minY = Infinity,
|
|
416
|
+
maxY = -Infinity,
|
|
417
|
+
minStartX = Infinity,
|
|
418
|
+
minStartY = Infinity;
|
|
419
|
+
|
|
420
|
+
const stageState = this.render.getStageState();
|
|
421
|
+
for (const node of nodes) {
|
|
422
|
+
if (node instanceof Konva.Group) {
|
|
423
|
+
const { x, y, width, height } = ((rect) => ({
|
|
424
|
+
x: this.render.toStageValue(rect.x - stageState.x),
|
|
425
|
+
y: this.render.toStageValue(rect.y - stageState.y),
|
|
426
|
+
width: this.render.toStageValue(rect.width),
|
|
427
|
+
height: this.render.toStageValue(rect.height)
|
|
428
|
+
}))(node.getClientRect());
|
|
429
|
+
if (x < minX) {
|
|
430
|
+
minX = x;
|
|
431
|
+
}
|
|
432
|
+
if (x + width > maxX) {
|
|
433
|
+
maxX = x + width;
|
|
434
|
+
}
|
|
435
|
+
if (y < minY) {
|
|
436
|
+
minY = y;
|
|
437
|
+
}
|
|
438
|
+
if (y + height > maxY) {
|
|
439
|
+
maxY = y + height;
|
|
440
|
+
}
|
|
441
|
+
if (x < minStartX) {
|
|
442
|
+
minStartX = x;
|
|
443
|
+
}
|
|
444
|
+
if (y < minStartY) {
|
|
445
|
+
minStartY = y;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
// 移除辅助元素
|
|
449
|
+
if (node instanceof Konva.Group) {
|
|
450
|
+
const clickMask = node.findOne('#click-mask');
|
|
451
|
+
if (clickMask) {
|
|
452
|
+
clickMask.destroy();
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
} else if (node instanceof Konva.Line && node.name() === 'link-line') {
|
|
456
|
+
// 连线占用空间
|
|
457
|
+
const points = node.points();
|
|
458
|
+
for (let i = 0; i < points.length; i += 2) {
|
|
459
|
+
const [x, y] = [points[i], points[i + 1]];
|
|
460
|
+
if (x < minX) {
|
|
461
|
+
minX = x - 1;
|
|
462
|
+
}
|
|
463
|
+
if (x > maxX) {
|
|
464
|
+
maxX = x + 1;
|
|
465
|
+
}
|
|
466
|
+
if (y < minY) {
|
|
467
|
+
minY = y - 1;
|
|
468
|
+
}
|
|
469
|
+
if (y > maxY) {
|
|
470
|
+
maxY = y + 1;
|
|
471
|
+
}
|
|
472
|
+
if (x < minStartX) {
|
|
473
|
+
minStartX = x - 1;
|
|
474
|
+
}
|
|
475
|
+
if (y < minStartY) {
|
|
476
|
+
minStartY = y - 1;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
for (const node of nodes) {
|
|
483
|
+
if (node instanceof Konva.Group) {
|
|
484
|
+
node.x(node.x() - minStartX);
|
|
485
|
+
node.y(node.y() - minStartY);
|
|
486
|
+
} else if (node instanceof Konva.Line && node.name() === 'link-line') {
|
|
487
|
+
const points = node.points();
|
|
488
|
+
for (let i = 0; i < points.length; i += 2) {
|
|
489
|
+
points[i] = points[i] - minStartX;
|
|
490
|
+
points[i + 1] = points[i + 1] - minStartY;
|
|
491
|
+
}
|
|
492
|
+
node.points(points);
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
copy.x(0);
|
|
497
|
+
copy.y(0);
|
|
498
|
+
copy.width(maxX - minX);
|
|
499
|
+
copy.height(maxY - minY);
|
|
500
|
+
copy.scale({ x: 1, y: 1 });
|
|
501
|
+
return copy;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* 获得元素(用于另存为元素)
|
|
506
|
+
* @returns Konva.Stage
|
|
507
|
+
*/
|
|
508
|
+
getAsset() {
|
|
509
|
+
const copy = this.getAssetView();
|
|
510
|
+
// 添加背景
|
|
511
|
+
const background = this.render.getBackground();
|
|
512
|
+
background.width(copy.width());
|
|
513
|
+
background.height(copy.height());
|
|
514
|
+
copy.children[0].add(background);
|
|
515
|
+
background.moveToBottom();
|
|
516
|
+
const json = copy.toJSON();
|
|
517
|
+
const obj = JSON.parse(json);
|
|
518
|
+
const assets = obj.children[0].children;
|
|
519
|
+
|
|
520
|
+
for (const asset of assets) {
|
|
521
|
+
if (asset.attrs.name === 'asset') {
|
|
522
|
+
asset.attrs.name = 'sub-asset';
|
|
523
|
+
}
|
|
524
|
+
if (asset.attrs.selected) {
|
|
525
|
+
asset.attrs.selected = false;
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
this.render.linkTool.jsonIdCover(assets);
|
|
530
|
+
|
|
531
|
+
// 通过 stage api 导出 json
|
|
532
|
+
const result = JSON.stringify({
|
|
533
|
+
...obj.children[0],
|
|
534
|
+
className: 'Group',
|
|
535
|
+
attrs: {
|
|
536
|
+
width: copy.width(),
|
|
537
|
+
height: copy.height(),
|
|
538
|
+
x: 0,
|
|
539
|
+
y: 0
|
|
540
|
+
}
|
|
541
|
+
});
|
|
542
|
+
|
|
543
|
+
copy.destroy();
|
|
544
|
+
return result;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
/**
|
|
548
|
+
* 添加文字素材
|
|
549
|
+
* @param pos 落点位置
|
|
550
|
+
* @param settings 设置项
|
|
551
|
+
* @returns
|
|
552
|
+
*/
|
|
553
|
+
addTextAsset(pos: Konva.Vector2d, settings?: Partial<AssetSettings>) {
|
|
554
|
+
// 获取页面默认设置
|
|
555
|
+
const pageSettings = this.render.getPageSettings();
|
|
556
|
+
|
|
557
|
+
// 合并设置
|
|
558
|
+
const assetSettings: AssetSettings = {
|
|
559
|
+
stroke: pageSettings.stroke,
|
|
560
|
+
strokeWidth: pageSettings.strokeWidth,
|
|
561
|
+
fill: pageSettings.fill,
|
|
562
|
+
arrowStart: false,
|
|
563
|
+
arrowEnd: false,
|
|
564
|
+
fontSize: pageSettings.fontSize,
|
|
565
|
+
textFill: pageSettings.textFill,
|
|
566
|
+
text: 'Text',
|
|
567
|
+
x: pos.x,
|
|
568
|
+
y: pos.y,
|
|
569
|
+
rotation: 0,
|
|
570
|
+
tension: 0.5,
|
|
571
|
+
...settings
|
|
572
|
+
};
|
|
573
|
+
|
|
574
|
+
const group = new Konva.Group({
|
|
575
|
+
id: nanoid(),
|
|
576
|
+
name: 'asset',
|
|
577
|
+
assetType: AssetType.Text,
|
|
578
|
+
draggable: true,
|
|
579
|
+
position: { x: pos.x, y: pos.y }
|
|
580
|
+
});
|
|
581
|
+
|
|
582
|
+
group.setAttr('assetSettings', assetSettings);
|
|
583
|
+
|
|
584
|
+
const text = new Konva.Text({
|
|
585
|
+
text: assetSettings.text,
|
|
586
|
+
fill: assetSettings.textFill,
|
|
587
|
+
fontSize: assetSettings.fontSize,
|
|
588
|
+
draggable: false,
|
|
589
|
+
name: 'text-node'
|
|
590
|
+
});
|
|
591
|
+
|
|
592
|
+
const bg = new Konva.Rect({
|
|
593
|
+
width: text.width(),
|
|
594
|
+
height: text.height()
|
|
595
|
+
});
|
|
596
|
+
|
|
597
|
+
group.add(text);
|
|
598
|
+
group.add(bg);
|
|
599
|
+
this.render.layer.add(group);
|
|
600
|
+
this.render.layer.draw();
|
|
601
|
+
return group;
|
|
602
|
+
}
|
|
603
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { AssetTool } from './asset-tool';
|
|
2
|
+
export { SelectionTool } from './selection-tool';
|
|
3
|
+
export { CopyTool } from './copy-tool';
|
|
4
|
+
export { PositionTool } from './position-tool';
|
|
5
|
+
export { ZIndexTool } from './z-index-tool';
|
|
6
|
+
export { ImportExportTool } from './import-export-tool';
|
|
7
|
+
export { AlignTool } from './align-tool';
|
|
8
|
+
export { LinkTool } from './link-tool';
|
|
9
|
+
export { AttractTool } from './attract-tool';
|