@logicflow/extension 2.0.16 → 2.0.18

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.
@@ -1,4 +1,15 @@
1
1
  "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
2
13
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
14
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
15
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -62,9 +73,10 @@ var Snapshot = /** @class */ (function () {
62
73
  }
63
74
  }); }); };
64
75
  /* 获取Blob对象 */
65
- lf.getSnapshotBlob = function (backgroundColor, fileType) { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) {
76
+ lf.getSnapshotBlob = function (backgroundColor, // 兼容老的使用方式
77
+ fileType, toImageOptions) { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) {
66
78
  switch (_a.label) {
67
- case 0: return [4 /*yield*/, this.getSnapshotBlob(backgroundColor, fileType)
79
+ case 0: return [4 /*yield*/, this.getSnapshotBlob(backgroundColor, fileType, toImageOptions)
68
80
  /* 获取Base64对象 */
69
81
  ];
70
82
  case 1: return [2 /*return*/, _a.sent()
@@ -73,9 +85,10 @@ var Snapshot = /** @class */ (function () {
73
85
  }
74
86
  }); }); };
75
87
  /* 获取Base64对象 */
76
- lf.getSnapshotBase64 = function (backgroundColor, fileType) { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) {
88
+ lf.getSnapshotBase64 = function (backgroundColor, // 兼容老的使用方式
89
+ fileType, toImageOptions) { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) {
77
90
  switch (_a.label) {
78
- case 0: return [4 /*yield*/, this.getSnapshotBase64(backgroundColor, fileType)];
91
+ case 0: return [4 /*yield*/, this.getSnapshotBase64(backgroundColor, fileType, toImageOptions)];
79
92
  case 1: return [2 /*return*/, _a.sent()];
80
93
  }
81
94
  }); }); };
@@ -140,13 +153,329 @@ var Snapshot = /** @class */ (function () {
140
153
  }
141
154
  };
142
155
  /**
143
- * 导出画布:导出前的处理画布工作,局部渲染模式处理、静默模式处理
144
- * @param fileName
145
- * @param toImageOptions
156
+ * 将图片转换为base64格式
157
+ * @param url - 图片URL
158
+ * @returns Promise<string> - base64字符串
146
159
  */
