leafer-draw 1.0.0-rc.9 → 1.0.1

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/dist/web.esm.js CHANGED
@@ -1,26 +1,47 @@
1
- import { Debug, LeaferCanvasBase, Platform, DataHelper, canvasSizeAttrs, ResizeEvent, canvasPatch, Creator, LeaferImage, FileHelper, LeafList, RenderEvent, ChildEvent, WatchEvent, PropertyEvent, LeafHelper, BranchHelper, Bounds, LeafBoundsHelper, LeafLevelList, LayoutEvent, Run, ImageManager, AnimateEvent, BoundsHelper, MatrixHelper, ImageEvent, PointHelper, Direction4, TwoPointBoundsHelper, TaskProcessor, Matrix } from '@leafer/core';
1
+ import { Debug, LeaferCanvasBase, Platform, DataHelper, canvasSizeAttrs, ResizeEvent, canvasPatch, Creator, LeaferImage, defineKey, FileHelper, LeafList, RenderEvent, ChildEvent, WatchEvent, PropertyEvent, LeafHelper, BranchHelper, Bounds, LeafBoundsHelper, LeafLevelList, LayoutEvent, Run, ImageManager, AnimateEvent, BoundsHelper, MatrixHelper, AlignHelper, ImageEvent, AroundHelper, PointHelper, Direction4, TwoPointBoundsHelper, TaskProcessor, Matrix } from '@leafer/core';
2
2
  export * from '@leafer/core';
3
3
  export { LeaferImage } from '@leafer/core';
4
- import { ColorConvert, Export, Group, TextConvert, Paint, PaintImage as PaintImage$1, PaintGradient as PaintGradient$1, Effect } from '@leafer-ui/draw';
4
+ import { PaintImage, ColorConvert, PaintGradient, Export, Group, TextConvert, Paint, Effect } from '@leafer-ui/draw';
5
5
  export * from '@leafer-ui/draw';
6
6
 
7
- const debug$2 = Debug.get('LeaferCanvas');
7
+ const debug$3 = Debug.get('LeaferCanvas');
8
8
  class LeaferCanvas extends LeaferCanvasBase {
9
+ set zIndex(zIndex) {
10
+ const { style } = this.view;
11
+ style.zIndex = zIndex;
12
+ this.setAbsolute(this.view);
13
+ }
14
+ set childIndex(index) {
15
+ const { view, parentView } = this;
16
+ if (view && parentView) {
17
+ const beforeNode = parentView.children[index];
18
+ if (beforeNode) {
19
+ this.setAbsolute(beforeNode);
20
+ parentView.insertBefore(view, beforeNode);
21
+ }
22
+ else {
23
+ parentView.appendChild(beforeNode);
24
+ }
25
+ }
26
+ }
9
27
  init() {
10
- const { view } = this.config;
28
+ const { config } = this;
29
+ const view = config.view || config.canvas;
11
30
  view ? this.__createViewFrom(view) : this.__createView();
12
31
  const { style } = this.view;
13
32
  style.display || (style.display = 'block');
14
33
  this.parentView = this.view.parentElement;
15
- if (this.parentView)
16
- this.parentView.style.userSelect = 'none';
34
+ if (this.parentView) {
35
+ const pStyle = this.parentView.style;
36
+ pStyle.webkitUserSelect = pStyle.userSelect = 'none';
37
+ }
17
38
  if (Platform.syncDomFont && !this.parentView) {
18
- this.view.style.display = 'none';
39
+ style.display = 'none';
19
40
  document.body.appendChild(this.view);
20
41
  }
21
42
  this.__createContext();
22
43
  if (!this.autoLayout)
23
- this.resize(this.config);
44
+ this.resize(config);
24
45
  }
25
46
  set backgroundColor(color) { this.view.style.backgroundColor = color; }
26
47
  get backgroundColor() { return this.view.style.backgroundColor; }
@@ -48,19 +69,22 @@ class LeaferCanvas extends LeaferCanvasBase {
48
69
  this.__createView();
49
70
  const view = this.view;
50
71
  if (parent.hasChildNodes()) {
51
- const { style } = view;
52
- style.position = 'absolute';
53
- style.top = style.left = '0px';
72
+ this.setAbsolute(view);
54
73
  parent.style.position || (parent.style.position = 'relative');
55
74
  }
56
75
  parent.appendChild(view);
57
76
  }
58
77
  }
59
78
  else {
60
- debug$2.error(`no id: ${inputView}`);
79
+ debug$3.error(`no id: ${inputView}`);
61
80
  this.__createView();
62
81
  }
63
82
  }
