@leafer-in/editor 1.0.0-rc.9 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,197 @@
1
- import { Event, defineKey, MatrixHelper, UI, Paint, Group, Rect, Bounds, LeafList, PointerEvent, DragEvent, MoveEvent, ZoomEvent, PointHelper, AroundHelper, Box, Line, Matrix, DataHelper, RotateEvent, MathHelper, RenderEvent, KeyEvent, Creator } from '@leafer-ui/core';
1
+ import { PathCommandMap, MatrixHelper, Leaf, Text, Path, Line, Polygon, Group, Box, Event, defineKey, UI, Paint, Rect, Answer, Bounds, LeafList, PointHelper, AroundHelper, Direction9, MathHelper, Matrix, Debug, DataHelper, LeafHelper, RenderEvent, getPointData, Creator } from '@leafer-ui/draw';
2
+ import { PointerEvent, DragEvent, MoveEvent, ZoomEvent, RotateEvent, KeyEvent } from '@leafer-ui/core';
3
+
4
+ const { M, L, C, Q, Z, N, D, X, G, F, O, P, U } = PathCommandMap;
5
+ const PathScaler = {
6
+ scale(data, scaleX, scaleY) {
7
+ if (!data)
8
+ return;
9
+ let command;
10
+ let i = 0, len = data.length;
11
+ while (i < len) {
12
+ command = data[i];
13
+ switch (command) {
14
+ case M:
15
+ scalePoints(data, scaleX, scaleY, i, 1);
16
+ i += 3;
17
+ break;
18
+ case L:
19
+ scalePoints(data, scaleX, scaleY, i, 1);
20
+ i += 3;
21
+ break;
22
+ case C:
23
+ scalePoints(data, scaleX, scaleY, i, 3);
24
+ i += 7;
25
+ break;
26
+ case Q:
27
+ scalePoints(data, scaleX, scaleY, i, 2);
28
+ i += 5;
29
+ break;
30
+ case Z:
31
+ i += 1;
32
+ break;
33
+ case N:
34
+ scalePoints(data, scaleX, scaleY, i, 2);
35
+ i += 5;
36
+ break;
37
+ case D:
38
+ scalePoints(data, scaleX, scaleY, i, 2);
39
+ i += 9;
40
+ break;
41
+ case X:
42
+ scalePoints(data, scaleX, scaleY, i, 2);
43
+ i += 6;
44
+ break;
45
+ case G:
46
+ scalePoints(data, scaleX, scaleY, i, 2);
47
+ i += 9;
48
+ break;
49
+ case F:
50
+ scalePoints(data, scaleX, scaleY, i, 2);
51
+ i += 5;
52
+ break;
53
+ case O:
54
+ data[i] = G;
55
+ data.splice(i + 4, 0, data[i + 3], 0);
56
+ scalePoints(data, scaleX, scaleY, i, 2);
57
+ i += 7 + 2;
58
+ len += 2;
59
+ break;
60
+ case P:
61
+ data[i] = F;
62
+ data.splice(i + 4, 0, data[i + 3]);
63
+ scalePoints(data, scaleX, scaleY, i, 2);
64
+ i += 4 + 1;
65
+ len += 1;
66
+ break;
67
+ case U:
68
+ scalePoints(data, scaleX, scaleY, i, 2);
69
+ i += 6;
70
+ break;
71
+ }
72
+ }
73
+ },
74
+ scalePoints(data, scaleX, scaleY, start, pointCount) {
75
+ for (let i = pointCount ? start + 1 : 0, end = pointCount ? i + pointCount * 2 : data.length; i < end; i += 2) {
76
+ data[i] *= scaleX;
77
+ data[i + 1] *= scaleY;
78
+ }
79
+ }
80
+ };
81
+ const { scalePoints } = PathScaler;
82
+
83
+ const matrix$1 = MatrixHelper.get();
84
+ function scaleResize(leaf, scaleX, scaleY) {
85
+ if (leaf.pathInputed) {
86
+ scaleResizePath(leaf, scaleX, scaleY);
87
+ }
88
+ else {
89
+ if (scaleX !== 1)
90
+ leaf.width *= scaleX;
91
+ if (scaleY !== 1)
92
+ leaf.height *= scaleY;
93
+ }
94
+ }
95
+ function scaleResizeFontSize(leaf, scaleX, scaleY) {
96
+ const { width, height } = leaf.__localBoxBounds;
97
+ if (scaleX !== 1) {
98
+ leaf.fontSize *= scaleX;
99
+ leaf.y -= height * (scaleX - scaleY) / 2;
100
+ }
101
+ else if (scaleY !== 1) {
102
+ leaf.fontSize *= scaleY;
103
+ leaf.x -= width * (scaleY - scaleX) / 2;
104
+ }
105
+ }
106
+ function scaleResizePath(leaf, scaleX, scaleY) {
107
+ PathScaler.scale(leaf.__.path, scaleX, scaleY);
108
+ leaf.path = leaf.__.path;
109
+ }
110
+ function scaleResizePoints(leaf, scaleX, scaleY) {
111
+ PathScaler.scalePoints(leaf.__.points, scaleX, scaleY);
112
+ leaf.points = leaf.__.points;
113
+ }
114
+ function scaleResizeGroup(group, scaleX, scaleY) {
115
+ const { children } = group;
116
+ for (let i = 0; i < children.length; i++) {
117
+ matrix$1.a = scaleX;
118
+ matrix$1.d = scaleY;
119
+ children[i].transform(matrix$1, true);
120
+ }
121
+ }
122
+
123
+ const leaf = Leaf.prototype;
124
+ leaf.scaleResize = function (scaleX, scaleY = scaleX, noResize) {
125
+ const data = this;
126
+ if (noResize || (data.editConfig && data.editConfig.editSize === 'scale')) {
127
+ data.scaleX *= scaleX;
128
+ data.scaleY *= scaleY;
129
+ }
130
+ else {
131
+ if (scaleX < 0)
132
+ data.scaleX *= -1, scaleX = -scaleX;
133
+ if (scaleY < 0)
134
+ data.scaleY *= -1, scaleY = -scaleY;
135
+ this.__scaleResize(scaleX, scaleY);
136
+ }
137
+ };
138
+ leaf.__scaleResize = function (scaleX, scaleY) {
139
+ scaleResize(this, scaleX, scaleY);
140
+ };
141
+ leaf.resizeWidth = function (width) {
142
+ const scale = width / this.getBounds('box', 'local').width;
143
+ this.scaleOf(this.__layout.boxBounds, scale, this.__.lockRatio ? scale : 1, true);
144
+ };
145
+ leaf.resizeHeight = function (height) {
146
+ const scale = height / this.getBounds('box', 'local').height;
147
+ this.scaleOf(this.__layout.boxBounds, this.__.lockRatio ? scale : 1, scale, true);
148
+ };
149
+ Text.prototype.__scaleResize = function (scaleX, scaleY) {
150
+ if (this.__.__autoSize && (this.__.resizeFontSize || (this.editConfig && this.editConfig.editSize === 'font-size'))) {
151
+ scaleResizeFontSize(this, scaleX, scaleY);
152
+ }
153
+ else {
154
+ scaleResize(this, scaleX, scaleY);
155
+ }
156
+ };
157
+ Path.prototype.__scaleResize = function (scaleX, scaleY) {
158
+ scaleResizePath(this, scaleX, scaleY);
159
+ };
160
+ Line.prototype.__scaleResize = function (scaleX, scaleY) {
161
+ if (this.pathInputed) {
162
+ scaleResizePath(this, scaleX, scaleY);
163
+ }
164
+ else if (this.points) {
165
+ scaleResizePoints(this, scaleX, scaleY);
166
+ }
167
+ else {
168
+ this.width *= scaleX;
169
+ }
170
+ };
171
+ Polygon.prototype.__scaleResize = function (scaleX, scaleY) {
172
+ if (this.pathInputed) {
173
+ scaleResizePath(this, scaleX, scaleY);
174
+ }
175
+ else if (this.points) {
176
+ scaleResizePoints(this, scaleX, scaleY);
177
+ }
178
+ else {
179
+ scaleResize(this, scaleX, scaleY);
180
+ }
181
+ };
182
+ Group.prototype.__scaleResize = function (scaleX, scaleY) {
183
+ scaleResizeGroup(this, scaleX, scaleY);
184
+ };
185
+ Box.prototype.__scaleResize = function (scaleX, scaleY) {
186
+ if (this.__.__autoSize && this.children.length) {
187
+ scaleResizeGroup(this, scaleX, scaleY);
188
+ }
189
+ else {
190
+ scaleResize(this, scaleX, scaleY);
191
+ if (this.__.resizeChildren)
192
+ scaleResizeGroup(this, scaleX, scaleY);
193
+ }
194
+ };
2
195
 