147
- Snapshot.prototype.getSnapshot = function (fileName, toImageOptions) {
160
+ Snapshot.prototype.convertImageToBase64 = function (url) {
148
161
  return __awaiter(this, void 0, void 0, function () {
149
- var curPartial, _a, partial, editConfig;
162
+ return __generator(this, function (_a) {
163
+ return [2 /*return*/, new Promise(function (resolve, reject) {
164
+ var img = new Image();
165
+ img.crossOrigin = 'anonymous'; // 处理跨域问题
166
+ img.onload = function () {
167
+ var canvas = document.createElement('canvas');
168
+ canvas.width = img.width;
169
+ canvas.height = img.height;
170
+ var ctx = canvas.getContext('2d');
171
+ ctx === null || ctx === void 0 ? void 0 : ctx.drawImage(img, 0, 0);
172
+ var base64 = canvas.toDataURL('image/png');
173
+ resolve(base64);
174
+ };
175
+ img.onerror = function () {
176
+ reject(new Error("Failed to load image: ".concat(url)));
177
+ };
178
+ img.src = url;
179
+ })];
180
+ });
181
+ });
182
+ };
183
+ /**
184
+ * 检查URL是否为相对路径
185
+ * @param url - 要检查的URL
186
+ * @returns boolean - 是否为相对路径
187
+ */
188
+ Snapshot.prototype.isRelativePath = function (url) {
189
+ return (!url.startsWith('data:') &&
190
+ !url.startsWith('http://') &&
191
+ !url.startsWith('https://') &&
192
+ !url.startsWith('//'));
193
+ };
194
+ /**
195
+ * 处理SVG中的图片元素
196
+ * @param element - SVG元素
197
+ */
198
+ Snapshot.prototype.processImages = function (element) {
199
+ return __awaiter(this, void 0, void 0, function () {
200
+ var images, i, image, href, base64, error_1, foreignObjects, i, foreignObject, images_1, j, image, src, base64, error_2;
201
+ return __generator(this, function (_a) {
202
+ switch (_a.label) {
203
+ case 0:
204
+ images = element.getElementsByTagName('image');
205
+ i = 0;
206
+ _a.label = 1;
207
+ case 1:
208
+ if (!(i < images.length)) return [3 /*break*/, 6];
209
+ image = images[i];
210
+ href = image.getAttributeNS('http://www.w3.org/1999/xlink', 'href') ||
211
+ image.getAttribute('href');
212
+ if (!(href && this.isRelativePath(href))) return [3 /*break*/, 5];
213
+ _a.label = 2;
214
+ case 2:
215
+ _a.trys.push([2, 4, , 5]);
216
+ return [4 /*yield*/, this.convertImageToBase64(href)];
217
+ case 3:
218
+ base64 = _a.sent();
219
+ image.setAttributeNS('http://www.w3.org/1999/xlink', 'href', base64);
220
+ image.setAttribute('href', base64);
221
+ return [3 /*break*/, 5];
222
+ case 4:
223
+ error_1 = _a.sent();
224
+ console.warn("Failed to convert image to base64: ".concat(href), error_1);
225
+ return [3 /*break*/, 5];
226
+ case 5:
227
+ i++;
228
+ return [3 /*break*/, 1];
229
+ case 6:
230
+ foreignObjects = element.getElementsByTagName('foreignObject');
231
+ i = 0;
232
+ _a.label = 7;
233
+ case 7:
234
+ if (!(i < foreignObjects.length)) return [3 /*break*/, 14];
235
+ foreignObject = foreignObjects[i];
236
+ images_1 = foreignObject.getElementsByTagName('img');
237
+ j = 0;
238
+ _a.label = 8;
239
+ case 8:
240
+ if (!(j < images_1.length)) return [3 /*break*/, 13];
241
+ image = images_1[j];
242
+ src = image.getAttribute('src');
243
+ if (!(src && this.isRelativePath(src))) return [3 /*break*/, 12];
244
+ _a.label = 9;
245
+ case 9:
246
+ _a.trys.push([9, 11, , 12]);
247
+ return [4 /*yield*/, this.convertImageToBase64(src)];
248
+ case 10:
249
+ base64 = _a.sent();
250
+ image.setAttribute('src', base64);
251
+ return [3 /*break*/, 12];
252
+ case 11:
253
+ error_2 = _a.sent();
254
+ console.warn("Failed to convert image to base64: ".concat(src), error_2);
255
+ return [3 /*break*/, 12];
256
+ case 12:
257
+ j++;
258
+ return [3 /*break*/, 8];
259
+ case 13:
260
+ i++;
261
+ return [3 /*break*/, 7];
262
+ case 14: return [2 /*return*/];
263
+ }
264
+ });
265
+ });
266
+ };
267
+ /**
268
+ * 克隆并处理画布节点
269
+ * @param svg
270
+ * @returns
271
+ */
272
+ Snapshot.prototype.cloneSvg = function (svg_1) {
273
+ return __awaiter(this, arguments, void 0, function (svg, addStyle) {
274
+ var copy, graph, childLength, i, lfLayer, layerClassList, lfBase, style, foreignObject;
275
+ var _this = this;
276
+ var _a;
277
+ if (addStyle === void 0) { addStyle = true; }
278
+ return __generator(this, function (_b) {
279
+ switch (_b.label) {
280
+ case 0:
281
+ copy = svg.cloneNode(true);
282
+ graph = copy.lastChild;
283
+ childLength = (_a = graph === null || graph === void 0 ? void 0 : graph.childNodes) === null || _a === void 0 ? void 0 : _a.length;
284
+ if (childLength) {
285
+ for (i = 0; i < childLength; i++) {
286
+ lfLayer = graph === null || graph === void 0 ? void 0 : graph.childNodes[i];
287
+ layerClassList = lfLayer.classList && Array.from(lfLayer.classList);
288
+ if (layerClassList && layerClassList.indexOf('lf-base') < 0) {
289
+ graph === null || graph === void 0 ? void 0 : graph.removeChild(graph.childNodes[i]);
290
+ childLength--;
291
+ i--;
292
+ }
293
+ else {
294
+ lfBase = graph === null || graph === void 0 ? void 0 : graph.childNodes[i];
295
+ lfBase &&
296
+ lfBase.childNodes.forEach(function (item) {
297
+ var element = item;
298
+ _this.removeAnchor(element.firstChild);
299
+ _this.removeRotateControl(element.firstChild);
300
+ });
301
+ }
302
+ }
303
+ }
304
+ // 处理图片路径
305
+ return [4 /*yield*/, this.processImages(copy)
306
+ // 设置css样式
307
+ ];
308
+ case 1:
309
+ // 处理图片路径
310
+ _b.sent();
311
+ // 设置css样式
312
+ if (addStyle) {
313
+ style = document.createElement('style');
314
+ style.innerHTML = this.getClassRules();
315
+ foreignObject = document.createElement('foreignObject');
316
+ foreignObject.appendChild(style);
317
+ copy.appendChild(foreignObject);
318
+ }
319
+ return [2 /*return*/, copy];
320
+ }
321
+ });
322
+ });
323
+ };
324
+ /**
325
+ * 获取脚本 css 样式
326
+ * @returns
327
+ */
328
+ Snapshot.prototype.getClassRules = function () {
329
+ var rules = '';
330
+ if (this.useGlobalRules) {
331
+ var styleSheets = document.styleSheets;
332
+ for (var i = 0; i < styleSheets.length; i++) {
333
+ var sheet = styleSheets[i];
334
+ // 这里是为了过滤掉不同源 css 脚本,防止报错终止导出
335
+ try {
336
+ for (var j = 0; j < sheet.cssRules.length; j++) {
337
+ rules += sheet.cssRules[j].cssText;
338
+ }
339
+ }
340
+ catch (error) {
341
+ console.log('CSS scripts from different sources have been filtered out');
342
+ }
343
+ }
344
+ }
345
+ if (this.customCssRules) {
346
+ rules += this.customCssRules;
347
+ }
348
+ return rules;
349
+ };
350
+ /**
351
+ * 将 svg 转化为 canvas
352
+ * @param svg - svg 元素
353
+ * @param toImageOptions - 图像选项
354
+ * @returns Promise<canvas> - 返回 canvas 对象
355
+ */
356
+ Snapshot.prototype.getCanvasData = function (svg, toImageOptions) {
357
+ return __awaiter(this, void 0, void 0, function () {
358
+ var width, height, backgroundColor, _a, padding, copy, dpr, base, bbox, layoutCanvas, layout, offsetX, offsetY, graphModel, transformModel, SCALE_X, SCALE_Y, TRANSLATE_X, TRANSLATE_Y, safetyFactor, actualWidth, actualHeight, bboxWidth, bboxHeight, canvas, safetyMargin, ctx, img, style, foreignObject;
359
+ return __generator(this, function (_b) {
360
+ switch (_b.label) {
361
+ case 0:
362
+ width = toImageOptions.width, height = toImageOptions.height, backgroundColor = toImageOptions.backgroundColor, _a = toImageOptions.padding, padding = _a === void 0 ? 40 : _a;
363
+ return [4 /*yield*/, this.cloneSvg(svg, false)];
364
+ case 1:
365
+ copy = _b.sent();
366
+ dpr = window.devicePixelRatio || 1;
367
+ if (dpr < 1) {
368
+ // https://github.com/didi/LogicFlow/issues/1222
369
+ // canvas.width = bboxWidth * dpr配合ctx.scale(dpr, dpr)是为了解决绘制模糊
370
+ // 比如dpr=2,先让canvas.width放大到等同于屏幕的物理像素宽高,然后自适应缩放适配canvas.style.width
371
+ // 由于所有元素都缩放了一半,因此需要ctx.scale(dpr, dpr)放大2倍整体绘制的内容
372
+ // 当用户缩放浏览器时,window.devicePixelRatio会随着变小
373
+ // 当window.devicePixelRatio变小到一定程度,会导致canvas.width<canvas.style.width
374
+ // 由于导出图片的svg的大小是canvas.style.width+canvas.style.height
375
+ // 因此会导致导出的svg图片无法完整绘制到canvas(因为canvas.width小于svg的宽)
376
+ // 从而导致canvas导出图片是缺失的svg
377
+ // 而dpr>=1就能保证canvas.width>=canvas.style.width
378
+ // 当dpr小于1的时候,我们强制转化为1,并不会产生绘制模糊等问题
379
+ dpr = 1;
380
+ }
381
+ base = this.lf.graphModel.rootEl.querySelector('.lf-base');
382
+ bbox = base.getBoundingClientRect();
383
+ layoutCanvas = this.lf.container.querySelector('.lf-canvas-overlay');
384
+ layout = layoutCanvas.getBoundingClientRect();
385
+ offsetX = bbox.x - layout.x;
386
+ offsetY = bbox.y - layout.y;
387
+ graphModel = this.lf.graphModel;
388
+ transformModel = graphModel.transformModel;
389
+ SCALE_X = transformModel.SCALE_X, SCALE_Y = transformModel.SCALE_Y, TRANSLATE_X = transformModel.TRANSLATE_X, TRANSLATE_Y = transformModel.TRANSLATE_Y;
390
+ safetyFactor = 1.1 // 安全系数,增加20%的空间
391
+ ;
392
+ actualWidth = (bbox.width / SCALE_X) * safetyFactor;
393
+ actualHeight = (bbox.height / SCALE_Y) * safetyFactor;
394
+ copy.lastChild.style.transform = "matrix(1, 0, 0, 1, ".concat((-offsetX + TRANSLATE_X) * (1 / SCALE_X) + padding / dpr, ", ").concat((-offsetY + TRANSLATE_Y) * (1 / SCALE_Y) + padding / dpr, ")");
395
+ bboxWidth = Math.ceil(actualWidth);
396
+ bboxHeight = Math.ceil(actualHeight);
397
+ canvas = document.createElement('canvas');
398
+ canvas.style.width = "".concat(bboxWidth, "px");
399
+ canvas.style.height = "".concat(bboxHeight, "px");
400
+ safetyMargin = 40 // 额外的安全边距
401
+ ;
402
+ canvas.width = bboxWidth * dpr + padding * 2 + safetyMargin;
403
+ canvas.height = bboxHeight * dpr + padding * 2 + safetyMargin;
404
+ ctx = canvas.getContext('2d');
405
+ if (ctx) {
406
+ // 清空canvas
407
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
408
+ ctx.scale(dpr, dpr);
409
+ // 如果有背景色,设置流程图导出的背景色
410
+ if (backgroundColor) {
411
+ ctx.fillStyle = backgroundColor;
412
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
413
+ }
414
+ else {
415
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
416
+ }
417
+ }
418
+ img = new Image();
419
+ style = document.createElement('style');
420
+ style.innerHTML = this.getClassRules();
421
+ foreignObject = document.createElement('foreignObject');
422
+ foreignObject.appendChild(style);
423
+ copy.appendChild(foreignObject);
424
+ return [2 /*return*/, new Promise(function (resolve) {
425
+ img.onload = function () {
426
+ var isFirefox = navigator.userAgent.indexOf('Firefox') > -1;
427
+ try {
428
+ if (isFirefox) {
429
+ createImageBitmap(img, {
430
+ resizeWidth: width && height
431
+ ? (0, utils_1.copyCanvas)(canvas, width, height).width
432
+ : canvas.width,
433
+ resizeHeight: width && height
434
+ ? (0, utils_1.copyCanvas)(canvas, width, height).height
435
+ : canvas.height,
436
+ }).then(function (imageBitmap) {
437
+ // 由于在transform矩阵中已经考虑了padding,这里不再需要额外的padding偏移
438
+ ctx === null || ctx === void 0 ? void 0 : ctx.drawImage(imageBitmap, 0, 0);
439
+ resolve(width && height ? (0, utils_1.copyCanvas)(canvas, width, height) : canvas);
440
+ });
441
+ }
442
+ else {
443
+ // 由于在transform矩阵中已经考虑了padding,这里不再需要额外的padding偏移
444
+ ctx === null || ctx === void 0 ? void 0 : ctx.drawImage(img, 0, 0);
445
+ resolve(width && height ? (0, utils_1.copyCanvas)(canvas, width, height) : canvas);
446
+ }
447
+ }
448
+ catch (e) {
449
+ // 由于在transform矩阵中已经考虑了padding,这里不再需要额外的padding偏移
450
+ ctx === null || ctx === void 0 ? void 0 : ctx.drawImage(img, 0, 0);
451
+ resolve(width && height ? (0, utils_1.copyCanvas)(canvas, width, height) : canvas);
452
+ }
453
+ };
454
+ /*
455
+ 因为svg中存在dom存放在foreignObject元素中
456
+ svg dom => Base64编码字符串 挂载到img上
457
+ fixme: XMLSerializer的中的css background url不会下载图片
458
+ */
459
+ var svg2Img = "data:image/svg+xml;charset=utf-8,".concat(new XMLSerializer().serializeToString(copy));
460
+ var imgSrc = svg2Img
461
+ .replace(/\n/g, '')
462
+ .replace(/\t/g, '')
463
+ .replace(/#/g, '%23');
464
+ img.src = imgSrc;
465
+ })];
466
+ }
467
+ });
468
+ });
469
+ };
470
+ /**
471
+ * 封装导出前的通用处理逻辑:局部渲染模式处理、静默模式处理
472
+ * @param callback 实际执行的导出操作回调函数
473
+ * @param toImageOptions 导出图片选项
474
+ * @returns 返回回调函数的执行结果
475
+ */
476
+ Snapshot.prototype.withExportPreparation = function (callback, toImageOptions) {
477
+ return __awaiter(this, void 0, void 0, function () {
478
+ var curPartial, _a, partial, editConfig, result;
150
479
  var _this = this;
151
480
  return __generator(this, function (_b) {
152
481
  switch (_b.label) {
@@ -160,30 +489,61 @@ var Snapshot = /** @class */ (function () {
160
489
  stopScrollGraph: true,
161
490
  stopMoveGraph: true,
162
491
  });
163
- if (!(curPartial !== partial)) return [3 /*break*/, 1];
492
+ _b.label = 1;
493
+ case 1:
494
+ _b.trys.push([1, , 6, 7]);
495
+ if (!(curPartial !== partial)) return [3 /*break*/, 3];
164
496
  this.lf.graphModel.setPartial(partial);
165
- this.lf.graphModel.eventCenter.once('graph:updated', function () { return __awaiter(_this, void 0, void 0, function () {
166
- return __generator(this, function (_a) {
167
- switch (_a.label) {
168
- case 0: return [4 /*yield*/, this.snapshot(fileName, toImageOptions)
169
- // 恢复原来渲染模式
170
- ];
171
- case 1:
172
- _a.sent();
173
- // 恢复原来渲染模式
174
- this.lf.graphModel.setPartial(curPartial);
175
- return [2 /*return*/];
176
- }
177
- });
178
- }); });
179
- return [3 /*break*/, 3];
180
- case 1: return [4 /*yield*/, this.snapshot(fileName, toImageOptions)];
497
+ return [4 /*yield*/, new Promise(function (resolve) {
498
+ _this.lf.graphModel.eventCenter.once('graph:updated', function () { return __awaiter(_this, void 0, void 0, function () {
499
+ var callbackResult;
500
+ return __generator(this, function (_a) {
501
+ switch (_a.label) {
502
+ case 0: return [4 /*yield*/, callback()
503
+ // 恢复原来渲染模式
504
+ ];
505
+ case 1:
506
+ callbackResult = _a.sent();
507
+ // 恢复原来渲染模式
508
+ this.lf.graphModel.setPartial(curPartial);
509
+ resolve(callbackResult);
510
+ return [2 /*return*/];
511
+ }
512
+ });
513
+ }); });
514
+ })];
181
515
  case 2:
182
- _b.sent();
183
- _b.label = 3;
184
- case 3:
516
+ // 等待画布更新完成
517
+ result = _b.sent();
518
+ return [3 /*break*/, 5];
519
+ case 3: return [4 /*yield*/, callback()];
520
+ case 4:
521
+ // 直接执行回调
522
+ result = _b.sent();
523
+ _b.label = 5;
524
+ case 5: return [3 /*break*/, 7];
525
+ case 6:
185
526
  // 恢复原来配置
186
527
  this.lf.updateEditConfig(editConfig);
528
+ return [7 /*endfinally*/];
529
+ case 7: return [2 /*return*/, result];
530
+ }
531
+ });
532
+ });
533
+ };
534
+ /**
535
+ * 导出画布:导出前的处理画布工作,局部渲染模式处理、静默模式处理
536
+ * @param fileName
537
+ * @param toImageOptions
538
+ */
539
+ Snapshot.prototype.getSnapshot = function (fileName, toImageOptions) {
540
+ return __awaiter(this, void 0, void 0, function () {
541
+ var _this = this;
542
+ return __generator(this, function (_a) {
543
+ switch (_a.label) {
544
+ case 0: return [4 /*yield*/, this.withExportPreparation(function () { return _this.snapshot(fileName, toImageOptions); }, toImageOptions)];
545
+ case 1:
546
+ _a.sent();
187
547
  return [2 /*return*/];
188
548
  }
189
549
  });
@@ -207,80 +567,63 @@ var Snapshot = /** @class */ (function () {
207
567
  return [4 /*yield*/, (0, utils_1.updateImageSource)(svg)];
208
568
  case 1:
209
569
  _c.sent();
210
- if (fileType === 'svg') {
211
- copy = this.cloneSvg(svg);
212
- svgString = new XMLSerializer().serializeToString(copy);
213
- blob = new Blob([svgString], {
214
- type: 'image/svg+xml;charset=utf-8',
215
- });
216
- url = URL.createObjectURL(blob);
217
- this.triggerDownload(url);
218
- }
219
- else {
220
- this.getCanvasData(svg, toImageOptions !== null && toImageOptions !== void 0 ? toImageOptions : {}).then(function (canvas) {
221
- // canvas元素 => base64 url image/octet-stream: 确保所有浏览器都能正常下载
222
- var imgUrl = canvas
223
- .toDataURL("image/".concat(fileType), quality)
224
- .replace("image/".concat(fileType), 'image/octet-stream');
225
- _this.triggerDownload(imgUrl);
226
- });
227
- }
228
- return [2 /*return*/];
570
+ if (!(fileType === 'svg')) return [3 /*break*/, 3];
571
+ return [4 /*yield*/, this.cloneSvg(svg)];
572
+ case 2:
573
+ copy = _c.sent();
574
+ svgString = new XMLSerializer().serializeToString(copy);
575
+ blob = new Blob([svgString], {
576
+ type: 'image/svg+xml;charset=utf-8',
577
+ });
578
+ url = URL.createObjectURL(blob);
579
+ this.triggerDownload(url);
580
+ return [3 /*break*/, 4];
581
+ case 3:
582
+ this.getCanvasData(svg, toImageOptions !== null && toImageOptions !== void 0 ? toImageOptions : {}).then(function (canvas) {
583
+ // canvas元素 => base64 url image/octet-stream: 确保所有浏览器都能正常下载
584
+ var imgUrl = canvas
585
+ .toDataURL("image/".concat(fileType), quality)
586
+ .replace("image/".concat(fileType), 'image/octet-stream');
587
+ _this.triggerDownload(imgUrl);
588
+ });
589
+ _c.label = 4;
590
+ case 4: return [2 /*return*/];
229
591
  }
230
592
  });
231
593
  });
232
594
  };
233
595
  /**
234
- * 获取base64对象
235
- * @param backgroundColor
596
+ * 获取Blob对象
236
597
  * @param fileType
598
+ * @param toImageOptions
237
599
  * @returns
238
600
  */
239
- Snapshot.prototype.getSnapshotBase64 = function (backgroundColor, fileType) {
601
+ Snapshot.prototype.getSnapshotBlob = function (backgroundColor, fileType, toImageOptions) {
240
602
  return __awaiter(this, void 0, void 0, function () {
241
- var svg;
242
603
  var _this = this;
243
604
  return __generator(this, function (_a) {
244
605
  switch (_a.label) {
245
- case 0:
246
- svg = this.getSvgRootElement(this.lf);
247
- return [4 /*yield*/, (0, utils_1.updateImageSource)(svg)];
248
- case 1:
249
- _a.sent();
250
- return [2 /*return*/, new Promise(function (resolve) {
251
- _this.getCanvasData(svg, { backgroundColor: backgroundColor }).then(function (canvas) {
252
- var base64 = canvas.toDataURL("image/".concat(fileType !== null && fileType !== void 0 ? fileType : 'png'));
253
- // 输出图片数据以及图片宽高
254
- resolve({
255
- data: base64,
256
- width: canvas.width,
257
- height: canvas.height,
258
- });
259
- });
260
- })];
606
+ case 0: return [4 /*yield*/, this.withExportPreparation(function () { return _this.snapshotBlob(toImageOptions, fileType, backgroundColor); }, toImageOptions)];
607
+ case 1: return [2 /*return*/, _a.sent()];
261
608
  }
262
609
  });
263
610
  });
264
611
  };
265
- /**
266
- * 获取Blob对象
267
- * @param backgroundColor
268
- * @param fileType
269
- * @returns
270
- */
271
- Snapshot.prototype.getSnapshotBlob = function (backgroundColor, fileType) {
612
+ // 内部方法处理blob转换
613
+ Snapshot.prototype.snapshotBlob = function (toImageOptions, baseFileType, backgroundColor) {
272
614
  return __awaiter(this, void 0, void 0, function () {
273
- var svg;
615
+ var _a, fileType, svg;
274
616
  var _this = this;
275
- return __generator(this, function (_a) {
276
- switch (_a.label) {
617
+ return __generator(this, function (_b) {
618
+ switch (_b.label) {
277
619
  case 0:
620
+ _a = (toImageOptions !== null && toImageOptions !== void 0 ? toImageOptions : {}).fileType, fileType = _a === void 0 ? baseFileType : _a;
278
621
  svg = this.getSvgRootElement(this.lf);
279
622
  return [4 /*yield*/, (0, utils_1.updateImageSource)(svg)];
280
623
  case 1:
281
- _a.sent();
624
+ _b.sent();
282
625
  return [2 /*return*/, new Promise(function (resolve) {
283
- _this.getCanvasData(svg, { backgroundColor: backgroundColor }).then(function (canvas) {
626
+ _this.getCanvasData(svg, __assign({ backgroundColor: backgroundColor }, (toImageOptions !== null && toImageOptions !== void 0 ? toImageOptions : {}))).then(function (canvas) {
284
627
  canvas.toBlob(function (blob) {
285
628
  // 输出图片数据以及图片宽高
286
629
  resolve({
@@ -296,182 +639,52 @@ var Snapshot = /** @class */ (function () {
296
639
  });
297
640
  };
298
641
  /**
299
- * 获取脚本 css 样式
642
+ * 获取base64对象
643
+ * @param backgroundColor
644
+ * @param fileType
645
+ * @param toImageOptions
300
646
  * @returns
301
647
  */
302
- Snapshot.prototype.getClassRules = function () {
303
- var rules = '';
304
- if (this.useGlobalRules) {
305
- var styleSheets = document.styleSheets;
306
- for (var i = 0; i < styleSheets.length; i++) {
307
- var sheet = styleSheets[i];
308
- // 这里是为了过滤掉不同源 css 脚本,防止报错终止导出
309
- try {
310
- for (var j = 0; j < sheet.cssRules.length; j++) {
311
- rules += sheet.cssRules[j].cssText;
312
- }
313
- }
314
- catch (error) {
315
- console.log('CSS scripts from different sources have been filtered out');
648
+ Snapshot.prototype.getSnapshotBase64 = function (backgroundColor, fileType, toImageOptions) {
649
+ return __awaiter(this, void 0, void 0, function () {
650
+ var _this = this;
651
+ return __generator(this, function (_a) {
652
+ switch (_a.label) {
653
+ case 0:
654
+ console.log('getSnapshotBase64---------------', backgroundColor, fileType, toImageOptions);
655
+ return [4 /*yield*/, this.withExportPreparation(function () { return _this._getSnapshotBase64(backgroundColor, fileType, toImageOptions); }, toImageOptions)];
656
+ case 1: return [2 /*return*/, _a.sent()];
316
657
  }
317
- }
318
- }
319
- if (this.customCssRules) {
320
- rules += this.customCssRules;
321
- }
322
- return rules;
658
+ });
659
+ });
323
660
  };
324
- /**
325
- * svg 转化为 canvas
326
- * @param svg - svg 元素
327
- * @param toImageOptions - 图像选项
328
- * @returns Promise<canvas> - 返回 canvas 对象
329
- */
330
- Snapshot.prototype.getCanvasData = function (svg, toImageOptions) {
661
+ // 内部方法处理实际的base64转换
662
+ Snapshot.prototype._getSnapshotBase64 = function (backgroundColor, baseFileType, toImageOptions) {
331
663
  return __awaiter(this, void 0, void 0, function () {
332
- var width, height, backgroundColor, _a, padding, copy, dpr, base, bbox, layoutCanvas, layout, offsetX, offsetY, graphModel, transformModel, SCALE_X, SCALE_Y, TRANSLATE_X, TRANSLATE_Y, bboxWidth, bboxHeight, canvas, ctx, img, style, foreignObject;
664
+ var _a, fileType, svg;
665
+ var _this = this;
333
666
  return __generator(this, function (_b) {
334
- width = toImageOptions.width, height = toImageOptions.height, backgroundColor = toImageOptions.backgroundColor, _a = toImageOptions.padding, padding = _a === void 0 ? 40 : _a;
335
- copy = this.cloneSvg(svg, false);
336
- dpr = window.devicePixelRatio || 1;
337
- if (dpr < 1) {
338
- // https://github.com/didi/LogicFlow/issues/1222
339
- // canvas.width = bboxWidth * dpr配合ctx.scale(dpr, dpr)是为了解决绘制模糊
340
- // 比如dpr=2,先让canvas.width放大到等同于屏幕的物理像素宽高,然后自适应缩放适配canvas.style.width
341
- // 由于所有元素都缩放了一半,因此需要ctx.scale(dpr, dpr)放大2倍整体绘制的内容
342
- // 当用户缩放浏览器时,window.devicePixelRatio会随着变小
343
- // 当window.devicePixelRatio变小到一定程度,会导致canvas.width<canvas.style.width
344
- // 由于导出图片的svg的大小是canvas.style.width+canvas.style.height
345
- // 因此会导致导出的svg图片无法完整绘制到canvas(因为canvas.width小于svg的宽)
346
- // 从而导致canvas导出图片是缺失的svg
347
- // 而dpr>=1就能保证canvas.width>=canvas.style.width
348
- // 当dpr小于1的时候,我们强制转化为1,并不会产生绘制模糊等问题
349
- dpr = 1;
350
- }
351
- base = this.lf.graphModel.rootEl.querySelector('.lf-base');
352
- bbox = base.getBoundingClientRect();
353
- layoutCanvas = this.lf.container.querySelector('.lf-canvas-overlay');
354
- layout = layoutCanvas.getBoundingClientRect();
355
- offsetX = bbox.x - layout.x;
356
- offsetY = bbox.y - layout.y;
357
- graphModel = this.lf.graphModel;
358
- transformModel = graphModel.transformModel;
359
- SCALE_X = transformModel.SCALE_X, SCALE_Y = transformModel.SCALE_Y, TRANSLATE_X = transformModel.TRANSLATE_X, TRANSLATE_Y = transformModel.TRANSLATE_Y;
360
- copy.lastChild.style.transform = "matrix(1, 0, 0, 1, ".concat((-offsetX + TRANSLATE_X) * (1 / SCALE_X), ", ").concat((-offsetY + TRANSLATE_Y) * (1 / SCALE_Y), ")");
361
- bboxWidth = Math.ceil(bbox.width / SCALE_X);
362
- bboxHeight = Math.ceil(bbox.height / SCALE_Y);
363
- canvas = document.createElement('canvas');
364
- canvas.style.width = "".concat(bboxWidth, "px");
365
- canvas.style.height = "".concat(bboxHeight, "px");
366
- // 宽高值 默认加padding 40,保证图形不会紧贴着下载图片
367
- canvas.width = bboxWidth * dpr + padding * 2;
368
- canvas.height = bboxHeight * dpr + padding * 2;
369
- ctx = canvas.getContext('2d');
370
- if (ctx) {
371
- // 清空canvas
372
- ctx.clearRect(0, 0, canvas.width, canvas.height);
373
- ctx.scale(dpr, dpr);
374
- // 如果有背景色,设置流程图导出的背景色
375
- if (backgroundColor) {
376
- ctx.fillStyle = backgroundColor;
377
- ctx.fillRect(0, 0, canvas.width, canvas.height);
378
- }
379
- else {
380
- ctx.clearRect(0, 0, canvas.width, canvas.height);
381
- }
382
- }
383
- img = new Image();
384
- style = document.createElement('style');
385
- style.innerHTML = this.getClassRules();
386
- foreignObject = document.createElement('foreignObject');
387
- foreignObject.appendChild(style);
388
- copy.appendChild(foreignObject);
389
- return [2 /*return*/, new Promise(function (resolve) {
390
- img.onload = function () {
391
- var isFirefox = navigator.userAgent.indexOf('Firefox') > -1;
392
- try {
393
- if (isFirefox) {
394
- createImageBitmap(img, {
395
- resizeWidth: width && height
396
- ? (0, utils_1.copyCanvas)(canvas, width, height).width
397
- : canvas.width,
398
- resizeHeight: width && height
399
- ? (0, utils_1.copyCanvas)(canvas, width, height).height
400
- : canvas.height,
401
- }).then(function (imageBitmap) {
402
- ctx === null || ctx === void 0 ? void 0 : ctx.drawImage(imageBitmap, padding / dpr, padding / dpr);
403
- resolve(width && height ? (0, utils_1.copyCanvas)(canvas, width, height) : canvas);
667
+ switch (_b.label) {
668
+ case 0:
669
+ _a = (toImageOptions !== null && toImageOptions !== void 0 ? toImageOptions : {}).fileType, fileType = _a === void 0 ? baseFileType : _a;
670
+ svg = this.getSvgRootElement(this.lf);
671
+ return [4 /*yield*/, (0, utils_1.updateImageSource)(svg)];
672
+ case 1:
673
+ _b.sent();
674
+ return [2 /*return*/, new Promise(function (resolve) {
675
+ _this.getCanvasData(svg, __assign({ backgroundColor: backgroundColor }, (toImageOptions !== null && toImageOptions !== void 0 ? toImageOptions : {}))).then(function (canvas) {
676
+ var base64 = canvas.toDataURL("image/".concat(fileType !== null && fileType !== void 0 ? fileType : 'png'));
677
+ resolve({
678
+ data: base64,
679
+ width: canvas.width,
680
+ height: canvas.height,
404
681
  });
405
- }
406
- else {
407
- ctx === null || ctx === void 0 ? void 0 : ctx.drawImage(img, padding / dpr, padding / dpr);
408
- resolve(width && height ? (0, utils_1.copyCanvas)(canvas, width, height) : canvas);
409
- }
410
- }
411
- catch (e) {
412
- ctx === null || ctx === void 0 ? void 0 : ctx.drawImage(img, padding / dpr, padding / dpr);
413
- resolve(width && height ? (0, utils_1.copyCanvas)(canvas, width, height) : canvas);
414
- }
415
- };
416
- /*
417
- 因为svg中存在dom存放在foreignObject元素中
418
- svg dom => Base64编码字符串 挂载到img上
419
- fixme: XMLSerializer的中的css background url不会下载图片
420
- */
421
- var svg2Img = "data:image/svg+xml;charset=utf-8,".concat(new XMLSerializer().serializeToString(copy));
422
- var imgSrc = svg2Img
423
- .replace(/\n/g, '')
424
- .replace(/\t/g, '')
425
- .replace(/#/g, '%23');
426
- img.src = imgSrc;
427
- })];
682
+ });
683
+ })];
684
+ }
428
685
  });
429
686
  });
430
687
  };
431
- /**
432
- * 克隆并处理画布节点
433
- * @param svg
434
- * @returns
435
- */
436
- Snapshot.prototype.cloneSvg = function (svg, addStyle) {
437
- var _this = this;
438
- var _a;
439
- if (addStyle === void 0) { addStyle = true; }
440
- var copy = svg.cloneNode(true);
441
- var graph = copy.lastChild;
442
- var childLength = (_a = graph === null || graph === void 0 ? void 0 : graph.childNodes) === null || _a === void 0 ? void 0 : _a.length;
443
- if (childLength) {
444
- for (var i = 0; i < childLength; i++) {
445
- var lfLayer = graph === null || graph === void 0 ? void 0 : graph.childNodes[i];
446
- // 只保留包含节点和边的基础图层进行下载,其他图层删除
447
- var layerClassList = lfLayer.classList && Array.from(lfLayer.classList);
448
- if (layerClassList && layerClassList.indexOf('lf-base') < 0) {
449
- graph === null || graph === void 0 ? void 0 : graph.removeChild(graph.childNodes[i]);
450
- childLength--;
451
- i--;
452
- }
453
- else {
454
- // 删除锚点
455
- var lfBase = graph === null || graph === void 0 ? void 0 : graph.childNodes[i];
456
- lfBase &&
457
- lfBase.childNodes.forEach(function (item) {
458
- var element = item;
459
- _this.removeAnchor(element.firstChild);
460
- _this.removeRotateControl(element.firstChild);
461
- });
462
- }
463
- }
464
- }
465
- // 设置css样式
466
- if (addStyle) {
467
- var style = document.createElement('style');
468
- style.innerHTML = this.getClassRules();
469
- var foreignObject = document.createElement('foreignObject');
470
- foreignObject.appendChild(style);
471
- copy.appendChild(foreignObject);
472
- }
473
- return copy;
474
- };
475
688
  Snapshot.pluginName = 'snapshot';
476
689
  return Snapshot;
477
690
  }());