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