leafer-ui 1.0.0-rc.2 → 1.0.0-rc.21

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,8 +1,230 @@
1
- import { LeafList, DataHelper, RenderEvent, ChildEvent, WatchEvent, PropertyEvent, LeafHelper, BranchHelper, Bounds, LeafBoundsHelper, BoundsHelper, Debug, LeafLevelList, LayoutEvent, Run, ImageManager, Platform, AnimateEvent, ResizeEvent, Creator, LeaferCanvasBase, Cursor, canvasSizeAttrs, canvasPatch, InteractionHelper, MathHelper, InteractionBase, LeaferImage, FileHelper, MatrixHelper, ImageEvent, PointHelper, TaskProcessor } from '@leafer/core';
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, Answer, MathHelper, MatrixHelper, ImageEvent, PointHelper, Direction4, TwoPointBoundsHelper, TaskProcessor, Matrix } from '@leafer/core';
2
2
  export * from '@leafer/core';
3
3
  export { LeaferImage } from '@leafer/core';
4
- import { ColorConvert as ColorConvert$1, Paint, Effect, TextConvert as TextConvert$1, Export as Export$1 } from '@leafer-ui/core';
4
+ import { InteractionHelper, InteractionBase, Cursor, HitCanvasManager, Leafer } from '@leafer-ui/core';
5
5
  export * from '@leafer-ui/core';
6
+ import { PaintImage, ColorConvert, PaintGradient, Export, Group, TextConvert, Paint, Effect } from '@leafer-ui/draw';
7
+
8
+ const debug$3 = Debug.get('LeaferCanvas');
9
+ class LeaferCanvas extends LeaferCanvasBase {
10
+ init() {
11
+ const { view } = this.config;
12
+ view ? this.__createViewFrom(view) : this.__createView();
13
+ const { style } = this.view;
14
+ style.display || (style.display = 'block');
15
+ this.parentView = this.view.parentElement;
16
+ if (this.parentView)
17
+ this.parentView.style.userSelect = 'none';
18
+ if (Platform.syncDomFont && !this.parentView) {
19
+ this.view.style.display = 'none';
20
+ document.body.appendChild(this.view);
21
+ }
22
+ this.__createContext();
23
+ if (!this.autoLayout)
24
+ this.resize(this.config);
25
+ }
26
+ set backgroundColor(color) { this.view.style.backgroundColor = color; }
27
+ get backgroundColor() { return this.view.style.backgroundColor; }
28
+ set hittable(hittable) { this.view.style.pointerEvents = hittable ? 'auto' : 'none'; }
29
+ get hittable() { return this.view.style.pointerEvents !== 'none'; }
30
+ __createView() {
31
+ this.view = document.createElement('canvas');
32
+ }
33
+ __createViewFrom(inputView) {
34
+ let find = (typeof inputView === 'string') ? document.getElementById(inputView) : inputView;
35
+ if (find) {
36
+ if (find instanceof HTMLCanvasElement) {
37
+ this.view = find;
38
+ }
39
+ else {
40
+ let parent = find;
41
+ if (find === window || find === document) {
42
+ const div = document.createElement('div');
43
+ const { style } = div;
44
+ style.position = 'absolute';
45
+ style.top = style.bottom = style.left = style.right = '0px';
46
+ document.body.appendChild(div);
47
+ parent = div;
48
+ }
49
+ this.__createView();
50
+ const view = this.view;
51
+ if (parent.hasChildNodes()) {
52
+ const { style } = view;
53
+ style.position = 'absolute';
54
+ style.top = style.left = '0px';
55
+ parent.style.position || (parent.style.position = 'relative');
56
+ }
57
+ parent.appendChild(view);
58
+ }
59
+ }
60
+ else {
61
+ debug$3.error(`no id: ${inputView}`);
62
+ this.__createView();
63
+ }
64
+ }
65
+ updateViewSize() {
66
+ const { width, height, pixelRatio } = this;
67
+ const { style } = this.view;
68
+ style.width = width + 'px';
69
+ style.height = height + 'px';
70
+ this.view.width = Math.ceil(width * pixelRatio);
71
+ this.view.height = Math.ceil(height * pixelRatio);
72
+ }
73
+ updateClientBounds() {
74
+ this.clientBounds = this.view.getBoundingClientRect();
75
+ }
76
+ startAutoLayout(autoBounds, listener) {
77
+ this.autoBounds = autoBounds;
78
+ this.resizeListener = listener;
79
+ try {
80
+ this.resizeObserver = new ResizeObserver((entries) => {
81
+ this.updateClientBounds();
82
+ for (const entry of entries)
83
+ this.checkAutoBounds(entry.contentRect);
84
+ });
85
+ const parent = this.parentView;
86
+ if (parent) {
87
+ this.resizeObserver.observe(parent);
88
+ this.checkAutoBounds(parent.getBoundingClientRect());
89
+ }
90
+ }
91
+ catch (_a) {
92
+ this.imitateResizeObserver();
93
+ }
94
+ }
95
+ imitateResizeObserver() {
96
+ if (this.autoLayout) {
97
+ if (this.parentView)
98
+ this.checkAutoBounds(this.parentView.getBoundingClientRect());
99
+ Platform.requestRender(this.imitateResizeObserver.bind(this));
100
+ }
101
+ }
102
+ checkAutoBounds(parentSize) {
103
+ const view = this.view;
104
+ const { x, y, width, height } = this.autoBounds.getBoundsFrom(parentSize);
105
+ if (width !== this.width || height !== this.height) {
106
+ const { style } = view;
107
+ const { pixelRatio } = this;
108
+ style.marginLeft = x + 'px';
109
+ style.marginTop = y + 'px';
110
+ const size = { width, height, pixelRatio };
111
+ const oldSize = {};
112
+ DataHelper.copyAttrs(oldSize, this, canvasSizeAttrs);
113
+ this.resize(size);
114
+ if (this.width !== undefined)
115
+ this.resizeListener(new ResizeEvent(size, oldSize));
116
+ }
117
+ }
118
+ stopAutoLayout() {
119
+ this.autoLayout = false;
120
+ this.resizeListener = null;
121
+ if (this.resizeObserver) {
122
+ this.resizeObserver.disconnect();
123
+ this.resizeObserver = null;
124
+ }
125
+ }
126
+ unrealCanvas() {
127
+ if (!this.unreal && this.parentView) {
128
+ const view = this.view;
129
+ if (view)
130
+ view.remove();
131
+ this.view = this.parentView;
132
+ this.unreal = true;
133
+ }
134
+ }
135
+ destroy() {
136
+ if (this.view) {
137
+ this.stopAutoLayout();
138
+ if (!this.unreal) {
139
+ const view = this.view;
140
+ if (view.parentElement)
141
+ view.remove();
142
+ }
143
+ super.destroy();
144
+ }
145
+ }
146
+ }
147
+
148
+ canvasPatch(CanvasRenderingContext2D.prototype);
149
+ canvasPatch(Path2D.prototype);
150
+
151
+ const { mineType, fileType } = FileHelper;
152
+ Object.assign(Creator, {
153
+ canvas: (options, manager) => new LeaferCanvas(options, manager),
154
+ image: (options) => new LeaferImage(options)
155
+ });
156
+ function useCanvas(_canvasType, _power) {
157
+ Platform.origin = {
158
+ createCanvas(width, height) {
159
+ const canvas = document.createElement('canvas');
160
+ canvas.width = width;
161
+ canvas.height = height;
162
+ return canvas;
163
+ },
164
+ canvasToDataURL: (canvas, type, quality) => canvas.toDataURL(mineType(type), quality),
165
+ canvasToBolb: (canvas, type, quality) => new Promise((resolve) => canvas.toBlob(resolve, mineType(type), quality)),
166
+ canvasSaveAs: (canvas, filename, quality) => {
167
+ const url = canvas.toDataURL(mineType(fileType(filename)), quality);
168
+ return Platform.origin.download(url, filename);
169
+ },
170
+ download(url, filename) {
171
+ return new Promise((resolve) => {
172
+ let el = document.createElement('a');
173
+ el.href = url;
174
+ el.download = filename;
175
+ document.body.appendChild(el);
176
+ el.click();
177
+ document.body.removeChild(el);
178
+ resolve();
179
+ });
180
+ },
181
+ loadImage(src) {
182
+ return new Promise((resolve, reject) => {
183
+ const img = new Image();
184
+ const { suffix, crossOrigin } = Platform.image;
185
+ if (crossOrigin) {
186
+ img.setAttribute('crossOrigin', crossOrigin);
187
+ img.crossOrigin = crossOrigin;
188
+ }
189
+ img.onload = () => { resolve(img); };
190
+ img.onerror = (e) => { reject(e); };
191
+ if (!src.startsWith('data:') && !src.startsWith('blob:') && suffix)
192
+ src += (src.includes("?") ? "&" : "?") + suffix;
193
+ img.src = src;
194
+ });
195
+ }
196
+ };
197
+ Platform.event = {
198
+ stopDefault(origin) { origin.preventDefault(); },
199
+ stopNow(origin) { origin.stopImmediatePropagation(); },
200
+ stop(origin) { origin.stopPropagation(); }
201
+ };
202
+ Platform.canvas = Creator.canvas();
203
+ Platform.conicGradientSupport = !!Platform.canvas.context.createConicGradient;
204
+ }
205
+ Platform.name = 'web';
206
+ Platform.isMobile = 'ontouchstart' in window;
207
+ Platform.requestRender = function (render) { window.requestAnimationFrame(render); };
208
+ Platform.devicePixelRatio = Math.max(1, devicePixelRatio);
209
+ const { userAgent } = navigator;
210
+ if (userAgent.indexOf("Firefox") > -1) {
211
+ Platform.conicGradientRotate90 = true;
212
+ Platform.intWheelDeltaY = true;
213
+ Platform.syncDomFont = true;
214
+ }
215
+ else if (userAgent.indexOf("Safari") > -1 && userAgent.indexOf("Chrome") === -1) {
216
+ Platform.fullImageShadow = true;
217
+ }
218
+ if (userAgent.indexOf('Windows') > -1) {
219
+ Platform.os = 'Windows';
220
+ Platform.intWheelDeltaY = true;
221
+ }
222
+ else if (userAgent.indexOf('Mac') > -1) {
223
+ Platform.os = 'Mac';
224
+ }
225
+ else if (userAgent.indexOf('Linux') > -1) {
226
+ Platform.os = 'Linux';
227
+ }
6
228
 
7
229
  class Watcher {
8
230
  get childrenChanged() { return this.hasAdd || this.hasRemove || this.hasVisible; }
@@ -10,7 +232,7 @@ class Watcher {
10
232
  if (this.hasRemove) {
11
233
  const updatedList = new LeafList();
12
234
  this.__updatedList.list.forEach(item => { if (item.leafer)
13
- updatedList.push(item); });
235
+ updatedList.add(item); });
14
236
  return updatedList;
15
237
  }
16
238
  else {
@@ -45,7 +267,7 @@ class Watcher {
45
267
  this.target.emit(RenderEvent.REQUEST);
46
268
  }
47
269
  __onAttrChange(event) {
48
- this.__updatedList.push(event.target);
270
+ this.__updatedList.add(event.target);
49
271
  this.update();
50
272
  }
51
273
  __onChildEvent(event) {
@@ -55,12 +277,12 @@ class Watcher {
55
277
  }
56
278
  else {
57
279
  this.hasRemove = true;
58
- this.__updatedList.push(event.parent);
280
+ this.__updatedList.add(event.parent);
59
281
  }
60
282
  this.update();
61
283
  }
62
284
  __pushChild(child) {
63
- this.__updatedList.push(child);
285
+ this.__updatedList.add(child);
64
286
  if (child.isBranch)
65
287
  this.__loopChildren(child);
66
288
  }
@@ -99,22 +321,22 @@ class Watcher {
99
321
  }
100
322
  }
101
323
 
102
- const { updateAllWorldMatrix: updateAllWorldMatrix$1, updateAllWorldOpacity } = LeafHelper;
324
+ const { updateAllMatrix: updateAllMatrix$1, updateBounds: updateOneBounds, updateAllWorldOpacity } = LeafHelper;
103
325
  const { pushAllChildBranch, pushAllParent } = BranchHelper;