83
+ setAbsolute(view) {
84
+ const { style } = view;
85
+ style.position = 'absolute';
86
+ style.top = style.left = '0px';
87
+ }
64
88
  updateViewSize() {
65
89
  const { width, height, pixelRatio } = this;
66
90
  const { style } = this.view;
@@ -73,22 +97,37 @@ class LeaferCanvas extends LeaferCanvasBase {
73
97
  this.clientBounds = this.view.getBoundingClientRect();
74
98
  }
75
99
  startAutoLayout(autoBounds, listener) {
76
- this.autoBounds = autoBounds;
77
100
  this.resizeListener = listener;
78
- try {
79
- this.resizeObserver = new ResizeObserver((entries) => {
80
- this.updateClientBounds();
81
- for (const entry of entries)
82
- this.checkAutoBounds(entry.contentRect);
83
- });
84
- const parent = this.parentView;
85
- if (parent) {
86
- this.resizeObserver.observe(parent);
87
- this.checkAutoBounds(parent.getBoundingClientRect());
101
+ if (autoBounds) {
102
+ this.autoBounds = autoBounds;
103
+ try {
104
+ this.resizeObserver = new ResizeObserver((entries) => {
105
+ this.updateClientBounds();
106
+ for (const entry of entries)
107
+ this.checkAutoBounds(entry.contentRect);
108
+ });
109
+ const parent = this.parentView;
110
+ if (parent) {
111
+ this.resizeObserver.observe(parent);
112
+ this.checkAutoBounds(parent.getBoundingClientRect());
113
+ }
114
+ else {
115
+ this.checkAutoBounds(this.view);
116
+ debug$3.warn('no parent');
117
+ }
118
+ }
119
+ catch (_a) {
120
+ this.imitateResizeObserver();
88
121
  }
89
122
  }
90
- catch (_a) {
91
- this.imitateResizeObserver();
123
+ else {
124
+ window.addEventListener('resize', () => {
125
+ const pixelRatio = Platform.devicePixelRatio;
126
+ if (this.pixelRatio !== pixelRatio) {
127
+ const { width, height } = this;
128
+ this.emitResize({ width, height, pixelRatio });
129
+ }
130
+ });
92
131
  }
93
132
  }
94
133
  imitateResizeObserver() {
@@ -101,17 +140,12 @@ class LeaferCanvas extends LeaferCanvasBase {
101
140
  checkAutoBounds(parentSize) {
102
141
  const view = this.view;
103
142
  const { x, y, width, height } = this.autoBounds.getBoundsFrom(parentSize);
104
- if (width !== this.width || height !== this.height) {
143
+ const size = { width, height, pixelRatio: Platform.devicePixelRatio };
144
+ if (!this.isSameSize(size)) {
105
145
  const { style } = view;
106
- const { pixelRatio } = this;
107
146
  style.marginLeft = x + 'px';
108
147
  style.marginTop = y + 'px';
109
- const size = { width, height, pixelRatio };
110
- const oldSize = {};
111
- DataHelper.copyAttrs(oldSize, this, canvasSizeAttrs);
112
- this.resize(size);
113
- if (this.width !== undefined)
114
- this.resizeListener(new ResizeEvent(size, oldSize));
148
+ this.emitResize(size);
115
149
  }
116
150
  }
117
151
  stopAutoLayout() {
@@ -122,6 +156,13 @@ class LeaferCanvas extends LeaferCanvasBase {
122
156
  this.resizeObserver = null;
123
157
  }
124
158
  }
159
+ emitResize(size) {
160
+ const oldSize = {};
161
+ DataHelper.copyAttrs(oldSize, this, canvasSizeAttrs);
162
+ this.resize(size);
163
+ if (this.width !== undefined)
164
+ this.resizeListener(new ResizeEvent(size, oldSize));
165
+ }
125
166
  unrealCanvas() {
126
167
  if (!this.unreal && this.parentView) {
127
168
  const view = this.view;
@@ -163,9 +204,13 @@ function useCanvas(_canvasType, _power) {
163
204
  canvasToDataURL: (canvas, type, quality) => canvas.toDataURL(mineType(type), quality),
164
205
  canvasToBolb: (canvas, type, quality) => new Promise((resolve) => canvas.toBlob(resolve, mineType(type), quality)),
165
206
  canvasSaveAs: (canvas, filename, quality) => {
207
+ const url = canvas.toDataURL(mineType(fileType(filename)), quality);
208
+ return Platform.origin.download(url, filename);
209
+ },
210
+ download(url, filename) {
166
211
  return new Promise((resolve) => {
167
212
  let el = document.createElement('a');
168
- el.href = canvas.toDataURL(mineType(fileType(filename)), quality);
213
+ el.href = url;
169
214
  el.download = filename;
170
215
  document.body.appendChild(el);
171
216
  el.click();
@@ -176,16 +221,14 @@ function useCanvas(_canvasType, _power) {
176
221
  loadImage(src) {
177
222
  return new Promise((resolve, reject) => {
178
223
  const img = new Image();
179
- const { suffix, crossOrigin } = Platform.image;
224
+ const { crossOrigin } = Platform.image;
180
225
  if (crossOrigin) {
181
226
  img.setAttribute('crossOrigin', crossOrigin);
182
227
  img.crossOrigin = crossOrigin;
183
228
  }
184
229
  img.onload = () => { resolve(img); };
185
230
  img.onerror = (e) => { reject(e); };
186
- if (!src.startsWith('data:') && !src.startsWith('blob:') && suffix)
187
- src += (src.includes("?") ? "&" : "?") + suffix;
188
- img.src = src;
231
+ img.src = Platform.image.getRealURL(src);
189
232
  });
190
233
  }
191
234
  };
@@ -200,7 +243,7 @@ function useCanvas(_canvasType, _power) {
200
243
  Platform.name = 'web';
201
244
  Platform.isMobile = 'ontouchstart' in window;
202
245
  Platform.requestRender = function (render) { window.requestAnimationFrame(render); };
203
- Platform.devicePixelRatio = Math.max(1, devicePixelRatio);
246
+ defineKey(Platform, 'devicePixelRatio', { get() { return Math.max(1, devicePixelRatio); } });
204
247
  const { userAgent } = navigator;
205
248
  if (userAgent.indexOf("Firefox") > -1) {
206
249
  Platform.conicGradientRotate90 = true;
@@ -402,7 +445,7 @@ class LayoutBlockData {
402
445
  }
403
446
 
404
447
  const { updateAllMatrix, updateAllChange } = LeafHelper;
405
- const debug$1 = Debug.get('Layouter');
448
+ const debug$2 = Debug.get('Layouter');
406
449
  class Layouter {
407
450
  constructor(target, userConfig) {
408
451
  this.totalTimes = 0;
@@ -437,7 +480,7 @@ class Layouter {
437
480
  target.emitEvent(new LayoutEvent(LayoutEvent.END, this.layoutedBlocks, this.times));
438
481
  }
439
482
  catch (e) {
440
- debug$1.error(e);
483
+ debug$2.error(e);
441
484
  }
442
485
  this.layoutedBlocks = null;
443
486
  }
@@ -451,9 +494,9 @@ class Layouter {
451
494
  }
452
495
  layoutOnce() {
453
496
  if (this.layouting)
454
- return debug$1.warn('layouting');
497
+ return debug$2.warn('layouting');
455
498
  if (this.times > 3)
456
- return debug$1.warn('layout max times');
499
+ return debug$2.warn('layout max times');
457
500
  this.times++;
458
501
  this.totalTimes++;
459
502
  this.layouting = true;
@@ -519,9 +562,11 @@ class Layouter {
519
562
  updateAllChange(target);
520
563
  }
521
564
  addExtra(leaf) {
522
- const block = this.extraBlock || (this.extraBlock = new LayoutBlockData([]));
523
- block.updatedList.add(leaf);
524
- block.beforeBounds.add(leaf.__world);
565
+ if (!this.__updatedList.has(leaf)) {
566
+ const { updatedList, beforeBounds } = this.extraBlock || (this.extraBlock = new LayoutBlockData([]));
567
+ updatedList.length ? beforeBounds.add(leaf.__world) : beforeBounds.set(leaf.__world);
568
+ updatedList.add(leaf);
569
+ }
525
570
  }
526
571
  createBlock(data) {
527
572
  return new LayoutBlockData(data);
@@ -555,7 +600,7 @@ class Layouter {
555
600
  }
556
601
  }
557
602
 
558
- const debug = Debug.get('Renderer');
603
+ const debug$1 = Debug.get('Renderer');
559
604
  class Renderer {
560
605
  get needFill() { return !!(!this.canvas.allowBackgroundColor && this.config.fill); }
561
606
  constructor(target, canvas, userConfig) {
@@ -593,7 +638,7 @@ class Renderer {
593
638
  const { target } = this;
594
639
  this.times = 0;
595
640
  this.totalBounds = new Bounds();
596
- debug.log(target.innerName, '--->');
641
+ debug$1.log(target.innerName, '--->');
597
642
  try {
598
643
  this.emitRender(RenderEvent.START);
599
644
  this.renderOnce(callback);
@@ -602,9 +647,9 @@ class Renderer {
602
647
  }
603
648
  catch (e) {
604
649
  this.rendering = false;
605
- debug.error(e);
650
+ debug$1.error(e);
606
651
  }
607
- debug.log('-------------|');
652
+ debug$1.log('-------------|');
608
653
  }
609
654
  renderAgain() {
610
655
  if (this.rendering) {
@@ -616,9 +661,9 @@ class Renderer {
616
661
  }
617
662
  renderOnce(callback) {
618
663
  if (this.rendering)
619
- return debug.warn('rendering');
664
+ return debug$1.warn('rendering');
620
665
  if (this.times > 3)
621
- return debug.warn('render max times');
666
+ return debug$1.warn('render max times');
622
667
  this.times++;
623
668
  this.totalTimes++;
624
669
  this.rendering = true;
@@ -631,6 +676,10 @@ class Renderer {
631
676
  }
632
677
  else {
633
678
  this.requestLayout();
679
+ if (this.ignore) {
680
+ this.ignore = this.rendering = false;
681
+ return;
682
+ }
634
683
  this.emitRender(RenderEvent.BEFORE);
635
684
  if (this.config.usePartRender && this.totalTimes > 1) {
636
685
  this.partRender();
@@ -651,7 +700,7 @@ class Renderer {
651
700
  partRender() {
652
701
  const { canvas, updateBlocks: list } = this;
653
702
  if (!list)
654
- return debug.warn('PartRender: need update attr');
703
+ return debug$1.warn('PartRender: need update attr');
655
704
  this.mergeBlocks();
656
705
  list.forEach(block => { if (canvas.bounds.hit(block) && !block.isEmpty())
657
706
  this.clipRender(block); });
@@ -667,7 +716,7 @@ class Renderer {
667
716
  canvas.clear();
668
717
  }
669
718
  else {
670
- bounds.spread(1 + 1 / this.canvas.pixelRatio).ceil();
719
+ bounds.spread(10 + 1 / this.canvas.pixelRatio).ceil();
671
720
  canvas.clearWorld(bounds, true);
672
721
  canvas.clipWorld(bounds, true);
673
722
  }
@@ -691,14 +740,14 @@ class Renderer {
691
740
  if (Debug.showRepaint)
692
741
  this.canvas.strokeWorld(bounds, 'red');
693
742
  this.target.__render(this.canvas, options);
694
- this.renderBounds = realBounds || bounds;
743
+ this.renderBounds = realBounds = realBounds || bounds;
695
744
  this.renderOptions = options;
696
- this.totalBounds.isEmpty() ? this.totalBounds = this.renderBounds : this.totalBounds.add(this.renderBounds);
745
+ this.totalBounds.isEmpty() ? this.totalBounds = realBounds : this.totalBounds.add(realBounds);
697
746
  if (Debug.showHitView)
698
747
  this.renderHitView(options);
699
748
  if (Debug.showBoundsView)
700
749
  this.renderBoundsView(options);
701
- this.canvas.updateRender();
750
+ this.canvas.updateRender(realBounds);
702
751
  }
703
752
  renderHitView(_options) { }
704
753
  renderBoundsView(_options) { }
@@ -739,8 +788,11 @@ class Renderer {
739
788
  if (!bounds.includes(this.target.__world) || this.needFill || !e.samePixelRatio) {
740
789
  this.addBlock(this.canvas.bounds);
741
790
  this.target.forceUpdate('surface');
791
+ return;
742
792
  }
743
793
  }
794
+ this.addBlock(new Bounds(0, 0, 1, 1));
795
+ this.changed = true;
744
796
  }
745
797
  __onLayoutEnd(event) {
746
798
  if (event.data)
@@ -751,7 +803,7 @@ class Renderer {
751
803
  empty = (!leaf.__world.width || !leaf.__world.height);
752
804
  if (empty) {
753
805
  if (!leaf.isLeafer)
754
- debug.tip(leaf.innerName, ': empty');
806
+ debug$1.tip(leaf.innerName, ': empty');
755
807
  empty = (!leaf.isBranch || leaf.isBranchLeaf);
756
808
  }
757
809
  return empty;
@@ -778,9 +830,7 @@ class Renderer {
778
830
  if (this.target) {
779
831
  this.stop();
780
832
  this.__removeListenEvents();
781
- this.target = null;
782
- this.canvas = null;
783
- this.config = null;
833
+ this.target = this.canvas = this.config = null;
784
834
  }
785
835
  }
786
836
  }
@@ -794,9 +844,6 @@ Object.assign(Creator, {
794
844
  });
795
845
  Platform.layout = Layouter.fullLayout;
796
846
 
797
- const PaintImage = {};
798
- const PaintGradient = {};
799
-
800
847
  function fillText(ui, canvas) {
801
848
  let row;
802
849
  const { rows, decorationY, decorationHeight } = ui.__.__textDrawData;
@@ -1016,7 +1063,7 @@ function shape(ui, current, options) {
1016
1063
  }
1017
1064
  else {
1018
1065
  const { renderShapeSpread: spread } = ui.__layout;
1019
- const worldClipBounds = getIntersectData(spread ? getSpread(current.bounds, spread * scaleX, spread * scaleY) : current.bounds, nowWorld);
1066
+ const worldClipBounds = getIntersectData(spread ? getSpread(current.bounds, scaleX === scaleY ? spread * scaleX : [spread * scaleY, spread * scaleX]) : current.bounds, nowWorld);
1020
1067
  fitMatrix = current.bounds.getFitMatrix(worldClipBounds);
1021
1068
  let { a: fitScaleX, d: fitScaleY } = fitMatrix;
1022
1069
  if (fitMatrix.a < 1) {
@@ -1081,7 +1128,7 @@ function getLeafPaint(attrName, paint, ui) {
1081
1128
  case 'angular':
1082
1129
  return PaintGradient.conicGradient(paint, boxBounds);
1083
1130
  default:
1084
- return paint.r ? { type: 'solid', style: ColorConvert.string(paint) } : undefined;
1131
+ return paint.r !== undefined ? { type: 'solid', style: ColorConvert.string(paint) } : undefined;
1085
1132
  }
1086
1133
  }
1087
1134
 
@@ -1098,77 +1145,80 @@ const PaintModule = {
1098
1145
  };
1099
1146
 
1100
1147
  let origin = {};
1101
- const { get: get$4, rotateOfOuter: rotateOfOuter$2, translate: translate$1, scaleOfOuter: scaleOfOuter$2, scale: scaleHelper, rotate } = MatrixHelper;
1102
- function fillOrFitMode(data, mode, box, width, height, rotation) {
1103
- const transform = get$4();
1104
- const swap = rotation && rotation !== 180;
1105
- const sw = box.width / (swap ? height : width);
1106
- const sh = box.height / (swap ? width : height);
1107
- const scale = mode === 'fit' ? Math.min(sw, sh) : Math.max(sw, sh);
1108
- const x = box.x + (box.width - width * scale) / 2;
1109
- const y = box.y + (box.height - height * scale) / 2;
1110
- translate$1(transform, x, y);
1111
- scaleHelper(transform, scale);
1148
+ const { get: get$3, rotateOfOuter: rotateOfOuter$1, translate: translate$1, scaleOfOuter: scaleOfOuter$1, scale: scaleHelper, rotate } = MatrixHelper;
1149
+ function fillOrFitMode(data, box, x, y, scaleX, scaleY, rotation) {
1150
+ const transform = get$3();
1151
+ translate$1(transform, box.x + x, box.y + y);
1152
+ scaleHelper(transform, scaleX, scaleY);
1112
1153
  if (rotation)
1113
- rotateOfOuter$2(transform, { x: box.x + box.width / 2, y: box.y + box.height / 2 }, rotation);
1114
- data.scaleX = data.scaleY = scale;
1154
+ rotateOfOuter$1(transform, { x: box.x + box.width / 2, y: box.y + box.height / 2 }, rotation);
1115
1155
  data.transform = transform;
1116
1156
  }
1117
1157
  function clipMode(data, box, x, y, scaleX, scaleY, rotation) {
1118
- const transform = get$4();
1119
- translate$1(transform, box.x, box.y);
1120
- if (x || y)
1121
- translate$1(transform, x, y);
1122
- if (scaleX) {
1158
+ const transform = get$3();
1159
+ translate$1(transform, box.x + x, box.y + y);
1160
+ if (scaleX)
1123
1161
  scaleHelper(transform, scaleX, scaleY);
1124
- data.scaleX = transform.a;
1125
- data.scaleY = transform.d;
1126
- }
1127
1162
  if (rotation)
1128
1163
  rotate(transform, rotation);
1129
1164
  data.transform = transform;
1130
1165
  }
1131
- function repeatMode(data, box, width, height, x, y, scaleX, scaleY, rotation) {
1132
- const transform = get$4();
1166
+ function repeatMode(data, box, width, height, x, y, scaleX, scaleY, rotation, align) {
1167
+ const transform = get$3();
1133
1168
  if (rotation) {
1134
- rotate(transform, rotation);
1135
- switch (rotation) {
1136
- case 90:
1137
- translate$1(transform, height, 0);
1138
- break;
1139
- case 180:
1140
- translate$1(transform, width, height);
1141
- break;
1142
- case 270:
1143
- translate$1(transform, 0, width);
1144
- break;
1169
+ if (align === 'center') {
1170
+ rotateOfOuter$1(transform, { x: width / 2, y: height / 2 }, rotation);
1171
+ }
1172
+ else {
1173
+ rotate(transform, rotation);
1174
+ switch (rotation) {
1175
+ case 90:
1176
+ translate$1(transform, height, 0);
1177
+ break;
1178
+ case 180:
1179
+ translate$1(transform, width, height);
1180
+ break;
1181
+ case 270:
1182
+ translate$1(transform, 0, width);
1183
+ break;
1184
+ }
1145
1185
  }
1146
1186
  }
1147
- origin.x = box.x;
1148
- origin.y = box.y;
1149
- if (x || y)
1150
- origin.x += x, origin.y += y;
1187
+ origin.x = box.x + x;
1188
+ origin.y = box.y + y;
1151
1189
  translate$1(transform, origin.x, origin.y);
1152
- if (scaleX) {
1153
- scaleOfOuter$2(transform, origin, scaleX, scaleY);
1154
- data.scaleX = scaleX;
1155
- data.scaleY = scaleY;
1156
- }
1190
+ if (scaleX)
1191
+ scaleOfOuter$1(transform, origin, scaleX, scaleY);
1157
1192
  data.transform = transform;
1158
1193
  }
1159
1194
 
1160
- const { get: get$3, translate } = MatrixHelper;
1195
+ const { get: get$2, translate } = MatrixHelper;
1196
+ const tempBox = new Bounds();
1197
+ const tempPoint = {};
1161
1198
  function createData(leafPaint, image, paint, box) {
1162
- let { width, height } = image;
1163
- const { opacity, mode, offset, scale, size, rotation, blendMode, repeat } = paint;
1164
- const sameBox = box.width === width && box.height === height;
1199
+ const { blendMode } = paint;
1165
1200
  if (blendMode)
1166
1201
  leafPaint.blendMode = blendMode;
1167
- const data = leafPaint.data = { mode };
1168
- let x, y, scaleX, scaleY;
1169
- if (offset)
1170
- x = offset.x, y = offset.y;
1171
- if (size) {
1202
+ leafPaint.data = getPatternData(paint, box, image);
1203
+ }
1204
+ function getPatternData(paint, box, image) {
1205
+ let { width, height } = image;
1206
+ if (paint.padding)
1207
+ box = tempBox.set(box).shrink(paint.padding);
1208
+ const { opacity, mode, align, offset, scale, size, rotation, repeat } = paint;
1209
+ const sameBox = box.width === width && box.height === height;
1210
+ const data = { mode };
1211
+ const swapSize = align !== 'center' && (rotation || 0) % 180 === 90;
1212
+ const swapWidth = swapSize ? height : width, swapHeight = swapSize ? width : height;
1213
+ let x = 0, y = 0, scaleX, scaleY;
1214
+ if (!mode || mode === 'cover' || mode === 'fit') {
1215
+ if (!sameBox || rotation) {
1216
+ const sw = box.width / swapWidth, sh = box.height / swapHeight;
1217
+ scaleX = scaleY = mode === 'fit' ? Math.min(sw, sh) : Math.max(sw, sh);
1218
+ x += (box.width - width * scaleX) / 2, y += (box.height - height * scaleY) / 2;
1219
+ }
1220
+ }
1221
+ else if (size) {
1172
1222
  scaleX = (typeof size === 'number' ? size : size.width) / width;
1173
1223
  scaleY = (typeof size === 'number' ? size : size.height) / height;
1174
1224
  }
@@ -1176,30 +1226,46 @@ function createData(leafPaint, image, paint, box) {
1176
1226
  scaleX = typeof scale === 'number' ? scale : scale.x;
1177
1227
  scaleY = typeof scale === 'number' ? scale : scale.y;
1178
1228
  }
1229
+ if (align) {
1230
+ const imageBounds = { x, y, width: swapWidth, height: swapHeight };
1231
+ if (scaleX)
1232
+ imageBounds.width *= scaleX, imageBounds.height *= scaleY;
1233
+ AlignHelper.toPoint(align, imageBounds, box, tempPoint, true);
1234
+ x += tempPoint.x, y += tempPoint.y;
1235
+ }
1236
+ if (offset)
1237
+ x += offset.x, y += offset.y;
1179
1238
  switch (mode) {
1180
1239
  case 'strench':
1181
1240
  if (!sameBox)
1182
1241
  width = box.width, height = box.height;
1183
- if (box.x || box.y) {
1184
- data.transform = get$3();
1185
- translate(data.transform, box.x, box.y);
1186
- }
1187
1242
  break;
1243
+ case 'normal':
1188
1244
  case 'clip':
1189
- if (offset || scaleX || rotation)
1245
+ if (x || y || scaleX || rotation)
1190
1246
  clipMode(data, box, x, y, scaleX, scaleY, rotation);
1191
1247
  break;
1192
1248
  case 'repeat':
1193
1249
  if (!sameBox || scaleX || rotation)
1194
- repeatMode(data, box, width, height, x, y, scaleX, scaleY, rotation);
1250
+ repeatMode(data, box, width, height, x, y, scaleX, scaleY, rotation, align);
1195
1251
  if (!repeat)
1196
1252
  data.repeat = 'repeat';
1197
1253
  break;
1198
1254
  case 'fit':
1199
1255
  case 'cover':
1200
1256
  default:
1201
- if (!sameBox || rotation)
1202
- fillOrFitMode(data, mode, box, width, height, rotation);
1257
+ if (scaleX)
1258
+ fillOrFitMode(data, box, x, y, scaleX, scaleY, rotation);
1259
+ }
1260
+ if (!data.transform) {
1261
+ if (box.x || box.y) {
1262
+ data.transform = get$2();
1263
+ translate(data.transform, box.x, box.y);
1264
+ }
1265
+ }
1266
+ if (scaleX && mode !== 'strench') {
1267
+ data.scaleX = scaleX;
1268
+ data.scaleY = scaleY;
1203
1269
  }
1204
1270
  data.width = width;
1205
1271
  data.height = height;
@@ -1207,6 +1273,7 @@ function createData(leafPaint, image, paint, box) {
1207
1273
  data.opacity = opacity;
1208
1274
  if (repeat)
1209
1275
  data.repeat = typeof repeat === 'string' ? (repeat === 'x' ? 'repeat-x' : 'repeat-y') : 'repeat';
1276
+ return data;
1210
1277
  }
1211
1278
 
1212
1279
  let cache, box = new Bounds();
@@ -1218,8 +1285,7 @@ function image(ui, attrName, paint, boxBounds, firstUse) {
1218
1285
  leafPaint = cache.leafPaint;
1219
1286
  }
1220
1287
  else {
1221
- leafPaint = { type: paint.type };
1222
- leafPaint.image = image;
1288
+ leafPaint = { type: paint.type, image };
1223
1289
  cache = image.use > 1 ? { leafPaint, paint, boxBounds: box.set(boxBounds) } : null;
1224
1290
  }
1225
1291
  if (firstUse || image.loading)
@@ -1236,16 +1302,22 @@ function image(ui, attrName, paint, boxBounds, firstUse) {
1236
1302
  onLoadError(ui, event, image.error);
1237
1303
  }
1238
1304
  else {
1305
+ ignoreRender(ui, true);
1239
1306
  if (firstUse)
1240
1307
  onLoad(ui, event);
1241
1308
  leafPaint.loadId = image.load(() => {
1309
+ ignoreRender(ui, false);
1242
1310
  if (!ui.destroyed) {
1243
- if (checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds))
1311
+ if (checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds)) {
1312
+ if (image.hasOpacityPixel)
1313
+ ui.__layout.hitCanvasChanged = true;
1244
1314
  ui.forceUpdate('surface');
1315
+ }
1245
1316
  onLoadSuccess(ui, event);
1246
1317
  }
1247
1318
  leafPaint.loadId = null;
1248
1319
  }, (error) => {
1320
+ ignoreRender(ui, false);
1249
1321
  onLoadError(ui, event, error);
1250
1322
  leafPaint.loadId = null;
1251
1323
  });
@@ -1255,9 +1327,9 @@ function image(ui, attrName, paint, boxBounds, firstUse) {
1255
1327
  function checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds) {
1256
1328
  if (attrName === 'fill' && !ui.__.__naturalWidth) {
1257
1329
  const data = ui.__;
1258
- data.__naturalWidth = image.width;
1259
- data.__naturalHeight = image.height;
1260
- if (data.__autoWidth || data.__autoHeight) {
1330
+ data.__naturalWidth = image.width / data.pixelRatio;
1331
+ data.__naturalHeight = image.height / data.pixelRatio;
1332
+ if (data.__autoSide) {
1261
1333
  ui.forceUpdate('width');
1262
1334
  if (ui.__proxyData) {
1263
1335
  ui.setProxyAttr('width', data.width);
@@ -1285,11 +1357,16 @@ function emit(ui, type, data) {
1285
1357
  if (ui.hasEvent(type))
1286
1358
  ui.emitEvent(new ImageEvent(type, data));
1287
1359
  }
1360
+ function ignoreRender(ui, value) {
1361
+ const { leafer } = ui;
1362
+ if (leafer && leafer.viewReady)
1363
+ leafer.renderer.ignore = value;
1364
+ }
1288
1365
 
1289
- const { get: get$2, scale, copy: copy$1 } = MatrixHelper;
1290
- const { round, abs: abs$1 } = Math;
1366
+ const { get: get$1, scale, copy: copy$1 } = MatrixHelper;
1367
+ const { ceil, abs: abs$1 } = Math;
1291
1368
  function createPattern(ui, paint, pixelRatio) {
1292
- let { scaleX, scaleY } = ui.__world;
1369
+ let { scaleX, scaleY } = ImageManager.patternLocked ? ui.__world : ui.__nowWorld;
1293
1370
  const id = scaleX + '-' + scaleY;
1294
1371
  if (paint.patternId !== id && !ui.destroyed) {
1295
1372
  scaleX = abs$1(scaleX);
@@ -1297,7 +1374,7 @@ function createPattern(ui, paint, pixelRatio) {
1297
1374
  const { image, data } = paint;
1298
1375
  let imageScale, imageMatrix, { width, height, scaleX: sx, scaleY: sy, opacity, transform, repeat } = data;
1299
1376
  if (sx) {
1300
- imageMatrix = get$2();
1377
+ imageMatrix = get$1();
1301
1378
  copy$1(imageMatrix, transform);
1302
1379
  scale(imageMatrix, 1 / sx, 1 / sy);
1303
1380
  scaleX *= sx;
@@ -1332,13 +1409,13 @@ function createPattern(ui, paint, pixelRatio) {
1332
1409
  }
1333
1410
  if (transform || scaleX !== 1 || scaleY !== 1) {
1334
1411
  if (!imageMatrix) {
1335
- imageMatrix = get$2();
1412
+ imageMatrix = get$1();
1336
1413
  if (transform)
1337
1414
  copy$1(imageMatrix, transform);
1338
1415
  }
1339
1416
  scale(imageMatrix, 1 / scaleX, 1 / scaleY);
1340
1417
  }
1341
- const canvas = image.getCanvas(width < 1 ? 1 : round(width), height < 1 ? 1 : round(height), opacity);
1418
+ const canvas = image.getCanvas(ceil(width) || 1, ceil(height) || 1, opacity);
1342
1419
  const pattern = image.getPattern(canvas, repeat || (Platform.origin.noRepeat || 'no-repeat'), imageMatrix, paint);
1343
1420
  paint.style = pattern;
1344
1421
  paint.patternId = id;
@@ -1383,8 +1460,8 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
1383
1460
 
1384
1461
  const { abs } = Math;
1385
1462
  function checkImage(ui, canvas, paint, allowPaint) {
1386
- const { scaleX, scaleY } = ui.__world;
1387
- if (!paint.data || paint.patternId === scaleX + '-' + scaleY) {
1463
+ const { scaleX, scaleY } = ImageManager.patternLocked ? ui.__world : ui.__nowWorld;
1464
+ if (!paint.data || (paint.patternId === scaleX + '-' + scaleY && !Export.running)) {
1388
1465
  return false;
1389
1466
  }
1390
1467
  else {
@@ -1398,7 +1475,7 @@ function checkImage(ui, canvas, paint, allowPaint) {
1398
1475
  width *= data.scaleX;
1399
1476
  height *= data.scaleY;
1400
1477
  }
1401
- allowPaint = width * height > Platform.image.maxCacheSize;
1478
+ allowPaint = (width * height > Platform.image.maxCacheSize) || Export.running;
1402
1479
  }
1403
1480
  else {
1404
1481
  allowPaint = false;
@@ -1425,7 +1502,7 @@ function checkImage(ui, canvas, paint, allowPaint) {
1425
1502
  if (!paint.patternTask) {
1426
1503
  paint.patternTask = ImageManager.patternTasker.add(() => __awaiter(this, void 0, void 0, function* () {
1427
1504
  paint.patternTask = null;
1428
- if (canvas.bounds.hit(ui.__world))
1505
+ if (canvas.bounds.hit(ui.__nowWorld))
1429
1506
  createPattern(ui, paint, canvas.pixelRatio);
1430
1507
  ui.forceUpdate('surface');
1431
1508
  }), 300);
@@ -1465,22 +1542,24 @@ function recycleImage(attrName, data) {
1465
1542
 
1466
1543
  const PaintImageModule = {
1467
1544
  image,
1545
+ checkImage,
1546
+ createPattern,
1547
+ recycleImage,
1468
1548
  createData,
1549
+ getPatternData,
1469
1550
  fillOrFitMode,
1470
1551
  clipMode,
1471
- repeatMode,
1472
- createPattern,
1473
- checkImage,
1474
- recycleImage
1552
+ repeatMode
1475
1553
  };
1476
1554
 
1477
- const defaultFrom$2 = { x: 0.5, y: 0 };
1478
- const defaultTo$2 = { x: 0.5, y: 1 };
1555
+ const { toPoint: toPoint$2 } = AroundHelper;
1556
+ const realFrom$2 = {};
1557
+ const realTo$2 = {};
1479
1558
  function linearGradient(paint, box) {
1480
1559
  let { from, to, type, blendMode, opacity } = paint;
1481
- from || (from = defaultFrom$2);
1482
- to || (to = defaultTo$2);
1483
- const style = Platform.canvas.createLinearGradient(box.x + from.x * box.width, box.y + from.y * box.height, box.x + to.x * box.width, box.y + to.y * box.height);
1560
+ toPoint$2(from || 'top', box, realFrom$2);
1561
+ toPoint$2(to || 'bottom', box, realTo$2);
1562
+ const style = Platform.canvas.createLinearGradient(realFrom$2.x, realFrom$2.y, realTo$2.x, realTo$2.y);
1484
1563
  applyStops(style, paint.stops, opacity);
1485
1564
  const data = { type, style };
1486
1565
  if (blendMode)
@@ -1491,63 +1570,66 @@ function applyStops(gradient, stops, opacity) {
1491
1570
  let stop;
1492
1571
  for (let i = 0, len = stops.length; i < len; i++) {
1493
1572
  stop = stops[i];
1494
- gradient.addColorStop(stop.offset, ColorConvert.string(stop.color, opacity));
1573
+ if (typeof stop === 'string') {
1574
+ gradient.addColorStop(i / (len - 1), ColorConvert.string(stop, opacity));
1575
+ }
1576
+ else {
1577
+ gradient.addColorStop(stop.offset, ColorConvert.string(stop.color, opacity));
1578
+ }
1495
1579
  }
1496
1580
  }
1497
1581
 
1498
- const { set: set$1, getAngle: getAngle$1, getDistance: getDistance$1 } = PointHelper;
1499
- const { get: get$1, rotateOfOuter: rotateOfOuter$1, scaleOfOuter: scaleOfOuter$1 } = MatrixHelper;
1500
- const defaultFrom$1 = { x: 0.5, y: 0.5 };
1501
- const defaultTo$1 = { x: 0.5, y: 1 };
1582
+ const { getAngle, getDistance: getDistance$1 } = PointHelper;
1583
+ const { get, rotateOfOuter, scaleOfOuter } = MatrixHelper;
1584
+ const { toPoint: toPoint$1 } = AroundHelper;
1502
1585
  const realFrom$1 = {};
1503
1586
  const realTo$1 = {};
1504
1587
  function radialGradient(paint, box) {
1505
1588
  let { from, to, type, opacity, blendMode, stretch } = paint;
1506
- from || (from = defaultFrom$1);
1507
- to || (to = defaultTo$1);
1508
- const { x, y, width, height } = box;
1509
- set$1(realFrom$1, x + from.x * width, y + from.y * height);
1510
- set$1(realTo$1, x + to.x * width, y + to.y * height);
1511
- let transform;
1512
- if (width !== height || stretch) {
1513
- transform = get$1();
1514
- scaleOfOuter$1(transform, realFrom$1, width / height * (stretch || 1), 1);
1515
- rotateOfOuter$1(transform, realFrom$1, getAngle$1(realFrom$1, realTo$1) + 90);
1516
- }
1589
+ toPoint$1(from || 'center', box, realFrom$1);
1590
+ toPoint$1(to || 'bottom', box, realTo$1);
1517
1591
  const style = Platform.canvas.createRadialGradient(realFrom$1.x, realFrom$1.y, 0, realFrom$1.x, realFrom$1.y, getDistance$1(realFrom$1, realTo$1));
1518
1592
  applyStops(style, paint.stops, opacity);
1519
- const data = { type, style, transform };
1593
+ const data = { type, style };
1594
+ const transform = getTransform(box, realFrom$1, realTo$1, stretch, true);
1595
+ if (transform)
1596
+ data.transform = transform;
1520
1597
  if (blendMode)
1521
1598
  data.blendMode = blendMode;
1522
1599
  return data;
1523
1600
  }
1601
+ function getTransform(box, from, to, stretch, rotate90) {
1602
+ let transform;
1603
+ const { width, height } = box;
1604
+ if (width !== height || stretch) {
1605
+ const angle = getAngle(from, to);
1606
+ transform = get();
1607
+ if (rotate90) {
1608
+ scaleOfOuter(transform, from, width / height * (stretch || 1), 1);
1609
+ rotateOfOuter(transform, from, angle + 90);
1610
+ }
1611
+ else {
1612
+ scaleOfOuter(transform, from, 1, width / height * (stretch || 1));
1613
+ rotateOfOuter(transform, from, angle);
1614
+ }
1615
+ }
1616
+ return transform;
1617
+ }
1524
1618
 
1525
- const { set, getAngle, getDistance } = PointHelper;
1526
- const { get, rotateOfOuter, scaleOfOuter } = MatrixHelper;
1527
- const defaultFrom = { x: 0.5, y: 0.5 };
1528
- const defaultTo = { x: 0.5, y: 1 };
1619
+ const { getDistance } = PointHelper;
1620
+ const { toPoint } = AroundHelper;
1529
1621
  const realFrom = {};
1530
1622
  const realTo = {};
1531
1623
  function conicGradient(paint, box) {
1532
1624
  let { from, to, type, opacity, blendMode, stretch } = paint;
1533
- from || (from = defaultFrom);
1534
- to || (to = defaultTo);
1535
- const { x, y, width, height } = box;
1536
- set(realFrom, x + from.x * width, y + from.y * height);
1537
- set(realTo, x + to.x * width, y + to.y * height);
1538
- const transform = get();
1539
- const angle = getAngle(realFrom, realTo);
1540
- if (Platform.conicGradientRotate90) {
1541
- scaleOfOuter(transform, realFrom, width / height * (stretch || 1), 1);
1542
- rotateOfOuter(transform, realFrom, angle + 90);
1543
- }
1544
- else {
1545
- scaleOfOuter(transform, realFrom, 1, width / height * (stretch || 1));
1546
- rotateOfOuter(transform, realFrom, angle);
1547
- }
1625
+ toPoint(from || 'center', box, realFrom);
1626
+ toPoint(to || 'bottom', box, realTo);
1548
1627
  const style = Platform.conicGradientSupport ? Platform.canvas.createConicGradient(0, realFrom.x, realFrom.y) : Platform.canvas.createRadialGradient(realFrom.x, realFrom.y, 0, realFrom.x, realFrom.y, getDistance(realFrom, realTo));
1549
1628
  applyStops(style, paint.stops, opacity);
1550
- const data = { type, style, transform };
1629
+ const data = { type, style };
1630
+ const transform = getTransform(box, realFrom, realTo, stretch || 1, Platform.conicGradientRotate90);
1631
+ if (transform)
1632
+ data.transform = transform;
1551
1633
  if (blendMode)
1552
1634
  data.blendMode = blendMode;
1553
1635
  return data;
@@ -1556,7 +1638,8 @@ function conicGradient(paint, box) {
1556
1638
  const PaintGradientModule = {
1557
1639
  linearGradient,
1558
1640
  radialGradient,
1559
- conicGradient
1641
+ conicGradient,
1642
+ getTransform
1560
1643
  };
1561
1644
 
1562
1645
  const { copy, toOffsetOutBounds: toOffsetOutBounds$1 } = BoundsHelper;
@@ -1662,8 +1745,8 @@ function innerShadow(ui, current, shape) {
1662
1745
 
1663
1746
  function blur(ui, current, origin) {
1664
1747
  const { blur } = ui.__;
1665
- origin.setWorldBlur(blur * ui.__world.a);
1666
- origin.copyWorldToInner(current, ui.__world, ui.__layout.renderBounds);
1748
+ origin.setWorldBlur(blur * ui.__nowWorld.a);
1749
+ origin.copyWorldToInner(current, ui.__nowWorld, ui.__layout.renderBounds);
1667
1750
  origin.filter = 'none';
1668
1751
  }
1669
1752
 
@@ -1688,7 +1771,7 @@ Group.prototype.__renderMask = function (canvas, options) {
1688
1771
  maskEnd(this, currentMask, canvas, contentCanvas, maskCanvas, maskOpacity);
1689
1772
  maskCanvas = contentCanvas = null;
1690
1773
  }
1691
- if (child.__.maskType === 'path') {
1774
+ if (child.__.mask === 'path') {
1692
1775
  if (child.opacity < 1) {
1693
1776
  currentMask = 'opacity-path';
1694
1777
  maskOpacity = child.opacity;
@@ -1709,7 +1792,7 @@ Group.prototype.__renderMask = function (canvas, options) {
1709
1792
  contentCanvas = getCanvas(canvas);
1710
1793
  child.__render(maskCanvas, options);
1711
1794
  }
1712
- if (child.__.maskType !== 'clipping')
1795
+ if (child.__.mask !== 'clipping')
1713
1796
  continue;
1714
1797
  }
1715
1798
  if (excludeRenderBounds(child, options))
@@ -1904,7 +1987,8 @@ function createRows(drawData, content, style) {
1904
1987
  if (breakAll) {
1905
1988
  if (wordWidth)
1906
1989
  addWord();
1907
- addRow();
1990
+ if (rowWidth)
1991
+ addRow();
1908
1992
  }
1909
1993
  else {
1910
1994
  if (!afterBreak)
@@ -1912,10 +1996,12 @@ function createRows(drawData, content, style) {
1912
1996
  if (langBreak || afterBreak || charType === Break || charType === Before || charType === Single || (wordWidth + charWidth > realWidth)) {
1913
1997
  if (wordWidth)
1914
1998
  addWord();
1915
- addRow();
1999
+ if (rowWidth)
2000
+ addRow();
1916
2001
  }
1917
2002
  else {
1918
- addRow();
2003
+ if (rowWidth)
2004
+ addRow();
1919
2005
  }
1920
2006
  }
1921
2007
  }
@@ -2010,11 +2096,11 @@ function layoutChar(drawData, style, width, _height) {
2010
2096
  if (mode === WordMode) {
2011
2097
  wordChar = { char: '', x: charX };
2012
2098
  charX = toWordChar(word.data, charX, wordChar);
2013
- if (wordChar.char !== ' ')
2099
+ if (row.isOverflow || wordChar.char !== ' ')
2014
2100
  row.data.push(wordChar);
2015
2101
  }
2016
2102
  else {
2017
- charX = toChar(word.data, charX, row.data);
2103
+ charX = toChar(word.data, charX, row.data, row.isOverflow);
2018
2104
  }
2019
2105
  if (!row.paraEnd && addWordWidth) {
2020
2106
  charX += addWordWidth;
@@ -2041,9 +2127,9 @@ function toWordChar(data, charX, wordChar) {
2041
2127
  });
2042
2128
  return charX;
2043
2129
  }
2044
- function toChar(data, charX, rowData) {
2130
+ function toChar(data, charX, rowData, isOverflow) {
2045
2131
  data.forEach(char => {
2046
- if (char.char !== ' ') {
2132
+ if (isOverflow || char.char !== ' ') {
2047
2133
  char.x = charX;
2048
2134
  rowData.push(char);
2049
2135
  }
@@ -2075,12 +2161,14 @@ function layoutText(drawData, style) {
2075
2161
  for (let i = 0, len = rows.length; i < len; i++) {
2076
2162
  row = rows[i];
2077
2163
  row.x = x;
2078
- switch (textAlign) {
2079
- case 'center':
2080
- row.x += (width - row.width) / 2;
2081
- break;
2082
- case 'right':
2083
- row.x += width - row.width;
2164
+ if (row.width < width || (row.width > width && !__clipText)) {
2165
+ switch (textAlign) {
2166
+ case 'center':
2167
+ row.x += (width - row.width) / 2;
2168
+ break;
2169
+ case 'right':
2170
+ row.x += width - row.width;
2171
+ }
2084
2172
  }
2085
2173
  if (row.paraStart && paraSpacing && i > 0)
2086
2174
  starY += paraSpacing;
@@ -2116,16 +2204,20 @@ function layoutText(drawData, style) {
2116
2204
  bounds.height = realHeight;
2117
2205
  }
2118
2206
 
2119
- function clipText(drawData, style) {
2207
+ function clipText(drawData, style, x, width) {
2208
+ if (!width)
2209
+ return;
2120
2210
  const { rows, overflow } = drawData;
2121
2211
  let { textOverflow } = style;
2122
2212
  rows.splice(overflow);
2123
- if (textOverflow !== 'hide') {
2124
- if (textOverflow === 'ellipsis')
2213
+ if (textOverflow && textOverflow !== 'show') {
2214
+ if (textOverflow === 'hide')
2215
+ textOverflow = '';
2216
+ else if (textOverflow === 'ellipsis')
2125
2217
  textOverflow = '...';
2126
2218
  let char, charRight;
2127
- const ellipsisWidth = Platform.canvas.measureText(textOverflow).width;
2128
- const right = style.x + style.width - ellipsisWidth;
2219
+ const ellipsisWidth = textOverflow ? Platform.canvas.measureText(textOverflow).width : 0;
2220
+ const right = x + width - ellipsisWidth;
2129
2221
  const list = style.textWrap === 'none' ? rows : [rows[overflow - 1]];
2130
2222
  list.forEach(row => {
2131
2223
  if (row.isOverflow && row.data) {
@@ -2201,7 +2293,7 @@ function getDrawData(content, style) {
2201
2293
  layoutText(drawData, style);
2202
2294
  layoutChar(drawData, style, width);
2203
2295
  if (drawData.overflow)
2204
- clipText(drawData, style);
2296
+ clipText(drawData, style, x, width);
2205
2297
  if (textDecoration !== 'none')
2206
2298
  decorationText(drawData, style);
2207
2299
  return drawData;
@@ -2272,46 +2364,101 @@ function getTrimBounds(canvas) {
2272
2364
  const ExportModule = {
2273
2365
  export(leaf, filename, options) {
2274
2366
  this.running = true;
2367
+ const fileType = FileHelper.fileType(filename);
2368
+ options = FileHelper.getExportOptions(options);
2275
2369
  return addTask((success) => new Promise((resolve) => {
2276
2370
  const over = (result) => {
2277
2371
  success(result);
2278
2372
  resolve();
2279
2373
  this.running = false;
2280
2374
  };
2375
+ const { toURL } = Platform;
2376
+ const { download } = Platform.origin;
2377
+ if (filename === 'json') {
2378
+ return over({ data: leaf.toJSON(options.json) });
2379
+ }
2380
+ else if (fileType === 'json') {
2381
+ download(toURL(JSON.stringify(leaf.toJSON(options.json)), 'text'), filename);
2382
+ return over({ data: true });
2383
+ }
2384
+ if (filename === 'svg') {
2385
+ return over({ data: leaf.toSVG() });
2386
+ }
2387
+ else if (fileType === 'svg') {
2388
+ download(toURL(leaf.toSVG(), 'svg'), filename);
2389
+ return over({ data: true });
2390
+ }
2281
2391
  const { leafer } = leaf;
2282
2392
  if (leafer) {
2393
+ checkLazy(leaf);
2283
2394
  leafer.waitViewCompleted(() => __awaiter(this, void 0, void 0, function* () {
2284
2395
  let renderBounds, trimBounds, scaleX = 1, scaleY = 1;
2285
- options = FileHelper.getExportOptions(options);
2286
- const { scale, pixelRatio, slice, trim } = options;
2396
+ const { worldTransform, isLeafer, isFrame } = leaf;
2397
+ const { slice, trim, onCanvas } = options;
2398
+ let scale = options.scale || 1;
2399
+ let pixelRatio = options.pixelRatio || 1;
2400
+ const smooth = options.smooth === undefined ? leafer.config.smooth : options.smooth;
2401
+ const contextSettings = options.contextSettings || leafer.config.contextSettings;
2402
+ if (leaf.isApp) {
2403
+ scale *= pixelRatio;
2404
+ pixelRatio = leaf.app.pixelRatio;
2405
+ }
2287
2406
  const screenshot = options.screenshot || leaf.isApp;
2288
- const fill = options.fill === undefined ? ((leaf.isLeafer && screenshot) ? leaf.fill : '') : options.fill;
2407
+ const fill = (isLeafer && screenshot) ? (options.fill === undefined ? leaf.fill : options.fill) : options.fill;
2289
2408
  const needFill = FileHelper.isOpaqueImage(filename) || fill, matrix = new Matrix();
2290
2409
  if (screenshot) {
2291
- renderBounds = screenshot === true ? (leaf.isLeafer ? leafer.canvas.bounds : leaf.worldRenderBounds) : screenshot;
2410
+ renderBounds = screenshot === true ? (isLeafer ? leafer.canvas.bounds : leaf.worldRenderBounds) : screenshot;
2292
2411
  }
2293
2412
  else {
2294
- const { localTransform, __world: world } = leaf;
2295
- matrix.set(world).divide(localTransform).invert();
2296
- scaleX = 1 / (world.scaleX / leaf.scaleX);
2297
- scaleY = 1 / (world.scaleY / leaf.scaleY);
2298
- renderBounds = leaf.getBounds('render', 'local');
2299
- }
2300
- let { x, y, width, height } = renderBounds;
2301
- if (scale) {
2302
- matrix.scale(scale);
2303
- width *= scale, height *= scale;
2304
- scaleX *= scale, scaleY *= scale;
2413
+ let relative = options.relative || (isLeafer ? 'inner' : 'local');
2414
+ scaleX = worldTransform.scaleX;
2415
+ scaleY = worldTransform.scaleY;
2416
+ switch (relative) {
2417
+ case 'inner':
2418
+ matrix.set(worldTransform);
2419
+ break;
2420
+ case 'local':
2421
+ matrix.set(worldTransform).divide(leaf.localTransform);
2422
+ scaleX /= leaf.scaleX;
2423
+ scaleY /= leaf.scaleY;
2424
+ break;
2425
+ case 'world':
2426
+ scaleX = 1;
2427
+ scaleY = 1;
2428
+ break;
2429
+ case 'page':
2430
+ relative = leaf.leafer;
2431
+ default:
2432
+ matrix.set(worldTransform).divide(leaf.getTransform(relative));
2433
+ const l = relative.worldTransform;
2434
+ scaleX /= scaleX / l.scaleX;
2435
+ scaleY /= scaleY / l.scaleY;
2436
+ }
2437
+ renderBounds = leaf.getBounds('render', relative);
2305
2438
  }
2306
- let canvas = Creator.canvas({ width, height, pixelRatio });
2307
- const renderOptions = { matrix: matrix.translate(-x, -y).withScale(scaleX, scaleY) };
2439
+ const { x, y, width, height } = new Bounds(renderBounds).scale(scale);
2440
+ let canvas = Creator.canvas({ width: Math.round(width), height: Math.round(height), pixelRatio, smooth, contextSettings });
2441
+ const renderOptions = { matrix: matrix.scale(1 / scale).invert().translate(-x, -y).withScale(1 / scaleX * scale, 1 / scaleY * scale) };
2442
+ let sliceLeaf;
2308
2443
  if (slice) {
2444
+ sliceLeaf = leaf;
2445
+ sliceLeaf.__worldOpacity = 0;
2309
2446
  leaf = leafer;
2310
2447
  renderOptions.bounds = canvas.bounds;
2311
2448
  }
2312
2449
  canvas.save();
2313
- leaf.__render(canvas, renderOptions);
2450
+ if (isFrame && fill !== undefined) {
2451
+ const oldFill = leaf.get('fill');
2452
+ leaf.fill = '';
2453
+ leaf.__render(canvas, renderOptions);
2454
+ leaf.fill = oldFill;
2455
+ }
2456
+ else {
2457
+ leaf.__render(canvas, renderOptions);
2458
+ }
2314
2459
  canvas.restore();
2460
+ if (sliceLeaf)
2461
+ sliceLeaf.__updateWorldOpacity();
2315
2462
  if (trim) {
2316
2463
  trimBounds = getTrimBounds(canvas);
2317
2464
  const old = canvas, { width, height } = trimBounds;
@@ -2321,8 +2468,10 @@ const ExportModule = {
2321
2468
  }
2322
2469
  if (needFill)
2323
2470
  canvas.fillWorld(canvas.bounds, fill || '#FFFFFF', 'destination-over');
2471
+ if (onCanvas)
2472
+ onCanvas(canvas);
2324
2473
  const data = filename === 'canvas' ? canvas : yield canvas.export(filename, options);
2325
- over({ data, renderBounds, trimBounds });
2474
+ over({ data, width: canvas.pixelWidth, height: canvas.pixelHeight, renderBounds, trimBounds });
2326
2475
  }));
2327
2476
  }
2328
2477
  else {
@@ -2339,12 +2488,56 @@ function addTask(task) {
2339
2488
  tasker.add(() => __awaiter(this, void 0, void 0, function* () { return yield task(resolve); }), { parallel: false });
2340
2489
  });
2341
2490
  }
2491
+ function checkLazy(leaf) {
2492
+ if (leaf.__.__needComputePaint)
2493
+ leaf.__.__computePaint();
2494
+ if (leaf.isBranch)
2495
+ leaf.children.forEach(child => checkLazy(child));
2496
+ }
2497
+
2498
+ const canvas = LeaferCanvasBase.prototype;
2499
+ const debug = Debug.get('@leafer-ui/export');
2500
+ canvas.export = function (filename, options) {
2501
+ const { quality, blob } = FileHelper.getExportOptions(options);
2502
+ if (filename.includes('.')) {
2503
+ return this.saveAs(filename, quality);
2504
+ }
2505
+ else if (blob) {
2506
+ return this.toBlob(filename, quality);
2507
+ }
2508
+ else {
2509
+ return this.toDataURL(filename, quality);
2510
+ }
2511
+ };
2512
+ canvas.toBlob = function (type, quality) {
2513
+ return new Promise((resolve) => {
2514
+ Platform.origin.canvasToBolb(this.view, type, quality).then((blob) => {
2515
+ resolve(blob);
2516
+ }).catch((e) => {
2517
+ debug.error(e);
2518
+ resolve(null);
2519
+ });
2520
+ });
2521
+ };
2522
+ canvas.toDataURL = function (type, quality) {
2523
+ return Platform.origin.canvasToDataURL(this.view, type, quality);
2524
+ };
2525
+ canvas.saveAs = function (filename, quality) {
2526
+ return new Promise((resolve) => {
2527
+ Platform.origin.canvasSaveAs(this.view, filename, quality).then(() => {
2528
+ resolve(true);
2529
+ }).catch((e) => {
2530
+ debug.error(e);
2531
+ resolve(false);
2532
+ });
2533
+ });
2534
+ };
2342
2535
 
2343
2536
  Object.assign(TextConvert, TextConvertModule);
2344
2537
  Object.assign(ColorConvert, ColorConvertModule);
2345
2538
  Object.assign(Paint, PaintModule);
2346
- Object.assign(PaintImage$1, PaintImageModule);
2347
- Object.assign(PaintGradient$1, PaintGradientModule);
2539
+ Object.assign(PaintImage, PaintImageModule);
2540
+ Object.assign(PaintGradient, PaintGradientModule);
2348
2541
  Object.assign(Effect, EffectModule);
2349
2542
  Object.assign(Export, ExportModule);
2350
2543