@logicflow/extension 2.0.0-beta.2 → 2.0.0-beta.4
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/.turbo/turbo-build.log +7 -7
- package/dist/index.min.js +2 -2
- package/es/components/menu/index.d.ts +1 -1
- package/es/components/menu/index.js +9 -10
- package/es/components/menu/index.js.map +1 -1
- package/es/index.d.ts +1 -0
- package/es/index.js +1 -0
- package/es/index.js.map +1 -1
- package/es/insert-node-in-polyline/index.js +3 -3
- package/es/insert-node-in-polyline/index.js.map +1 -1
- package/es/materials/node-selection/index.d.ts +2 -1
- package/es/materials/node-selection/index.js +64 -56
- package/es/materials/node-selection/index.js.map +1 -1
- package/es/tools/snapshot/index.d.ts +101 -11
- package/es/tools/snapshot/index.js +331 -147
- package/es/tools/snapshot/index.js.map +1 -1
- package/es/tools/snapshot/utils.d.ts +35 -0
- package/es/tools/snapshot/utils.js +238 -0
- package/es/tools/snapshot/utils.js.map +1 -0
- package/lib/components/menu/index.d.ts +1 -1
- package/lib/components/menu/index.js +9 -10
- package/lib/components/menu/index.js.map +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -1
- package/lib/insert-node-in-polyline/index.js +2 -2
- package/lib/insert-node-in-polyline/index.js.map +1 -1
- package/lib/materials/node-selection/index.d.ts +2 -1
- package/lib/materials/node-selection/index.js +63 -55
- package/lib/materials/node-selection/index.js.map +1 -1
- package/lib/tools/snapshot/index.d.ts +101 -11
- package/lib/tools/snapshot/index.js +331 -147
- package/lib/tools/snapshot/index.js.map +1 -1
- package/lib/tools/snapshot/utils.d.ts +35 -0
- package/lib/tools/snapshot/utils.js +247 -0
- package/lib/tools/snapshot/utils.js.map +1 -0
- package/package.json +7 -4
- package/src/components/menu/index.ts +16 -13
- package/src/index.ts +1 -0
- package/src/insert-node-in-polyline/index.ts +3 -3
- package/src/materials/node-selection/index.ts +72 -69
- package/src/tools/snapshot/README.md +130 -5
- package/src/tools/snapshot/index.ts +264 -98
- package/src/tools/snapshot/utils.ts +163 -0
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
12
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
13
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
14
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
|
+
function step(op) {
|
|
16
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
17
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
18
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
19
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
20
|
+
switch (op[0]) {
|
|
21
|
+
case 0: case 1: t = op; break;
|
|
22
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
23
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
24
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
25
|
+
default:
|
|
26
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
27
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
28
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
29
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
30
|
+
if (t[2]) _.ops.pop();
|
|
31
|
+
_.trys.pop(); continue;
|
|
32
|
+
}
|
|
33
|
+
op = body.call(thisArg, _);
|
|
34
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
35
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
var __read = (this && this.__read) || function (o, n) {
|
|
39
|
+
var m = typeof Symbol === "function" && o[Symbol.iterator];
|
|
40
|
+
if (!m) return o;
|
|
41
|
+
var i = m.call(o), r, ar = [], e;
|
|
42
|
+
try {
|
|
43
|
+
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
|
|
44
|
+
}
|
|
45
|
+
catch (error) { e = { error: error }; }
|
|
46
|
+
finally {
|
|
47
|
+
try {
|
|
48
|
+
if (r && !r.done && (m = i["return"])) m.call(i);
|
|
49
|
+
}
|
|
50
|
+
finally { if (e) throw e.error; }
|
|
51
|
+
}
|
|
52
|
+
return ar;
|
|
53
|
+
};
|
|
54
|
+
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
55
|
+
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
56
|
+
if (ar || !(i in from)) {
|
|
57
|
+
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
58
|
+
ar[i] = from[i];
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return to.concat(ar || Array.prototype.slice.call(from));
|
|
62
|
+
};
|
|
63
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
64
|
+
exports.copyCanvas = exports.updateImageSource = exports.updateBackgroundImageWithBase64Image = exports.updateImageSrcOrHrefWithBase64Image = exports.convertImageToBase64 = exports.isTextPlainBase64 = void 0;
|
|
65
|
+
/**
|
|
66
|
+
* 图片缓存, 已请求过的图片直接从缓存中获取
|
|
67
|
+
*/
|
|
68
|
+
var imageCache = {};
|
|
69
|
+
/**
|
|
70
|
+
* 当获取图片失败时会返回失败信息,是 text/plain 类型的数据
|
|
71
|
+
* @param str - 图片内容
|
|
72
|
+
* @returns
|
|
73
|
+
*/
|
|
74
|
+
function isTextPlainBase64(str) {
|
|
75
|
+
return str.startsWith('data:text/plain');
|
|
76
|
+
}
|
|
77
|
+
exports.isTextPlainBase64 = isTextPlainBase64;
|
|
78
|
+
/**
|
|
79
|
+
* 将网络图片转为 base64
|
|
80
|
+
* @param url - 图片地址
|
|
81
|
+
* @returns
|
|
82
|
+
*/
|
|
83
|
+
function convertImageToBase64(url) {
|
|
84
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
85
|
+
return __generator(this, function (_a) {
|
|
86
|
+
if (imageCache[url]) {
|
|
87
|
+
return [2 /*return*/, imageCache[url]];
|
|
88
|
+
}
|
|
89
|
+
return [2 /*return*/, new Promise(function (resolve, reject) {
|
|
90
|
+
try {
|
|
91
|
+
fetch(url)
|
|
92
|
+
.then(function (response) { return response.blob(); })
|
|
93
|
+
.then(function (blob) {
|
|
94
|
+
var reader = new FileReader();
|
|
95
|
+
reader.onloadend = function () {
|
|
96
|
+
resolve((imageCache[url] = reader.result));
|
|
97
|
+
};
|
|
98
|
+
reader.onerror = reject;
|
|
99
|
+
reader.readAsDataURL(blob);
|
|
100
|
+
})
|
|
101
|
+
.catch(function () {
|
|
102
|
+
resolve((imageCache[url] = url));
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
// 如果转换失败,后续大概率仍然会失败,因此直接缓存
|
|
107
|
+
return (imageCache[url] = url);
|
|
108
|
+
}
|
|
109
|
+
})];
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
exports.convertImageToBase64 = convertImageToBase64;
|
|
114
|
+
/**
|
|
115
|
+
* 使用 base64 的图片替换 img 标签的 src 或 image 标签的 href
|
|
116
|
+
* @param node - html 节点或 svg 节点
|
|
117
|
+
*/
|
|
118
|
+
function updateImageSrcOrHrefWithBase64Image(node, attrName) {
|
|
119
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
120
|
+
var url, base64Image, error_1;
|
|
121
|
+
return __generator(this, function (_a) {
|
|
122
|
+
switch (_a.label) {
|
|
123
|
+
case 0:
|
|
124
|
+
_a.trys.push([0, 2, , 3]);
|
|
125
|
+
url = node.getAttribute(attrName) || '';
|
|
126
|
+
// 已经是 base64 图片,不需要处理
|
|
127
|
+
if (url.startsWith('data:')) {
|
|
128
|
+
return [2 /*return*/];
|
|
129
|
+
}
|
|
130
|
+
return [4 /*yield*/, convertImageToBase64(url)];
|
|
131
|
+
case 1:
|
|
132
|
+
base64Image = _a.sent();
|
|
133
|
+
if (isTextPlainBase64(base64Image)) {
|
|
134
|
+
return [2 /*return*/];
|
|
135
|
+
}
|
|
136
|
+
node.setAttribute(attrName, base64Image);
|
|
137
|
+
return [3 /*break*/, 3];
|
|
138
|
+
case 2:
|
|
139
|
+
error_1 = _a.sent();
|
|
140
|
+
console.error(error_1);
|
|
141
|
+
return [3 /*break*/, 3];
|
|
142
|
+
case 3: return [2 /*return*/];
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
exports.updateImageSrcOrHrefWithBase64Image = updateImageSrcOrHrefWithBase64Image;
|
|
148
|
+
/**
|
|
149
|
+
* 使用 base64 的图片替换背景图片
|
|
150
|
+
* @param node - html 节点
|
|
151
|
+
* @param styleAttr - 样式属性名称
|
|
152
|
+
*/
|
|
153
|
+
function updateBackgroundImageWithBase64Image(node, url) {
|
|
154
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
155
|
+
var base64Image, error_2;
|
|
156
|
+
return __generator(this, function (_a) {
|
|
157
|
+
switch (_a.label) {
|
|
158
|
+
case 0:
|
|
159
|
+
_a.trys.push([0, 2, , 3]);
|
|
160
|
+
// 已经是 base64 图片,不需要处理
|
|
161
|
+
if (url.startsWith('data:')) {
|
|
162
|
+
return [2 /*return*/];
|
|
163
|
+
}
|
|
164
|
+
return [4 /*yield*/, convertImageToBase64(url)];
|
|
165
|
+
case 1:
|
|
166
|
+
base64Image = _a.sent();
|
|
167
|
+
if (isTextPlainBase64(base64Image)) {
|
|
168
|
+
return [2 /*return*/];
|
|
169
|
+
}
|
|
170
|
+
node.style.backgroundImage = "url(".concat(base64Image, ")");
|
|
171
|
+
return [3 /*break*/, 3];
|
|
172
|
+
case 2:
|
|
173
|
+
error_2 = _a.sent();
|
|
174
|
+
console.error(error_2);
|
|
175
|
+
return [3 /*break*/, 3];
|
|
176
|
+
case 3: return [2 /*return*/];
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
exports.updateBackgroundImageWithBase64Image = updateBackgroundImageWithBase64Image;
|
|
182
|
+
/**
|
|
183
|
+
* 更新图片数据
|
|
184
|
+
* @param node - 节点
|
|
185
|
+
*/
|
|
186
|
+
function updateImageSource(node) {
|
|
187
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
188
|
+
var nodes, nodePtr, promises, _a, background, backgroundImage, backgroundUrlMatch, imageUrl, backgroundImageUrlMatch, imageUrl;
|
|
189
|
+
return __generator(this, function (_b) {
|
|
190
|
+
switch (_b.label) {
|
|
191
|
+
case 0:
|
|
192
|
+
nodes = [node];
|
|
193
|
+
promises = [];
|
|
194
|
+
while (nodes.length) {
|
|
195
|
+
nodePtr = nodes.shift();
|
|
196
|
+
if (nodePtr.children.length) {
|
|
197
|
+
nodes.push.apply(nodes, __spreadArray([], __read(nodePtr.children), false));
|
|
198
|
+
}
|
|
199
|
+
if (nodePtr instanceof HTMLElement) {
|
|
200
|
+
_a = nodePtr.style, background = _a.background, backgroundImage = _a.backgroundImage;
|
|
201
|
+
backgroundUrlMatch = background.match(/url\(["']?(.*?)["']?\)/);
|
|
202
|
+
if (backgroundUrlMatch && backgroundUrlMatch[1]) {
|
|
203
|
+
imageUrl = backgroundUrlMatch[1];
|
|
204
|
+
promises.push(updateBackgroundImageWithBase64Image(nodePtr, imageUrl));
|
|
205
|
+
}
|
|
206
|
+
backgroundImageUrlMatch = backgroundImage.match(/url\(["']?(.*?)["']?\)/);
|
|
207
|
+
if (backgroundImageUrlMatch && backgroundImageUrlMatch[1]) {
|
|
208
|
+
imageUrl = backgroundImageUrlMatch[1];
|
|
209
|
+
promises.push(updateBackgroundImageWithBase64Image(nodePtr, imageUrl));
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
// 如果有 img 和 image 标签,尝试将 src 和 href 替换为 base64 图片
|
|
213
|
+
if (nodePtr instanceof HTMLImageElement) {
|
|
214
|
+
promises.push(updateImageSrcOrHrefWithBase64Image(nodePtr, 'src'));
|
|
215
|
+
}
|
|
216
|
+
else if (nodePtr instanceof SVGImageElement) {
|
|
217
|
+
promises.push(updateImageSrcOrHrefWithBase64Image(nodePtr, 'href'));
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return [4 /*yield*/, Promise.all(promises)];
|
|
221
|
+
case 1:
|
|
222
|
+
_b.sent();
|
|
223
|
+
return [2 /*return*/];
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
exports.updateImageSource = updateImageSource;
|
|
229
|
+
/**
|
|
230
|
+
* 重新复制canvas 用于在不裁剪原canvas的基础上通过拉伸方式达到自定义宽高目的
|
|
231
|
+
* @param originCanvas HTMLCanvasElement
|
|
232
|
+
* @param targetWidth number
|
|
233
|
+
* @param targetHeight number
|
|
234
|
+
*/
|
|
235
|
+
function copyCanvas(originCanvas, targetWidth, targetHeight) {
|
|
236
|
+
var newCanvas = document.createElement('canvas');
|
|
237
|
+
newCanvas.width = targetWidth;
|
|
238
|
+
newCanvas.height = targetHeight;
|
|
239
|
+
var newCtx = newCanvas.getContext('2d');
|
|
240
|
+
if (newCtx) {
|
|
241
|
+
// 注意: 自定义宽高时,可能会拉伸图形,这时候padding也会被拉伸导致不准确
|
|
242
|
+
newCtx.drawImage(originCanvas, 0, 0, originCanvas.width, originCanvas.height, 0, 0, targetWidth, targetHeight);
|
|
243
|
+
}
|
|
244
|
+
return newCanvas;
|
|
245
|
+
}
|
|
246
|
+
exports.copyCanvas = copyCanvas;
|
|
247
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/tools/snapshot/utils.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@logicflow/extension",
|
|
3
|
-
"version": "2.0.0-beta.
|
|
3
|
+
"version": "2.0.0-beta.4",
|
|
4
4
|
"description": "LogicFlow Extensions",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"module": "es/index.js",
|
|
@@ -20,12 +20,15 @@
|
|
|
20
20
|
"author": "Logicflow-Team",
|
|
21
21
|
"license": "Apache-2.0",
|
|
22
22
|
"peerDependencies": {
|
|
23
|
-
"@logicflow/core": "2.0.0-beta.
|
|
23
|
+
"@logicflow/core": "2.0.0-beta.4"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
+
"lodash-es": "^4.17.21",
|
|
26
27
|
"@antv/hierarchy": "^0.6.11",
|
|
27
|
-
"
|
|
28
|
-
|
|
28
|
+
"@logicflow/core": "2.0.0-beta.4"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"preact": "^10.17.1"
|
|
29
32
|
},
|
|
30
33
|
"scripts": {
|
|
31
34
|
"clean:turbo": "rss",
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import LogicFlow from '@logicflow/core'
|
|
2
2
|
|
|
3
|
+
import GraphData = LogicFlow.GraphData
|
|
4
|
+
import NodeData = LogicFlow.NodeData
|
|
5
|
+
import EdgeData = LogicFlow.EdgeData
|
|
6
|
+
|
|
3
7
|
type SetType = 'add' | 'reset'
|
|
4
8
|
|
|
5
9
|
export type MenuItem = {
|
|
@@ -25,7 +29,7 @@ class Menu {
|
|
|
25
29
|
private __container?: HTMLElement
|
|
26
30
|
private __menuDOM?: HTMLElement
|
|
27
31
|
private menuTypeMap?: Map<string, MenuItem[]>
|
|
28
|
-
private __currentData:
|
|
32
|
+
private __currentData: EdgeData | NodeData | GraphData | null = null
|
|
29
33
|
static pluginName = 'menu'
|
|
30
34
|
|
|
31
35
|
constructor({ lf }) {
|
|
@@ -107,7 +111,7 @@ class Menu {
|
|
|
107
111
|
this.menuTypeMap?.set(DefaultSelectionMenuKey, DefaultSelectionMenu)
|
|
108
112
|
}
|
|
109
113
|
|
|
110
|
-
render(lf, container) {
|
|
114
|
+
render(lf: LogicFlow, container: HTMLElement) {
|
|
111
115
|
if (lf.options.isSilentMode) return
|
|
112
116
|
this.__container = container
|
|
113
117
|
this.__currentData = null // 当前展示的菜单所属元素的model数据
|
|
@@ -147,7 +151,7 @@ class Menu {
|
|
|
147
151
|
)
|
|
148
152
|
}
|
|
149
153
|
// 通过事件控制菜单的显示和隐藏
|
|
150
|
-
this.lf.on('node:contextmenu', ({ data, position, e }
|
|
154
|
+
this.lf.on('node:contextmenu', ({ data, position, e }) => {
|
|
151
155
|
const {
|
|
152
156
|
domOverlayPosition: { x, y },
|
|
153
157
|
} = position
|
|
@@ -157,14 +161,14 @@ class Menu {
|
|
|
157
161
|
if (!model) return
|
|
158
162
|
let menuList: any = []
|
|
159
163
|
const typeMenus = this.menuTypeMap?.get(model.type)
|
|
160
|
-
//
|
|
164
|
+
// 1.如果单个节点自定义了菜单,以单个节点自定义为准
|
|
161
165
|
if (model && model.menu && Array.isArray(model.menu)) {
|
|
162
166
|
menuList = model.menu
|
|
163
167
|
} else if (typeMenus) {
|
|
164
|
-
//
|
|
168
|
+
// 2.如果当前节点类型定义了菜单,再取该配置
|
|
165
169
|
menuList = typeMenus
|
|
166
170
|
} else {
|
|
167
|
-
//
|
|
171
|
+
// 3.最后取全局默认
|
|
168
172
|
menuList = this.menuTypeMap?.get(DefaultNodeMenuKey)
|
|
169
173
|
}
|
|
170
174
|
this.__currentData = data
|
|
@@ -175,7 +179,7 @@ class Menu {
|
|
|
175
179
|
clientY: e.clientY,
|
|
176
180
|
})
|
|
177
181
|
})
|
|
178
|
-
this.lf.on('edge:contextmenu', ({ data, position, e }
|
|
182
|
+
this.lf.on('edge:contextmenu', ({ data, position, e }) => {
|
|
179
183
|
const {
|
|
180
184
|
domOverlayPosition: { x, y },
|
|
181
185
|
} = position
|
|
@@ -183,15 +187,13 @@ class Menu {
|
|
|
183
187
|
const model = this.lf.graphModel.getEdgeModelById(id)
|
|
184
188
|
if (!model) return
|
|
185
189
|
let menuList: any = []
|
|
186
|
-
const typeMenus = this.menuTypeMap?.get(model.type)
|
|
187
|
-
//
|
|
190
|
+
const typeMenus = this.menuTypeMap?.get(model.type)
|
|
191
|
+
// 菜单优先级: model.menu > typeMenus > defaultEdgeMenu,注释同上节点
|
|
188
192
|
if (model && model.menu && Array.isArray(model.menu)) {
|
|
189
193
|
menuList = model.menu
|
|
190
194
|
} else if (typeMenus) {
|
|
191
|
-
// 如果定义当前边类型的元素
|
|
192
195
|
menuList = typeMenus
|
|
193
196
|
} else {
|
|
194
|
-
// 最后取全局默认
|
|
195
197
|
menuList = this.menuTypeMap?.get(DefaultEdgeMenuKey) ?? []
|
|
196
198
|
}
|
|
197
199
|
this.__currentData = data
|
|
@@ -202,14 +204,14 @@ class Menu {
|
|
|
202
204
|
clientY: e.clientY,
|
|
203
205
|
})
|
|
204
206
|
})
|
|
205
|
-
this.lf.on('blank:contextmenu', ({ position }
|
|
207
|
+
this.lf.on('blank:contextmenu', ({ position }) => {
|
|
206
208
|
const menuList = this.menuTypeMap?.get(DefaultGraphMenuKey) ?? []
|
|
207
209
|
const {
|
|
208
210
|
domOverlayPosition: { x, y },
|
|
209
211
|
} = position
|
|
210
212
|
this.showMenu(x, y, menuList)
|
|
211
213
|
})
|
|
212
|
-
this.lf.on('selection:contextmenu', ({ data, position }
|
|
214
|
+
this.lf.on('selection:contextmenu', ({ data, position }) => {
|
|
213
215
|
const menuList = this.menuTypeMap?.get(DefaultSelectionMenuKey)
|
|
214
216
|
const {
|
|
215
217
|
domOverlayPosition: { x, y },
|
|
@@ -217,6 +219,7 @@ class Menu {
|
|
|
217
219
|
this.__currentData = data
|
|
218
220
|
this.showMenu(x, y, menuList)
|
|
219
221
|
})
|
|
222
|
+
|
|
220
223
|
this.lf.on('node:mousedown', () => {
|
|
221
224
|
this.__menuDOM!.style.display = 'none'
|
|
222
225
|
})
|
package/src/index.ts
CHANGED
|
@@ -14,6 +14,7 @@ export * from './components/selection-select'
|
|
|
14
14
|
export * from './components/mini-map'
|
|
15
15
|
export * from './materials/curved-edge'
|
|
16
16
|
export * from './materials/group'
|
|
17
|
+
export * from './materials/node-selection'
|
|
17
18
|
export * from './NodeResize'
|
|
18
19
|
export * from './tools/flow-path'
|
|
19
20
|
export * from './tools/auto-layout'
|
|
@@ -2,7 +2,7 @@ import LogicFlow, {
|
|
|
2
2
|
BaseNodeModel,
|
|
3
3
|
PolylineEdgeModel,
|
|
4
4
|
EventType,
|
|
5
|
-
|
|
5
|
+
formatAnchorConnectValidateData,
|
|
6
6
|
} from '@logicflow/core'
|
|
7
7
|
import { cloneDeep } from 'lodash-es'
|
|
8
8
|
import { isNodeInSegment } from './edge'
|
|
@@ -85,9 +85,9 @@ export class InsertNodeInPolyline {
|
|
|
85
85
|
)
|
|
86
86
|
|
|
87
87
|
const { isAllPass: isSourcePass, msg: sourceMsg } =
|
|
88
|
-
|
|
88
|
+
formatAnchorConnectValidateData(sourceRuleResultData)
|
|
89
89
|
const { isAllPass: isTargetPass, msg: targetMsg } =
|
|
90
|
-
|
|
90
|
+
formatAnchorConnectValidateData(targetRuleResultData)
|
|
91
91
|
|
|
92
92
|
return {
|
|
93
93
|
isPass: isSourcePass && isTargetPass,
|
|
@@ -2,17 +2,6 @@ import { get } from 'lodash-es'
|
|
|
2
2
|
import { h, PolygonNode, PolygonNodeModel } from '@logicflow/core'
|
|
3
3
|
|
|
4
4
|
class NodeSelectionView extends PolygonNode {
|
|
5
|
-
d = 10
|
|
6
|
-
|
|
7
|
-
getShapeStyle() {
|
|
8
|
-
// 设置边框为虚线
|
|
9
|
-
const style = this.props.model.getNodeStyle()
|
|
10
|
-
// @ts-ignore
|
|
11
|
-
style.strokeDashArray = '10 5'
|
|
12
|
-
|
|
13
|
-
return style
|
|
14
|
-
}
|
|
15
|
-
|
|
16
5
|
getLabelShape(): h.JSX.Element {
|
|
17
6
|
const { id, x, y, width, height, properties } = this.props.model
|
|
18
7
|
const style = this.props.model.getNodeStyle()
|
|
@@ -21,38 +10,38 @@ class NodeSelectionView extends PolygonNode {
|
|
|
21
10
|
{
|
|
22
11
|
x: x - width / 2,
|
|
23
12
|
y: y - height / 2,
|
|
13
|
+
width: 50,
|
|
14
|
+
height: 24,
|
|
24
15
|
style: 'z-index: 0; background: none; overflow: auto;',
|
|
25
16
|
},
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
'x',
|
|
55
|
-
),
|
|
17
|
+
[
|
|
18
|
+
properties.labelText
|
|
19
|
+
? h(
|
|
20
|
+
'text',
|
|
21
|
+
{
|
|
22
|
+
x: 0,
|
|
23
|
+
y: -5,
|
|
24
|
+
fontSize: '16px',
|
|
25
|
+
fill: style.stroke,
|
|
26
|
+
},
|
|
27
|
+
properties.labelText,
|
|
28
|
+
)
|
|
29
|
+
: '',
|
|
30
|
+
properties.disabledDelete
|
|
31
|
+
? ''
|
|
32
|
+
: h(
|
|
33
|
+
'text',
|
|
34
|
+
{
|
|
35
|
+
x: properties.labelText ? 50 : 0,
|
|
36
|
+
y: -5,
|
|
37
|
+
fontSize: '24px',
|
|
38
|
+
cursor: 'pointer',
|
|
39
|
+
fill: style.stroke,
|
|
40
|
+
onclick: this.handleCustomDeleteIconClick.bind(this, id),
|
|
41
|
+
},
|
|
42
|
+
'x',
|
|
43
|
+
),
|
|
44
|
+
],
|
|
56
45
|
)
|
|
57
46
|
}
|
|
58
47
|
|
|
@@ -72,7 +61,7 @@ class NodeSelectionView extends PolygonNode {
|
|
|
72
61
|
this.getLabelShape(),
|
|
73
62
|
])
|
|
74
63
|
}
|
|
75
|
-
|
|
64
|
+
// 避免点击时,该节点置于最高层,挡住内部节点
|
|
76
65
|
toFront() {}
|
|
77
66
|
|
|
78
67
|
/**
|
|
@@ -88,36 +77,46 @@ class NodeSelectionView extends PolygonNode {
|
|
|
88
77
|
class NodeSelectionModel extends PolygonNodeModel {
|
|
89
78
|
d = 10
|
|
90
79
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
this.points = []
|
|
94
|
-
|
|
95
|
-
this.text = {
|
|
80
|
+
initNodeData(data) {
|
|
81
|
+
data.text = {
|
|
96
82
|
value: '',
|
|
97
|
-
x:
|
|
98
|
-
y:
|
|
83
|
+
x: data.x,
|
|
84
|
+
y: data.y,
|
|
99
85
|
draggable: false,
|
|
100
86
|
editable: false,
|
|
101
87
|
}
|
|
102
|
-
|
|
88
|
+
super.initNodeData(data)
|
|
103
89
|
this.zIndex = 0
|
|
104
|
-
this.draggable =
|
|
105
|
-
|
|
90
|
+
this.draggable = true
|
|
91
|
+
}
|
|
106
92
|
|
|
107
|
-
|
|
108
|
-
|
|
93
|
+
setAttributes() {
|
|
94
|
+
// 默认不显示
|
|
95
|
+
this.points = []
|
|
96
|
+
|
|
97
|
+
// 图render的时候,会把所有nodes数据实例化,全部实例化完成后,放到nodesMap里。
|
|
98
|
+
// 节点的setAttributes在实例化的时候执行第一次
|
|
99
|
+
// updatePointsByNodes中的getNodeModelById方法,是从nodesMap取的数据,第一次就拿不到,所以要加setTimeout
|
|
100
|
+
if ((this.properties?.node_selection_ids as string[]).length > 1) {
|
|
109
101
|
setTimeout(() => {
|
|
110
|
-
this.updatePointsByNodes(this.properties
|
|
102
|
+
this.updatePointsByNodes(this.properties?.node_selection_ids || [])
|
|
111
103
|
})
|
|
112
104
|
}
|
|
113
105
|
}
|
|
114
106
|
|
|
107
|
+
getNodeStyle() {
|
|
108
|
+
const style = super.getNodeStyle()
|
|
109
|
+
style.stroke = this.properties.strokeColor || '#008000'
|
|
110
|
+
style.strokeDasharray = '10 5'
|
|
111
|
+
return style
|
|
112
|
+
}
|
|
113
|
+
|
|
115
114
|
getDefaultAnchor() {
|
|
116
115
|
return []
|
|
117
116
|
}
|
|
118
117
|
|
|
119
118
|
/**
|
|
120
|
-
* 更新points
|
|
119
|
+
* 更新points - 多边形顶点坐标集合
|
|
121
120
|
* @param points
|
|
122
121
|
*/
|
|
123
122
|
updatePoints(points) {
|
|
@@ -125,7 +124,7 @@ class NodeSelectionModel extends PolygonNodeModel {
|
|
|
125
124
|
}
|
|
126
125
|
|
|
127
126
|
/**
|
|
128
|
-
* 更新x y
|
|
127
|
+
* 更新x y - 多边形中点坐标
|
|
129
128
|
*/
|
|
130
129
|
updateCoordinate({ x, y }) {
|
|
131
130
|
this.x = x
|
|
@@ -133,10 +132,9 @@ class NodeSelectionModel extends PolygonNodeModel {
|
|
|
133
132
|
}
|
|
134
133
|
|
|
135
134
|
/**
|
|
136
|
-
*
|
|
135
|
+
* 计算新的 points 和 x y
|
|
137
136
|
*/
|
|
138
137
|
updatePointsByNodes(nodesIds) {
|
|
139
|
-
// TODO: 临时方案矩形
|
|
140
138
|
const points: [number, number][] = []
|
|
141
139
|
let minX = Infinity
|
|
142
140
|
let minY = Infinity
|
|
@@ -164,7 +162,7 @@ class NodeSelectionModel extends PolygonNodeModel {
|
|
|
164
162
|
}
|
|
165
163
|
}
|
|
166
164
|
|
|
167
|
-
|
|
165
|
+
class NodeSelection {
|
|
168
166
|
static pluginName = 'node-selection'
|
|
169
167
|
lf // lf 实例
|
|
170
168
|
selectNodes: any[] = [] // 选择的nodes
|
|
@@ -237,26 +235,20 @@ export class NodeSelection {
|
|
|
237
235
|
|
|
238
236
|
lf.on('node:click', (val) => {
|
|
239
237
|
if (!val.e.shiftKey || val.data.type === 'node-selection') return
|
|
240
|
-
|
|
241
238
|
this.currentClickNode = val.data
|
|
242
239
|
|
|
243
240
|
// 如果selectNodesIds中已存在此节点,则取消选中此节点
|
|
244
|
-
let
|
|
241
|
+
let hasExists = false
|
|
245
242
|
if (this.selectNodesIds.includes(val.data.id)) {
|
|
246
243
|
this.lf.getNodeModelById(val.data.id).setSelected(false)
|
|
247
|
-
|
|
244
|
+
hasExists = true
|
|
248
245
|
}
|
|
249
246
|
|
|
250
247
|
// 获取所有被选中的节点,获取到的数组是无序的
|
|
251
248
|
const { nodes } = lf.getSelectElements(true)
|
|
252
|
-
// 使用插件时判断是否允许使用node-selection
|
|
253
|
-
if (lf.disableNodeSelection && lf.disableNodeSelection(nodes)) {
|
|
254
|
-
return
|
|
255
|
-
}
|
|
256
249
|
this.selectNodes = nodes
|
|
257
|
-
|
|
258
250
|
if (this.selectNodes.length === 1) {
|
|
259
|
-
if (!
|
|
251
|
+
if (!hasExists) {
|
|
260
252
|
this.addNodeSelection()
|
|
261
253
|
} else {
|
|
262
254
|
this.updateNodeSelection()
|
|
@@ -265,7 +257,18 @@ export class NodeSelection {
|
|
|
265
257
|
this.updateNodeSelection()
|
|
266
258
|
}
|
|
267
259
|
})
|
|
260
|
+
lf.graphModel.addNodeMoveRules((model, deltaX, deltaY) => {
|
|
261
|
+
if (model.type === 'node-selection') {
|
|
262
|
+
// 如果移动的是分组,那么分组的子节点也跟着移动。
|
|
263
|
+
const nodeIds = model.properties.node_selection_ids
|
|
264
|
+
lf.graphModel.moveNodes(nodeIds, deltaX, deltaY, true)
|
|
265
|
+
return true
|
|
266
|
+
}
|
|
267
|
+
return true
|
|
268
|
+
})
|
|
268
269
|
}
|
|
269
270
|
}
|
|
270
271
|
|
|
271
272
|
export default NodeSelection
|
|
273
|
+
|
|
274
|
+
export { NodeSelection }
|