3
196
  /******************************************************************************
4
197
  Copyright (c) Microsoft Corporation.
@@ -29,7 +222,12 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
29
222
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
30
223
  };
31
224
 
225
+ function toList(value) {
226
+ return value ? (value instanceof Array ? value : [value]) : [];
227
+ }
32
228
  class EditorEvent extends Event {
229
+ get list() { return toList(this.value); }
230
+ get oldList() { return toList(this.oldValue); }
33
231
  constructor(type, data) {
34
232
  super(type);
35
233
  if (data)
@@ -83,7 +281,7 @@ function targetAttr(fn) {
83
281
 
84
282
  const matrix = MatrixHelper.get();
85
283
  const { abs } = Math;
86
- const { copy, scale } = MatrixHelper;
284
+ const { copy: copy$1, scale } = MatrixHelper;
87
285
  class Stroker extends UI {
88
286
  constructor() {
89
287
  super();
@@ -92,40 +290,43 @@ class Stroker extends UI {
92
290
  this.strokeAlign = 'center';
93
291
  }
94
292
  setTarget(target, style) {
95
- const { stroke, strokeWidth } = style;
96
- this.set({ stroke, strokeWidth });
293
+ this.set(style);
97
294
  this.target = target;
98
295
  }
99
296
  __draw(canvas, options) {
100
297
  const { list } = this;
101
298
  if (list.length) {
102
299
  let leaf;
103
- const { stroke, strokeWidth } = this.__;
300
+ const { stroke, strokeWidth, fill } = this.__;
104
301
  const { bounds } = options;
105
302
  for (let i = 0; i < list.length; i++) {
106
303
  leaf = list[i];
107
304
  if (bounds && bounds.hit(leaf.__world, options.matrix)) {
108
- let drewPath;
109
- if (leaf.__.editSize === 'scale') {
110
- const aScaleX = abs(leaf.__world.scaleX), aScaleY = abs(leaf.__world.scaleY);
111
- if (aScaleX !== aScaleY) {
112
- copy(matrix, leaf.__world);
113
- scale(matrix, 1 / aScaleX, 1 / aScaleY);
114
- canvas.setWorld(matrix, options.matrix);
115
- canvas.beginPath();
116
- this.__.strokeWidth = strokeWidth;
117
- const { x, y, width, height } = leaf.__layout.boxBounds;
118
- canvas.rect(x * aScaleX, y * aScaleY, width * aScaleX, height * aScaleY);
119
- drewPath = true;
120
- }
305
+ const aScaleX = abs(leaf.__world.scaleX), aScaleY = abs(leaf.__world.scaleY);
306
+ if (aScaleX !== aScaleY) {
307
+ copy$1(matrix, leaf.__world);
308
+ scale(matrix, 1 / aScaleX, 1 / aScaleY);
309
+ canvas.setWorld(matrix, options.matrix);
310
+ canvas.beginPath();
311
+ this.__.strokeWidth = strokeWidth;
312
+ const { x, y, width, height } = leaf.__layout.boxBounds;
313
+ canvas.rect(x * aScaleX, y * aScaleY, width * aScaleX, height * aScaleY);
121
314
  }
122
- if (!drewPath) {
315
+ else {
123
316
  canvas.setWorld(leaf.__world, options.matrix);
124
317
  canvas.beginPath();
125
- leaf.__.__pathForRender ? leaf.__drawRenderPath(canvas) : leaf.__drawPathByBox(canvas);
318
+ if (leaf.__.__useArrow) {
319
+ leaf.__drawPath(canvas);
320
+ }
321
+ else {
322
+ leaf.__.__pathForRender ? leaf.__drawRenderPath(canvas) : leaf.__drawPathByBox(canvas);
323
+ }
126
324
  this.__.strokeWidth = strokeWidth / abs(leaf.__world.scaleX);
127
325
  }
128
- typeof stroke === 'string' ? Paint.stroke(stroke, this, canvas, options) : Paint.strokes(stroke, this, canvas, options);
326
+ if (stroke)
327
+ typeof stroke === 'string' ? Paint.stroke(stroke, this, canvas) : Paint.strokes(stroke, this, canvas);
328
+ if (fill)
329
+ typeof fill === 'string' ? Paint.fill(fill, this, canvas) : Paint.fills(fill, this, canvas);
129
330
  }
130
331
  }
131
332
  this.__.strokeWidth = strokeWidth;
@@ -165,21 +366,13 @@ class SelectArea extends Group {
165
366
  }
166
367
  }
167
368
 
168
- var AnswerType;
169
- (function (AnswerType) {
170
- AnswerType[AnswerType["No"] = 0] = "No";
171
- AnswerType[AnswerType["Yes"] = 1] = "Yes";
172
- AnswerType[AnswerType["NoAndSkip"] = 2] = "NoAndSkip";
173
- AnswerType[AnswerType["YesAndSkip"] = 3] = "YesAndSkip";
174
- })(AnswerType || (AnswerType = {}));
175
-
176
- const { No, Yes, NoAndSkip, YesAndSkip } = AnswerType;
369
+ const { No, Yes, NoAndSkip, YesAndSkip } = Answer;
177
370
  const EditSelectHelper = {
178
371
  findOne(path) {
179
372
  return path.list.find((leaf) => leaf.editable);
180
373
  },
181
374
  findBounds(leaf, bounds) {
182
- if (leaf.__.hittable && !leaf.__.locked && bounds.hit(leaf.__world)) {
375
+ if (leaf.__.hittable && leaf.__.visible && !leaf.__.locked && bounds.hit(leaf.__world)) {
183
376
  if (leaf.__.editable) {
184
377
  if (leaf.isBranch && !leaf.__.hitChildren) {
185
378
  return leaf.__.hitSelf ? YesAndSkip : NoAndSkip;
@@ -203,7 +396,7 @@ const EditSelectHelper = {
203
396
  const { findOne } = EditSelectHelper;
204
397
  class EditSelect extends Group {
205
398
  get dragging() { return !!this.originList; }
206
- get running() { return this.editor.hittable && this.editor.config.selector; }
399
+ get running() { const { editor } = this; return this.hittable && editor.visible && editor.hittable && editor.mergeConfig.selector; }
207
400
  get isMoveMode() { return this.app && this.app.interaction.moveMode; }
208
401
  constructor(editor) {
209
402
  super();
@@ -219,8 +412,8 @@ class EditSelect extends Group {
219
412
  onHover() {
220
413
  const { editor } = this;
221
414
  if (this.running && !this.dragging && !editor.dragging) {
222
- const { stroke, strokeWidth, hover } = editor.config;
223
- this.hoverStroker.setTarget(hover ? this.editor.hoverTarget : null, { stroke, strokeWidth });
415
+ const { stroke, strokeWidth, hover, hoverStyle } = editor.mergeConfig;
416
+ this.hoverStroker.setTarget(hover ? this.editor.hoverTarget : null, Object.assign({ stroke, strokeWidth }, (hoverStyle || {})));
224
417
  }
225
418
  else {
226
419
  this.hoverStroker.target = null;
@@ -228,62 +421,72 @@ class EditSelect extends Group {
228
421
  }
229
422
  onSelect() {
230
423
  if (this.running) {
231
- const { config, list } = this.editor;
424
+ const { mergeConfig: config, list } = this.editor;
232
425
  const { stroke, strokeWidth } = config;
233
426
  this.targetStroker.setTarget(list, { stroke, strokeWidth: Math.max(1, strokeWidth / 2) });
234
427
  this.hoverStroker.target = null;
235
428
  }
236
429
  }
237
430
  update() {
238
- if (this.running)
431
+ if (this.targetStroker.target)
239
432
  this.targetStroker.forceUpdate();
240
433
  }
241
434
  onPointerMove(e) {
242
- if (this.running && !this.isMoveMode) {
243
- const find = e.shiftKey ? this.findDeepOne(e) : findOne(e.path);
244
- this.editor.hoverTarget = this.editor.hasItem(find) ? null : find;
435
+ const { app, editor } = this;
436
+ if (this.running && !this.isMoveMode && app.config.pointer.hover && !app.interaction.dragging) {
437
+ const find = this.findUI(e);
438
+ editor.hoverTarget = editor.hasItem(find) ? null : find;
245
439
  }
246
440
  if (this.isMoveMode) {
247
- this.editor.hoverTarget = null;
441
+ editor.hoverTarget = null;
248
442
  }
249
443
  }
250
444
  onBeforeDown(e) {
251
- if (this.running && !this.isMoveMode && !e.middle) {
252
- const find = this.lastDownLeaf = findOne(e.path);
445
+ const { select } = this.editor.mergeConfig;
446
+ if (select === 'press')
447
+ this.checkAndSelect(e);
448
+ }
449
+ onTap(e) {
450
+ const { editor } = this;
451
+ const { select } = editor.mergeConfig;
452
+ if (select === 'tap')
453
+ this.checkAndSelect(e);
454
+ if (this.needRemoveItem) {
455
+ editor.removeItem(this.needRemoveItem);
456
+ }
457
+ else if (this.isMoveMode) {
458
+ editor.target = null;
459
+ }
460
+ }
461
+ checkAndSelect(e) {
462
+ this.needRemoveItem = null;
463
+ if (this.allowSelect(e)) {
464
+ const { editor } = this;
465
+ const find = this.findUI(e);
253
466
  if (find) {
254
- if (e.shiftKey) {
255
- this.editor.shiftItem(find);
467
+ if (this.isMultipleSelect(e)) {
468
+ if (editor.hasItem(find))
469
+ this.needRemoveItem = find;
470
+ else
471
+ editor.addItem(find);
256
472
  }
257
473
  else {
258
- this.editor.target = find;
474
+ editor.target = find;
259
475
  }
260
- this.editor.updateLayout();
261
- find.leafer.interaction.updateDownData();
262
476
  }
263
477
  else if (this.allow(e.target)) {
264
478
  if (!e.shiftKey)
265
- this.editor.target = null;
479
+ editor.target = null;
266
480
  }
267
481
  }
268
482
  }
269
- onTap(e) {
270
- if (this.running && e.shiftKey && !e.middle && !this.lastDownLeaf) {
271
- const find = this.findDeepOne(e);
272
- if (find)
273
- this.editor.shiftItem(find);
274
- }
275
- else if (this.isMoveMode) {
276
- this.editor.target = null;
277
- }
278
- this.lastDownLeaf = null;
279
- }
280
483
  onDragStart(e) {
281
- if (this.running && this.allowDrag(e)) {
484
+ if (this.allowDrag(e)) {
282
485
  const { editor } = this;
283
- const { stroke, strokeWidth, area } = editor.config;
486
+ const { stroke, area } = editor.mergeConfig;
284
487
  const { x, y } = e.getInner(this);
285
488
  this.bounds.set(x, y);
286
- this.selectArea.setStyle({ visible: true, stroke, strokeWidth, x, y }, area);
489
+ this.selectArea.setStyle({ visible: true, stroke, x, y }, area);
287
490
  this.selectArea.setBounds(this.bounds.get());
288
491
  this.originList = editor.leafList.clone();
289
492
  }
@@ -313,8 +516,6 @@ class EditSelect extends Group {
313
516
  }
314
517
  else {
315
518
  editor.target = this.originList.list;
316
- if (editor.leafList.length)
317
- editor.update();
318
519
  }
319
520
  }
320
521
  }
@@ -333,17 +534,26 @@ class EditSelect extends Group {
333
534
  return target.leafer !== this.editor.leafer;
334
535
  }
335
536
  allowDrag(e) {
336
- if (this.editor.config.boxSelect && !e.target.draggable) {
337
- return (!this.editor.hasTarget && this.allow(e.target)) || (e.shiftKey && !findOne(e.path));
537
+ if (this.running && this.editor.mergeConfig.boxSelect && !e.target.draggable) {
538
+ return (!this.editor.editing && this.allow(e.target)) || (e.shiftKey && !findOne(e.path));
338
539
  }
339
540
  else {
340
541
  return false;
341
542
  }
342
543
  }
544
+ allowSelect(e) {
545
+ return this.running && !this.isMoveMode && !e.middle;
546
+ }
343
547
  findDeepOne(e) {
344
548
  const options = { exclude: new LeafList(this.editor.editBox.rect) };
345
549
  return findOne(e.target.leafer.interaction.findPath(e, options));
346
550
  }
551
+ findUI(e) {
552
+ return this.isMultipleSelect(e) ? this.findDeepOne(e) : findOne(e.path);
553
+ }
554
+ isMultipleSelect(e) {
555
+ return e.shiftKey || this.editor.mergeConfig.continuousSelect;
556
+ }
347
557
  __listenEvents() {
348
558
  const { editor } = this;
349
559
  editor.waitLeafer(() => {
@@ -370,29 +580,17 @@ class EditSelect extends Group {
370
580
  }
371
581
  }
372
582
  destroy() {
373
- this.editor = this.originList = this.lastDownLeaf = null;
583
+ this.editor = this.originList = this.needRemoveItem = null;
374
584
  this.__removeListenEvents();
375
585
  super.destroy();
376
586
  }
377
587
  }
378
588
 
379
- var IDirection8;
380
- (function (IDirection8) {
381
- IDirection8[IDirection8["topLeft"] = 0] = "topLeft";
382
- IDirection8[IDirection8["top"] = 1] = "top";
383
- IDirection8[IDirection8["topRight"] = 2] = "topRight";
384
- IDirection8[IDirection8["right"] = 3] = "right";
385
- IDirection8[IDirection8["bottomRight"] = 4] = "bottomRight";
386
- IDirection8[IDirection8["bottom"] = 5] = "bottom";
387
- IDirection8[IDirection8["bottomLeft"] = 6] = "bottomLeft";
388
- IDirection8[IDirection8["left"] = 7] = "left";
389
- })(IDirection8 || (IDirection8 = {}));
390
-
391
- const { topLeft: topLeft$1, top: top$1, topRight: topRight$1, right: right$2, bottomRight: bottomRight$1, bottom: bottom$1, bottomLeft: bottomLeft$1, left: left$2 } = IDirection8;
589
+ const { topLeft, top, topRight, right: right$1, bottomRight, bottom, bottomLeft, left: left$1 } = Direction9;
392
590
  const { toPoint } = AroundHelper;
393
591
  const EditDataHelper = {
394
592
  getScaleData(bounds, direction, pointMove, lockRatio, around) {
395
- let origin, scaleX = 1, scaleY = 1;
593
+ let align, origin = {}, scaleX = 1, scaleY = 1;
396
594
  const { width, height } = bounds;
397
595
  if (around) {
398
596
  pointMove.x *= 2;
@@ -407,100 +605,102 @@ const EditDataHelper = {
407
605
  const bottomScale = (pointMove.y + height) / height;
408
606
  const leftScale = (-pointMove.x + width) / width;
409
607
  switch (direction) {
410
- case top$1:
608
+ case top:
411
609
  scaleY = topScale;
412
- origin = { x: 0.5, y: 1 };
610
+ align = 'bottom';
413
611
  break;
414
- case right$2:
612
+ case right$1:
415
613
  scaleX = rightScale;
416
- origin = { x: 0, y: 0.5 };
614
+ align = 'left';
417
615
  break;
418
- case bottom$1:
616
+ case bottom:
419
617
  scaleY = bottomScale;
420
- origin = { x: 0.5, y: 0 };
618
+ align = 'top';
421
619
  break;
422
- case left$2:
620
+ case left$1:
423
621
  scaleX = leftScale;
424
- origin = { x: 1, y: 0.5 };
622
+ align = 'right';
425
623
  break;
426
- case topLeft$1:
624
+ case topLeft:
427
625
  scaleY = topScale;
428
626
  scaleX = leftScale;
429
- origin = { x: 1, y: 1 };
627
+ align = 'bottom-right';
430
628
  break;
431
- case topRight$1:
629
+ case topRight:
432
630
  scaleY = topScale;
433
631
  scaleX = rightScale;
434
- origin = { x: 0, y: 1 };
632
+ align = 'bottom-left';
435
633
  break;
436
- case bottomRight$1:
634
+ case bottomRight:
437
635
  scaleY = bottomScale;
438
636
  scaleX = rightScale;
439
- origin = { x: 0, y: 0 };
637
+ align = 'top-left';
440
638
  break;
441
- case bottomLeft$1:
639
+ case bottomLeft:
442
640
  scaleY = bottomScale;
443
641
  scaleX = leftScale;
444
- origin = { x: 1, y: 0 };
642
+ align = 'top-right';
445
643
  }
446
644
  if (lockRatio) {
447
- if (scaleX !== 1)
448
- scaleY = scaleX;
449
- else
450
- scaleX = scaleY;
645
+ const unlockSide = lockRatio === 'corner' && direction % 2;
646
+ if (!unlockSide) {
647
+ const scale = Math.sqrt(Math.abs(scaleX * scaleY));
648
+ scaleX = scaleX < 0 ? -scale : scale;
649
+ scaleY = scaleY < 0 ? -scale : scale;
650
+ }
451
651
  }
452
- toPoint(around || origin, bounds, origin);
652
+ toPoint(around || align, bounds, origin);
453
653
  return { origin, scaleX, scaleY, direction, lockRatio, around };
454
654
  },
455
655
  getRotateData(bounds, direction, current, last, around) {
456
- let origin;
656
+ let align, origin = {};
457
657
  switch (direction) {
458
- case topLeft$1:
459
- origin = { x: 1, y: 1 };
658
+ case topLeft:
659
+ align = 'bottom-right';
460
660
  break;
461
- case topRight$1:
462
- origin = { x: 0, y: 1 };
661
+ case topRight:
662
+ align = 'bottom-left';
463
663
  break;
464
- case bottomRight$1:
465
- origin = { x: 0, y: 0 };
664
+ case bottomRight:
665
+ align = 'top-left';
466
666
  break;
467
- case bottomLeft$1:
468
- origin = { x: 1, y: 0 };
667
+ case bottomLeft:
668
+ align = 'top-right';
469
669
  break;
470
670
  default:
471
- origin = { x: 0.5, y: 0.5 };
671
+ align = 'center';
472
672
  }
473
- toPoint(around || origin, bounds, origin);
673
+ toPoint(around || align, bounds, origin);
474
674
  return { origin, rotation: PointHelper.getRotation(last, origin, current) };
475
675
  },
476
676
  getSkewData(bounds, direction, move, around) {
477
- let origin, skewX = 0, skewY = 0;
677
+ let align, origin = {}, skewX = 0, skewY = 0;
478
678
  let last;
479
679
  switch (direction) {
480
- case top$1:
680
+ case top:
481
681
  last = { x: 0.5, y: 0 };
482
- origin = { x: 0.5, y: 1 };
682
+ align = 'bottom';
483
683
  skewX = 1;
484
684
  break;
485
- case bottom$1:
685
+ case bottom:
486
686
  last = { x: 0.5, y: 1 };
487
- origin = { x: 0.5, y: 0 };
687
+ align = 'top';
488
688
  skewX = 1;
489
689
  break;
490
- case left$2:
690
+ case left$1:
491
691
  last = { x: 0, y: 0.5 };
492
- origin = { x: 1, y: 0.5 };
692
+ align = 'right';
493
693
  skewY = 1;
494
694
  break;
495
- case right$2:
695
+ case right$1:
496
696
  last = { x: 1, y: 0.5 };
497
- origin = { x: 0, y: 0.5 };
697
+ align = 'left';
498
698
  skewY = 1;
499
699
  }
500
700
  const { x, y, width, height } = bounds;
501
701
  last.x = x + last.x * width;
502
702
  last.y = y + last.y * height;
503
- toPoint(around || origin, bounds, origin);
703
+ toPoint(around || align, bounds, origin);
504
704
  const rotation = PointHelper.getRotation(last, origin, { x: last.x + (skewX ? move.x : 0), y: last.y + (skewY ? move.y : 0) });
505
705
  skewX ? skewX = -rotation : skewY = rotation;
506
706
  return { origin, skewX, skewY };
@@ -513,53 +713,87 @@ const EditDataHelper = {
513
713
  if (direction < 0)
514
714
  direction += totalDirection;
515
715
  return direction;
716
+ },
717
+ getFlipDirection(direction, flipedX, flipedY) {
718
+ if (flipedX) {
719
+ switch (direction) {
720
+ case left$1:
721
+ direction = right$1;
722
+ break;
723
+ case topLeft:
724
+ direction = topRight;
725
+ break;
726
+ case bottomLeft:
727
+ direction = bottomRight;
728
+ break;
729
+ case right$1:
730
+ direction = left$1;
731
+ break;
732
+ case topRight:
733
+ direction = topLeft;
734
+ break;
735
+ case bottomRight:
736
+ direction = bottomLeft;
737
+ break;
738
+ }
739
+ }
740
+ if (flipedY) {
741
+ switch (direction) {
742
+ case top:
743
+ direction = bottom;
744
+ break;
745
+ case topLeft:
746
+ direction = bottomLeft;
747
+ break;
748
+ case topRight:
749
+ direction = bottomRight;
750
+ break;
751
+ case bottom:
752
+ direction = top;
753
+ break;
754
+ case bottomLeft:
755
+ direction = topLeft;
756
+ break;
757
+ case bottomRight:
758
+ direction = topRight;
759
+ break;
760
+ }
761
+ }
762
+ return direction;
516
763
  }
517
764
  };
518
765
 
519
- const { topLeft, top, topRight, right: right$1, bottomRight, bottom, bottomLeft, left: left$1 } = IDirection8;
766
+ const cacheCursors = {};
520
767
  function updateCursor(editor, e) {
521
768
  const { editBox } = editor, point = editBox.enterPoint;
522
- if (!point || !editor.hasTarget || !editBox.visible)
769
+ if (!point || !editor.editing || !editBox.visible)
770
+ return;
771
+ if (point.name === 'circle')
523
772
  return;
524
773
  let { rotation } = editBox;
525
- let { resizeCursor, rotateCursor, resizeable, rotateable } = editor.config;
526
- const { direction, pointType } = point;
527
- editBox.enterPoint = point;
528
- const isResizePoint = pointType === 'resize';
529
- if (isResizePoint && rotateable && (e.metaKey || e.ctrlKey || !resizeable))
530
- resizeCursor = rotateCursor;
531
- if (editBox.flipped) {
532
- const { flippedX, flippedY } = editBox;
533
- mirrorCursors(resizeCursor = [...resizeCursor], flippedX, flippedY);
534
- mirrorCursors(rotateCursor = [...rotateCursor], flippedY, flippedX);
535
- if (editBox.flippedOne)
536
- rotation = -rotation;
774
+ const { resizeCursor, rotateCursor, skewCursor, resizeable, rotateable, skewable } = editor.mergeConfig;
775
+ const { pointType } = point, { flippedX, flippedY } = editBox;
776
+ let showResize = pointType === 'resize';
777
+ if (showResize && rotateable && (e.metaKey || e.ctrlKey || !resizeable))
778
+ showResize = false;
779
+ const showSkew = skewable && !showResize && point.name === 'resize-line';
780
+ const cursor = showSkew ? skewCursor : (showResize ? resizeCursor : rotateCursor);
781
+ rotation += (EditDataHelper.getFlipDirection(point.direction, flippedX, flippedY) + 1) * 45;
782
+ rotation = Math.round(MathHelper.formatRotation(rotation, true) / 2) * 2;
783
+ const { url, x, y } = cursor;
784
+ const key = url + rotation;
785
+ if (cacheCursors[key]) {
786
+ point.cursor = cacheCursors[key];
787
+ }
788
+ else {
789
+ cacheCursors[key] = point.cursor = { url: toDataURL(url, rotation), x, y };
537
790
  }
538
- const index = EditDataHelper.getRotateDirection(direction, rotation);
539
- point.cursor = isResizePoint ? resizeCursor[index] : rotateCursor[index];
540
791
  }
541
792
  function updateMoveCursor(editor) {
542
- editor.editBox.rect.cursor = editor.config.moveCursor;
793
+ editor.editBox.rect.cursor = editor.mergeConfig.moveCursor;
543
794
  }
544
- function mirrorCursors(mirror, mirrorX, mirrorY) {
545
- if (mirrorX) {
546
- const topCursor = mirror[top], topLeftCursor = mirror[topLeft], topRightCursor = mirror[topRight];
547
- mirror[top] = mirror[bottom];
548
- mirror[topLeft] = mirror[bottomLeft];
549
- mirror[topRight] = mirror[bottomRight];
550
- mirror[bottom] = topCursor;
551
- mirror[bottomLeft] = topLeftCursor;
552
- mirror[bottomRight] = topRightCursor;
553
- }
554
- if (mirrorY) {
555
- const leftCursor = mirror[left$1], topLeftCursor = mirror[topLeft], bottomLeftCursor = mirror[bottomLeft];
556
- mirror[left$1] = mirror[right$1];
557
- mirror[topLeft] = mirror[topRight];
558
- mirror[bottomLeft] = mirror[bottomRight];
559
- mirror[right$1] = leftCursor;
560
- mirror[topRight] = topLeftCursor;
561
- mirror[bottomRight] = bottomLeftCursor;
562
- }
795
+ function toDataURL(svg, rotation) {
796
+ return '"data:image/svg+xml,' + encodeURIComponent(svg.replace('{{rotation}}', rotation.toString())) + '"';
563
797
  }
564
798
 
565
799
  class EditPoint extends Box {
@@ -573,8 +807,9 @@ class EditBox extends Group {
573
807
  get flippedOne() { return this.scaleX * this.scaleY < 0; }
574
808
  constructor(editor) {
575
809
  super();
810
+ this.view = new Group();
576
811
  this.rect = new Box({ name: 'rect', hitFill: 'all', hitStroke: 'none', strokeAlign: 'center', hitRadius: 5 });
577
- this.circle = new EditPoint({ name: 'circle', strokeAlign: 'outside', around: 'center', cursor: 'crosshair', hitRadius: 5 });
812
+ this.circle = new EditPoint({ name: 'circle', strokeAlign: 'center', around: 'center', cursor: 'crosshair', hitRadius: 5 });
578
813
  this.buttons = new Group({ around: 'center', hitSelf: false });
579
814
  this.resizePoints = [];
580
815
  this.rotatePoints = [];
@@ -583,14 +818,15 @@ class EditBox extends Group {
583
818
  this.editor = editor;
584
819
  this.visible = false;
585
820
  this.create();
821
+ this.rect.syncEventer = editor;
586
822
  this.__listenEvents();
587
823
  }
588
824
  create() {
589
825
  let rotatePoint, resizeLine, resizePoint;
590
- const { resizePoints, rotatePoints, resizeLines, rect, circle, buttons } = this;
591
- const arounds = [{ x: 1, y: 1 }, { x: 0.5, y: 1 }, { x: 0, y: 1 }, { x: 0, y: 0.5 }, { x: 0, y: 0 }, { x: 0.5, y: 0 }, { x: 1, y: 0 }, { x: 1, y: 0.5 }];
826
+ const { view, resizePoints, rotatePoints, resizeLines, rect, circle, buttons } = this;
827
+ const arounds = ['bottom-right', 'bottom', 'bottom-left', 'left', 'top-left', 'top', 'top-right', 'right'];
592
828
  for (let i = 0; i < 8; i++) {
593
- rotatePoint = new EditPoint({ around: arounds[i], width: 15, height: 15, hitFill: "all" });
829
+ rotatePoint = new EditPoint({ name: 'rotate-point', around: arounds[i], width: 15, height: 15, hitFill: "all" });
594
830
  rotatePoints.push(rotatePoint);
595
831
  this.listenPointEvents(rotatePoint, 'rotate', i);
596
832
  if (i % 2) {
@@ -598,58 +834,82 @@ class EditBox extends Group {
598
834
  resizeLines.push(resizeLine);
599
835
  this.listenPointEvents(resizeLine, 'resize', i);
600
836
  }
601
- resizePoint = new EditPoint({ name: 'resize-point', around: 'center', strokeAlign: 'outside', hitRadius: 5 });
837
+ resizePoint = new EditPoint({ name: 'resize-point', hitRadius: 5 });
602
838
  resizePoints.push(resizePoint);
603
839
  this.listenPointEvents(resizePoint, 'resize', i);
604
840
  }
605
841
  buttons.add(circle);
606
842
  this.listenPointEvents(circle, 'rotate', 2);
607
- this.addMany(...rotatePoints, rect, buttons, ...resizeLines, ...resizePoints);
843
+ view.addMany(...rotatePoints, rect, buttons, ...resizeLines, ...resizePoints);
844
+ this.add(view);
608
845
  }
609
- update(bounds) {
610
- const { config, list } = this.editor;
611
- const { width, height } = bounds;
612
- const { rect, circle, resizePoints, rotatePoints, resizeLines } = this;
613
- const { middlePoint, resizeable, rotateable, stroke, strokeWidth } = config;
846
+ load() {
847
+ const { mergeConfig, element, single } = this.editor;
848
+ const { rect, circle, resizePoints } = this;
849
+ const { stroke, strokeWidth, moveable } = mergeConfig;
614
850
  const pointsStyle = this.getPointsStyle();
615
851
  const middlePointsStyle = this.getMiddlePointsStyle();
616
- this.visible = list[0] && !list[0].locked;
617
- let point = {}, style, rotateP, resizeP, resizeL;
852
+ let resizeP;
618
853
  for (let i = 0; i < 8; i++) {
619
- AroundHelper.toPoint(AroundHelper.directionData[i], bounds, point);
620
- style = this.getPointStyle((i % 2) ? middlePointsStyle[((i - 1) / 2) % middlePointsStyle.length] : pointsStyle[(i / 2) % pointsStyle.length]);
621
- resizeP = resizePoints[i], rotateP = rotatePoints[i], resizeL = resizeLines[Math.floor(i / 2)];
622
- resizeP.set(style);
623
- resizeP.set(point), rotateP.set(point), resizeL.set(point);
624
- resizeP.visible = resizeL.visible = resizeable || rotateable;
625
- rotateP.visible = rotateable && resizeable;
626
- if (i % 2) {
627
- resizeP.visible = rotateP.visible = !!middlePoint;
628
- if (((i + 1) / 2) % 2) {
629
- resizeL.width = width;
630
- if (resizeP.width > width - 30)
631
- resizeP.visible = false;
632
- }
633
- else {
634
- resizeL.height = height;
635
- resizeP.rotation = 90;
636
- if (resizeP.width > height - 30)
637
- resizeP.visible = false;
638
- }
639
- }
640
- else {
854
+ resizeP = resizePoints[i];
855
+ resizeP.set(this.getPointStyle((i % 2) ? middlePointsStyle[((i - 1) / 2) % middlePointsStyle.length] : pointsStyle[(i / 2) % pointsStyle.length]));
856
+ if (!(i % 2))
641
857
  resizeP.rotation = (i / 2) * 90;
858
+ }
859
+ circle.set(this.getPointStyle(mergeConfig.rotatePoint || pointsStyle[0]));
860
+ rect.set(Object.assign({ stroke, strokeWidth }, (mergeConfig.rect || {})));
861
+ rect.hittable = !single && moveable;
862
+ element.syncEventer = (single && moveable) ? rect : null;
863
+ this.app.interaction.bottomList = (single && moveable) ? [{ target: rect, proxy: element }] : null;
864
+ }
865
+ update(bounds) {
866
+ this.visible = !this.editor.element.locked;
867
+ if (this.view.worldOpacity) {
868
+ const { mergeConfig } = this.editor;
869
+ const { width, height } = bounds;
870
+ const { rect, circle, resizePoints, rotatePoints, resizeLines } = this;
871
+ const { middlePoint, resizeable, rotateable, hideOnSmall } = mergeConfig;
872
+ const smallSize = typeof hideOnSmall === 'number' ? hideOnSmall : 10;
873
+ const showPoints = !(hideOnSmall && width < smallSize && height < smallSize);
874
+ let point = {}, rotateP, resizeP, resizeL;
875
+ for (let i = 0; i < 8; i++) {
876
+ AroundHelper.toPoint(AroundHelper.directionData[i], bounds, point);
877
+ resizeP = resizePoints[i];
878
+ rotateP = rotatePoints[i];
879
+ resizeL = resizeLines[Math.floor(i / 2)];
880
+ resizeP.set(point);
881
+ rotateP.set(point);
882
+ resizeL.set(point);
883
+ resizeP.visible = resizeL.visible = showPoints && !!(resizeable || rotateable);
884
+ rotateP.visible = showPoints && rotateable && resizeable && !mergeConfig.rotatePoint;
885
+ if (i % 2) {
886
+ resizeP.visible = rotateP.visible = showPoints && !!middlePoint;
887
+ if (((i + 1) / 2) % 2) {
888
+ resizeL.width = width;
889
+ if (resizeP.width > width - 30)
890
+ resizeP.visible = false;
891
+ }
892
+ else {
893
+ resizeL.height = height;
894
+ resizeP.rotation = 90;
895
+ if (resizeP.width > height - 30)
896
+ resizeP.visible = false;
897
+ }
898
+ }
642
899
  }
900
+ circle.visible = showPoints && rotateable && !!mergeConfig.rotatePoint;
901
+ if (rect.path)
902
+ rect.path = null;
903
+ rect.set(Object.assign(Object.assign({}, bounds), { visible: true }));
904
+ const buttonVisible = showPoints && (circle.visible || this.buttons.children.length > 1);
905
+ this.buttons.visible = buttonVisible;
906
+ if (buttonVisible)
907
+ this.layoutButtons();
643
908
  }
644
- circle.visible = rotateable && !!config.rotatePoint;
645
- circle.set(this.getPointStyle(config.rotatePoint || pointsStyle[0]));
646
- rect.set(Object.assign({ stroke, strokeWidth }, (config.rect || {})));
647
- rect.set(Object.assign(Object.assign({}, bounds), { visible: true }));
648
- this.layoutButtons();
649
909
  }
650
910
  layoutButtons() {
651
911
  const { buttons, resizePoints } = this;
652
- const { buttonsDirection, buttonsFixed, buttonsMargin, middlePoint } = this.editor.config;
912
+ const { buttonsDirection, buttonsFixed, buttonsMargin, middlePoint } = this.editor.mergeConfig;
653
913
  const { flippedX, flippedY } = this;
654
914
  let index = fourDirection.indexOf(buttonsDirection);
655
915
  if ((index % 2 && flippedX) || ((index + 1) % 2 && flippedY)) {
@@ -676,42 +936,58 @@ class EditBox extends Group {
676
936
  buttons.scaleY = flippedY ? -1 : 1;
677
937
  }
678
938
  }
939
+ unload() {
940
+ this.visible = false;
941
+ }
679
942
  getPointStyle(userStyle) {
680
- const { stroke, strokeWidth, pointFill, pointSize, pointRadius } = this.editor.config;
681
- const defaultStyle = { fill: pointFill, stroke, strokeWidth, width: pointSize, height: pointSize, cornerRadius: pointRadius };
943
+ const { stroke, strokeWidth, pointFill, pointSize, pointRadius } = this.editor.mergeConfig;
944
+ const defaultStyle = { fill: pointFill, stroke, strokeWidth, around: 'center', strokeAlign: 'center', width: pointSize, height: pointSize, cornerRadius: pointRadius };
682
945
  return userStyle ? Object.assign(defaultStyle, userStyle) : defaultStyle;
683
946
  }
684
947
  getPointsStyle() {
685
- const { point } = this.editor.config;
948
+ const { point } = this.editor.mergeConfig;
686
949
  return point instanceof Array ? point : [point];
687
950
  }
688
951
  getMiddlePointsStyle() {
689
- const { middlePoint } = this.editor.config;
952
+ const { middlePoint } = this.editor.mergeConfig;
690
953
  return middlePoint instanceof Array ? middlePoint : (middlePoint ? [middlePoint] : this.getPointsStyle());
691
954
  }
955
+ onSelect(e) {
956
+ if (e.oldList.length === 1) {
957
+ e.oldList[0].syncEventer = null;
958
+ if (this.app)
959
+ this.app.interaction.bottomList = null;
960
+ }
961
+ }
692
962
  onDragStart(e) {
693
963
  this.dragging = true;
694
- if (e.target.name === 'rect')
695
- this.editor.opacity = this.editor.config.hideOnMove ? 0 : 1;
964
+ if (e.current.name === 'rect') {
965
+ const { editor } = this;
966
+ this.moving = true;
967
+ editor.dragStartPoint = { x: editor.element.x, y: editor.element.y };
968
+ editor.opacity = editor.mergeConfig.hideOnMove ? 0 : 1;
969
+ }
696
970
  }
697
971
  onDragEnd(e) {
698
972
  this.dragging = false;
699
- if (e.target.name === 'rect')
973
+ this.moving = false;
974
+ if (e.current.name === 'rect')
700
975
  this.editor.opacity = 1;
701
976
  }
702
977
  onDrag(e) {
703
978
  const { editor } = this;
704
- const point = e.current;
705
- if (point.pointType === 'rotate' || e.metaKey || e.ctrlKey || !editor.config.resizeable) {
706
- if (editor.config.rotateable)
979
+ const point = this.enterPoint = e.current;
980
+ if (point.pointType === 'rotate' || e.metaKey || e.ctrlKey || !editor.mergeConfig.resizeable) {
981
+ if (editor.mergeConfig.rotateable)
707
982
  editor.onRotate(e);
708
983
  }
709
984
  else {
710
985
  editor.onScale(e);
711
986
  }
987
+ updateCursor(editor, e);
712
988
  }
713
989
  onArrow(e) {
714
- if (this.editor.hasTarget) {
990
+ if (this.editor.editing && this.editor.mergeConfig.keyEvent) {
715
991
  const move = { x: 0, y: 0 };
716
992
  const distance = e.shiftKey ? 10 : 1;
717
993
  switch (e.code) {
@@ -727,13 +1003,29 @@ class EditBox extends Group {
727
1003
  case 'ArrowRight':
728
1004
  move.x = distance;
729
1005
  }
730
- if (move.x || move.y)
731
- this.editor.move(move.x, move.y);
1006
+ this.editor.move(move);
732
1007
  }
733
1008
  }
734
- onDoubleClick() {
1009
+ onDoubleTap(e) {
1010
+ if (this.editor.mergeConfig.openInner === 'double')
1011
+ this.openInner(e);
1012
+ }
1013
+ onLongPress(e) {
1014
+ if (this.editor.mergeConfig.openInner === 'long')
1015
+ this.openInner(e);
1016
+ }
1017
+ openInner(e) {
735
1018
  const { editor } = this;
736
- if (editor.single && editor.element.isBranch) ;
1019
+ if (editor.single) {
1020
+ const { element } = editor;
1021
+ if (element.isBranch) {
1022
+ editor.openGroup(element);
1023
+ editor.target = editor.selector.findDeepOne(e);
1024
+ }
1025
+ else {
1026
+ editor.openInnerEditor();
1027
+ }
1028
+ }
737
1029
  }
738
1030
  listenPointEvents(point, type, direction) {
739
1031
  const { editor } = this;
@@ -749,12 +1041,15 @@ class EditBox extends Group {
749
1041
  __listenEvents() {
750
1042
  const { rect, editor } = this;
751
1043
  this.__eventIds = [
752
- editor.on_(EditorEvent.SELECT, () => { this.visible = editor.hasTarget; }),
1044
+ editor.on_(EditorEvent.SELECT, this.onSelect, this),
753
1045
  rect.on_(DragEvent.START, this.onDragStart, this),
754
1046
  rect.on_(DragEvent.DRAG, editor.onMove, editor),
755
1047
  rect.on_(DragEvent.END, this.onDragEnd, this),
1048
+ rect.on_(ZoomEvent.BEFORE_ZOOM, editor.onScale, editor, true),
1049
+ rect.on_(RotateEvent.BEFORE_ROTATE, editor.onRotate, editor, true),
756
1050
  rect.on_(PointerEvent.ENTER, () => updateMoveCursor(editor)),
757
- rect.on_(PointerEvent.DOUBLE_CLICK, this.onDoubleClick, this)
1051
+ rect.on_(PointerEvent.DOUBLE_TAP, this.onDoubleTap, this),
1052
+ rect.on_(PointerEvent.LONG_PRESS, this.onLongPress, this)
758
1053
  ];
759
1054
  }
760
1055
  __removeListenEvents() {
@@ -768,164 +1063,108 @@ class EditBox extends Group {
768
1063
  }
769
1064
  }
770
1065
 
1066
+ class EditMask extends UI {
1067
+ constructor(editor) {
1068
+ super();
1069
+ this.editor = editor;
1070
+ this.hittable = false;
1071
+ }
1072
+ __draw(canvas, options) {
1073
+ const { editor } = this;
1074
+ const { mask } = editor.mergeConfig;
1075
+ if (mask && editor.list.length) {
1076
+ const { rect } = editor.editBox;
1077
+ const { width, height } = rect.__;
1078
+ canvas.resetTransform();
1079
+ canvas.fillWorld(canvas.bounds, mask);
1080
+ canvas.setWorld(rect.__world, options.matrix);
1081
+ canvas.clearRect(0, 0, width, height);
1082
+ }
1083
+ }
1084
+ destroy() {
1085
+ this.editor = null;
1086
+ super.destroy();
1087
+ }
1088
+ }
1089
+
1090
+ const filterStyle = `
1091
+ <feOffset dy="1"/>
1092
+ <feGaussianBlur stdDeviation="1.5"/>
1093
+ <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2 0"/>
1094
+ <feBlend mode="normal" in="SourceGraphic" result="shape"/>`;
1095
+ const resizeSVG = `
1096
+ <svg width="24" height="24" xmlns="http://www.w3.org/2000/svg">
1097
+ <g filter="url(#f)">
1098
+ <g transform="rotate({{rotation}},12,12)">
1099
+ <path d="M7.5 8.0H8.5V5.9L6.8 7.2L7.5 8.0ZM3 11.4L2.3 10.6L1.3 11.4L2.3 12.2L3 11.4ZM7.5 10.4H6.5V11.4H7.5V10.4ZM16.5 10.4V11.4H17.5V10.4H16.5ZM16.5 8.0L17.1 7.2L15.5 5.9V8.0H16.5ZM21 11.4L21.6 12.2L22.6 11.4L21.6 10.6L21 11.4ZM16.5 14.9H15.5V16.9L17.1 15.7L16.5 14.9ZM16.5 12.4H17.5V11.4H16.5V12.4ZM7.5 12.4V11.4H6.5V12.4H7.5ZM7.5 14.9L6.8 15.7L8.5 16.9V14.9H7.5ZM6.8 7.2L2.3 10.6L3.6 12.2L8.1 8.7L6.8 7.2ZM8.5 10.4V8.0H6.5V10.4H8.5ZM16.5 9.4H7.5V11.4H16.5V9.4ZM17.5 10.4V8.0H15.5V10.4H17.5ZM15.8 8.7L20.3 12.2L21.6 10.6L17.1 7.2L15.8 8.7ZM20.3 10.6L15.8 14.1L17.1 15.7L21.6 12.2L20.3 10.6ZM17.5 14.9V12.4H15.5V14.9H17.5ZM7.5 13.4H16.5V11.4H7.5V13.4ZM8.5 14.9V12.4H6.5V14.9H8.5ZM2.3 12.2L6.8 15.7L8.1 14.1L3.6 10.6L2.3 12.2Z" fill="white"/>
1100
+ <path fill-rule="evenodd" d="M3 11.4L7.5 8.0V10.4H16.5V8.0L21 11.4L16.5 14.9V12.4H7.5V14.9L3 11.4Z" fill="black"/>
1101
+ </g>
1102
+ </g>
1103
+ <defs>
1104
+ <filter id="f" x="-1.6" y="3.9" width="27.2" height="16.9" filterUnits="userSpaceOnUse">
1105
+ ${filterStyle}
1106
+ </filter>
1107
+ </defs>
1108
+ </svg>
1109
+ `;
1110
+ const rotateSVG = `
1111
+ <svg width="24" height="24" xmlns="http://www.w3.org/2000/svg">
1112
+ <g filter="url(#f)">
1113
+ <g transform="rotate(135,12,12),rotate({{rotation}},12,12)">
1114
+ <path d="M20.4 8H21.4L20.8 7.1L17.3 2.6L17 2.1L16.6 2.6L13.1 7.1L12.5 8H13.5H15.4C14.9 11.8 11.8 14.9 8 15.4V13.5V12.5L7.1 13.1L2.6 16.6L2.1 17L2.6 17.3L7.1 20.8L8 21.4V20.4V18.4C13.5 17.9 17.9 13.5 18.4 8H20.4Z" stroke="white"/>
1115
+ <path fill-rule="evenodd" d="M17 3L20.4 7.5H17.9C17.7 13.1 13.1 17.7 7.5 17.9V20.4L3 17L7.5 13.5V15.9C12.0 15.7 15.7 12.0 15.9 7.5H13.5L17 3Z" fill="black"/>
1116
+ </g>
1117
+ </g>
1118
+ <defs>
1119
+ <filter id="f" x="-1.6" y="-0.6" width="27.1" height="27.1" filterUnits="userSpaceOnUse">
1120
+ ${filterStyle}
1121
+ </filter>
1122
+ </defs>
1123
+ </svg>
1124
+ `;
1125
+ const skewSVG = `
1126
+ <svg width="24" height="24" xmlns="http://www.w3.org/2000/svg">
1127
+ <g filter="url(#f)">
1128
+ <g transform="rotate(90,12,12),rotate({{rotation}},12,12)">
1129
+ <path d="M21 10.4L21 11.4L23.8 11.4L21.6 9.6L21 10.4ZM17 10.4V11.4L17 11.4L17 10.4ZM15.5 6L16.1 5.2L14.5 3.9V6H15.5ZM15.5 8.4V9.4H16.5V8.4H15.5ZM6 8.4V7.4H5V8.4H6ZM6 10.4H5V11.4H6V10.4ZM7 14.4V13.4L7 13.4L7 14.4ZM3 14.4L3 13.4L0.1 13.4L2.3 15.2L3 14.4ZM8.5 18.9L7.8 19.7L9.5 21.0V18.9H8.5ZM8.5 16.4V15.4H7.5V16.4H8.5ZM19 16.4V17.4H20V16.4H19ZM19 14.4H20V13.4H19V14.4ZM21 9.4L17 9.4L17 11.4L21 11.4L21 9.4ZM14.8 6.7L20.3 11.2L21.6 9.6L16.1 5.2L14.8 6.7ZM16.5 8.4V6H14.5V8.4H16.5ZM6 9.4H15.5V7.4H6V9.4ZM7 10.4V8.4H5V10.4H7ZM15.5 9.4H6V11.4H15.5V9.4ZM17 9.4H15.5V11.4H17V9.4ZM7 15.4H8.5V13.4H7V15.4ZM3 15.4L7 15.4L7 13.4L3 13.4L3 15.4ZM9.1 18.1L3.6 13.6L2.3 15.2L7.8 19.7L9.1 18.1ZM7.5 16.4V18.9H9.5V16.4H7.5ZM19 15.4H8.5V17.4H19V15.4ZM18 14.4V16.4H20V14.4H18ZM8.5 15.4H19V13.4H8.5V15.4Z" fill="white"/>
1130
+ <path fill-rule="evenodd" d="M17 10.4L21 10.4L15.5 6V8.4H6V10.4H15.5H17ZM8.5 14.4H7L3 14.4L8.5 18.9V16.4H19V14.4H8.5Z" fill="black"/>
1131
+ </g>
1132
+ </g>
1133
+ <defs>
1134
+ <filter x="-2.8" y="1.9" width="29.6" height="23.1" filterUnits="userSpaceOnUse" >
1135
+ ${filterStyle}
1136
+ </filter>
1137
+ </defs>
1138
+ </svg>
1139
+ `;
1140
+
771
1141
  const config = {
772
- editSize: 'auto',
1142
+ editSize: 'size',
1143
+ keyEvent: true,
773
1144
  stroke: '#836DFF',
774
1145
  strokeWidth: 2,
775
1146
  pointFill: '#FFFFFF',
776
- pointSize: 8,
1147
+ pointSize: 10,
777
1148
  pointRadius: 16,
778
1149
  rotateGap: 45,
779
1150
  buttonsDirection: 'bottom',
780
1151
  buttonsMargin: 12,
1152
+ hideOnSmall: true,
781
1153
  moveCursor: 'move',
782
- resizeCursor: ['nwse-resize', 'ns-resize', 'nesw-resize', 'ew-resize', 'nwse-resize', 'ns-resize', 'nesw-resize', 'ew-resize'],
783
- rotateCursor: ['ne-resize', 'e-resize', 'se-resize', 's-resize', 'sw-resize', 'w-resize', 'nw-resize', 'n-resize'],
1154
+ resizeCursor: { url: resizeSVG, x: 12, y: 12 },
1155
+ rotateCursor: { url: rotateSVG, x: 12, y: 12 },
1156
+ skewCursor: { url: skewSVG, x: 12, y: 12 },
784
1157
  selector: true,
785
1158
  hover: true,
1159
+ select: 'press',
1160
+ openInner: 'double',
786
1161
  boxSelect: true,
1162
+ moveable: true,
787
1163
  resizeable: true,
788
1164
  rotateable: true,
789
1165
  skewable: true
790
1166
  };
791
1167
 
792
- class EditTool {
793
- constructor() {
794
- this.tag = 'EditTool';
795
- }
796
- onMove(e) {
797
- const { moveX, moveY, editor } = e;
798
- const { app, list } = editor;
799
- app.lockLayout();
800
- list.forEach(target => {
801
- const move = target.getLocalPoint({ x: moveX, y: moveY }, null, true);
802
- target.move(move.x, move.y);
803
- });
804
- app.unlockLayout();
805
- }
806
- onScale(e) {
807
- const { scaleX, scaleY, transform, worldOrigin, editor } = e;
808
- const { app, list } = editor;
809
- app.lockLayout();
810
- list.forEach(target => {
811
- const resize = editor.getEditSize(target) === 'size';
812
- if (transform) {
813
- target.transform(transform, resize);
814
- }
815
- else {
816
- target.scaleOf(target.getInnerPoint(worldOrigin), scaleX, scaleY, resize);
817
- }
818
- });
819
- app.unlockLayout();
820
- }
821
- onRotate(e) {
822
- const { rotation, worldOrigin, editor } = e;
823
- const { app, list } = editor;
824
- app.lockLayout();
825
- list.forEach(target => {
826
- target.rotateOf(target.getInnerPoint(worldOrigin), rotation);
827
- });
828
- app.unlockLayout();
829
- }
830
- onSkew(e) {
831
- const { skewX, skewY, transform, worldOrigin, editor } = e;
832
- const { app, list } = editor;
833
- app.lockLayout();
834
- list.forEach(target => {
835
- const resize = editor.getEditSize(target) === 'size';
836
- if (transform) {
837
- target.transform(transform, resize);
838
- }
839
- else {
840
- target.skewOf(target.getInnerPoint(worldOrigin), skewX, skewY, resize);
841
- }
842
- });
843
- app.unlockLayout();
844
- }
845
- update(editor) {
846
- const { simulateTarget, element } = editor;
847
- if (editor.multiple)
848
- simulateTarget.parent.updateLayout();
849
- const { x, y, scaleX, scaleY, rotation, skewX, skewY, width, height } = element.getLayoutBounds('box', editor, true);
850
- editor.editBox.set({ x, y, scaleX, scaleY, rotation, skewX, skewY });
851
- editor.editBox.update({ x: 0, y: 0, width, height });
852
- }
853
- }
854
- EditTool.list = [];
855
-
856
- const { left, right } = IDirection8;
857
- class LineEditTool extends EditTool {
858
- constructor() {
859
- super(...arguments);
860
- this.tag = 'LineEditTool';
861
- this.scaleOfEvent = true;
862
- }
863
- onScaleWithDrag(e) {
864
- const { drag, direction, lockRatio, around } = e;
865
- const target = e.target;
866
- const fromPoint = { x: 0, y: 0 };
867
- const { toPoint } = target;
868
- target.rotation = 0;
869
- let { x, y } = drag.getInnerMove(target);
870
- if (lockRatio) {
871
- if (Math.abs(x) > Math.abs(y)) {
872
- y = 0;
873
- }
874
- else {
875
- x = 0;
876
- }
877
- }
878
- if (direction === left) {
879
- fromPoint.x += x;
880
- fromPoint.y += y;
881
- if (around) {
882
- toPoint.x -= x;
883
- toPoint.y -= y;
884
- }
885
- }
886
- else {
887
- if (around) {
888
- fromPoint.x -= x;
889
- fromPoint.y -= y;
890
- }
891
- toPoint.x += x;
892
- toPoint.y += y;
893
- }
894
- target.getLocalPointByInner(fromPoint, null, null, true);
895
- target.getLocalPointByInner(toPoint, null, null, true);
896
- target.x = fromPoint.x;
897
- target.y = fromPoint.y;
898
- target.getInnerPointByLocal(toPoint, null, null, true);
899
- target.toPoint = toPoint;
900
- }
901
- onSkew(_e) {
902
- }
903
- update(editor) {
904
- const { rotatePoints, resizeLines, resizePoints } = editor.editBox;
905
- super.update(editor);
906
- for (let i = 0; i < 8; i++) {
907
- if (i < 4)
908
- resizeLines[i].visible = false;
909
- resizePoints[i].visible = rotatePoints[i].visible = (i === left || i === right);
910
- }
911
- }
912
- }
913
-
914
- function getEditTool(list) {
915
- if (list.length === 1) {
916
- const leaf = list[0];
917
- if (leaf instanceof Line && !leaf.points) {
918
- return new LineEditTool();
919
- }
920
- else {
921
- return new EditTool();
922
- }
923
- }
924
- else {
925
- return new EditTool();
926
- }
927
- }
928
-
929
1168
  function simulate(editor) {
930
1169
  const { simulateTarget, leafList: targetList } = editor;
931
1170
  const { x, y, width, height } = new Bounds().setListWithFn(targetList.list, (leaf) => leaf.worldBoxBounds);
@@ -943,7 +1182,8 @@ function onTarget(editor, oldValue) {
943
1182
  editor.leafList.reset();
944
1183
  }
945
1184
  editor.emitEvent(new EditorEvent(EditorEvent.SELECT, { editor, value: target, oldValue }));
946
- if (editor.hasTarget) {
1185
+ editor.checkOpenedGroups();
1186
+ if (editor.editing) {
947
1187
  editor.waitLeafer(() => {
948
1188
  if (editor.multiple)
949
1189
  simulate(editor);
@@ -954,6 +1194,7 @@ function onTarget(editor, oldValue) {
954
1194
  });
955
1195
  }
956
1196
  else {
1197
+ editor.updateEditTool();
957
1198
  editor.removeTargetEvents();
958
1199
  }
959
1200
  }
@@ -964,11 +1205,16 @@ function onHover(editor, oldValue) {
964
1205
  const order = (a, b) => a.parent.children.indexOf(a) - b.parent.children.indexOf(b);
965
1206
  const reverseOrder = (a, b) => b.parent.children.indexOf(b) - a.parent.children.indexOf(a);
966
1207
  const EditorHelper = {
967
- group(list, element, group) {
1208
+ group(list, element, userGroup) {
968
1209
  list.sort(reverseOrder);
969
1210
  const { app, parent } = list[0];
970
- if (!group)
971
- group = new Group();
1211
+ let group;
1212
+ if (userGroup && userGroup.add) {
1213
+ group = userGroup;
1214
+ }
1215
+ else {
1216
+ group = new Group(userGroup);
1217
+ }
972
1218
  parent.addAt(group, parent.children.indexOf(list[0]));
973
1219
  list.sort(order);
974
1220
  const matrx = new Matrix(element.worldTransform);
@@ -1017,25 +1263,79 @@ const EditorHelper = {
1017
1263
  }
1018
1264
  };
1019
1265
 
1266
+ const debug = Debug.get('EditToolCreator');
1267
+ function registerEditTool() {
1268
+ return (target) => {
1269
+ EditToolCreator.register(target);
1270
+ };
1271
+ }
1272
+ const registerInnerEditor = registerEditTool;
1273
+ const EditToolCreator = {
1274
+ list: {},
1275
+ register(EditTool) {
1276
+ const { tag } = EditTool.prototype;
1277
+ list[tag] ? debug.repeat(tag) : (list[tag] = EditTool);
1278
+ },
1279
+ get(tag, editor) {
1280
+ return new list[tag](editor);
1281
+ }
1282
+ };
1283
+ const { list } = EditToolCreator;
1284
+
1285
+ class InnerEditorEvent extends EditorEvent {
1286
+ constructor(type, data) {
1287
+ super(type, data);
1288
+ }
1289
+ }
1290
+ InnerEditorEvent.BEFORE_OPEN = 'innerEditor.before_open';
1291
+ InnerEditorEvent.OPEN = 'innerEditor.open';
1292
+ InnerEditorEvent.BEFORE_CLOSE = 'innerEditor.before_close';
1293
+ InnerEditorEvent.CLOSE = 'innerEditor.close';
1294
+
1295
+ class EditorGroupEvent extends EditorEvent {
1296
+ constructor(type, data) {
1297
+ super(type, data);
1298
+ }
1299
+ }
1300
+ EditorGroupEvent.GROUP = 'editor.group';
1301
+ EditorGroupEvent.BEFORE_UNGROUP = 'editor.before_ungroup';
1302
+ EditorGroupEvent.UNGROUP = 'editor.ungroup';
1303
+ EditorGroupEvent.OPEN = 'editor.open_group';
1304
+ EditorGroupEvent.CLOSE = 'editor.close_group';
1305
+
1020
1306
  class Editor extends Group {
1307
+ get mergeConfig() {
1308
+ const { element, config } = this;
1309
+ return this.single && element.editConfig ? Object.assign(Object.assign({}, config), element.editConfig) : config;
1310
+ }
1021
1311
  get list() { return this.leafList.list; }
1022
- get hasTarget() { return !!this.list.length; }
1312
+ get editing() { return !!this.list.length; }
1313
+ get groupOpening() { return !!this.openedGroupList.length; }
1023
1314
  get multiple() { return this.list.length > 1; }
1024
1315
  get single() { return this.list.length === 1; }
1316
+ get dragging() { return this.editBox.dragging; }
1025
1317
  get element() { return this.multiple ? this.simulateTarget : this.list[0]; }
1026
1318
  get buttons() { return this.editBox.buttons; }
1027
- get dragging() { return this.editBox.dragging; }
1028
1319
  constructor(userConfig, data) {
1029
1320
  super(data);
1030
1321
  this.config = config;
1031
1322
  this.leafList = new LeafList();
1323
+ this.openedGroupList = new LeafList();
1032
1324
  this.simulateTarget = new Rect({ visible: false });
1033
1325
  this.editBox = new EditBox(this);
1326
+ this.editToolList = {};
1034
1327
  this.selector = new EditSelect(this);
1328
+ this.editMask = new EditMask(this);
1035
1329
  this.targetEventIds = [];
1036
1330
  if (userConfig)
1037
1331
  this.config = DataHelper.default(userConfig, this.config);
1038
- this.addMany(this.selector, this.editBox);
1332
+ this.addMany(this.editMask, this.selector, this.editBox);
1333
+ }
1334
+ select(target) {
1335
+ this.target = target;
1336
+ }
1337
+ cancel() {
1338
+ this.target = null;
1039
1339
  }
1040
1340
  hasItem(item) {
1041
1341
  return this.leafList.has(item);
@@ -1052,52 +1352,82 @@ class Editor extends Group {
1052
1352
  this.hasItem(item) ? this.removeItem(item) : this.addItem(item);
1053
1353
  }
1054
1354
  update() {
1055
- if (this.target) {
1056
- this.editTool.update(this);
1355
+ if (this.editing) {
1356
+ if (this.innerEditing)
1357
+ this.innerEditor.update();
1358
+ this.editTool.update();
1057
1359
  this.selector.update();
1058
1360
  }
1059
1361
  }
1362
+ updateEditBox() {
1363
+ if (this.multiple)
1364
+ simulate(this);
1365
+ this.update();
1366
+ }
1060
1367
  updateEditTool() {
1061
- this.editTool = getEditTool(this.list);
1368
+ const tool = this.editTool;
1369
+ if (tool) {
1370
+ this.editBox.unload();
1371
+ tool.unload();
1372
+ this.editTool = null;
1373
+ }
1374
+ if (this.editing) {
1375
+ const tag = this.single ? this.list[0].editOuter : 'EditTool';
1376
+ this.editTool = this.editToolList[tag] = this.editToolList[tag] || EditToolCreator.get(tag, this);
1377
+ this.editBox.load();
1378
+ this.editTool.load();
1379
+ }
1062
1380
  }
1063
- getEditSize(ui) {
1064
- let { editSize } = this.config;
1065
- return editSize === 'auto' ? ui.editSize : editSize;
1381
+ getEditSize(_ui) {
1382
+ return this.mergeConfig.editSize;
1066
1383
  }
1067
1384
  onMove(e) {
1068
- const move = e.getLocalMove(this.element);
1385
+ const total = { x: e.totalX, y: e.totalY };
1069
1386
  if (e.shiftKey) {
1070
- if (Math.abs(move.x) > Math.abs(move.y))
1071
- move.y = 0;
1387
+ if (Math.abs(total.x) > Math.abs(total.y))
1388
+ total.y = 0;
1072
1389
  else
1073
- move.x = 0;
1390
+ total.x = 0;
1074
1391
  }
1075
- this.move(move.x, move.y);
1392
+ this.move(DragEvent.getValidMove(this.element, this.dragStartPoint, total));
1076
1393
  }
1077
1394
  onScale(e) {
1078
1395
  const { element } = this;
1079
- const { direction } = e.current;
1080
- let { around, lockRatio } = this.config;
1081
- if (e.shiftKey)
1082
- lockRatio = true;
1083
- const data = EditDataHelper.getScaleData(element.boxBounds, direction, e.getInnerMove(element), lockRatio, EditDataHelper.getAround(around, e.altKey));
1084
- if (this.editTool.onScaleWithDrag) {
1085
- data.drag = e;
1086
- this.scaleWithDrag(data);
1396
+ if (e instanceof ZoomEvent) {
1397
+ if (this.mergeConfig.resizeable === 'zoom') {
1398
+ e.stop();
1399
+ this.scaleOf(element.getInnerPoint(e), e.scale, e.scale);
1400
+ }
1087
1401
  }
1088
1402
  else {
1089
- this.scaleOf(data.origin, data.scaleX, data.scaleY);
1403
+ const { direction } = e.current;
1404
+ let { around, lockRatio } = this.mergeConfig;
1405
+ if (e.shiftKey || element.lockRatio)
1406
+ lockRatio = true;
1407
+ const data = EditDataHelper.getScaleData(element.boxBounds, direction, e.getInnerMove(element), lockRatio, EditDataHelper.getAround(around, e.altKey));
1408
+ if (this.editTool.onScaleWithDrag) {
1409
+ data.drag = e;
1410
+ this.scaleWithDrag(data);
1411
+ }
1412
+ else {
1413
+ this.scaleOf(data.origin, data.scaleX, data.scaleY);
1414
+ }
1090
1415
  }
1091
1416
  }
1092
1417
  onRotate(e) {
1093
- const { skewable, around, rotateGap } = this.config;
1418
+ const { skewable, around, rotateGap } = this.mergeConfig;
1094
1419
  const { direction, name } = e.current;
1095
1420
  if (skewable && name === 'resize-line')
1096
1421
  return this.onSkew(e);
1097
- const { element, editBox } = this;
1422
+ const { element } = this;
1098
1423
  let origin, rotation;
1099
1424
  if (e instanceof RotateEvent) {
1100
- rotation = e.rotation, origin = element.getInnerPoint(e);
1425
+ if (this.mergeConfig.rotateable === 'rotate') {
1426
+ e.stop();
1427
+ rotation = e.rotation, origin = element.getInnerPoint(e);
1428
+ }
1429
+ else
1430
+ return;
1101
1431
  }
1102
1432
  else {
1103
1433
  const last = { x: e.x - e.moveX, y: e.y - e.moveY };
@@ -1108,21 +1438,23 @@ class Editor extends Group {
1108
1438
  rotation = MathHelper.getGapRotation(rotation, rotateGap, element.rotation);
1109
1439
  if (!rotation)
1110
1440
  return;
1111
- if (editBox.flippedOne)
1441
+ if (element.scaleX * element.scaleY < 0)
1112
1442
  rotation = -rotation;
1113
- this.rotateOf(origin, rotation);
1443
+ this.rotateOf(origin, MathHelper.float(rotation, 2));
1114
1444
  }
1115
1445
  onSkew(e) {
1116
1446
  const { element } = this;
1117
- const { around } = this.config;
1447
+ const { around } = this.mergeConfig;
1118
1448
  const { origin, skewX, skewY } = EditDataHelper.getSkewData(element.boxBounds, e.current.direction, e.getInnerMove(element), EditDataHelper.getAround(around, e.altKey));
1119
1449
  if (!skewX && !skewY)
1120
1450
  return;
1121
1451
  this.skewOf(origin, skewX, skewY);
1122
1452
  }
1123
- move(x, y) {
1453
+ move(x, y = 0) {
1454
+ if (!this.mergeConfig.moveable || this.element.locked)
1455
+ return;
1124
1456
  const { element } = this;
1125
- const world = element.getWorldPointByLocal({ x, y }, null, true);
1457
+ const world = element.getWorldPointByLocal(typeof x === 'object' ? Object.assign({}, x) : { x, y }, null, true);
1126
1458
  const event = new EditorMoveEvent(EditorMoveEvent.MOVE, { target: element, editor: this, moveX: world.x, moveY: world.y });
1127
1459
  this.editTool.onMove(event);
1128
1460
  this.emitEvent(event);
@@ -1130,6 +1462,8 @@ class Editor extends Group {
1130
1462
  element.move(x, y);
1131
1463
  }
1132
1464
  scaleWithDrag(data) {
1465
+ if (!this.mergeConfig.resizeable || this.element.locked)
1466
+ return;
1133
1467
  const { element } = this;
1134
1468
  const worldOrigin = element.getWorldPoint(data.origin);
1135
1469
  const event = new EditorScaleEvent(EditorScaleEvent.SCALE, Object.assign(Object.assign({}, data), { target: element, editor: this, worldOrigin }));
@@ -1137,35 +1471,45 @@ class Editor extends Group {
1137
1471
  this.emitEvent(event);
1138
1472
  }
1139
1473
  scaleOf(origin, scaleX, scaleY = scaleX, _resize) {
1474
+ if (!this.mergeConfig.resizeable || this.element.locked)
1475
+ return;
1140
1476
  const { element } = this;
1141
- const worldOrigin = element.getWorldPoint(origin);
1477
+ const worldOrigin = element.getWorldPoint(LeafHelper.getInnerOrigin(element, origin));
1142
1478
  let transform;
1143
1479
  if (this.multiple) {
1144
- const childMatrix = Object.assign({}, element.localTransform);
1480
+ const oldMatrix = new Matrix(element.worldTransform);
1145
1481
  element.scaleOf(origin, scaleX, scaleY);
1146
- transform = new Matrix(element.localTransform).divide(childMatrix);
1482
+ transform = new Matrix(element.worldTransform).divide(oldMatrix);
1147
1483
  }
1148
1484
  const event = new EditorScaleEvent(EditorScaleEvent.SCALE, { target: element, editor: this, worldOrigin, scaleX, scaleY, transform });
1149
1485
  this.editTool.onScale(event);
1150
1486
  this.emitEvent(event);
1151
1487
  }
1152
1488
  rotateOf(origin, rotation) {
1489
+ if (!this.mergeConfig.rotateable || this.element.locked)
1490
+ return;
1153
1491
  const { element } = this;
1154
- const worldOrigin = element.getWorldPoint(origin);
1155
- const event = new EditorRotateEvent(EditorRotateEvent.ROTATE, { target: element, editor: this, worldOrigin, rotation });
1492
+ const worldOrigin = element.getWorldPoint(LeafHelper.getInnerOrigin(element, origin));
1493
+ let transform;
1494
+ if (this.multiple) {
1495
+ const oldMatrix = new Matrix(element.worldTransform);
1496
+ element.rotateOf(origin, rotation);
1497
+ transform = new Matrix(element.worldTransform).divide(oldMatrix);
1498
+ }
1499
+ const event = new EditorRotateEvent(EditorRotateEvent.ROTATE, { target: element, editor: this, worldOrigin, rotation, transform });
1156
1500
  this.editTool.onRotate(event);
1157
1501
  this.emitEvent(event);
1158
- if (this.multiple)
1159
- element.rotateOf(origin, rotation);
1160
1502
  }
1161
1503
  skewOf(origin, skewX, skewY = 0, _resize) {
1504
+ if (!this.mergeConfig.skewable || this.element.locked)
1505
+ return;
1162
1506
  const { element } = this;
1163
- const worldOrigin = element.getWorldPoint(origin);
1507
+ const worldOrigin = element.getWorldPoint(LeafHelper.getInnerOrigin(element, origin));
1164
1508
  let transform;
1165
1509
  if (this.multiple) {
1166
- const childMatrix = Object.assign({}, element.localTransform);
1510
+ const oldMatrix = new Matrix(element.worldTransform);
1167
1511
  element.skewOf(origin, skewX, skewY);
1168
- transform = new Matrix(element.localTransform).divide(childMatrix);
1512
+ transform = new Matrix(element.worldTransform).divide(oldMatrix);
1169
1513
  }
1170
1514
  const event = new EditorSkewEvent(EditorSkewEvent.SKEW, {
1171
1515
  target: element, editor: this, skewX, skewY, transform, worldOrigin
@@ -1173,16 +1517,92 @@ class Editor extends Group {
1173
1517
  this.editTool.onSkew(event);
1174
1518
  this.emitEvent(event);
1175
1519
  }
1176
- group(group) {
1177
- if (this.multiple)
1178
- this.target = EditorHelper.group(this.list, this.element, group);
1520
+ group(userGroup) {
1521
+ if (this.multiple) {
1522
+ this.target = EditorHelper.group(this.list, this.element, userGroup);
1523
+ this.emitGroupEvent(EditorGroupEvent.GROUP, this.target);
1524
+ }
1179
1525
  return this.target;
1180
1526
  }
1181
1527
  ungroup() {
1182
- if (this.list.length)
1183
- this.target = EditorHelper.ungroup(this.list);
1528
+ const { list } = this;
1529
+ if (list.length) {
1530
+ list.forEach(item => item.isBranch && this.emitGroupEvent(EditorGroupEvent.BEFORE_UNGROUP, item));
1531
+ this.target = EditorHelper.ungroup(list);
1532
+ list.forEach(item => item.isBranch && this.emitGroupEvent(EditorGroupEvent.UNGROUP, item));
1533
+ }
1184
1534
  return this.list;
1185
1535
  }
1536
+ openGroup(group) {
1537
+ this.openedGroupList.add(group);
1538
+ group.hitChildren = true;
1539
+ this.emitGroupEvent(EditorGroupEvent.OPEN, group);
1540
+ }
1541
+ closeGroup(group) {
1542
+ this.openedGroupList.remove(group);
1543
+ group.hitChildren = false;
1544
+ this.emitGroupEvent(EditorGroupEvent.CLOSE, group);
1545
+ }
1546
+ checkOpenedGroups() {
1547
+ const opened = this.openedGroupList;
1548
+ if (opened.length) {
1549
+ let { list } = opened;
1550
+ if (this.editing)
1551
+ list = [], opened.forEach(item => this.list.every(leaf => !LeafHelper.hasParent(leaf, item)) && list.push(item));
1552
+ list.forEach(item => this.closeGroup(item));
1553
+ }
1554
+ if (this.editing && !this.selector.dragging)
1555
+ this.checkDeepSelect();
1556
+ }
1557
+ checkDeepSelect() {
1558
+ let parent, { list } = this;
1559
+ for (let i = 0; i < list.length; i++) {
1560
+ parent = list[i].parent;
1561
+ while (parent && !parent.hitChildren) {
1562
+ this.openGroup(parent);
1563
+ parent = parent.parent;
1564
+ }
1565
+ }
1566
+ }
1567
+ emitGroupEvent(type, group) {
1568
+ const event = new EditorGroupEvent(type, { editTarget: group });
1569
+ this.emitEvent(event);
1570
+ group.emitEvent(event);
1571
+ }
1572
+ openInnerEditor(target) {
1573
+ if (target)
1574
+ this.target = target;
1575
+ if (this.single) {
1576
+ const editTarget = this.element;
1577
+ const tag = editTarget.editInner;
1578
+ if (tag && EditToolCreator.list[tag]) {
1579
+ this.editTool.unload();
1580
+ this.innerEditing = true;
1581
+ this.innerEditor = this.editToolList[tag] || EditToolCreator.get(tag, this);
1582
+ this.innerEditor.editTarget = editTarget;
1583
+ this.emitInnerEvent(InnerEditorEvent.BEFORE_OPEN);
1584
+ this.innerEditor.load();
1585
+ this.emitInnerEvent(InnerEditorEvent.OPEN);
1586
+ }
1587
+ }
1588
+ }
1589
+ closeInnerEditor() {
1590
+ if (this.innerEditing) {
1591
+ this.innerEditing = false;
1592
+ this.emitInnerEvent(InnerEditorEvent.BEFORE_CLOSE);
1593
+ this.innerEditor.unload();
1594
+ this.emitInnerEvent(InnerEditorEvent.CLOSE);
1595
+ this.editTool.load();
1596
+ this.innerEditor = null;
1597
+ }
1598
+ }
1599
+ emitInnerEvent(type) {
1600
+ const { innerEditor } = this;
1601
+ const { editTarget } = innerEditor;
1602
+ const event = new InnerEditorEvent(type, { editTarget, innerEditor });
1603
+ this.emitEvent(event);
1604
+ editTarget.emitEvent(event);
1605
+ }
1186
1606
  lock() {
1187
1607
  this.list.forEach(leaf => leaf.locked = true);
1188
1608
  this.update();
@@ -1223,7 +1643,9 @@ class Editor extends Group {
1223
1643
  destroy() {
1224
1644
  if (!this.destroyed) {
1225
1645
  this.simulateTarget.destroy();
1226
- this.target = this.hoverTarget = this.simulateTarget = null;
1646
+ Object.values(this.editToolList).forEach(item => item.destroy());
1647
+ this.editToolList = {};
1648
+ this.target = this.hoverTarget = this.simulateTarget = this.editTool = this.innerEditor = null;
1227
1649
  super.destroy();
1228
1650
  }
1229
1651
  }
@@ -1235,8 +1657,254 @@ __decorate([
1235
1657
  targetAttr(onTarget)
1236
1658
  ], Editor.prototype, "target", void 0);
1237
1659
 
1238
- Creator.editor = function (options) {
1239
- return new Editor(options);
1660
+ class InnerEditor {
1661
+ static registerInnerEditor() {
1662
+ EditToolCreator.register(this);
1663
+ }
1664
+ get tag() { return 'InnerEditor'; }
1665
+ get editBox() { return this.editor.editBox; }
1666
+ constructor(editor) {
1667
+ this.editor = editor;
1668
+ this.create();
1669
+ }
1670
+ onCreate() { }
1671
+ create() {
1672
+ this.view = new Group();
1673
+ this.onCreate();
1674
+ }
1675
+ onLoad() { }
1676
+ load() {
1677
+ this.editor.selector.hittable = this.editor.app.tree.hitChildren = false;
1678
+ this.onLoad();
1679
+ }
1680
+ onUpdate() { }
1681
+ update() { this.onUpdate(); }
1682
+ onUnload() { }
1683
+ unload() {
1684
+ this.editor.selector.hittable = this.editor.app.tree.hitChildren = true;
1685
+ this.onUnload();
1686
+ }
1687
+ onDestroy() { }
1688
+ destroy() {
1689
+ this.onDestroy();
1690
+ if (this.editor) {
1691
+ if (this.view)
1692
+ this.view.destroy();
1693
+ if (this.eventIds)
1694
+ this.editor.off_(this.eventIds);
1695
+ this.editor = this.view = this.eventIds = null;
1696
+ }
1697
+ }
1698
+ }
1699
+
1700
+ let EditTool = class EditTool extends InnerEditor {
1701
+ static registerEditTool() {
1702
+ EditToolCreator.register(this);
1703
+ }
1704
+ get tag() { return 'EditTool'; }
1705
+ onMove(e) {
1706
+ const { moveX, moveY, editor } = e;
1707
+ const { app, list } = editor;
1708
+ app.lockLayout();
1709
+ list.forEach(target => {
1710
+ target.moveWorld(moveX, moveY);
1711
+ });
1712
+ app.unlockLayout();
1713
+ }
1714
+ onScale(e) {
1715
+ const { scaleX, scaleY, transform, worldOrigin, editor } = e;
1716
+ const { app, list } = editor;
1717
+ app.lockLayout();
1718
+ list.forEach(target => {
1719
+ const resize = editor.getEditSize(target) !== 'scale';
1720
+ if (transform) {
1721
+ target.transformWorld(transform, resize);
1722
+ }
1723
+ else {
1724
+ target.scaleOfWorld(worldOrigin, scaleX, scaleY, resize);
1725
+ }
1726
+ });
1727
+ app.unlockLayout();
1728
+ }
1729
+ onRotate(e) {
1730
+ const { rotation, transform, worldOrigin, editor } = e;
1731
+ const { app, list } = editor;
1732
+ app.lockLayout();
1733
+ list.forEach(target => {
1734
+ const resize = editor.getEditSize(target) !== 'scale';
1735
+ if (transform) {
1736
+ target.transformWorld(transform, resize);
1737
+ }
1738
+ else {
1739
+ target.rotateOfWorld(worldOrigin, rotation);
1740
+ }
1741
+ });
1742
+ app.unlockLayout();
1743
+ }
1744
+ onSkew(e) {
1745
+ const { skewX, skewY, transform, worldOrigin, editor } = e;
1746
+ const { app, list } = editor;
1747
+ app.lockLayout();
1748
+ list.forEach(target => {
1749
+ const resize = editor.getEditSize(target) !== 'scale';
1750
+ if (transform) {
1751
+ target.transformWorld(transform, resize);
1752
+ }
1753
+ else {
1754
+ target.skewOfWorld(worldOrigin, skewX, skewY, resize);
1755
+ }
1756
+ });
1757
+ app.unlockLayout();
1758
+ }
1759
+ load() {
1760
+ this.editBox.view.visible = true;
1761
+ this.onLoad();
1762
+ }
1763
+ update() {
1764
+ const { editor, editBox } = this;
1765
+ const { simulateTarget, element } = editor;
1766
+ if (editor.multiple)
1767
+ simulateTarget.parent.updateLayout();
1768
+ const { x, y, scaleX, scaleY, rotation, skewX, skewY, width, height } = element.getLayoutBounds('box', editor, true);
1769
+ editBox.set({ x, y, scaleX, scaleY, rotation, skewX, skewY });
1770
+ editBox.update({ x: 0, y: 0, width, height });
1771
+ this.onUpdate();
1772
+ }
1773
+ unload() {
1774
+ this.editBox.view.visible = false;
1775
+ this.onUnload();
1776
+ }
1777
+ };
1778
+ EditTool = __decorate([
1779
+ registerEditTool()
1780
+ ], EditTool);
1781
+
1782
+ const { left, right } = Direction9;
1783
+ const { move, copy } = PointHelper;
1784
+ let LineEditTool = class LineEditTool extends EditTool {
1785
+ constructor() {
1786
+ super(...arguments);
1787
+ this.scaleOfEvent = true;
1788
+ }
1789
+ get tag() { return 'LineEditTool'; }
1790
+ onScaleWithDrag(e) {
1791
+ const { drag, direction, lockRatio, around } = e;
1792
+ const line = e.target;
1793
+ const isDragFrom = direction === left;
1794
+ if (line.pathInputed) {
1795
+ const { path } = line.__;
1796
+ const { from, to } = this.getFromToByPath(path);
1797
+ this.dragPoint(from, to, isDragFrom, around, this.getInnerMove(line, drag, lockRatio));
1798
+ path[1] = from.x, path[2] = from.y;
1799
+ path[4] = to.x, path[5] = to.y;
1800
+ line.path = path;
1801
+ }
1802
+ else if (line.points) {
1803
+ const { points } = line;
1804
+ const { from, to } = this.getFromToByPoints(points);
1805
+ this.dragPoint(from, to, isDragFrom, around, this.getInnerMove(line, drag, lockRatio));
1806
+ points[0] = from.x, points[1] = from.y;
1807
+ points[2] = to.x, points[3] = to.y;
1808
+ line.points = points;
1809
+ }
1810
+ else {
1811
+ const from = getPointData();
1812
+ const { toPoint } = line;
1813
+ line.rotation = 0;
1814
+ this.dragPoint(from, toPoint, isDragFrom, around, this.getInnerMove(line, drag, lockRatio));
1815
+ line.getLocalPointByInner(from, null, null, true);
1816
+ line.getLocalPointByInner(toPoint, null, null, true);
1817
+ line.x = from.x;
1818
+ line.y = from.y;
1819
+ line.getInnerPointByLocal(toPoint, null, null, true);
1820
+ line.toPoint = toPoint;
1821
+ }
1822
+ }
1823
+ getInnerMove(ui, event, lockRatio) {
1824
+ const movePoint = event.getInnerMove(ui);
1825
+ if (lockRatio) {
1826
+ if (Math.abs(movePoint.x) > Math.abs(movePoint.y)) {
1827
+ movePoint.y = 0;
1828
+ }
1829
+ else {
1830
+ movePoint.x = 0;
1831
+ }
1832
+ }
1833
+ return movePoint;
1834
+ }
1835
+ getFromToByPath(path) {
1836
+ return {
1837
+ from: { x: path[1], y: path[2] },
1838
+ to: { x: path[4], y: path[5] }
1839
+ };
1840
+ }
1841
+ getFromToByPoints(points) {
1842
+ return {
1843
+ from: { x: points[0], y: points[1] },
1844
+ to: { x: points[2], y: points[3] }
1845
+ };
1846
+ }
1847
+ dragPoint(fromPoint, toPoint, isDragFrom, around, movePoint) {
1848
+ const { x, y } = movePoint;
1849
+ if (isDragFrom) {
1850
+ move(fromPoint, x, y);
1851
+ if (around)
1852
+ move(toPoint, -x, -y);
1853
+ }
1854
+ else {
1855
+ if (around)
1856
+ move(fromPoint, -x, -y);
1857
+ move(toPoint, x, y);
1858
+ }
1859
+ }
1860
+ onSkew(_e) {
1861
+ }
1862
+ onUpdate() {
1863
+ const { editBox } = this, { rotatePoints, resizeLines, resizePoints, rect } = editBox;
1864
+ const line = this.editor.element;
1865
+ let fromTo, leftOrRight;
1866
+ if (line.pathInputed)
1867
+ fromTo = this.getFromToByPath(line.__.path);
1868
+ else if (line.points)
1869
+ fromTo = this.getFromToByPoints(line.__.points);
1870
+ if (fromTo) {
1871
+ const { from, to } = fromTo;
1872
+ line.innerToWorld(from, from, false, editBox);
1873
+ line.innerToWorld(to, to, false, editBox);
1874
+ rect.pen.clearPath().moveTo(from.x, from.y).lineTo(to.x, to.y);
1875
+ copy(resizePoints[7], from);
1876
+ copy(rotatePoints[7], from);
1877
+ copy(resizePoints[3], to);
1878
+ copy(rotatePoints[3], to);
1879
+ }
1880
+ for (let i = 0; i < 8; i++) {
1881
+ if (i < 4)
1882
+ resizeLines[i].visible = false;
1883
+ leftOrRight = i === left || i === right;
1884
+ resizePoints[i].visible = leftOrRight;
1885
+ rotatePoints[i].visible = fromTo ? false : leftOrRight;
1886
+ }
1887
+ }
1888
+ };
1889
+ LineEditTool = __decorate([
1890
+ registerEditTool()
1891
+ ], LineEditTool);
1892
+
1893
+ Creator.editor = function (options) { return new Editor(options); };
1894
+ UI.setEditConfig = function (config) {
1895
+ defineKey(this.prototype, 'editConfig', {
1896
+ get() { return typeof config === 'function' ? config(this) : config; }
1897
+ });
1898
+ };
1899
+ UI.setEditOuter = function (toolName) {
1900
+ defineKey(this.prototype, 'editOuter', {
1901
+ get() { return typeof toolName === 'string' ? toolName : toolName(this); }
1902
+ });
1903
+ };
1904
+ UI.setEditInner = function (editorName) {
1905
+ defineKey(this.prototype, 'editInner', {
1906
+ get() { return typeof editorName === 'string' ? editorName : editorName(this); }
1907
+ });
1240
1908
  };
1241
1909
 
1242
- export { EditBox, EditDataHelper, EditPoint, EditSelect, EditSelectHelper, EditTool, Editor, EditorEvent, EditorHelper, EditorMoveEvent, EditorRotateEvent, EditorScaleEvent, EditorSkewEvent, LineEditTool, SelectArea, Stroker };
1910
+ export { EditBox, EditDataHelper, EditPoint, EditSelect, EditSelectHelper, EditTool, EditToolCreator, Editor, EditorEvent, EditorGroupEvent, EditorHelper, EditorMoveEvent, EditorRotateEvent, EditorScaleEvent, EditorSkewEvent, InnerEditor, InnerEditorEvent, LineEditTool, PathScaler, SelectArea, Stroker, registerEditTool, registerInnerEditor, scaleResize, scaleResizeFontSize, scaleResizeGroup, scaleResizePath, scaleResizePoints };