104
326
  function updateMatrix(updateList, levelList) {
105
327
  let layout;
106
328
  updateList.list.forEach(leaf => {
107
329
  layout = leaf.__layout;
108
- if (levelList.without(leaf) && !layout.useZoomProxy) {
330
+ if (levelList.without(leaf) && !layout.proxyZoom) {
109
331
  if (layout.matrixChanged) {
110
- updateAllWorldMatrix$1(leaf);
111
- levelList.push(leaf);
332
+ updateAllMatrix$1(leaf, true);
333
+ levelList.add(leaf);
112
334
  if (leaf.isBranch)
113
335
  pushAllChildBranch(leaf, levelList);
114
336
  pushAllParent(leaf, levelList);
115
337
  }
116
338
  else if (layout.boundsChanged) {
117
- levelList.push(leaf);
339
+ levelList.add(leaf);
118
340
  if (leaf.isBranch)
119
341
  leaf.__tempNumber = 0;
120
342
  pushAllParent(leaf, levelList);
@@ -123,20 +345,21 @@ function updateMatrix(updateList, levelList) {
123
345
  });
124
346
  }
125
347
  function updateBounds(boundsList) {
126
- let itemList, branch;
348
+ let list, branch, children;
127
349
  boundsList.sort(true);
128
350
  boundsList.levels.forEach(level => {
129
- itemList = boundsList.levelMap[level];
130
- for (let i = 0, len = itemList.length; i < len; i++) {
131
- branch = itemList[i];
351
+ list = boundsList.levelMap[level];
352
+ for (let i = 0, len = list.length; i < len; i++) {
353
+ branch = list[i];
132
354
  if (branch.isBranch && branch.__tempNumber) {
133
- for (let j = 0, jLen = branch.children.length; j < jLen; j++) {
134
- if (!branch.children[j].isBranch) {
135
- branch.children[j].__updateWorldBounds();
355
+ children = branch.children;
356
+ for (let j = 0, jLen = children.length; j < jLen; j++) {
357
+ if (!children[j].isBranch) {
358
+ updateOneBounds(children[j]);
136
359
  }
137
360
  }
138
361
  }
139
- branch.__updateWorldBounds();
362
+ updateOneBounds(branch);
140
363
  }
141
364
  });
142
365
  }
@@ -149,7 +372,7 @@ function updateChange(updateList) {
149
372
  }
150
373
 
151
374
  const { worldBounds } = LeafBoundsHelper;
152
- const { setByListWithHandle } = BoundsHelper;
375
+ const bigBounds = { x: 0, y: 0, width: 100000, height: 100000 };
153
376
  class LayoutBlockData {
154
377
  constructor(list) {
155
378
  this.updatedBounds = new Bounds();
@@ -160,14 +383,20 @@ class LayoutBlockData {
160
383
  this.updatedList = list;
161
384
  }
162
385
  setBefore() {
163
- setByListWithHandle(this.beforeBounds, this.updatedList.list, worldBounds);
386
+ this.beforeBounds.setListWithFn(this.updatedList.list, worldBounds);
164
387
  }
165
388
  setAfter() {
166
- setByListWithHandle(this.afterBounds, this.updatedList.list, worldBounds);
167
- this.updatedBounds.setByList([this.beforeBounds, this.afterBounds]);
389
+ const { list } = this.updatedList;
390
+ if (list.some(leaf => leaf.noBounds)) {
391
+ this.afterBounds.set(bigBounds);
392
+ }
393
+ else {
394
+ this.afterBounds.setListWithFn(list, worldBounds);
395
+ }
396
+ this.updatedBounds.setList([this.beforeBounds, this.afterBounds]);
168
397
  }
169
398
  merge(data) {
170
- this.updatedList.pushList(data.updatedList.list);
399
+ this.updatedList.addList(data.updatedList.list);
171
400
  this.beforeBounds.add(data.beforeBounds);
172
401
  this.afterBounds.add(data.afterBounds);
173
402
  this.updatedBounds.add(data.updatedBounds);
@@ -177,8 +406,7 @@ class LayoutBlockData {
177
406
  }
178
407
  }
179
408
 
180
- const { updateAllWorldMatrix, updateAllChange } = LeafHelper;
181
- const { pushAllBranchStack, updateWorldBoundsByBranchStack } = BranchHelper;
409
+ const { updateAllMatrix, updateAllChange } = LeafHelper;
182
410
  const debug$2 = Debug.get('Layouter');
183
411
  class Layouter {
184
412
  constructor(target, userConfig) {
@@ -255,12 +483,15 @@ class Layouter {
255
483
  const { target, __updatedList: updateList } = this;
256
484
  const { BEFORE, LAYOUT, AFTER } = LayoutEvent;
257
485
  const blocks = this.getBlocks(updateList);
258
- blocks.forEach(item => { item.setBefore(); });
486
+ blocks.forEach(item => item.setBefore());
259
487
  target.emitEvent(new LayoutEvent(BEFORE, blocks, this.times));
488
+ this.extraBlock = null;
260
489
  updateList.sort();
261
490
  updateMatrix(updateList, this.__levelList);
262
491
  updateBounds(this.__levelList);
263
492
  updateChange(updateList);
493
+ if (this.extraBlock)
494
+ blocks.push(this.extraBlock);
264
495
  blocks.forEach(item => item.setAfter());
265
496
  target.emitEvent(new LayoutEvent(LAYOUT, blocks, this.times));
266
497
  target.emitEvent(new LayoutEvent(AFTER, blocks, this.times));
@@ -283,17 +514,22 @@ class Layouter {
283
514
  Run.end(t);
284
515
  }
285
516
  static fullLayout(target) {
286
- updateAllWorldMatrix(target);
517
+ updateAllMatrix(target, true);
287
518
  if (target.isBranch) {
288
- const branchStack = [target];
289
- pushAllBranchStack(target, branchStack);
290
- updateWorldBoundsByBranchStack(branchStack);
519
+ BranchHelper.updateBounds(target);
291
520
  }
292
521
  else {
293
- target.__updateWorldBounds();
522
+ LeafHelper.updateBounds(target);
294
523
  }
295
524
  updateAllChange(target);
296
525
  }
526
+ addExtra(leaf) {
527
+ if (!this.__updatedList.has(leaf)) {
528
+ const { updatedList, beforeBounds } = this.extraBlock || (this.extraBlock = new LayoutBlockData([]));
529
+ updatedList.length ? beforeBounds.add(leaf.__world) : beforeBounds.set(leaf.__world);
530
+ updatedList.add(leaf);
531
+ }
532
+ }
297
533
  createBlock(data) {
298
534
  return new LayoutBlockData(data);
299
535
  }
@@ -321,8 +557,7 @@ class Layouter {
321
557
  if (this.target) {
322
558
  this.stop();
323
559
  this.__removeListenEvents();
324
- this.target = null;
325
- this.config = null;
560
+ this.target = this.config = null;
326
561
  }
327
562
  }
328
563
  }
@@ -403,6 +638,10 @@ class Renderer {
403
638
  }
404
639
  else {
405
640
  this.requestLayout();
641
+ if (this.ignore) {
642
+ this.ignore = this.rendering = false;
643
+ return;
644
+ }
406
645
  this.emitRender(RenderEvent.BEFORE);
407
646
  if (this.config.usePartRender && this.totalTimes > 1) {
408
647
  this.partRender();
@@ -424,8 +663,7 @@ class Renderer {
424
663
  const { canvas, updateBlocks: list } = this;
425
664
  if (!list)
426
665
  return debug$1.warn('PartRender: need update attr');
427
- if (list.some(block => block.includes(this.target.__world)))
428
- this.mergeBlocks();
666
+ this.mergeBlocks();
429
667
  list.forEach(block => { if (canvas.bounds.hit(block) && !block.isEmpty())
430
668
  this.clipRender(block); });
431
669
  }
@@ -434,7 +672,7 @@ class Renderer {
434
672
  const { canvas } = this;
435
673
  const bounds = block.getIntersect(canvas.bounds);
436
674
  const includes = block.includes(this.target.__world);
437
- const realBounds = new Bounds().copy(bounds);
675
+ const realBounds = new Bounds(bounds);
438
676
  canvas.save();
439
677
  if (includes && !Debug.showRepaint) {
440
678
  canvas.clear();
@@ -444,7 +682,7 @@ class Renderer {
444
682
  canvas.clearWorld(bounds, true);
445
683
  canvas.clipWorld(bounds, true);
446
684
  }
447
- this.__render(bounds, realBounds);
685
+ this.__render(bounds, includes, realBounds);
448
686
  canvas.restore();
449
687
  Run.end(t);
450
688
  }
@@ -453,12 +691,12 @@ class Renderer {
453
691
  const { canvas } = this;
454
692
  canvas.save();
455
693
  canvas.clear();
456
- this.__render(canvas.bounds);
694
+ this.__render(canvas.bounds, true);
457
695
  canvas.restore();
458
696
  Run.end(t);
459
697
  }
460
- __render(bounds, realBounds) {
461
- const options = (bounds === null || bounds === void 0 ? void 0 : bounds.includes(this.target.__world)) ? {} : { bounds };
698
+ __render(bounds, includes, realBounds) {
699
+ const options = bounds.includes(this.target.__world) ? { includes } : { bounds, includes };
462
700
  if (this.needFill)
463
701
  this.canvas.fillWorld(bounds, this.config.fill);
464
702
  if (Debug.showRepaint)
@@ -484,7 +722,7 @@ class Renderer {
484
722
  const { updateBlocks: list } = this;
485
723
  if (list) {
486
724
  const bounds = new Bounds();
487
- bounds.setByList(list);
725
+ bounds.setList(list);
488
726
  list.length = 0;
489
727
  list.push(bounds);
490
728
  }
@@ -493,12 +731,12 @@ class Renderer {
493
731
  const startTime = Date.now();
494
732
  Platform.requestRender(() => {
495
733
  this.FPS = Math.min(60, Math.ceil(1000 / (Date.now() - startTime)));
496
- if (this.changed) {
497
- if (this.running && this.canvas.view)
734
+ if (this.running) {
735
+ this.target.emit(AnimateEvent.FRAME);
736
+ if (this.changed && this.canvas.view)
498
737
  this.render();
738
+ this.target.emit(RenderEvent.NEXT);
499
739
  }
500
- if (this.running)
501
- this.target.emit(AnimateEvent.FRAME);
502
740
  if (this.target)
503
741
  this.__requestRender();
504
742
  });
@@ -511,7 +749,7 @@ class Renderer {
511
749
  const bounds = new Bounds(0, 0, width, height);
512
750
  if (!bounds.includes(this.target.__world) || this.needFill || !e.samePixelRatio) {
513
751
  this.addBlock(this.canvas.bounds);
514
- this.target.forceUpdate('blendMode');
752
+ this.target.forceUpdate('surface');
515
753
  }
516
754
  }
517
755
  }
@@ -524,7 +762,7 @@ class Renderer {
524
762
  empty = (!leaf.__world.width || !leaf.__world.height);
525
763
  if (empty) {
526
764
  if (!leaf.isLeafer)
527
- debug$1.warn(leaf.innerName, ': empty');
765
+ debug$1.tip(leaf.innerName, ': empty');
528
766
  empty = (!leaf.isBranch || leaf.isBranchLeaf);
529
767
  }
530
768
  return empty;
@@ -551,15 +789,13 @@ class Renderer {
551
789
  if (this.target) {
552
790
  this.stop();
553
791
  this.__removeListenEvents();
554
- this.target = null;
555
- this.canvas = null;
556
- this.config = null;
792
+ this.target = this.canvas = this.config = null;
557
793
  }
558
794
  }
559
795
  }
560
796
 
561
797
  const { hitRadiusPoint } = BoundsHelper;
562
- class FindPath {
798
+ class Picker {
563
799
  constructor(target, selector) {
564
800
  this.target = target;
565
801
  this.selector = selector;
@@ -571,15 +807,17 @@ class FindPath {
571
807
  options = {};
572
808
  const through = options.through || false;
573
809
  const ignoreHittable = options.ignoreHittable || false;
810
+ const target = options.target || this.target;
574
811
  this.exclude = options.exclude || null;
575
812
  this.point = { x: hitPoint.x, y: hitPoint.y, radiusX: hitRadius, radiusY: hitRadius };
576
- this.findList = [];
577
- this.eachFind(this.target.children, this.target.__onlyHitMask);
813
+ this.findList = options.findList || [];
814
+ if (!options.findList)
815
+ this.eachFind(target.children, target.__onlyHitMask);
578
816
  const list = this.findList;
579
817
  const leaf = this.getBestMatchLeaf();
580
818
  const path = ignoreHittable ? this.getPath(leaf) : this.getHitablePath(leaf);
581
819
  this.clear();
582
- return through ? { path, leaf, throughPath: list.length ? this.getThroughPath(list) : path } : { path, leaf };
820
+ return through ? { path, target: leaf, throughPath: list.length ? this.getThroughPath(list) : path } : { path, target: leaf };
583
821
  }
584
822
  getBestMatchLeaf() {
585
823
  const { findList: targets } = this;
@@ -602,20 +840,20 @@ class FindPath {
602
840
  getPath(leaf) {
603
841
  const path = new LeafList();
604
842
  while (leaf) {
605
- path.push(leaf);
843
+ path.add(leaf);
606
844
  leaf = leaf.parent;
607
845
  }
608
- path.push(this.target);
846
+ path.add(this.target);
609
847
  return path;
610
848
  }
611
849
  getHitablePath(leaf) {
612
- const path = this.getPath(leaf);
850
+ const path = this.getPath(leaf && leaf.hittable ? leaf : null);
613
851
  let item, hittablePath = new LeafList();
614
852
  for (let i = path.list.length - 1; i > -1; i--) {
615
853
  item = path.list[i];
616
854
  if (!item.__.hittable)
617
855
  break;
618
- hittablePath.unshift(item);
856
+ hittablePath.addAt(item, 0);
619
857
  if (!item.__.hitChildren)
620
858
  break;
621
859
  }
@@ -634,7 +872,7 @@ class FindPath {
634
872
  leaf = path.list[j];
635
873
  if (nextPath && nextPath.has(leaf))
636
874
  break;
637
- throughPath.push(leaf);
875
+ throughPath.add(leaf);
638
876
  }
639
877
  }
640
878
  return throughPath;
@@ -644,7 +882,7 @@ class FindPath {
644
882
  const { point } = this, len = children.length;
645
883
  for (let i = len - 1; i > -1; i--) {
646
884
  child = children[i];
647
- if (!child.__.visible || (hitMask && !child.__.isMask))
885
+ if (!child.__.visible || (hitMask && !child.__.mask))
648
886
  continue;
649
887
  hit = child.__.hitRadius ? true : hitRadiusPoint(child.__world, point);
650
888
  if (child.isBranch) {
@@ -676,120 +914,113 @@ class FindPath {
676
914
  }
677
915
  }
678
916
 
917
+ const { Yes, NoAndSkip, YesAndSkip } = Answer;
679
918
  class Selector {
680
919
  constructor(target, userConfig) {
681
920
  this.config = {};
682
- this.innerIdList = {};
683
- this.idList = {};
684
- this.classNameList = {};
685
- this.tagNameList = {};
921
+ this.innerIdMap = {};
922
+ this.idMap = {};
923
+ this.methods = {
924
+ id: (leaf, name) => leaf.id === name ? (this.idMap[name] = leaf, 1) : 0,
925
+ innerId: (leaf, innerId) => leaf.innerId === innerId ? (this.innerIdMap[innerId] = leaf, 1) : 0,
926
+ className: (leaf, name) => leaf.className === name ? 1 : 0,
927
+ tag: (leaf, name) => leaf.__tag === name ? 1 : 0
928
+ };
686
929
  this.target = target;
687
930
  if (userConfig)
688
931
  this.config = DataHelper.default(userConfig, this.config);
689
- this.findPath = new FindPath(target, this);
932
+ this.picker = new Picker(target, this);
690
933
  this.__listenEvents();
691
934
  }
935
+ getBy(condition, branch, one, options) {
936
+ switch (typeof condition) {
937
+ case 'number':
938
+ const leaf = this.getByInnerId(condition, branch);
939
+ return one ? leaf : (leaf ? [leaf] : []);
940
+ case 'string':
941
+ switch (condition[0]) {
942
+ case '#':
943
+ const leaf = this.getById(condition.substring(1), branch);
944
+ return one ? leaf : (leaf ? [leaf] : []);
945
+ case '.':
946
+ return this.getByMethod(this.methods.className, branch, one, condition.substring(1));
947
+ default:
948
+ return this.getByMethod(this.methods.tag, branch, one, condition);
949
+ }
950
+ case 'function':
951
+ return this.getByMethod(condition, branch, one, options);
952
+ }
953
+ }
692
954
  getByPoint(hitPoint, hitRadius, options) {
693
955
  if (Platform.name === 'node')
694
956
  this.target.emit(LayoutEvent.CHECK_UPDATE);
695
- return this.findPath.getByPoint(hitPoint, hitRadius, options);
696
- }
697
- find(name, branch) {
698
- if (typeof name === 'number') {
699
- return this.getByInnerId(name, branch);
700
- }
701
- else if (name.startsWith('#')) {
702
- return this.getById(name.substring(1), branch);
703
- }
704
- else if (name.startsWith('.')) {
705
- return this.getByClassName(name.substring(1), branch);
706
- }
707
- else {
708
- return this.getByTagName(name, branch);
709
- }
957
+ return this.picker.getByPoint(hitPoint, hitRadius, options);
710
958
  }
711
- getByInnerId(name, branch) {
712
- let cache = this.innerIdList[name];
959
+ getByInnerId(innerId, branch) {
960
+ const cache = this.innerIdMap[innerId];
713
961
  if (cache)
714
962
  return cache;
715
- if (!branch)
716
- branch = this.target;
717
- let find;
718
- this.loopFind(branch, (leaf) => {
719
- if (leaf.innerId === name) {
720
- find = leaf;
721
- this.innerIdList[name] = find;
722
- return true;
723
- }
724
- else {
725
- return false;
726
- }
727
- });
728
- return find;
963
+ this.eachFind(this.toChildren(branch), this.methods.innerId, null, innerId);
964
+ return this.findLeaf;
729
965
  }
730
- getById(name, branch) {
731
- let cache = this.idList[name];
732
- if (cache)
966
+ getById(id, branch) {
967
+ const cache = this.idMap[id];
968
+ if (cache && LeafHelper.hasParent(cache, branch || this.target))
733
969
  return cache;
734
- if (!branch)
735
- branch = this.target;
736
- let find;
737
- this.loopFind(branch, (leaf) => {
738
- if (leaf.id === name) {
739
- find = leaf;
740
- this.idList[name] = find;
741
- return true;
742
- }
743
- else {
744
- return false;
745
- }
746
- });
747
- return find;
748
- }
749
- getByClassName(name, branch) {
750
- if (!branch)
751
- branch = this.target;
752
- let find = [];
753
- this.loopFind(branch, (leaf) => {
754
- if (leaf.className === name)
755
- find.push(leaf);
756
- return false;
757
- });
758
- return find;
759
- }
760
- getByTagName(name, branch) {
761
- if (!branch)
762
- branch = this.target;
763
- let find = [];
764
- this.loopFind(branch, (leaf) => {
765
- if (leaf.__tag === name)
766
- find.push(leaf);
767
- return false;
768
- });
769
- return find;
970
+ this.eachFind(this.toChildren(branch), this.methods.id, null, id);
971
+ return this.findLeaf;
770
972
  }
771
- loopFind(branch, find) {
772
- if (find(branch))
773
- return;
774
- const { children } = branch;
973
+ getByClassName(className, branch) {
974
+ return this.getByMethod(this.methods.className, branch, false, className);
975
+ }
976
+ getByTag(tag, branch) {
977
+ return this.getByMethod(this.methods.tag, branch, false, tag);
978
+ }
979
+ getByMethod(method, branch, one, options) {
980
+ const list = one ? null : [];
981
+ this.eachFind(this.toChildren(branch), method, list, options);
982
+ return list || this.findLeaf;
983
+ }
984
+ eachFind(children, method, list, options) {
985
+ let child, result;
775
986
  for (let i = 0, len = children.length; i < len; i++) {
776
- branch = children[i];
777
- if (find(branch))
778
- return;
779
- if (branch.isBranch)
780
- this.loopFind(branch, find);
987
+ child = children[i];
988
+ result = method(child, options);
989
+ if (result === Yes || result === YesAndSkip) {
990
+ if (list) {
991
+ list.push(child);
992
+ }
993
+ else {
994
+ this.findLeaf = child;
995
+ return;
996
+ }
997
+ }
998
+ if (child.isBranch && result < NoAndSkip)
999
+ this.eachFind(child.children, method, list, options);
781
1000
  }
782
1001
  }
1002
+ toChildren(branch) {
1003
+ this.findLeaf = null;
1004
+ return [branch || this.target];
1005
+ }
783
1006
  __onRemoveChild(event) {
784
- const target = event.target;
785
- if (this.idList[target.id])
786
- this.idList[target.id] = null;
787
- if (this.innerIdList[target.id])
788
- this.innerIdList[target.innerId] = null;
1007
+ const { id, innerId } = event.child;
1008
+ if (this.idMap[id])
1009
+ delete this.idMap[id];
1010
+ if (this.innerIdMap[innerId])
1011
+ delete this.innerIdMap[innerId];
1012
+ }
1013
+ __checkIdChange(event) {
1014
+ if (event.attrName === 'id') {
1015
+ const id = event.oldValue;
1016
+ if (this.idMap[id])
1017
+ delete this.idMap[id];
1018
+ }
789
1019
  }
790
1020
  __listenEvents() {
791
1021
  this.__eventIds = [
792
- this.target.on_(ChildEvent.REMOVE, this.__onRemoveChild, this)
1022
+ this.target.on_(ChildEvent.REMOVE, this.__onRemoveChild, this),
1023
+ this.target.on_(PropertyEvent.CHANGE, this.__checkIdChange, this)
793
1024
  ];
794
1025
  }
795
1026
  __removeListenEvents() {
@@ -799,11 +1030,10 @@ class Selector {
799
1030
  destroy() {
800
1031
  if (this.__eventIds.length) {
801
1032
  this.__removeListenEvents();
802
- this.findPath.destroy();
803
- this.innerIdList = {};
804
- this.idList = {};
805
- this.classNameList = {};
806
- this.tagNameList = {};
1033
+ this.picker.destroy();
1034
+ this.findLeaf = null;
1035
+ this.innerIdMap = {};
1036
+ this.idMap = {};
807
1037
  }
808
1038
  }
809
1039
  }
@@ -816,169 +1046,6 @@ Object.assign(Creator, {
816
1046
  });
817
1047
  Platform.layout = Layouter.fullLayout;
818
1048
 
819
- const debug = Debug.get('LeaferCanvas');
820
- class LeaferCanvas extends LeaferCanvasBase {
821
- init() {
822
- const { view } = this.config;
823
- view ? this.__createViewFrom(view) : this.__createView();
824
- const { style } = this.view;
825
- style.display || (style.display = 'block');
826
- this.parentView = this.view.parentElement;
827
- if (Platform.syncDomFont && !this.parentView) {
828
- this.view.style.display = 'none';
829
- document.body.appendChild(this.view);
830
- }
831
- this.__createContext();
832
- if (!this.autoLayout)
833
- this.resize(this.config);
834
- }
835
- set backgroundColor(color) { this.view.style.backgroundColor = color; }
836
- get backgroundColor() { return this.view.style.backgroundColor; }
837
- set hittable(hittable) { this.view.style.pointerEvents = hittable ? 'auto' : 'none'; }
838
- get hittable() { return this.view.style.pointerEvents !== 'none'; }
839
- __createView() {
840
- this.view = document.createElement('canvas');
841
- }
842
- setCursor(cursor) {
843
- const list = [];
844
- this.eachCursor(cursor, list);
845
- if (typeof list[list.length - 1] === 'object')
846
- list.push('default');
847
- this.view.style.cursor = list.map(item => (typeof item === 'object') ? `url(${item.url}) ${item.x || 0} ${item.y || 0}` : item).join(',');
848
- }
849
- eachCursor(cursor, list, level = 0) {
850
- level++;
851
- if (cursor instanceof Array) {
852
- cursor.forEach(item => this.eachCursor(item, list, level));
853
- }
854
- else {
855
- const custom = typeof cursor === 'string' && Cursor.get(cursor);
856
- if (custom && level < 2) {
857
- this.eachCursor(custom, list, level);
858
- }
859
- else {
860
- list.push(cursor);
861
- }
862
- }
863
- }
864
- __createViewFrom(inputView) {
865
- let find = (typeof inputView === 'string') ? document.getElementById(inputView) : inputView;
866
- if (find) {
867
- if (find instanceof HTMLCanvasElement) {
868
- this.view = find;
869
- }
870
- else {
871
- let parent = find;
872
- if (find === window || find === document) {
873
- const div = document.createElement('div');
874
- const { style } = div;
875
- style.position = 'absolute';
876
- style.top = style.bottom = style.left = style.right = '0px';
877
- document.body.appendChild(div);
878
- parent = div;
879
- }
880
- this.__createView();
881
- const view = this.view;
882
- if (parent.hasChildNodes()) {
883
- const { style } = view;
884
- style.position = 'absolute';
885
- style.top = style.left = '0px';
886
- parent.style.position || (parent.style.position = 'relative');
887
- }
888
- parent.appendChild(view);
889
- }
890
- }
891
- else {
892
- debug.error(`no id: ${inputView}`);
893
- this.__createView();
894
- }
895
- }
896
- updateViewSize() {
897
- const { width, height, pixelRatio } = this;
898
- const { style } = this.view;
899
- style.width = width + 'px';
900
- style.height = height + 'px';
901
- this.view.width = width * pixelRatio;
902
- this.view.height = height * pixelRatio;
903
- }
904
- updateClientBounds() {
905
- this.clientBounds = this.view.getBoundingClientRect();
906
- }
907
- startAutoLayout(autoBounds, listener) {
908
- this.autoBounds = autoBounds;
909
- this.resizeListener = listener;
910
- try {
911
- this.resizeObserver = new ResizeObserver((entries) => {
912
- this.updateClientBounds();
913
- for (const entry of entries)
914
- this.checkAutoBounds(entry.contentRect);
915
- });
916
- const parent = this.parentView;
917
- if (parent) {
918
- this.resizeObserver.observe(parent);
919
- this.checkAutoBounds(parent.getBoundingClientRect());
920
- }
921
- }
922
- catch (_a) {
923
- this.imitateResizeObserver();
924
- }
925
- }
926
- imitateResizeObserver() {
927
- if (this.autoLayout) {
928
- if (this.parentView)
929
- this.checkAutoBounds(this.parentView.getBoundingClientRect());
930
- Platform.requestRender(this.imitateResizeObserver.bind(this));
931
- }
932
- }
933
- checkAutoBounds(parentSize) {
934
- const view = this.view;
935
- const { x, y, width, height } = this.autoBounds.getBoundsFrom(parentSize);
936
- if (width !== this.width || height !== this.height) {
937
- const { style } = view;
938
- const { pixelRatio } = this;
939
- style.marginLeft = x + 'px';
940
- style.marginTop = y + 'px';
941
- const size = { width, height, pixelRatio };
942
- const oldSize = {};
943
- DataHelper.copyAttrs(oldSize, this, canvasSizeAttrs);
944
- this.resize(size);
945
- if (this.width !== undefined)
946
- this.resizeListener(new ResizeEvent(size, oldSize));
947
- }
948
- }
949
- stopAutoLayout() {
950
- this.autoLayout = false;
951
- this.resizeListener = null;
952
- if (this.resizeObserver) {
953
- this.resizeObserver.disconnect();
954
- this.resizeObserver = null;
955
- }
956
- }
957
- unrealCanvas() {
958
- if (!this.unreal && this.parentView) {
959
- const view = this.view;
960
- if (view)
961
- view.remove();
962
- this.view = this.parentView;
963
- this.unreal = true;
964
- }
965
- }
966
- destroy() {
967
- if (this.view) {
968
- this.stopAutoLayout();
969
- if (!this.unreal) {
970
- const view = this.view;
971
- if (view.parentElement)
972
- view.remove();
973
- }
974
- super.destroy();
975
- }
976
- }
977
- }
978
-
979
- canvasPatch(CanvasRenderingContext2D.prototype);
980
- canvasPatch(Path2D.prototype);
981
-
982
1049
  const PointerEventHelper = {
983
1050
  convert(e, local) {
984
1051
  const base = InteractionHelper.getBase(e);
@@ -1025,7 +1092,7 @@ const WheelEventHelper = {
1025
1092
  let { zoomMode, zoomSpeed } = config;
1026
1093
  const delta = e.deltaY || e.deltaX;
1027
1094
  if (zoomMode) {
1028
- zoom = !e.deltaX && (Platform.intWheelDeltaY ? Math.abs(delta) > 17 : Math.ceil(delta) !== delta);
1095
+ zoom = (zoomMode === 'mouse') ? true : (!e.deltaX && (Platform.intWheelDeltaY ? Math.abs(delta) > 17 : Math.ceil(delta) !== delta));
1029
1096
  if (e.shiftKey || e.metaKey || e.ctrlKey)
1030
1097
  zoom = true;
1031
1098
  }
@@ -1035,7 +1102,7 @@ const WheelEventHelper = {
1035
1102
  if (zoom) {
1036
1103
  zoomSpeed = MathHelper.within(zoomSpeed, 0, 1);
1037
1104
  const min = e.deltaY ? config.delta.y : config.delta.x;
1038
- scale = 1 - delta / (min * 25 * (1 - zoomSpeed) + 10);
1105
+ scale = 1 - delta / (min * 4) * zoomSpeed;
1039
1106
  if (scale < 0.5)
1040
1107
  scale = 0.5;
1041
1108
  if (scale >= 1.5)
@@ -1062,6 +1129,7 @@ class Interaction extends InteractionBase {
1062
1129
  'pointerdown': this.onPointerDown,
1063
1130
  'mousedown': this.onMouseDown,
1064
1131
  'touchstart': this.onTouchStart,
1132
+ 'contextmenu': this.onContextMenu,
1065
1133
  'wheel': this.onWheel,
1066
1134
  'gesturestart': this.onGesturestart,
1067
1135
  'gesturechange': this.onGesturechange,
@@ -1134,6 +1202,11 @@ class Interaction extends InteractionBase {
1134
1202
  onKeyUp(e) {
1135
1203
  this.keyUp(KeyEventHelper.convert(e));
1136
1204
  }
1205
+ onContextMenu(e) {
1206
+ if (this.config.pointer.preventDefaultMenu)
1207
+ e.preventDefault();
1208
+ this.menu(PointerEventHelper.convert(e, this.getLocal(e)));
1209
+ }
1137
1210
  onScroll() {
1138
1211
  this.canvas.updateClientBounds();
1139
1212
  }
@@ -1288,6 +1361,29 @@ class Interaction extends InteractionBase {
1288
1361
  this.preventDefaultWheel(e);
1289
1362
  this.transformEnd();
1290
1363
  }
1364
+ setCursor(cursor) {
1365
+ super.setCursor(cursor);
1366
+ const list = [];
1367
+ this.eachCursor(cursor, list);
1368
+ if (typeof list[list.length - 1] === 'object')
1369
+ list.push('default');
1370
+ this.canvas.view.style.cursor = list.map(item => (typeof item === 'object') ? `url(${item.url}) ${item.x || 0} ${item.y || 0}` : item).join(',');
1371
+ }
1372
+ eachCursor(cursor, list, level = 0) {
1373
+ level++;
1374
+ if (cursor instanceof Array) {
1375
+ cursor.forEach(item => this.eachCursor(item, list, level));
1376
+ }
1377
+ else {
1378
+ const custom = typeof cursor === 'string' && Cursor.get(cursor);
1379
+ if (custom && level < 2) {
1380
+ this.eachCursor(custom, list, level);
1381
+ }
1382
+ else {
1383
+ list.push(cursor);
1384
+ }
1385
+ }
1386
+ }
1291
1387
  destroy() {
1292
1388
  if (this.view) {
1293
1389
  super.destroy();
@@ -1297,416 +1393,34 @@ class Interaction extends InteractionBase {
1297
1393
  }
1298
1394
  }
1299
1395
 
1300
- const { mineType, fileType } = FileHelper;
1301
- Object.assign(Creator, {
1302
- canvas: (options, manager) => new LeaferCanvas(options, manager),
1303
- image: (options) => new LeaferImage(options),
1304
- hitCanvas: (options, manager) => new LeaferCanvas(options, manager),
1305
- interaction: (target, canvas, selector, options) => new Interaction(target, canvas, selector, options),
1306
- });
1307
- function useCanvas(_canvasType, _power) {
1308
- Platform.origin = {
1309
- createCanvas(width, height) {
1310
- const canvas = document.createElement('canvas');
1311
- canvas.width = width;
1312
- canvas.height = height;
1313
- return canvas;
1314
- },
1315
- canvasToDataURL: (canvas, type, quality) => canvas.toDataURL(mineType(type), quality),
1316
- canvasToBolb: (canvas, type, quality) => new Promise((resolve) => canvas.toBlob(resolve, mineType(type), quality)),
1317
- canvasSaveAs: (canvas, filename, quality) => {
1318
- return new Promise((resolve) => {
1319
- let el = document.createElement('a');
1320
- el.href = canvas.toDataURL(mineType(fileType(filename)), quality);
1321
- el.download = filename;
1322
- document.body.appendChild(el);
1323
- el.click();
1324
- document.body.removeChild(el);
1325
- resolve();
1326
- });
1327
- },
1328
- loadImage(src) {
1329
- return new Promise((resolve, reject) => {
1330
- const img = new Image();
1331
- img.setAttribute('crossOrigin', 'anonymous');
1332
- img.crossOrigin = 'anonymous';
1333
- img.onload = () => { resolve(img); };
1334
- img.onerror = (e) => { reject(e); };
1335
- if (!src.startsWith('data:') && Platform.imageSuffix)
1336
- src += (src.includes("?") ? "&" : "?") + Platform.imageSuffix;
1337
- img.src = src;
1396
+ function fillText(ui, canvas) {
1397
+ let row;
1398
+ const { rows, decorationY, decorationHeight } = ui.__.__textDrawData;
1399
+ for (let i = 0, len = rows.length; i < len; i++) {
1400
+ row = rows[i];
1401
+ if (row.text) {
1402
+ canvas.fillText(row.text, row.x, row.y);
1403
+ }
1404
+ else if (row.data) {
1405
+ row.data.forEach(charData => {
1406
+ canvas.fillText(charData.char, charData.x, row.y);
1338
1407
  });
1339
1408
  }
1340
- };
1341
- Platform.canvas = Creator.canvas();
1342
- Platform.conicGradientSupport = !!Platform.canvas.context.createConicGradient;
1343
- }
1344
- Platform.name = 'web';
1345
- Platform.isMobile = 'ontouchstart' in window;
1346
- Platform.requestRender = function (render) { window.requestAnimationFrame(render); };
1347
- Platform.devicePixelRatio = devicePixelRatio;
1348
- Platform.realtimeLayout = true;
1349
- const { userAgent } = navigator;
1350
- if (userAgent.indexOf("Firefox") > -1) {
1351
- Platform.conicGradientRotate90 = true;
1352
- Platform.intWheelDeltaY = true;
1353
- Platform.syncDomFont = true;
1354
- }
1355
- else if (userAgent.indexOf("Safari") > -1 && userAgent.indexOf("Chrome") === -1) {
1356
- Platform.fullImageShadow = true;
1357
- }
1358
- if (userAgent.indexOf('Windows') > -1) {
1359
- Platform.os = 'Windows';
1360
- Platform.intWheelDeltaY = true;
1361
- }
1362
- else if (userAgent.indexOf('Mac') > -1) {
1363
- Platform.os = 'Mac';
1364
- }
1365
- else if (userAgent.indexOf('Linux') > -1) {
1366
- Platform.os = 'Linux';
1409
+ if (decorationY)
1410
+ canvas.fillRect(row.x, row.y + decorationY, row.width, decorationHeight);
1411
+ }
1367
1412
  }
1368
1413
 
1369
- const { get: get$4, rotateOfOuter: rotateOfOuter$2, translate: translate$1, scaleOfOuter: scaleOfOuter$2, scale: scaleHelper$1, rotate } = MatrixHelper;
1370
- function fillOrFitMode(data, mode, box, width, height, rotation) {
1371
- const transform = get$4();
1372
- const swap = rotation && rotation !== 180;
1373
- const sw = box.width / (swap ? height : width);
1374
- const sh = box.height / (swap ? width : height);
1375
- const scale = mode === 'fit' ? Math.min(sw, sh) : Math.max(sw, sh);
1376
- const x = box.x + (box.width - width * scale) / 2;
1377
- const y = box.y + (box.height - height * scale) / 2;
1378
- translate$1(transform, x, y);
1379
- scaleHelper$1(transform, scale);
1380
- if (rotation)
1381
- rotateOfOuter$2(transform, { x: box.x + box.width / 2, y: box.y + box.height / 2 }, rotation);
1382
- data.scaleX = data.scaleY = scale;
1383
- data.transform = transform;
1384
- }
1385
- function clipMode(data, box, offset, scale, rotation) {
1386
- const transform = get$4();
1387
- translate$1(transform, box.x, box.y);
1388
- if (offset)
1389
- translate$1(transform, offset.x, offset.y);
1390
- if (scale) {
1391
- typeof scale === 'number' ? scaleHelper$1(transform, scale) : scaleHelper$1(transform, scale.x, scale.y);
1392
- data.scaleX = transform.a;
1393
- data.scaleY = transform.d;
1394
- }
1395
- if (rotation)
1396
- rotate(transform, rotation);
1397
- data.transform = transform;
1398
- }
1399
- function repeatMode(data, box, width, height, scale, rotation) {
1400
- const transform = get$4();
1401
- if (rotation) {
1402
- rotate(transform, rotation);
1403
- switch (rotation) {
1404
- case 90:
1405
- translate$1(transform, height, 0);
1406
- break;
1407
- case 180:
1408
- translate$1(transform, width, height);
1409
- break;
1410
- case 270:
1411
- translate$1(transform, 0, width);
1412
- break;
1413
- }
1414
- }
1415
- translate$1(transform, box.x, box.y);
1416
- if (scale) {
1417
- scaleOfOuter$2(transform, box, scale);
1418
- data.scaleX = data.scaleY = scale;
1419
- }
1420
- data.transform = transform;
1421
- }
1422
-
1423
- const { get: get$3, translate } = MatrixHelper;
1424
- function createData(leafPaint, image, paint, box) {
1425
- let { width, height } = image;
1426
- const { opacity, mode, offset, scale, rotation, blendMode } = paint;
1427
- const sameBox = box.width === width && box.height === height;
1428
- if (blendMode)
1429
- leafPaint.blendMode = blendMode;
1430
- const data = leafPaint.data = { mode };
1431
- switch (mode) {
1432
- case 'strench':
1433
- if (!sameBox)
1434
- width = box.width, height = box.height;
1435
- if (box.x || box.y) {
1436
- data.transform = get$3();
1437
- translate(data.transform, box.x, box.y);
1438
- }
1439
- break;
1440
- case 'clip':
1441
- if (offset || scale || rotation)
1442
- clipMode(data, box, offset, scale, rotation);
1443
- break;
1444
- case 'repeat':
1445
- if (!sameBox || scale || rotation)
1446
- repeatMode(data, box, width, height, scale, rotation);
1447
- break;
1448
- case 'fit':
1449
- case 'cover':
1450
- default:
1451
- if (!sameBox || rotation)
1452
- fillOrFitMode(data, mode, box, width, height, rotation);
1453
- }
1454
- data.width = width;
1455
- data.height = height;
1456
- if (opacity)
1457
- data.opacity = opacity;
1458
- }
1459
-
1460
- function image(ui, attrName, attrValue, box, firstUse) {
1461
- const leafPaint = { type: attrValue.type };
1462
- const image = leafPaint.image = ImageManager.get(attrValue);
1463
- const event = (firstUse || image.loading) && { target: ui, image, attrName, attrValue };
1464
- if (image.ready) {
1465
- if (hasNaturalSize(ui, attrName, image))
1466
- createData(leafPaint, image, attrValue, box);
1467
- if (firstUse) {
1468
- emit(ImageEvent.LOAD, event);
1469
- emit(ImageEvent.LOADED, event);
1470
- }
1471
- }
1472
- else if (image.error) {
1473
- if (firstUse) {
1474
- ui.forceUpdate('surface');
1475
- event.error = image.error;
1476
- emit(ImageEvent.ERROR, event);
1477
- }
1478
- }
1479
- else {
1480
- if (firstUse)
1481
- emit(ImageEvent.LOAD, event);
1482
- leafPaint.loadId = image.load(() => {
1483
- if (!ui.destroyed) {
1484
- if (hasNaturalSize(ui, attrName, image)) {
1485
- createData(leafPaint, image, attrValue, box);
1486
- ui.forceUpdate('surface');
1487
- }
1488
- emit(ImageEvent.LOADED, event);
1489
- }
1490
- }, (error) => {
1491
- ui.forceUpdate('surface');
1492
- event.error = error;
1493
- emit(ImageEvent.ERROR, event);
1494
- });
1495
- }
1496
- return leafPaint;
1497
- }
1498
- function hasNaturalSize(ui, attrName, image) {
1499
- if (attrName === 'fill' && !ui.__.__naturalWidth) {
1500
- const { __: d } = ui;
1501
- d.__naturalWidth = image.width;
1502
- d.__naturalHeight = image.height;
1503
- if (!d.__getInput('width') || !d.__getInput('height')) {
1504
- ui.forceUpdate('width');
1505
- return false;
1506
- }
1507
- }
1508
- return true;
1509
- }
1510
- function emit(type, data) {
1511
- if (data.target.hasEvent(type))
1512
- data.target.emitEvent(new ImageEvent(type, data));
1513
- }
1514
-
1515
- /******************************************************************************
1516
- Copyright (c) Microsoft Corporation.
1517
-
1518
- Permission to use, copy, modify, and/or distribute this software for any
1519
- purpose with or without fee is hereby granted.
1520
-
1521
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
1522
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
1523
- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
1524
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
1525
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
1526
- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
1527
- PERFORMANCE OF THIS SOFTWARE.
1528
- ***************************************************************************** */
1529
- /* global Reflect, Promise, SuppressedError, Symbol */
1530
-
1531
-
1532
- function __awaiter(thisArg, _arguments, P, generator) {
1533
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
1534
- return new (P || (P = Promise))(function (resolve, reject) {
1535
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
1536
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
1537
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
1538
- step((generator = generator.apply(thisArg, _arguments || [])).next());
1539
- });
1540
- }
1541
-
1542
- typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
1543
- var e = new Error(message);
1544
- return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
1545
- };
1546
-
1547
- const { get: get$2, scale: scaleHelper, copy: copy$1 } = MatrixHelper;
1548
- function createPattern(ui, paint, pixelRatio) {
1549
- let { scaleX, scaleY } = ui.__world;
1550
- const id = scaleX + '-' + scaleY;
1551
- if (paint.patternId !== id && !ui.destroyed) {
1552
- paint.patternId = id;
1553
- scaleX = Math.abs(scaleX);
1554
- scaleY = Math.abs(scaleY);
1555
- const { image, data } = paint;
1556
- const maxWidth = image.isSVG ? 4096 : Math.min(image.width, 4096);
1557
- const maxHeight = image.isSVG ? 4096 : Math.min(image.height, 4096);
1558
- let scale, matrix, { width, height, scaleX: sx, scaleY: sy, opacity, transform, mode } = data;
1559
- if (sx) {
1560
- matrix = get$2();
1561
- copy$1(matrix, transform);
1562
- scaleHelper(matrix, 1 / sx, 1 / sy);
1563
- scaleX *= sx;
1564
- scaleY *= sy;
1565
- }
1566
- scaleX *= pixelRatio;
1567
- scaleY *= pixelRatio;
1568
- width *= scaleX;
1569
- height *= scaleY;
1570
- if (width > maxWidth || height > maxHeight) {
1571
- scale = Math.max(width / maxWidth, height / maxHeight);
1572
- }
1573
- if (scale) {
1574
- scaleX /= scale;
1575
- scaleY /= scale;
1576
- width /= scale;
1577
- height /= scale;
1578
- }
1579
- if (sx) {
1580
- scaleX /= sx;
1581
- scaleY /= sy;
1582
- }
1583
- if (transform || scaleX !== 1 || scaleY !== 1) {
1584
- if (!matrix) {
1585
- matrix = get$2();
1586
- if (transform)
1587
- copy$1(matrix, transform);
1588
- }
1589
- scaleHelper(matrix, 1 / scaleX, 1 / scaleY);
1590
- }
1591
- const style = Platform.canvas.createPattern(image.getCanvas(width < 1 ? 1 : width, height < 1 ? 1 : height, opacity), mode === 'repeat' ? 'repeat' : (Platform.origin.noRepeat || 'no-repeat'));
1592
- try {
1593
- if (paint.transform)
1594
- paint.transform = null;
1595
- if (matrix)
1596
- style.setTransform ? style.setTransform(matrix) : paint.transform = matrix;
1597
- }
1598
- catch (_a) {
1599
- paint.transform = matrix;
1600
- }
1601
- paint.style = style;
1602
- return true;
1603
- }
1604
- else {
1605
- return false;
1606
- }
1607
- }
1608
-
1609
- function checkImage(ui, canvas, paint, allowPaint) {
1610
- const { scaleX, scaleY } = ui.__world;
1611
- if (!paint.data || paint.patternId === scaleX + '-' + scaleY) {
1612
- return false;
1613
- }
1614
- else {
1615
- if (allowPaint) {
1616
- if (paint.image.isSVG && paint.data.mode !== 'repeat') {
1617
- let { width, height } = paint.data;
1618
- width *= scaleX * canvas.pixelRatio;
1619
- height *= scaleY * canvas.pixelRatio;
1620
- allowPaint = width > 4096 || height > 4096;
1621
- }
1622
- else {
1623
- allowPaint = false;
1624
- }
1625
- }
1626
- if (allowPaint) {
1627
- canvas.save();
1628
- canvas.clip();
1629
- const { data } = paint;
1630
- if (paint.blendMode)
1631
- canvas.blendMode = paint.blendMode;
1632
- if (data.opacity)
1633
- canvas.opacity *= data.opacity;
1634
- if (data.transform)
1635
- canvas.transform(data.transform);
1636
- canvas.drawImage(paint.image.view, 0, 0, data.width, data.height);
1637
- canvas.restore();
1638
- return true;
1639
- }
1640
- else {
1641
- if (!paint.style) {
1642
- createPattern(ui, paint, canvas.pixelRatio);
1643
- }
1644
- else {
1645
- ImageManager.patternTasker.add(() => __awaiter(this, void 0, void 0, function* () {
1646
- if (canvas.bounds.hit(ui.__world) && createPattern(ui, paint, canvas.pixelRatio))
1647
- ui.forceUpdate('surface');
1648
- }), 300);
1649
- }
1650
- return false;
1651
- }
1652
- }
1653
- }
1654
-
1655
- function recycleImage(data, attrName) {
1656
- const paints = (attrName === 'fill' ? data._fill : data._stroke);
1657
- if (paints instanceof Array) {
1658
- let image, recycleMap, input, url;
1659
- for (let i = 0, len = paints.length; i < len; i++) {
1660
- image = paints[i].image;
1661
- url = image && image.url;
1662
- if (url) {
1663
- if (!recycleMap)
1664
- recycleMap = {};
1665
- recycleMap[url] = true;
1666
- ImageManager.recycle(image);
1667
- if (image.loading) {
1668
- if (!input) {
1669
- input = (data.__input && data.__input[attrName]) || [];
1670
- if (!(input instanceof Array))
1671
- input = [input];
1672
- }
1673
- image.unload(paints[i].loadId, !input.some((item) => item.url === url));
1674
- }
1675
- }
1676
- }
1677
- return recycleMap;
1678
- }
1679
- return null;
1680
- }
1681
-
1682
- function fillText(ui, canvas) {
1683
- let row;
1684
- const { rows, decorationY, decorationHeight } = ui.__.__textDrawData;
1685
- for (let i = 0, len = rows.length; i < len; i++) {
1686
- row = rows[i];
1687
- if (row.text) {
1688
- canvas.fillText(row.text, row.x, row.y);
1689
- }
1690
- else if (row.data) {
1691
- row.data.forEach(charData => {
1692
- canvas.fillText(charData.char, charData.x, row.y);
1693
- });
1694
- }
1695
- if (decorationY)
1696
- canvas.fillRect(row.x, row.y + decorationY, row.width, decorationHeight);
1697
- }
1698
- }
1699
-
1700
- function fill(ui, canvas, fill) {
1414
+ function fill(fill, ui, canvas) {
1701
1415
  canvas.fillStyle = fill;
1702
1416
  ui.__.__font ? fillText(ui, canvas) : (ui.__.windingRule ? canvas.fill(ui.__.windingRule) : canvas.fill());
1703
1417
  }
1704
- function fills(ui, canvas, fills) {
1418
+ function fills(fills, ui, canvas) {
1705
1419
  let item;
1706
1420
  const { windingRule, __font } = ui.__;
1707
1421
  for (let i = 0, len = fills.length; i < len; i++) {
1708
1422
  item = fills[i];
1709
- if (item.image && checkImage(ui, canvas, item, !__font))
1423
+ if (item.image && PaintImage.checkImage(ui, canvas, item, !__font))
1710
1424
  continue;
1711
1425
  if (item.style) {
1712
1426
  canvas.fillStyle = item.style;
@@ -1732,33 +1446,38 @@ function fills(ui, canvas, fills) {
1732
1446
  }
1733
1447
  }
1734
1448
 
1735
- function strokeText(ui, canvas, stroke) {
1449
+ function strokeText(stroke, ui, canvas) {
1736
1450
  const { strokeAlign } = ui.__;
1737
1451
  const isStrokes = typeof stroke !== 'string';
1738
1452
  switch (strokeAlign) {
1739
1453
  case 'center':
1740
1454
  canvas.setStroke(isStrokes ? undefined : stroke, ui.__.strokeWidth, ui.__);
1741
- isStrokes ? drawStrokesStyle(ui, stroke, canvas, true) : drawTextStroke(ui, canvas);
1455
+ isStrokes ? drawStrokesStyle(stroke, true, ui, canvas) : drawTextStroke(ui, canvas);
1742
1456
  break;
1743
1457
  case 'inside':
1744
- drawAlignStroke(ui, canvas, stroke, 'inside', isStrokes);
1458
+ drawAlignStroke('inside', stroke, isStrokes, ui, canvas);
1745
1459
  break;
1746
1460
  case 'outside':
1747
- drawAlignStroke(ui, canvas, stroke, 'outside', isStrokes);
1461
+ drawAlignStroke('outside', stroke, isStrokes, ui, canvas);
1748
1462
  break;
1749
1463
  }
1750
1464
  }
1751
- function drawAlignStroke(ui, canvas, stroke, align, isStrokes) {
1752
- const { strokeWidth, __font } = ui.__;
1753
- const out = canvas.getSameCanvas(true);
1754
- out.setStroke(isStrokes ? undefined : stroke, strokeWidth * 2, ui.__);
1465
+ function drawAlignStroke(align, stroke, isStrokes, ui, canvas) {
1466
+ const { __strokeWidth, __font } = ui.__;
1467
+ const out = canvas.getSameCanvas(true, true);
1468
+ out.setStroke(isStrokes ? undefined : stroke, __strokeWidth * 2, ui.__);
1755
1469
  out.font = __font;
1756
- isStrokes ? drawStrokesStyle(ui, stroke, out, true) : drawTextStroke(ui, out);
1470
+ isStrokes ? drawStrokesStyle(stroke, true, ui, out) : drawTextStroke(ui, out);
1757
1471
  out.blendMode = align === 'outside' ? 'destination-out' : 'destination-in';
1758
1472
  fillText(ui, out);
1759
1473
  out.blendMode = 'normal';
1760
- canvas.copyWorldToInner(out, ui.__world, ui.__layout.renderBounds);
1761
- out.recycle();
1474
+ if (ui.__worldFlipped) {
1475
+ canvas.copyWorldByReset(out, ui.__nowWorld);
1476
+ }
1477
+ else {
1478
+ canvas.copyWorldToInner(out, ui.__nowWorld, ui.__layout.renderBounds);
1479
+ }
1480
+ out.recycle(ui.__nowWorld);
1762
1481
  }
1763
1482
  function drawTextStroke(ui, canvas) {
1764
1483
  let row;
@@ -1777,11 +1496,11 @@ function drawTextStroke(ui, canvas) {
1777
1496
  canvas.strokeRect(row.x, row.y + decorationY, row.width, decorationHeight);
1778
1497
  }
1779
1498
  }
1780
- function drawStrokesStyle(ui, strokes, canvas, isText) {
1499
+ function drawStrokesStyle(strokes, isText, ui, canvas) {
1781
1500
  let item;
1782
1501
  for (let i = 0, len = strokes.length; i < len; i++) {
1783
1502
  item = strokes[i];
1784
- if (item.image && checkImage(ui, canvas, item, false))
1503
+ if (item.image && PaintImage.checkImage(ui, canvas, item, false))
1785
1504
  continue;
1786
1505
  if (item.style) {
1787
1506
  canvas.strokeStyle = item.style;
@@ -1797,121 +1516,575 @@ function drawStrokesStyle(ui, strokes, canvas, isText) {
1797
1516
  }
1798
1517
  }
1799
1518
 
1800
- function stroke(ui, canvas, stroke) {
1519
+ function stroke(stroke, ui, canvas) {
1801
1520
  const options = ui.__;
1802
- const { strokeWidth, strokeAlign, __font } = options;
1803
- if (!strokeWidth)
1521
+ const { __strokeWidth, strokeAlign, __font } = options;
1522
+ if (!__strokeWidth)
1804
1523
  return;
1805
1524
  if (__font) {
1806
- strokeText(ui, canvas, stroke);
1525
+ strokeText(stroke, ui, canvas);
1807
1526
  }
1808
1527
  else {
1809
1528
  switch (strokeAlign) {
1810
1529
  case 'center':
1811
- canvas.setStroke(stroke, strokeWidth, options);
1530
+ canvas.setStroke(stroke, __strokeWidth, options);
1812
1531
  canvas.stroke();
1813
1532
  break;
1814
1533
  case 'inside':
1815
1534
  canvas.save();
1816
- canvas.setStroke(stroke, strokeWidth * 2, options);
1535
+ canvas.setStroke(stroke, __strokeWidth * 2, options);
1817
1536
  options.windingRule ? canvas.clip(options.windingRule) : canvas.clip();
1818
1537
  canvas.stroke();
1819
1538
  canvas.restore();
1820
1539
  break;
1821
1540
  case 'outside':
1822
- const out = canvas.getSameCanvas(true);
1823
- out.setStroke(stroke, strokeWidth * 2, ui.__);
1541
+ const out = canvas.getSameCanvas(true, true);
1542
+ out.setStroke(stroke, __strokeWidth * 2, options);
1824
1543
  ui.__drawRenderPath(out);
1825
1544
  out.stroke();
1826
1545
  options.windingRule ? out.clip(options.windingRule) : out.clip();
1827
1546
  out.clearWorld(ui.__layout.renderBounds);
1828
- canvas.copyWorldToInner(out, ui.__world, ui.__layout.renderBounds);
1829
- out.recycle();
1547
+ if (ui.__worldFlipped) {
1548
+ canvas.copyWorldByReset(out, ui.__nowWorld);
1549
+ }
1550
+ else {
1551
+ canvas.copyWorldToInner(out, ui.__nowWorld, ui.__layout.renderBounds);
1552
+ }
1553
+ out.recycle(ui.__nowWorld);
1554
+ break;
1555
+ }
1556
+ }
1557
+ }
1558
+ function strokes(strokes, ui, canvas) {
1559
+ const options = ui.__;
1560
+ const { __strokeWidth, strokeAlign, __font } = options;
1561
+ if (!__strokeWidth)
1562
+ return;
1563
+ if (__font) {
1564
+ strokeText(strokes, ui, canvas);
1565
+ }
1566
+ else {
1567
+ switch (strokeAlign) {
1568
+ case 'center':
1569
+ canvas.setStroke(undefined, __strokeWidth, options);
1570
+ drawStrokesStyle(strokes, false, ui, canvas);
1571
+ break;
1572
+ case 'inside':
1573
+ canvas.save();
1574
+ canvas.setStroke(undefined, __strokeWidth * 2, options);
1575
+ options.windingRule ? canvas.clip(options.windingRule) : canvas.clip();
1576
+ drawStrokesStyle(strokes, false, ui, canvas);
1577
+ canvas.restore();
1578
+ break;
1579
+ case 'outside':
1580
+ const { renderBounds } = ui.__layout;
1581
+ const out = canvas.getSameCanvas(true, true);
1582
+ ui.__drawRenderPath(out);
1583
+ out.setStroke(undefined, __strokeWidth * 2, options);
1584
+ drawStrokesStyle(strokes, false, ui, out);
1585
+ options.windingRule ? out.clip(options.windingRule) : out.clip();
1586
+ out.clearWorld(renderBounds);
1587
+ if (ui.__worldFlipped) {
1588
+ canvas.copyWorldByReset(out, ui.__nowWorld);
1589
+ }
1590
+ else {
1591
+ canvas.copyWorldToInner(out, ui.__nowWorld, renderBounds);
1592
+ }
1593
+ out.recycle(ui.__nowWorld);
1594
+ break;
1595
+ }
1596
+ }
1597
+ }
1598
+
1599
+ const { getSpread, getOuterOf, getByMove, getIntersectData } = BoundsHelper;
1600
+ function shape(ui, current, options) {
1601
+ const canvas = current.getSameCanvas();
1602
+ const nowWorld = ui.__nowWorld;
1603
+ let bounds, fitMatrix, shapeBounds, worldCanvas;
1604
+ let { scaleX, scaleY } = nowWorld;
1605
+ if (scaleX < 0)
1606
+ scaleX = -scaleX;
1607
+ if (scaleY < 0)
1608
+ scaleY = -scaleY;
1609
+ if (current.bounds.includes(nowWorld)) {
1610
+ worldCanvas = canvas;
1611
+ bounds = shapeBounds = nowWorld;
1612
+ }
1613
+ else {
1614
+ const { renderShapeSpread: spread } = ui.__layout;
1615
+ const worldClipBounds = getIntersectData(spread ? getSpread(current.bounds, spread * scaleX, spread * scaleY) : current.bounds, nowWorld);
1616
+ fitMatrix = current.bounds.getFitMatrix(worldClipBounds);
1617
+ let { a: fitScaleX, d: fitScaleY } = fitMatrix;
1618
+ if (fitMatrix.a < 1) {
1619
+ worldCanvas = current.getSameCanvas();
1620
+ ui.__renderShape(worldCanvas, options);
1621
+ scaleX *= fitScaleX;
1622
+ scaleY *= fitScaleY;
1623
+ }
1624
+ shapeBounds = getOuterOf(nowWorld, fitMatrix);
1625
+ bounds = getByMove(shapeBounds, -fitMatrix.e, -fitMatrix.f);
1626
+ if (options.matrix) {
1627
+ const { matrix } = options;
1628
+ fitMatrix.multiply(matrix);
1629
+ fitScaleX *= matrix.scaleX;
1630
+ fitScaleY *= matrix.scaleY;
1631
+ }
1632
+ options = Object.assign(Object.assign({}, options), { matrix: fitMatrix.withScale(fitScaleX, fitScaleY) });
1633
+ }
1634
+ ui.__renderShape(canvas, options);
1635
+ return {
1636
+ canvas, matrix: fitMatrix, bounds,
1637
+ worldCanvas, shapeBounds, scaleX, scaleY
1638
+ };
1639
+ }
1640
+
1641
+ let recycleMap;
1642
+ function compute(attrName, ui) {
1643
+ const data = ui.__, leafPaints = [];
1644
+ let paints = data.__input[attrName], hasOpacityPixel;
1645
+ if (!(paints instanceof Array))
1646
+ paints = [paints];
1647
+ recycleMap = PaintImage.recycleImage(attrName, data);
1648
+ for (let i = 0, len = paints.length, item; i < len; i++) {
1649
+ item = getLeafPaint(attrName, paints[i], ui);
1650
+ if (item)
1651
+ leafPaints.push(item);
1652
+ }
1653
+ data['_' + attrName] = leafPaints.length ? leafPaints : undefined;
1654
+ if (leafPaints.length && leafPaints[0].image)
1655
+ hasOpacityPixel = leafPaints[0].image.hasOpacityPixel;
1656
+ if (attrName === 'fill') {
1657
+ data.__pixelFill = hasOpacityPixel;
1658
+ }
1659
+ else {
1660
+ data.__pixelStroke = hasOpacityPixel;
1661
+ }
1662
+ }
1663
+ function getLeafPaint(attrName, paint, ui) {
1664
+ if (typeof paint !== 'object' || paint.visible === false || paint.opacity === 0)
1665
+ return undefined;
1666
+ const { boxBounds } = ui.__layout;
1667
+ switch (paint.type) {
1668
+ case 'solid':
1669
+ let { type, blendMode, color, opacity } = paint;
1670
+ return { type, blendMode, style: ColorConvert.string(color, opacity) };
1671
+ case 'image':
1672
+ return PaintImage.image(ui, attrName, paint, boxBounds, !recycleMap || !recycleMap[paint.url]);
1673
+ case 'linear':
1674
+ return PaintGradient.linearGradient(paint, boxBounds);
1675
+ case 'radial':
1676
+ return PaintGradient.radialGradient(paint, boxBounds);
1677
+ case 'angular':
1678
+ return PaintGradient.conicGradient(paint, boxBounds);
1679
+ default:
1680
+ return paint.r ? { type: 'solid', style: ColorConvert.string(paint) } : undefined;
1681
+ }
1682
+ }
1683
+
1684
+ const PaintModule = {
1685
+ compute,
1686
+ fill,
1687
+ fills,
1688
+ fillText,
1689
+ stroke,
1690
+ strokes,
1691
+ strokeText,
1692
+ drawTextStroke,
1693
+ shape
1694
+ };
1695
+
1696
+ let origin = {};
1697
+ const { get: get$4, rotateOfOuter: rotateOfOuter$2, translate: translate$1, scaleOfOuter: scaleOfOuter$2, scale: scaleHelper, rotate } = MatrixHelper;
1698
+ function fillOrFitMode(data, mode, box, width, height, rotation) {
1699
+ const transform = get$4();
1700
+ const swap = rotation && rotation !== 180;
1701
+ const sw = box.width / (swap ? height : width);
1702
+ const sh = box.height / (swap ? width : height);
1703
+ const scale = mode === 'fit' ? Math.min(sw, sh) : Math.max(sw, sh);
1704
+ const x = box.x + (box.width - width * scale) / 2;
1705
+ const y = box.y + (box.height - height * scale) / 2;
1706
+ translate$1(transform, x, y);
1707
+ scaleHelper(transform, scale);
1708
+ if (rotation)
1709
+ rotateOfOuter$2(transform, { x: box.x + box.width / 2, y: box.y + box.height / 2 }, rotation);
1710
+ data.scaleX = data.scaleY = scale;
1711
+ data.transform = transform;
1712
+ }
1713
+ function clipMode(data, box, x, y, scaleX, scaleY, rotation) {
1714
+ const transform = get$4();
1715
+ translate$1(transform, box.x, box.y);
1716
+ if (x || y)
1717
+ translate$1(transform, x, y);
1718
+ if (scaleX) {
1719
+ scaleHelper(transform, scaleX, scaleY);
1720
+ data.scaleX = transform.a;
1721
+ data.scaleY = transform.d;
1722
+ }
1723
+ if (rotation)
1724
+ rotate(transform, rotation);
1725
+ data.transform = transform;
1726
+ }
1727
+ function repeatMode(data, box, width, height, x, y, scaleX, scaleY, rotation) {
1728
+ const transform = get$4();
1729
+ if (rotation) {
1730
+ rotate(transform, rotation);
1731
+ switch (rotation) {
1732
+ case 90:
1733
+ translate$1(transform, height, 0);
1734
+ break;
1735
+ case 180:
1736
+ translate$1(transform, width, height);
1830
1737
  break;
1738
+ case 270:
1739
+ translate$1(transform, 0, width);
1740
+ break;
1741
+ }
1742
+ }
1743
+ origin.x = box.x;
1744
+ origin.y = box.y;
1745
+ if (x || y)
1746
+ origin.x += x, origin.y += y;
1747
+ translate$1(transform, origin.x, origin.y);
1748
+ if (scaleX) {
1749
+ scaleOfOuter$2(transform, origin, scaleX, scaleY);
1750
+ data.scaleX = scaleX;
1751
+ data.scaleY = scaleY;
1752
+ }
1753
+ data.transform = transform;
1754
+ }
1755
+
1756
+ const { get: get$3, translate } = MatrixHelper;
1757
+ const tempBox = new Bounds();
1758
+ function createData(leafPaint, image, paint, box) {
1759
+ let { width, height } = image;
1760
+ if (paint.padding)
1761
+ box = tempBox.set(box).shrink(paint.padding);
1762
+ const { opacity, mode, offset, scale, size, rotation, blendMode, repeat } = paint;
1763
+ const sameBox = box.width === width && box.height === height;
1764
+ if (blendMode)
1765
+ leafPaint.blendMode = blendMode;
1766
+ const data = leafPaint.data = { mode };
1767
+ let x, y, scaleX, scaleY;
1768
+ if (offset)
1769
+ x = offset.x, y = offset.y;
1770
+ if (size) {
1771
+ scaleX = (typeof size === 'number' ? size : size.width) / width;
1772
+ scaleY = (typeof size === 'number' ? size : size.height) / height;
1773
+ }
1774
+ else if (scale) {
1775
+ scaleX = typeof scale === 'number' ? scale : scale.x;
1776
+ scaleY = typeof scale === 'number' ? scale : scale.y;
1777
+ }
1778
+ switch (mode) {
1779
+ case 'strench':
1780
+ if (!sameBox)
1781
+ width = box.width, height = box.height;
1782
+ break;
1783
+ case 'clip':
1784
+ if (offset || scaleX || rotation)
1785
+ clipMode(data, box, x, y, scaleX, scaleY, rotation);
1786
+ break;
1787
+ case 'repeat':
1788
+ if (!sameBox || scaleX || rotation)
1789
+ repeatMode(data, box, width, height, x, y, scaleX, scaleY, rotation);
1790
+ if (!repeat)
1791
+ data.repeat = 'repeat';
1792
+ break;
1793
+ case 'fit':
1794
+ case 'cover':
1795
+ default:
1796
+ if (!sameBox || rotation)
1797
+ fillOrFitMode(data, mode, box, width, height, rotation);
1798
+ }
1799
+ if (!data.transform) {
1800
+ if (box.x || box.y) {
1801
+ data.transform = get$3();
1802
+ translate(data.transform, box.x, box.y);
1803
+ }
1804
+ }
1805
+ data.width = width;
1806
+ data.height = height;
1807
+ if (opacity)
1808
+ data.opacity = opacity;
1809
+ if (repeat)
1810
+ data.repeat = typeof repeat === 'string' ? (repeat === 'x' ? 'repeat-x' : 'repeat-y') : 'repeat';
1811
+ }
1812
+
1813
+ let cache, box = new Bounds();
1814
+ const { isSame } = BoundsHelper;
1815
+ function image(ui, attrName, paint, boxBounds, firstUse) {
1816
+ let leafPaint, event;
1817
+ const image = ImageManager.get(paint);
1818
+ if (cache && paint === cache.paint && isSame(boxBounds, cache.boxBounds)) {
1819
+ leafPaint = cache.leafPaint;
1820
+ }
1821
+ else {
1822
+ leafPaint = { type: paint.type, image };
1823
+ cache = image.use > 1 ? { leafPaint, paint, boxBounds: box.set(boxBounds) } : null;
1824
+ }
1825
+ if (firstUse || image.loading)
1826
+ event = { image, attrName, attrValue: paint };
1827
+ if (image.ready) {
1828
+ checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds);
1829
+ if (firstUse) {
1830
+ onLoad(ui, event);
1831
+ onLoadSuccess(ui, event);
1832
+ }
1833
+ }
1834
+ else if (image.error) {
1835
+ if (firstUse)
1836
+ onLoadError(ui, event, image.error);
1837
+ }
1838
+ else {
1839
+ ignoreRender(ui, true);
1840
+ if (firstUse)
1841
+ onLoad(ui, event);
1842
+ leafPaint.loadId = image.load(() => {
1843
+ ignoreRender(ui, false);
1844
+ if (!ui.destroyed) {
1845
+ if (checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds)) {
1846
+ if (image.hasOpacityPixel)
1847
+ ui.__layout.hitCanvasChanged = true;
1848
+ ui.forceUpdate('surface');
1849
+ }
1850
+ onLoadSuccess(ui, event);
1851
+ }
1852
+ leafPaint.loadId = null;
1853
+ }, (error) => {
1854
+ ignoreRender(ui, false);
1855
+ onLoadError(ui, event, error);
1856
+ leafPaint.loadId = null;
1857
+ });
1858
+ }
1859
+ return leafPaint;
1860
+ }
1861
+ function checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds) {
1862
+ if (attrName === 'fill' && !ui.__.__naturalWidth) {
1863
+ const data = ui.__;
1864
+ data.__naturalWidth = image.width / data.pixelRatio;
1865
+ data.__naturalHeight = image.height / data.pixelRatio;
1866
+ if (data.__autoSide) {
1867
+ ui.forceUpdate('width');
1868
+ if (ui.__proxyData) {
1869
+ ui.setProxyAttr('width', data.width);
1870
+ ui.setProxyAttr('height', data.height);
1871
+ }
1872
+ return false;
1873
+ }
1874
+ }
1875
+ if (!leafPaint.data)
1876
+ createData(leafPaint, image, paint, boxBounds);
1877
+ return true;
1878
+ }
1879
+ function onLoad(ui, event) {
1880
+ emit(ui, ImageEvent.LOAD, event);
1881
+ }
1882
+ function onLoadSuccess(ui, event) {
1883
+ emit(ui, ImageEvent.LOADED, event);
1884
+ }
1885
+ function onLoadError(ui, event, error) {
1886
+ event.error = error;
1887
+ ui.forceUpdate('surface');
1888
+ emit(ui, ImageEvent.ERROR, event);
1889
+ }
1890
+ function emit(ui, type, data) {
1891
+ if (ui.hasEvent(type))
1892
+ ui.emitEvent(new ImageEvent(type, data));
1893
+ }
1894
+ function ignoreRender(ui, value) {
1895
+ const { leafer } = ui;
1896
+ if (leafer && leafer.viewReady)
1897
+ leafer.renderer.ignore = value;
1898
+ }
1899
+
1900
+ const { get: get$2, scale, copy: copy$1 } = MatrixHelper;
1901
+ const { ceil, abs: abs$1 } = Math;
1902
+ function createPattern(ui, paint, pixelRatio) {
1903
+ let { scaleX, scaleY } = ImageManager.patternLocked ? ui.__world : ui.__nowWorld;
1904
+ const id = scaleX + '-' + scaleY;
1905
+ if (paint.patternId !== id && !ui.destroyed) {
1906
+ scaleX = abs$1(scaleX);
1907
+ scaleY = abs$1(scaleY);
1908
+ const { image, data } = paint;
1909
+ let imageScale, imageMatrix, { width, height, scaleX: sx, scaleY: sy, opacity, transform, repeat } = data;
1910
+ if (sx) {
1911
+ imageMatrix = get$2();
1912
+ copy$1(imageMatrix, transform);
1913
+ scale(imageMatrix, 1 / sx, 1 / sy);
1914
+ scaleX *= sx;
1915
+ scaleY *= sy;
1916
+ }
1917
+ scaleX *= pixelRatio;
1918
+ scaleY *= pixelRatio;
1919
+ width *= scaleX;
1920
+ height *= scaleY;
1921
+ const size = width * height;
1922
+ if (!repeat) {
1923
+ if (size > Platform.image.maxCacheSize)
1924
+ return false;
1925
+ }
1926
+ let maxSize = Platform.image.maxPatternSize;
1927
+ if (!image.isSVG) {
1928
+ const imageSize = image.width * image.height;
1929
+ if (maxSize > imageSize)
1930
+ maxSize = imageSize;
1931
+ }
1932
+ if (size > maxSize)
1933
+ imageScale = Math.sqrt(size / maxSize);
1934
+ if (imageScale) {
1935
+ scaleX /= imageScale;
1936
+ scaleY /= imageScale;
1937
+ width /= imageScale;
1938
+ height /= imageScale;
1939
+ }
1940
+ if (sx) {
1941
+ scaleX /= sx;
1942
+ scaleY /= sy;
1831
1943
  }
1832
- }
1833
- }
1834
- function strokes(ui, canvas, strokes) {
1835
- const options = ui.__;
1836
- const { strokeWidth, strokeAlign, __font } = options;
1837
- if (!strokeWidth)
1838
- return;
1839
- if (__font) {
1840
- strokeText(ui, canvas, strokes);
1944
+ if (transform || scaleX !== 1 || scaleY !== 1) {
1945
+ if (!imageMatrix) {
1946
+ imageMatrix = get$2();
1947
+ if (transform)
1948
+ copy$1(imageMatrix, transform);
1949
+ }
1950
+ scale(imageMatrix, 1 / scaleX, 1 / scaleY);
1951
+ }
1952
+ const canvas = image.getCanvas(ceil(width) || 1, ceil(height) || 1, opacity);
1953
+ const pattern = image.getPattern(canvas, repeat || (Platform.origin.noRepeat || 'no-repeat'), imageMatrix, paint);
1954
+ paint.style = pattern;
1955
+ paint.patternId = id;
1956
+ return true;
1841
1957
  }
1842
1958
  else {
1843
- switch (strokeAlign) {
1844
- case 'center':
1845
- canvas.setStroke(undefined, strokeWidth, options);
1846
- drawStrokesStyle(ui, strokes, canvas);
1847
- break;
1848
- case 'inside':
1849
- canvas.save();
1850
- canvas.setStroke(undefined, strokeWidth * 2, options);
1851
- options.windingRule ? canvas.clip(options.windingRule) : canvas.clip();
1852
- drawStrokesStyle(ui, strokes, canvas);
1853
- canvas.restore();
1854
- break;
1855
- case 'outside':
1856
- const { renderBounds } = ui.__layout;
1857
- const out = canvas.getSameCanvas(true);
1858
- ui.__drawRenderPath(out);
1859
- out.setStroke(undefined, strokeWidth * 2, ui.__);
1860
- drawStrokesStyle(ui, strokes, out);
1861
- options.windingRule ? out.clip(options.windingRule) : out.clip();
1862
- out.clearWorld(renderBounds);
1863
- canvas.copyWorldToInner(out, ui.__world, renderBounds);
1864
- out.recycle();
1865
- break;
1866
- }
1959
+ return false;
1867
1960
  }
1868
1961
  }
1869
1962
 
1870
- const { getSpread, getOuterOf, getByMove, getIntersectData } = BoundsHelper;
1871
- function shape(ui, current, options) {
1872
- const canvas = current.getSameCanvas();
1873
- let bounds, matrix, shapeBounds;
1874
- let worldCanvas;
1875
- const { __world } = ui;
1876
- let { scaleX, scaleY } = __world;
1877
- if (scaleX < 0)
1878
- scaleX = -scaleX;
1879
- if (scaleY < 0)
1880
- scaleY = -scaleY;
1881
- if (!current.bounds.includes(__world, options.matrix)) {
1882
- const { renderShapeSpread: spread } = ui.__layout;
1883
- const worldClipBounds = getIntersectData(spread ? getSpread(current.bounds, spread * scaleX, spread * scaleY) : current.bounds, __world, options.matrix);
1884
- matrix = current.bounds.getFitMatrix(worldClipBounds);
1885
- if (matrix.a < 1) {
1886
- worldCanvas = current.getSameCanvas();
1887
- ui.__renderShape(worldCanvas, options);
1888
- scaleX *= matrix.a;
1889
- scaleY *= matrix.d;
1890
- }
1891
- shapeBounds = getOuterOf(__world, matrix);
1892
- bounds = getByMove(shapeBounds, -matrix.e, -matrix.f);
1893
- if (options.matrix)
1894
- matrix.multiply(options.matrix);
1895
- options = Object.assign(Object.assign({}, options), { matrix });
1963
+ /******************************************************************************
1964
+ Copyright (c) Microsoft Corporation.
1965
+
1966
+ Permission to use, copy, modify, and/or distribute this software for any
1967
+ purpose with or without fee is hereby granted.
1968
+
1969
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
1970
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
1971
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
1972
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
1973
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
1974
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
1975
+ PERFORMANCE OF THIS SOFTWARE.
1976
+ ***************************************************************************** */
1977
+ /* global Reflect, Promise, SuppressedError, Symbol */
1978
+
1979
+
1980
+ function __awaiter(thisArg, _arguments, P, generator) {
1981
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
1982
+ return new (P || (P = Promise))(function (resolve, reject) {
1983
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
1984
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
1985
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
1986
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
1987
+ });
1988
+ }
1989
+
1990
+ typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
1991
+ var e = new Error(message);
1992
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
1993
+ };
1994
+
1995
+ const { abs } = Math;
1996
+ function checkImage(ui, canvas, paint, allowPaint) {
1997
+ const { scaleX, scaleY } = ImageManager.patternLocked ? ui.__world : ui.__nowWorld;
1998
+ if (!paint.data || paint.patternId === scaleX + '-' + scaleY) {
1999
+ return false;
1896
2000
  }
1897
2001
  else {
1898
- if (options.matrix) {
1899
- scaleX *= options.matrix.a;
1900
- scaleY *= options.matrix.d;
1901
- bounds = shapeBounds = getOuterOf(__world, options.matrix);
2002
+ const { data } = paint;
2003
+ if (allowPaint) {
2004
+ if (!data.repeat) {
2005
+ let { width, height } = data;
2006
+ width *= abs(scaleX) * canvas.pixelRatio;
2007
+ height *= abs(scaleY) * canvas.pixelRatio;
2008
+ if (data.scaleX) {
2009
+ width *= data.scaleX;
2010
+ height *= data.scaleY;
2011
+ }
2012
+ allowPaint = width * height > Platform.image.maxCacheSize;
2013
+ }
2014
+ else {
2015
+ allowPaint = false;
2016
+ }
2017
+ }
2018
+ if (allowPaint) {
2019
+ canvas.save();
2020
+ canvas.clip();
2021
+ if (paint.blendMode)
2022
+ canvas.blendMode = paint.blendMode;
2023
+ if (data.opacity)
2024
+ canvas.opacity *= data.opacity;
2025
+ if (data.transform)
2026
+ canvas.transform(data.transform);
2027
+ canvas.drawImage(paint.image.view, 0, 0, data.width, data.height);
2028
+ canvas.restore();
2029
+ return true;
1902
2030
  }
1903
2031
  else {
1904
- bounds = shapeBounds = __world;
2032
+ if (!paint.style || Export.running) {
2033
+ createPattern(ui, paint, canvas.pixelRatio);
2034
+ }
2035
+ else {
2036
+ if (!paint.patternTask) {
2037
+ paint.patternTask = ImageManager.patternTasker.add(() => __awaiter(this, void 0, void 0, function* () {
2038
+ paint.patternTask = null;
2039
+ if (canvas.bounds.hit(ui.__nowWorld))
2040
+ createPattern(ui, paint, canvas.pixelRatio);
2041
+ ui.forceUpdate('surface');
2042
+ }), 300);
2043
+ }
2044
+ }
2045
+ return false;
1905
2046
  }
1906
- worldCanvas = canvas;
1907
2047
  }
1908
- ui.__renderShape(canvas, options);
1909
- return {
1910
- canvas, matrix, bounds,
1911
- worldCanvas, shapeBounds, scaleX, scaleY
1912
- };
1913
2048
  }
1914
2049
 
2050
+ function recycleImage(attrName, data) {
2051
+ const paints = data['_' + attrName];
2052
+ if (paints instanceof Array) {
2053
+ let image, recycleMap, input, url;
2054
+ for (let i = 0, len = paints.length; i < len; i++) {
2055
+ image = paints[i].image;
2056
+ url = image && image.url;
2057
+ if (url) {
2058
+ if (!recycleMap)
2059
+ recycleMap = {};
2060
+ recycleMap[url] = true;
2061
+ ImageManager.recycle(image);
2062
+ if (image.loading) {
2063
+ if (!input) {
2064
+ input = (data.__input && data.__input[attrName]) || [];
2065
+ if (!(input instanceof Array))
2066
+ input = [input];
2067
+ }
2068
+ image.unload(paints[i].loadId, !input.some((item) => item.url === url));
2069
+ }
2070
+ }
2071
+ }
2072
+ return recycleMap;
2073
+ }
2074
+ return null;
2075
+ }
2076
+
2077
+ const PaintImageModule = {
2078
+ image,
2079
+ createData,
2080
+ fillOrFitMode,
2081
+ clipMode,
2082
+ repeatMode,
2083
+ createPattern,
2084
+ checkImage,
2085
+ recycleImage
2086
+ };
2087
+
1915
2088
  const defaultFrom$2 = { x: 0.5, y: 0 };
1916
2089
  const defaultTo$2 = { x: 0.5, y: 1 };
1917
2090
  function linearGradient(paint, box) {
@@ -1929,7 +2102,7 @@ function applyStops(gradient, stops, opacity) {
1929
2102
  let stop;
1930
2103
  for (let i = 0, len = stops.length; i < len; i++) {
1931
2104
  stop = stops[i];
1932
- gradient.addColorStop(stop.offset, ColorConvert$1.string(stop.color, opacity));
2105
+ gradient.addColorStop(stop.offset, ColorConvert.string(stop.color, opacity));
1933
2106
  }
1934
2107
  }
1935
2108
 
@@ -1991,62 +2164,18 @@ function conicGradient(paint, box) {
1991
2164
  return data;
1992
2165
  }
1993
2166
 
1994
- let recycleMap;
1995
- function compute(ui, attrName) {
1996
- const value = [];
1997
- let item;
1998
- let paints = ui.__.__input[attrName];
1999
- if (!(paints instanceof Array))
2000
- paints = [paints];
2001
- recycleMap = recycleImage(ui.__, attrName);
2002
- for (let i = 0, len = paints.length; i < len; i++) {
2003
- item = getLeafPaint(ui, paints[i], attrName);
2004
- if (item)
2005
- value.push(item);
2006
- }
2007
- ui.__['_' + attrName] = value.length ? value : undefined;
2008
- }
2009
- function getLeafPaint(ui, paint, attrName) {
2010
- if (typeof paint !== 'object' || paint.visible === false || paint.opacity === 0)
2011
- return undefined;
2012
- const { boxBounds } = ui.__layout;
2013
- switch (paint.type) {
2014
- case 'solid':
2015
- let { type, blendMode, color, opacity } = paint;
2016
- return { type, blendMode, style: ColorConvert$1.string(color, opacity) };
2017
- case 'image':
2018
- return image(ui, attrName, paint, boxBounds, !recycleMap || !recycleMap[paint.url]);
2019
- case 'linear':
2020
- return linearGradient(paint, boxBounds);
2021
- case 'radial':
2022
- return radialGradient(paint, boxBounds);
2023
- case 'angular':
2024
- return conicGradient(paint, boxBounds);
2025
- default:
2026
- return paint.r ? { type: 'solid', style: ColorConvert$1.string(paint) } : undefined;
2027
- }
2028
- }
2029
-
2030
- var UIPaint = /*#__PURE__*/Object.freeze({
2031
- __proto__: null,
2032
- compute: compute,
2033
- drawTextStroke: drawTextStroke,
2034
- fill: fill,
2035
- fillText: fillText,
2036
- fills: fills,
2037
- recycleImage: recycleImage,
2038
- shape: shape,
2039
- stroke: stroke,
2040
- strokeText: strokeText,
2041
- strokes: strokes
2042
- });
2167
+ const PaintGradientModule = {
2168
+ linearGradient,
2169
+ radialGradient,
2170
+ conicGradient
2171
+ };
2043
2172
 
2044
2173
  const { copy, toOffsetOutBounds: toOffsetOutBounds$1 } = BoundsHelper;
2045
2174
  const tempBounds = {};
2046
2175
  const offsetOutBounds$1 = {};
2047
- function shadow(ui, current, shape, _options) {
2176
+ function shadow(ui, current, shape) {
2048
2177
  let copyBounds, spreadScale;
2049
- const { __world, __layout } = ui;
2178
+ const { __nowWorld: nowWorld, __layout } = ui;
2050
2179
  const { shadow } = ui.__;
2051
2180
  const { worldCanvas, bounds, shapeBounds, scaleX, scaleY } = shape;
2052
2181
  const other = current.getSameCanvas();
@@ -2061,21 +2190,21 @@ function shadow(ui, current, shape, _options) {
2061
2190
  other.restore();
2062
2191
  other.save();
2063
2192
  if (worldCanvas) {
2064
- other.copyWorld(other, bounds, __world, 'copy');
2065
- copyBounds = __world;
2193
+ other.copyWorld(other, bounds, nowWorld, 'copy');
2194
+ copyBounds = nowWorld;
2066
2195
  }
2067
- worldCanvas ? other.copyWorld(worldCanvas, __world, __world, 'destination-out') : other.copyWorld(shape.canvas, shapeBounds, bounds, 'destination-out');
2196
+ worldCanvas ? other.copyWorld(worldCanvas, nowWorld, nowWorld, 'destination-out') : other.copyWorld(shape.canvas, shapeBounds, bounds, 'destination-out');
2068
2197
  }
2069
- if (ui.__hasMirror) {
2070
- current.copyWorldByReset(other, copyBounds, __world, item.blendMode);
2198
+ if (ui.__worldFlipped) {
2199
+ current.copyWorldByReset(other, copyBounds, nowWorld, item.blendMode);
2071
2200
  }
2072
2201
  else {
2073
2202
  current.copyWorldToInner(other, copyBounds, __layout.renderBounds, item.blendMode);
2074
2203
  }
2075
2204
  if (end && index < end)
2076
- other.clear();
2205
+ other.clearWorld(copyBounds, true);
2077
2206
  });
2078
- other.recycle();
2207
+ other.recycle(copyBounds);
2079
2208
  }
2080
2209
  function drawWorldShadow(canvas, outBounds, spreadScale, shape) {
2081
2210
  const { bounds, shapeBounds } = shape;
@@ -2106,9 +2235,9 @@ function drawWorldShadow(canvas, outBounds, spreadScale, shape) {
2106
2235
 
2107
2236
  const { toOffsetOutBounds } = BoundsHelper;
2108
2237
  const offsetOutBounds = {};
2109
- function innerShadow(ui, current, shape, _options) {
2238
+ function innerShadow(ui, current, shape) {
2110
2239
  let copyBounds, spreadScale;
2111
- const { __world, __layout: __layout } = ui;
2240
+ const { __nowWorld: nowWorld, __layout: __layout } = ui;
2112
2241
  const { innerShadow } = ui.__;
2113
2242
  const { worldCanvas, bounds, shapeBounds, scaleX, scaleY } = shape;
2114
2243
  const other = current.getSameCanvas();
@@ -2121,40 +2250,115 @@ function innerShadow(ui, current, shape, _options) {
2121
2250
  drawWorldShadow(other, offsetOutBounds, spreadScale, shape);
2122
2251
  other.restore();
2123
2252
  if (worldCanvas) {
2124
- other.copyWorld(other, bounds, __world, 'copy');
2125
- other.copyWorld(worldCanvas, __world, __world, 'source-out');
2126
- copyBounds = __world;
2253
+ other.copyWorld(other, bounds, nowWorld, 'copy');
2254
+ other.copyWorld(worldCanvas, nowWorld, nowWorld, 'source-out');
2255
+ copyBounds = nowWorld;
2127
2256
  }
2128
2257
  else {
2129
2258
  other.copyWorld(shape.canvas, shapeBounds, bounds, 'source-out');
2130
2259
  copyBounds = bounds;
2131
2260
  }
2132
2261
  other.fillWorld(copyBounds, item.color, 'source-in');
2133
- if (ui.__hasMirror) {
2134
- current.copyWorldByReset(other, copyBounds, __world, item.blendMode);
2262
+ if (ui.__worldFlipped) {
2263
+ current.copyWorldByReset(other, copyBounds, nowWorld, item.blendMode);
2135
2264
  }
2136
2265
  else {
2137
2266
  current.copyWorldToInner(other, copyBounds, __layout.renderBounds, item.blendMode);
2138
2267
  }
2139
2268
  if (end && index < end)
2140
- other.clear();
2269
+ other.clearWorld(copyBounds, true);
2141
2270
  });
2142
- other.recycle();
2271
+ other.recycle(copyBounds);
2143
2272
  }
2144
2273
 
2145
2274
  function blur(ui, current, origin) {
2146
2275
  const { blur } = ui.__;
2147
- origin.setWorldBlur(blur * ui.__world.a);
2148
- origin.copyWorldToInner(current, ui.__world, ui.__layout.renderBounds);
2276
+ origin.setWorldBlur(blur * ui.__nowWorld.a);
2277
+ origin.copyWorldToInner(current, ui.__nowWorld, ui.__layout.renderBounds);
2149
2278
  origin.filter = 'none';
2150
2279
  }
2151
2280
 
2152
- var UIEffect = /*#__PURE__*/Object.freeze({
2153
- __proto__: null,
2154
- blur: blur,
2155
- innerShadow: innerShadow,
2156
- shadow: shadow
2157
- });
2281
+ function backgroundBlur(_ui, _current, _shape) {
2282
+ }
2283
+
2284
+ const EffectModule = {
2285
+ shadow,
2286
+ innerShadow,
2287
+ blur,
2288
+ backgroundBlur
2289
+ };
2290
+
2291
+ const { excludeRenderBounds } = LeafBoundsHelper;
2292
+ Group.prototype.__renderMask = function (canvas, options) {
2293
+ let child, maskCanvas, contentCanvas, maskOpacity, currentMask;
2294
+ const { children } = this;
2295
+ for (let i = 0, len = children.length; i < len; i++) {
2296
+ child = children[i];
2297
+ if (child.__.mask) {
2298
+ if (currentMask) {
2299
+ maskEnd(this, currentMask, canvas, contentCanvas, maskCanvas, maskOpacity);
2300
+ maskCanvas = contentCanvas = null;
2301
+ }
2302
+ if (child.__.maskType === 'path') {
2303
+ if (child.opacity < 1) {
2304
+ currentMask = 'opacity-path';
2305
+ maskOpacity = child.opacity;
2306
+ if (!contentCanvas)
2307
+ contentCanvas = getCanvas(canvas);
2308
+ }
2309
+ else {
2310
+ currentMask = 'path';
2311
+ canvas.save();
2312
+ }
2313
+ child.__clip(contentCanvas || canvas, options);
2314
+ }
2315
+ else {
2316
+ currentMask = 'alpha';
2317
+ if (!maskCanvas)
2318
+ maskCanvas = getCanvas(canvas);
2319
+ if (!contentCanvas)
2320
+ contentCanvas = getCanvas(canvas);
2321
+ child.__render(maskCanvas, options);
2322
+ }
2323
+ if (child.__.maskType !== 'clipping')
2324
+ continue;
2325
+ }
2326
+ if (excludeRenderBounds(child, options))
2327
+ continue;
2328
+ child.__render(contentCanvas || canvas, options);
2329
+ }
2330
+ maskEnd(this, currentMask, canvas, contentCanvas, maskCanvas, maskOpacity);
2331
+ };
2332
+ function maskEnd(leaf, maskMode, canvas, contentCanvas, maskCanvas, maskOpacity) {
2333
+ switch (maskMode) {
2334
+ case 'alpha':
2335
+ usePixelMask(leaf, canvas, contentCanvas, maskCanvas);
2336
+ break;
2337
+ case 'opacity-path':
2338
+ copyContent(leaf, canvas, contentCanvas, maskOpacity);
2339
+ break;
2340
+ case 'path':
2341
+ canvas.restore();
2342
+ }
2343
+ }
2344
+ function getCanvas(canvas) {
2345
+ return canvas.getSameCanvas(false, true);
2346
+ }
2347
+ function usePixelMask(leaf, canvas, content, mask) {
2348
+ const realBounds = leaf.__nowWorld;
2349
+ content.resetTransform();
2350
+ content.opacity = 1;
2351
+ content.useMask(mask, realBounds);
2352
+ mask.recycle(realBounds);
2353
+ copyContent(leaf, canvas, content, 1);
2354
+ }
2355
+ function copyContent(leaf, canvas, content, maskOpacity) {
2356
+ const realBounds = leaf.__nowWorld;
2357
+ canvas.resetTransform();
2358
+ canvas.opacity = maskOpacity;
2359
+ canvas.copyWorld(content, realBounds);
2360
+ content.recycle(realBounds);
2361
+ }
2158
2362
 
2159
2363
  const money = '¥¥$€££¢¢';
2160
2364
  const letter = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz';
@@ -2268,7 +2472,7 @@ function getTextCase(char, textCase, firstChar) {
2268
2472
  const { trimRight } = TextRowHelper;
2269
2473
  const { Letter, Single, Before, After, Symbol, Break } = CharType;
2270
2474
  let word, row, wordWidth, rowWidth, realWidth;
2271
- let char, charWidth, charType, lastCharType, langBreak, afterBreak, paraStart;
2475
+ let char, charWidth, startCharSize, charSize, charType, lastCharType, langBreak, afterBreak, paraStart;
2272
2476
  let textDrawData, rows = [], bounds;
2273
2477
  function createRows(drawData, content, style) {
2274
2478
  textDrawData = drawData;
@@ -2279,9 +2483,11 @@ function createRows(drawData, content, style) {
2279
2483
  const { width, height } = bounds;
2280
2484
  const charMode = width || height || __letterSpacing || (textCase !== 'none');
2281
2485
  if (charMode) {
2486
+ const wrap = style.textWrap !== 'none';
2487
+ const breakAll = style.textWrap === 'break';
2282
2488
  paraStart = true;
2283
2489
  lastCharType = null;
2284
- wordWidth = rowWidth = 0;
2490
+ startCharSize = charWidth = charSize = wordWidth = rowWidth = 0;
2285
2491
  word = { data: [] }, row = { words: [] };
2286
2492
  for (let i = 0, len = content.length; i < len; i++) {
2287
2493
  char = content[i];
@@ -2297,21 +2503,31 @@ function createRows(drawData, content, style) {
2297
2503
  if (charType === Letter && textCase !== 'none')
2298
2504
  char = getTextCase(char, textCase, !wordWidth);
2299
2505
  charWidth = canvas.measureText(char).width;
2300
- if (__letterSpacing)
2506
+ if (__letterSpacing) {
2507
+ if (__letterSpacing < 0)
2508
+ charSize = charWidth;
2301
2509
  charWidth += __letterSpacing;
2510
+ }
2302
2511
  langBreak = (charType === Single && (lastCharType === Single || lastCharType === Letter)) || (lastCharType === Single && charType !== After);
2303
2512
  afterBreak = ((charType === Before || charType === Single) && (lastCharType === Symbol || lastCharType === After));
2304
2513
  realWidth = paraStart && paraIndent ? width - paraIndent : width;
2305
- if (width && rowWidth + wordWidth + charWidth > realWidth) {
2306
- if (!afterBreak)
2307
- afterBreak = charType === Letter && lastCharType == After;
2308
- if (langBreak || afterBreak || charType === Break || charType === Before || charType === Single || (wordWidth + charWidth > realWidth)) {
2514
+ if (wrap && (width && rowWidth + wordWidth + charWidth > realWidth)) {
2515
+ if (breakAll) {
2309
2516
  if (wordWidth)
2310
2517
  addWord();
2311
2518
  addRow();
2312
2519
  }
2313
2520
  else {
2314
- addRow();
2521
+ if (!afterBreak)
2522
+ afterBreak = charType === Letter && lastCharType == After;
2523
+ if (langBreak || afterBreak || charType === Break || charType === Before || charType === Single || (wordWidth + charWidth > realWidth)) {
2524
+ if (wordWidth)
2525
+ addWord();
2526
+ addRow();
2527
+ }
2528
+ else {
2529
+ addRow();
2530
+ }
2315
2531
  }
2316
2532
  }
2317
2533
  if (char === ' ' && paraStart !== true && (rowWidth + wordWidth) === 0) ;
@@ -2348,6 +2564,8 @@ function createRows(drawData, content, style) {
2348
2564
  }
2349
2565
  }
2350
2566
  function addChar(char, width) {
2567
+ if (charSize && !startCharSize)
2568
+ startCharSize = charSize;
2351
2569
  word.data.push({ char, width });
2352
2570
  wordWidth += width;
2353
2571
  }
@@ -2364,6 +2582,11 @@ function addRow() {
2364
2582
  row.paraStart = true;
2365
2583
  paraStart = false;
2366
2584
  }
2585
+ if (charSize) {
2586
+ row.startCharSize = startCharSize;
2587
+ row.endCharSize = charSize;
2588
+ startCharSize = 0;
2589
+ }
2367
2590
  row.width = rowWidth;
2368
2591
  if (bounds.width)
2369
2592
  trimRight(row);
@@ -2374,7 +2597,7 @@ function addRow() {
2374
2597
 
2375
2598
  const CharMode = 0;
2376
2599
  const WordMode = 1;
2377
- const RowMode = 2;
2600
+ const TextMode = 2;
2378
2601
  function layoutChar(drawData, style, width, _height) {
2379
2602
  const { rows } = drawData;
2380
2603
  const { textAlign, paraIndent, letterSpacing } = style;
@@ -2383,15 +2606,12 @@ function layoutChar(drawData, style, width, _height) {
2383
2606
  if (row.words) {
2384
2607
  indentWidth = paraIndent && row.paraStart ? paraIndent : 0;
2385
2608
  addWordWidth = (width && textAlign === 'justify' && row.words.length > 1) ? (width - row.width - indentWidth) / (row.words.length - 1) : 0;
2386
- mode = (letterSpacing || row.isOverflow) ? CharMode : (addWordWidth > 0.01 ? WordMode : RowMode);
2387
- if (mode === RowMode) {
2388
- row.text = '';
2609
+ mode = (letterSpacing || row.isOverflow) ? CharMode : (addWordWidth > 0.01 ? WordMode : TextMode);
2610
+ if (row.isOverflow && !letterSpacing)
2611
+ row.textMode = true;
2612
+ if (mode === TextMode) {
2389
2613
  row.x += indentWidth;
2390
- row.words.forEach(word => {
2391
- word.data.forEach(char => {
2392
- row.text += char.char;
2393
- });
2394
- });
2614
+ toTextChar$1(row);
2395
2615
  }
2396
2616
  else {
2397
2617
  row.x += indentWidth;
@@ -2417,6 +2637,14 @@ function layoutChar(drawData, style, width, _height) {
2417
2637
  }
2418
2638
  });
2419
2639
  }
2640
+ function toTextChar$1(row) {
2641
+ row.text = '';
2642
+ row.words.forEach(word => {
2643
+ word.data.forEach(char => {
2644
+ row.text += char.char;
2645
+ });
2646
+ });
2647
+ }
2420
2648
  function toWordChar(data, charX, wordChar) {
2421
2649
  data.forEach(char => {
2422
2650
  wordChar.char += char.char;
@@ -2437,10 +2665,10 @@ function toChar(data, charX, rowData) {
2437
2665
 
2438
2666
  function layoutText(drawData, style) {
2439
2667
  const { rows, bounds } = drawData;
2440
- const { __lineHeight, __baseLine, textAlign, verticalAlign, paraSpacing, textOverflow } = style;
2668
+ const { __lineHeight, __baseLine, __letterSpacing, __clipText, textAlign, verticalAlign, paraSpacing } = style;
2441
2669
  let { x, y, width, height } = bounds, realHeight = __lineHeight * rows.length + (paraSpacing ? paraSpacing * (drawData.paraNumber - 1) : 0);
2442
2670
  let starY = __baseLine;
2443
- if (textOverflow !== 'show' && realHeight > height) {
2671
+ if (__clipText && realHeight > height) {
2444
2672
  realHeight = Math.max(height, __lineHeight);
2445
2673
  drawData.overflow = rows.length;
2446
2674
  }
@@ -2454,7 +2682,7 @@ function layoutText(drawData, style) {
2454
2682
  }
2455
2683
  }
2456
2684
  starY += y;
2457
- let row;
2685
+ let row, rowX, rowWidth;
2458
2686
  for (let i = 0, len = rows.length; i < len; i++) {
2459
2687
  row = rows[i];
2460
2688
  row.x = x;
@@ -2473,53 +2701,74 @@ function layoutText(drawData, style) {
2473
2701
  row.isOverflow = true;
2474
2702
  drawData.overflow = i + 1;
2475
2703
  }
2476
- if (row.width < 0) {
2477
- const charWidth = row.words[0].data[0].width;
2478
- const rowX = row.x + row.width;
2479
- if (rowX < bounds.x)
2480
- bounds.x = rowX - charWidth;
2481
- if (-row.width > bounds.width)
2482
- bounds.width = -row.width + style.fontSize + charWidth;
2704
+ rowX = row.x;
2705
+ rowWidth = row.width;
2706
+ if (__letterSpacing < 0) {
2707
+ if (row.width < 0) {
2708
+ rowWidth = -row.width + style.fontSize + __letterSpacing;
2709
+ rowX -= rowWidth;
2710
+ rowWidth += style.fontSize;
2711
+ }
2712
+ else {
2713
+ rowWidth -= __letterSpacing;
2714
+ }
2483
2715
  }
2484
- else {
2485
- if (row.x < bounds.x)
2486
- bounds.x = row.x;
2487
- if (row.width > bounds.width)
2488
- bounds.width = row.width;
2716
+ if (rowX < bounds.x)
2717
+ bounds.x = rowX;
2718
+ if (rowWidth > bounds.width)
2719
+ bounds.width = rowWidth;
2720
+ if (__clipText && width && width < rowWidth) {
2721
+ row.isOverflow = true;
2722
+ if (!drawData.overflow)
2723
+ drawData.overflow = rows.length;
2489
2724
  }
2490
2725
  }
2491
2726
  bounds.y = y;
2492
2727
  bounds.height = realHeight;
2493
2728
  }
2494
2729
 
2495
- function clipText(drawData, textOverflow) {
2730
+ function clipText(drawData, style) {
2496
2731
  const { rows, overflow } = drawData;
2732
+ let { textOverflow } = style;
2497
2733
  rows.splice(overflow);
2498
2734
  if (textOverflow !== 'hide') {
2499
2735
  if (textOverflow === 'ellipsis')
2500
2736
  textOverflow = '...';
2737
+ let char, charRight;
2501
2738
  const ellipsisWidth = Platform.canvas.measureText(textOverflow).width;
2502
- const row = rows[overflow - 1];
2503
- let char, end = row.data.length - 1, charRight;
2504
- const { x, width } = drawData.bounds;
2505
- const right = x + width - ellipsisWidth;
2506
- for (let i = end; i > -1; i--) {
2507
- char = row.data[i];
2508
- charRight = char.x + char.width;
2509
- if (i === end && charRight < right) {
2510
- break;
2511
- }
2512
- else if (charRight < right && char.char !== ' ') {
2513
- row.data.splice(i + 1);
2514
- row.width -= char.width;
2515
- break;
2739
+ const right = style.x + style.width - ellipsisWidth;
2740
+ const list = style.textWrap === 'none' ? rows : [rows[overflow - 1]];
2741
+ list.forEach(row => {
2742
+ if (row.isOverflow && row.data) {
2743
+ let end = row.data.length - 1;
2744
+ for (let i = end; i > -1; i--) {
2745
+ char = row.data[i];
2746
+ charRight = char.x + char.width;
2747
+ if (i === end && charRight < right) {
2748
+ break;
2749
+ }
2750
+ else if (charRight < right && char.char !== ' ') {
2751
+ row.data.splice(i + 1);
2752
+ row.width -= char.width;
2753
+ break;
2754
+ }
2755
+ row.width -= char.width;
2756
+ }
2757
+ row.width += ellipsisWidth;
2758
+ row.data.push({ char: textOverflow, x: charRight });
2759
+ if (row.textMode)
2760
+ toTextChar(row);
2516
2761
  }
2517
- row.width -= char.width;
2518
- }
2519
- row.width += ellipsisWidth;
2520
- row.data.push({ char: textOverflow, x: charRight });
2762
+ });
2521
2763
  }
2522
2764
  }
2765
+ function toTextChar(row) {
2766
+ row.text = '';
2767
+ row.data.forEach(char => {
2768
+ row.text += char.char;
2769
+ });
2770
+ row.data = null;
2771
+ }
2523
2772
 
2524
2773
  function decorationText(drawData, style) {
2525
2774
  const { fontSize } = style;
@@ -2533,101 +2782,190 @@ function decorationText(drawData, style) {
2533
2782
  }
2534
2783
  }
2535
2784
 
2536
- const TextConvert = {
2537
- getDrawData(content, style) {
2538
- if (typeof content !== 'string')
2539
- content = String(content);
2540
- let x = 0, y = 0;
2541
- let { width, height, padding } = style;
2542
- const { textDecoration, textOverflow, __font } = style;
2543
- if (!width)
2544
- width = 0;
2545
- if (padding) {
2546
- const [top, right, bottom, left] = MathHelper.fourNumber(padding);
2547
- if (width) {
2548
- x = left;
2549
- width -= (right + left);
2550
- }
2551
- if (height) {
2552
- y = top;
2553
- height -= (top + bottom);
2554
- }
2785
+ const { top, right, bottom, left } = Direction4;
2786
+ function getDrawData(content, style) {
2787
+ if (typeof content !== 'string')
2788
+ content = String(content);
2789
+ let x = 0, y = 0;
2790
+ let width = style.__getInput('width') || 0;
2791
+ let height = style.__getInput('height') || 0;
2792
+ const { textDecoration, __font, __padding: padding } = style;
2793
+ if (padding) {
2794
+ if (width) {
2795
+ x = padding[left];
2796
+ width -= (padding[right] + padding[left]);
2797
+ }
2798
+ if (height) {
2799
+ y = padding[top];
2800
+ height -= (padding[top] + padding[bottom]);
2801
+ }
2802
+ }
2803
+ const drawData = {
2804
+ bounds: { x, y, width, height },
2805
+ rows: [],
2806
+ paraNumber: 0,
2807
+ font: Platform.canvas.font = __font
2808
+ };
2809
+ createRows(drawData, content, style);
2810
+ if (padding)
2811
+ padAutoText(padding, drawData, style, width, height);
2812
+ layoutText(drawData, style);
2813
+ layoutChar(drawData, style, width);
2814
+ if (drawData.overflow)
2815
+ clipText(drawData, style);
2816
+ if (textDecoration !== 'none')
2817
+ decorationText(drawData, style);
2818
+ return drawData;
2819
+ }
2820
+ function padAutoText(padding, drawData, style, width, height) {
2821
+ if (!width) {
2822
+ switch (style.textAlign) {
2823
+ case 'left':
2824
+ offsetText(drawData, 'x', padding[left]);
2825
+ break;
2826
+ case 'right':
2827
+ offsetText(drawData, 'x', -padding[right]);
2828
+ }
2829
+ }
2830
+ if (!height) {
2831
+ switch (style.verticalAlign) {
2832
+ case 'top':
2833
+ offsetText(drawData, 'y', padding[top]);
2834
+ break;
2835
+ case 'bottom':
2836
+ offsetText(drawData, 'y', -padding[bottom]);
2555
2837
  }
2556
- const drawData = {
2557
- bounds: { x, y, width, height },
2558
- rows: [],
2559
- paraNumber: 0,
2560
- font: Platform.canvas.font = __font
2561
- };
2562
- createRows(drawData, content, style);
2563
- layoutText(drawData, style);
2564
- layoutChar(drawData, style, width);
2565
- if (drawData.overflow)
2566
- clipText(drawData, textOverflow);
2567
- if (textDecoration !== 'none')
2568
- decorationText(drawData, style);
2569
- return drawData;
2570
2838
  }
2839
+ }
2840
+ function offsetText(drawData, attrName, value) {
2841
+ const { bounds, rows } = drawData;
2842
+ bounds[attrName] += value;
2843
+ for (let i = 0; i < rows.length; i++)
2844
+ rows[i][attrName] += value;
2845
+ }
2846
+
2847
+ const TextConvertModule = {
2848
+ getDrawData
2571
2849
  };
2572
2850
 
2573
- const ColorConvert = {
2574
- string(color, opacity) {
2575
- if (typeof color === 'string')
2576
- return color;
2577
- let a = color.a === undefined ? 1 : color.a;
2578
- if (opacity)
2579
- a *= opacity;
2580
- const rgb = color.r + ',' + color.g + ',' + color.b;
2581
- return a === 1 ? 'rgb(' + rgb + ')' : 'rgba(' + rgb + ',' + a + ')';
2582
- }
2851
+ function string(color, opacity) {
2852
+ if (typeof color === 'string')
2853
+ return color;
2854
+ let a = color.a === undefined ? 1 : color.a;
2855
+ if (opacity)
2856
+ a *= opacity;
2857
+ const rgb = color.r + ',' + color.g + ',' + color.b;
2858
+ return a === 1 ? 'rgb(' + rgb + ')' : 'rgba(' + rgb + ',' + a + ')';
2859
+ }
2860
+
2861
+ const ColorConvertModule = {
2862
+ string
2583
2863
  };
2584
2864
 
2585
- const Export = {
2865
+ const { setPoint, addPoint, toBounds } = TwoPointBoundsHelper;
2866
+ function getTrimBounds(canvas) {
2867
+ const { width, height } = canvas.view;
2868
+ const { data } = canvas.context.getImageData(0, 0, width, height);
2869
+ let x, y, pointBounds, index = 0;
2870
+ for (let i = 0; i < data.length; i += 4) {
2871
+ if (data[i + 3] !== 0) {
2872
+ x = index % width;
2873
+ y = (index - x) / width;
2874
+ pointBounds ? addPoint(pointBounds, x, y) : setPoint(pointBounds = {}, x, y);
2875
+ }
2876
+ index++;
2877
+ }
2878
+ const bounds = new Bounds();
2879
+ toBounds(pointBounds, bounds);
2880
+ return bounds.scale(1 / canvas.pixelRatio).ceil();
2881
+ }
2882
+
2883
+ const ExportModule = {
2586
2884
  export(leaf, filename, options) {
2885
+ this.running = true;
2587
2886
  return addTask((success) => new Promise((resolve) => {
2887
+ const over = (result) => {
2888
+ success(result);
2889
+ resolve();
2890
+ this.running = false;
2891
+ };
2588
2892
  const { leafer } = leaf;
2589
2893
  if (leafer) {
2590
2894
  leafer.waitViewCompleted(() => __awaiter(this, void 0, void 0, function* () {
2591
- let quality, blob;
2592
- let { canvas } = leafer;
2593
- let { unreal } = canvas;
2594
- if (unreal) {
2595
- canvas = canvas.getSameCanvas();
2596
- canvas.backgroundColor = leafer.config.fill;
2597
- leafer.__render(canvas, {});
2895
+ options = FileHelper.getExportOptions(options);
2896
+ let renderBounds, trimBounds, scaleX = 1, scaleY = 1;
2897
+ const { worldTransform, isLeafer, isFrame } = leaf;
2898
+ const { slice, trim, onCanvas } = options;
2899
+ const scale = options.scale || 1;
2900
+ const pixelRatio = options.pixelRatio || 1;
2901
+ const screenshot = options.screenshot || leaf.isApp;
2902
+ const fill = (isLeafer && screenshot) ? (options.fill === undefined ? leaf.fill : options.fill) : options.fill;
2903
+ const needFill = FileHelper.isOpaqueImage(filename) || fill, matrix = new Matrix();
2904
+ if (screenshot) {
2905
+ renderBounds = screenshot === true ? (isLeafer ? leafer.canvas.bounds : leaf.worldRenderBounds) : screenshot;
2598
2906
  }
2599
- switch (typeof options) {
2600
- case 'object':
2601
- if (options.quality)
2602
- quality = options.quality;
2603
- if (options.blob)
2604
- blob = true;
2605
- break;
2606
- case 'number':
2607
- quality = options;
2608
- break;
2609
- case 'boolean':
2610
- blob = options;
2907
+ else {
2908
+ let relative = options.relative || (isLeafer ? 'inner' : 'local');
2909
+ scaleX = worldTransform.scaleX;
2910
+ scaleY = worldTransform.scaleY;
2911
+ switch (relative) {
2912
+ case 'inner':
2913
+ matrix.set(worldTransform);
2914
+ break;
2915
+ case 'local':
2916
+ matrix.set(worldTransform).divide(leaf.localTransform);
2917
+ scaleX /= leaf.scaleX;
2918
+ scaleY /= leaf.scaleY;
2919
+ break;
2920
+ case 'world':
2921
+ scaleX = 1;
2922
+ scaleY = 1;
2923
+ break;
2924
+ case 'page':
2925
+ relative = leaf.leafer;
2926
+ default:
2927
+ matrix.set(worldTransform).divide(leaf.getTransform(relative));
2928
+ const l = relative.worldTransform;
2929
+ scaleX /= scaleX / l.scaleX;
2930
+ scaleY /= scaleY / l.scaleY;
2931
+ }
2932
+ renderBounds = leaf.getBounds('render', relative);
2611
2933
  }
2612
- let data;
2613
- if (filename.includes('.')) {
2614
- data = yield canvas.saveAs(filename, quality);
2934
+ const { x, y, width, height } = new Bounds(renderBounds).scale(scale);
2935
+ let canvas = Creator.canvas({ width: Math.round(width), height: Math.round(height), pixelRatio });
2936
+ const renderOptions = { matrix: matrix.scale(1 / scale).invert().translate(-x, -y).withScale(1 / scaleX * scale, 1 / scaleY * scale) };
2937
+ if (slice) {
2938
+ leaf = leafer;
2939
+ renderOptions.bounds = canvas.bounds;
2615
2940
  }
2616
- else if (blob) {
2617
- data = yield canvas.toBlob(filename, quality);
2941
+ canvas.save();
2942
+ if (isFrame && fill !== undefined) {
2943
+ const oldFill = leaf.get('fill');
2944
+ leaf.fill = '';
2945
+ leaf.__render(canvas, renderOptions);
2946
+ leaf.fill = oldFill;
2618
2947
  }
2619
2948
  else {
2620
- data = yield canvas.toDataURL(filename, quality);
2949
+ leaf.__render(canvas, renderOptions);
2621
2950
  }
2622
- success({ data });
2623
- resolve();
2624
- if (unreal)
2625
- canvas.recycle();
2951
+ canvas.restore();
2952
+ if (trim) {
2953
+ trimBounds = getTrimBounds(canvas);
2954
+ const old = canvas, { width, height } = trimBounds;
2955
+ const config = { x: 0, y: 0, width, height, pixelRatio };
2956
+ canvas = Creator.canvas(config);
2957
+ canvas.copyWorld(old, trimBounds, config);
2958
+ }
2959
+ if (needFill)
2960
+ canvas.fillWorld(canvas.bounds, fill || '#FFFFFF', 'destination-over');
2961
+ if (onCanvas)
2962
+ onCanvas(canvas);
2963
+ const data = filename === 'canvas' ? canvas : yield canvas.export(filename, options);
2964
+ over({ data, width: canvas.pixelWidth, height: canvas.pixelHeight, renderBounds, trimBounds });
2626
2965
  }));
2627
2966
  }
2628
2967
  else {
2629
- success({ data: false });
2630
- resolve();
2968
+ over({ data: false });
2631
2969
  }
2632
2970
  }));
2633
2971
  }
@@ -2641,12 +2979,63 @@ function addTask(task) {
2641
2979
  });
2642
2980
  }
2643
2981
 
2644
- Object.assign(Paint, UIPaint);
2645
- Object.assign(Effect, UIEffect);
2646
- Object.assign(TextConvert$1, TextConvert);
2647
- Object.assign(ColorConvert$1, ColorConvert);
2648
- Object.assign(Export$1, Export);
2982
+ const canvas = LeaferCanvasBase.prototype;
2983
+ const debug = Debug.get('@leafer-ui/export');
2984
+ canvas.export = function (filename, options) {
2985
+ const { quality, blob } = FileHelper.getExportOptions(options);
2986
+ if (filename.includes('.')) {
2987
+ return this.saveAs(filename, quality);
2988
+ }
2989
+ else if (blob) {
2990
+ return this.toBlob(filename, quality);
2991
+ }
2992
+ else {
2993
+ return this.toDataURL(filename, quality);
2994
+ }
2995
+ };
2996
+ canvas.toBlob = function (type, quality) {
2997
+ return new Promise((resolve) => {
2998
+ Platform.origin.canvasToBolb(this.view, type, quality).then((blob) => {
2999
+ resolve(blob);
3000
+ }).catch((e) => {
3001
+ debug.error(e);
3002
+ resolve(null);
3003
+ });
3004
+ });
3005
+ };
3006
+ canvas.toDataURL = function (type, quality) {
3007
+ return Platform.origin.canvasToDataURL(this.view, type, quality);
3008
+ };
3009
+ canvas.saveAs = function (filename, quality) {
3010
+ return new Promise((resolve) => {
3011
+ Platform.origin.canvasSaveAs(this.view, filename, quality).then(() => {
3012
+ resolve(true);
3013
+ }).catch((e) => {
3014
+ debug.error(e);
3015
+ resolve(false);
3016
+ });
3017
+ });
3018
+ };
3019
+
3020
+ Object.assign(TextConvert, TextConvertModule);
3021
+ Object.assign(ColorConvert, ColorConvertModule);
3022
+ Object.assign(Paint, PaintModule);
3023
+ Object.assign(PaintImage, PaintImageModule);
3024
+ Object.assign(PaintGradient, PaintGradientModule);
3025
+ Object.assign(Effect, EffectModule);
3026
+ Object.assign(Export, ExportModule);
2649
3027
 
3028
+ Object.assign(Creator, {
3029
+ interaction: (target, canvas, selector, options) => new Interaction(target, canvas, selector, options),
3030
+ hitCanvas: (options, manager) => new LeaferCanvas(options, manager),
3031
+ hitCanvasManager: () => new HitCanvasManager()
3032
+ });
2650
3033
  useCanvas();
3034
+ window.addEventListener('unload', () => {
3035
+ const { list } = Leafer;
3036
+ list.forEach(leafer => leafer.destroy(true));
3037
+ list.destroy();
3038
+ ImageManager.destroy();
3039
+ });
2651
3040
 
2652
3041
  export { Interaction, Layouter, LeaferCanvas, Renderer, Selector, Watcher, useCanvas };