@leafer-in/editor 1.0.0-rc.8 → 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,133 +580,127 @@ 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;
399
597
  pointMove.y *= 2;
400
598
  }
599
+ if (Math.abs(pointMove.x) === width)
600
+ pointMove.x += 0.1;
601
+ if (Math.abs(pointMove.y) === height)
602
+ pointMove.y += 0.1;
401
603
  const topScale = (-pointMove.y + height) / height;
402
604
  const rightScale = (pointMove.x + width) / width;
403
605
  const bottomScale = (pointMove.y + height) / height;
404
606
  const leftScale = (-pointMove.x + width) / width;
405
607
  switch (direction) {
406
- case top$1:
608
+ case top:
407
609
  scaleY = topScale;
408
- origin = { x: 0.5, y: 1 };
610
+ align = 'bottom';
409
611
  break;
410
- case right$2:
612
+ case right$1:
411
613
  scaleX = rightScale;
412
- origin = { x: 0, y: 0.5 };
614
+ align = 'left';
413
615
  break;
414
- case bottom$1:
616
+ case bottom:
415
617
  scaleY = bottomScale;
416
- origin = { x: 0.5, y: 0 };
618
+ align = 'top';
417
619
  break;
418
- case left$2:
620
+ case left$1:
419
621
  scaleX = leftScale;
420
- origin = { x: 1, y: 0.5 };
622
+ align = 'right';
421
623
  break;
422
- case topLeft$1:
624
+ case topLeft:
423
625
  scaleY = topScale;
424
626
  scaleX = leftScale;
425
- origin = { x: 1, y: 1 };
627
+ align = 'bottom-right';
426
628
  break;
427
- case topRight$1:
629
+ case topRight:
428
630
  scaleY = topScale;
429
631
  scaleX = rightScale;
430
- origin = { x: 0, y: 1 };
632
+ align = 'bottom-left';
431
633
  break;
432
- case bottomRight$1:
634
+ case bottomRight:
433
635
  scaleY = bottomScale;
434
636
  scaleX = rightScale;
435
- origin = { x: 0, y: 0 };
637
+ align = 'top-left';
436
638
  break;
437
- case bottomLeft$1:
639
+ case bottomLeft:
438
640
  scaleY = bottomScale;
439
641
  scaleX = leftScale;
440
- origin = { x: 1, y: 0 };
642
+ align = 'top-right';
441
643
  }
442
644
  if (lockRatio) {
443
- if (scaleX !== 1)
444
- scaleY = scaleX;
445
- else
446
- 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
+ }
447
651
  }
448
- toPoint(around || origin, bounds, origin);
652
+ toPoint(around || align, bounds, origin);
449
653
  return { origin, scaleX, scaleY, direction, lockRatio, around };
450
654
  },
451
655
  getRotateData(bounds, direction, current, last, around) {
452
- let origin;
656
+ let align, origin = {};
453
657
  switch (direction) {
454
- case topLeft$1:
455
- origin = { x: 1, y: 1 };
658
+ case topLeft:
659
+ align = 'bottom-right';
456
660
  break;
457
- case topRight$1:
458
- origin = { x: 0, y: 1 };
661
+ case topRight:
662
+ align = 'bottom-left';
459
663
  break;
460
- case bottomRight$1:
461
- origin = { x: 0, y: 0 };
664
+ case bottomRight:
665
+ align = 'top-left';
462
666
  break;
463
- case bottomLeft$1:
464
- origin = { x: 1, y: 0 };
667
+ case bottomLeft:
668
+ align = 'top-right';
465
669
  break;
466
670
  default:
467
- origin = { x: 0.5, y: 0.5 };
671
+ align = 'center';
468
672
  }
469
- toPoint(around || origin, bounds, origin);
673
+ toPoint(around || align, bounds, origin);
470
674
  return { origin, rotation: PointHelper.getRotation(last, origin, current) };
471
675
  },
472
676
  getSkewData(bounds, direction, move, around) {
473
- let origin, skewX = 0, skewY = 0;
677
+ let align, origin = {}, skewX = 0, skewY = 0;
474
678
  let last;
475
679
  switch (direction) {
476
- case top$1:
680
+ case top:
477
681
  last = { x: 0.5, y: 0 };
478
- origin = { x: 0.5, y: 1 };
682
+ align = 'bottom';
479
683
  skewX = 1;
480
684
  break;
481
- case bottom$1:
685
+ case bottom:
482
686
  last = { x: 0.5, y: 1 };
483
- origin = { x: 0.5, y: 0 };
687
+ align = 'top';
484
688
  skewX = 1;
485
689
  break;
486
- case left$2:
690
+ case left$1:
487
691
  last = { x: 0, y: 0.5 };
488
- origin = { x: 1, y: 0.5 };
692
+ align = 'right';
489
693
  skewY = 1;
490
694
  break;
491
- case right$2:
695
+ case right$1:
492
696
  last = { x: 1, y: 0.5 };
493
- origin = { x: 0, y: 0.5 };
697
+ align = 'left';
494
698
  skewY = 1;
495
699
  }
496
700
  const { x, y, width, height } = bounds;
497
701
  last.x = x + last.x * width;
498
702
  last.y = y + last.y * height;
499
- toPoint(around || origin, bounds, origin);
703
+ toPoint(around || align, bounds, origin);
500
704
  const rotation = PointHelper.getRotation(last, origin, { x: last.x + (skewX ? move.x : 0), y: last.y + (skewY ? move.y : 0) });
501
705
  skewX ? skewX = -rotation : skewY = rotation;
502
706
  return { origin, skewX, skewY };
@@ -509,53 +713,87 @@ const EditDataHelper = {
509
713
  if (direction < 0)
510
714
  direction += totalDirection;
511
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;
512
763
  }
513
764
  };
514
765
 
515
- const { topLeft, top, topRight, right: right$1, bottomRight, bottom, bottomLeft, left: left$1 } = IDirection8;
766
+ const cacheCursors = {};
516
767
  function updateCursor(editor, e) {
517
768
  const { editBox } = editor, point = editBox.enterPoint;
518
- if (!point || !editor.hasTarget || !editBox.visible)
769
+ if (!point || !editor.editing || !editBox.visible)
770
+ return;
771
+ if (point.name === 'circle')
519
772
  return;
520
773
  let { rotation } = editBox;
521
- let { resizeCursor, rotateCursor, resizeable, rotateable } = editor.config;
522
- const { direction, pointType } = point;
523
- editBox.enterPoint = point;
524
- const isResizePoint = pointType === 'resize';
525
- if (isResizePoint && rotateable && (e.metaKey || e.ctrlKey || !resizeable))
526
- resizeCursor = rotateCursor;
527
- if (editBox.flipped) {
528
- const { flippedX, flippedY } = editBox;
529
- mirrorCursors(resizeCursor = [...resizeCursor], flippedX, flippedY);
530
- mirrorCursors(rotateCursor = [...rotateCursor], flippedY, flippedX);
531
- if (editBox.flippedOne)
532
- 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 };
533
790
  }
534
- const index = EditDataHelper.getRotateDirection(direction, rotation);
535
- point.cursor = isResizePoint ? resizeCursor[index] : rotateCursor[index];
536
791
  }
537
792
  function updateMoveCursor(editor) {
538
- editor.editBox.rect.cursor = editor.config.moveCursor;
793
+ editor.editBox.rect.cursor = editor.mergeConfig.moveCursor;
539
794
  }
540
- function mirrorCursors(mirror, mirrorX, mirrorY) {
541
- if (mirrorX) {
542
- const topCursor = mirror[top], topLeftCursor = mirror[topLeft], topRightCursor = mirror[topRight];
543
- mirror[top] = mirror[bottom];
544
- mirror[topLeft] = mirror[bottomLeft];
545
- mirror[topRight] = mirror[bottomRight];
546
- mirror[bottom] = topCursor;
547
- mirror[bottomLeft] = topLeftCursor;
548
- mirror[bottomRight] = topRightCursor;
549
- }
550
- if (mirrorY) {
551
- const leftCursor = mirror[left$1], topLeftCursor = mirror[topLeft], bottomLeftCursor = mirror[bottomLeft];
552
- mirror[left$1] = mirror[right$1];
553
- mirror[topLeft] = mirror[topRight];
554
- mirror[bottomLeft] = mirror[bottomRight];
555
- mirror[right$1] = leftCursor;
556
- mirror[topRight] = topLeftCursor;
557
- mirror[bottomRight] = bottomLeftCursor;
558
- }
795
+ function toDataURL(svg, rotation) {
796
+ return '"data:image/svg+xml,' + encodeURIComponent(svg.replace('{{rotation}}', rotation.toString())) + '"';
559
797
  }
560
798
 
561
799
  class EditPoint extends Box {
@@ -569,8 +807,9 @@ class EditBox extends Group {
569
807
  get flippedOne() { return this.scaleX * this.scaleY < 0; }
570
808
  constructor(editor) {
571
809
  super();
810
+ this.view = new Group();
572
811
  this.rect = new Box({ name: 'rect', hitFill: 'all', hitStroke: 'none', strokeAlign: 'center', hitRadius: 5 });
573
- 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 });
574
813
  this.buttons = new Group({ around: 'center', hitSelf: false });
575
814
  this.resizePoints = [];
576
815
  this.rotatePoints = [];
@@ -579,14 +818,15 @@ class EditBox extends Group {
579
818
  this.editor = editor;
580
819
  this.visible = false;
581
820
  this.create();
821
+ this.rect.syncEventer = editor;
582
822
  this.__listenEvents();
583
823
  }
584
824
  create() {
585
825
  let rotatePoint, resizeLine, resizePoint;
586
- const { resizePoints, rotatePoints, resizeLines, rect, circle, buttons } = this;
587
- 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'];
588
828
  for (let i = 0; i < 8; i++) {
589
- 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" });
590
830
  rotatePoints.push(rotatePoint);
591
831
  this.listenPointEvents(rotatePoint, 'rotate', i);
592
832
  if (i % 2) {
@@ -594,58 +834,82 @@ class EditBox extends Group {
594
834
  resizeLines.push(resizeLine);
595
835
  this.listenPointEvents(resizeLine, 'resize', i);
596
836
  }
597
- resizePoint = new EditPoint({ name: 'resize-point', around: 'center', strokeAlign: 'outside', hitRadius: 5 });
837
+ resizePoint = new EditPoint({ name: 'resize-point', hitRadius: 5 });
598
838
  resizePoints.push(resizePoint);
599
839
  this.listenPointEvents(resizePoint, 'resize', i);
600
840
  }
601
841
  buttons.add(circle);
602
842
  this.listenPointEvents(circle, 'rotate', 2);
603
- this.addMany(...rotatePoints, rect, buttons, ...resizeLines, ...resizePoints);
843
+ view.addMany(...rotatePoints, rect, buttons, ...resizeLines, ...resizePoints);
844
+ this.add(view);
604
845
  }
605
- update(bounds) {
606
- const { config, list } = this.editor;
607
- const { width, height } = bounds;
608
- const { rect, circle, resizePoints, rotatePoints, resizeLines } = this;
609
- 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;
610
850
  const pointsStyle = this.getPointsStyle();
611
851
  const middlePointsStyle = this.getMiddlePointsStyle();
612
- this.visible = list[0] && !list[0].locked;
613
- let point = {}, style, rotateP, resizeP, resizeL;
852
+ let resizeP;
614
853
  for (let i = 0; i < 8; i++) {
615
- AroundHelper.toPoint(AroundHelper.directionData[i], bounds, point);
616
- style = this.getPointStyle((i % 2) ? middlePointsStyle[((i - 1) / 2) % middlePointsStyle.length] : pointsStyle[(i / 2) % pointsStyle.length]);
617
- resizeP = resizePoints[i], rotateP = rotatePoints[i], resizeL = resizeLines[Math.floor(i / 2)];
618
- resizeP.set(style);
619
- resizeP.set(point), rotateP.set(point), resizeL.set(point);
620
- resizeP.visible = resizeL.visible = resizeable || rotateable;
621
- rotateP.visible = rotateable && resizeable;
622
- if (i % 2) {
623
- resizeP.visible = rotateP.visible = !!middlePoint;
624
- if (((i + 1) / 2) % 2) {
625
- resizeL.width = width;
626
- if (resizeP.width > width - 30)
627
- resizeP.visible = false;
628
- }
629
- else {
630
- resizeL.height = height;
631
- resizeP.rotation = 90;
632
- if (resizeP.width > height - 30)
633
- resizeP.visible = false;
634
- }
635
- }
636
- 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))
637
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
+ }
638
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();
639
908
  }
640
- circle.visible = rotateable && !!config.rotatePoint;
641
- circle.set(this.getPointStyle(config.rotatePoint || pointsStyle[0]));
642
- rect.set(Object.assign({ stroke, strokeWidth }, (config.rect || {})));
643
- rect.set(Object.assign(Object.assign({}, bounds), { visible: true }));
644
- this.layoutButtons();
645
909
  }
646
910
  layoutButtons() {
647
911
  const { buttons, resizePoints } = this;
648
- const { buttonsDirection, buttonsFixed, buttonsMargin, middlePoint } = this.editor.config;
912
+ const { buttonsDirection, buttonsFixed, buttonsMargin, middlePoint } = this.editor.mergeConfig;
649
913
  const { flippedX, flippedY } = this;
650
914
  let index = fourDirection.indexOf(buttonsDirection);
651
915
  if ((index % 2 && flippedX) || ((index + 1) % 2 && flippedY)) {
@@ -672,42 +936,58 @@ class EditBox extends Group {
672
936
  buttons.scaleY = flippedY ? -1 : 1;
673
937
  }
674
938
  }
939
+ unload() {
940
+ this.visible = false;
941
+ }
675
942
  getPointStyle(userStyle) {
676
- const { stroke, strokeWidth, pointFill, pointSize, pointRadius } = this.editor.config;
677
- 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 };
678
945
  return userStyle ? Object.assign(defaultStyle, userStyle) : defaultStyle;
679
946
  }
680
947
  getPointsStyle() {
681
- const { point } = this.editor.config;
948
+ const { point } = this.editor.mergeConfig;
682
949
  return point instanceof Array ? point : [point];
683
950
  }
684
951
  getMiddlePointsStyle() {
685
- const { middlePoint } = this.editor.config;
952
+ const { middlePoint } = this.editor.mergeConfig;
686
953
  return middlePoint instanceof Array ? middlePoint : (middlePoint ? [middlePoint] : this.getPointsStyle());
687
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
+ }
688
962
  onDragStart(e) {
689
963
  this.dragging = true;
690
- if (e.target.name === 'rect')
691
- 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
+ }
692
970
  }
693
971
  onDragEnd(e) {
694
972
  this.dragging = false;
695
- if (e.target.name === 'rect')
973
+ this.moving = false;
974
+ if (e.current.name === 'rect')
696
975
  this.editor.opacity = 1;
697
976
  }
698
977
  onDrag(e) {
699
978
  const { editor } = this;
700
- const point = e.current;
701
- if (point.pointType === 'rotate' || e.metaKey || e.ctrlKey || !editor.config.resizeable) {
702
- 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)
703
982
  editor.onRotate(e);
704
983
  }
705
984
  else {
706
985
  editor.onScale(e);
707
986
  }
987
+ updateCursor(editor, e);
708
988
  }
709
989
  onArrow(e) {
710
- if (this.editor.hasTarget) {
990
+ if (this.editor.editing && this.editor.mergeConfig.keyEvent) {
711
991
  const move = { x: 0, y: 0 };
712
992
  const distance = e.shiftKey ? 10 : 1;
713
993
  switch (e.code) {
@@ -723,13 +1003,29 @@ class EditBox extends Group {
723
1003
  case 'ArrowRight':
724
1004
  move.x = distance;
725
1005
  }
726
- if (move.x || move.y)
727
- this.editor.move(move.x, move.y);
1006
+ this.editor.move(move);
728
1007
  }
729
1008
  }
730
- 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) {
731
1018
  const { editor } = this;
732
- 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
+ }
733
1029
  }
734
1030
  listenPointEvents(point, type, direction) {
735
1031
  const { editor } = this;
@@ -745,12 +1041,15 @@ class EditBox extends Group {
745
1041
  __listenEvents() {
746
1042
  const { rect, editor } = this;
747
1043
  this.__eventIds = [
748
- editor.on_(EditorEvent.SELECT, () => { this.visible = editor.hasTarget; }),
1044
+ editor.on_(EditorEvent.SELECT, this.onSelect, this),
749
1045
  rect.on_(DragEvent.START, this.onDragStart, this),
750
1046
  rect.on_(DragEvent.DRAG, editor.onMove, editor),
751
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),
752
1050
  rect.on_(PointerEvent.ENTER, () => updateMoveCursor(editor)),
753
- 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)
754
1053
  ];
755
1054
  }
756
1055
  __removeListenEvents() {
@@ -764,164 +1063,108 @@ class EditBox extends Group {
764
1063
  }
765
1064
  }
766
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
+
767
1141
  const config = {
768
- editSize: 'auto',
1142
+ editSize: 'size',
1143
+ keyEvent: true,
769
1144
  stroke: '#836DFF',
770
1145
  strokeWidth: 2,
771
1146
  pointFill: '#FFFFFF',
772
- pointSize: 8,
1147
+ pointSize: 10,
773
1148
  pointRadius: 16,
774
1149
  rotateGap: 45,
775
1150
  buttonsDirection: 'bottom',
776
1151
  buttonsMargin: 12,
1152
+ hideOnSmall: true,
777
1153
  moveCursor: 'move',
778
- resizeCursor: ['nwse-resize', 'ns-resize', 'nesw-resize', 'ew-resize', 'nwse-resize', 'ns-resize', 'nesw-resize', 'ew-resize'],
779
- 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 },
780
1157
  selector: true,
781
1158
  hover: true,
1159
+ select: 'press',
1160
+ openInner: 'double',
782
1161
  boxSelect: true,
1162
+ moveable: true,
783
1163
  resizeable: true,
784
1164
  rotateable: true,
785
1165
  skewable: true
786
1166
  };
787
1167
 
788
- class EditTool {
789
- constructor() {
790
- this.tag = 'EditTool';
791
- }
792
- onMove(e) {
793
- const { moveX, moveY, editor } = e;
794
- const { app, list } = editor;
795
- app.lockLayout();
796
- list.forEach(target => {
797
- const move = target.getLocalPoint({ x: moveX, y: moveY }, null, true);
798
- target.move(move.x, move.y);
799
- });
800
- app.unlockLayout();
801
- }
802
- onScale(e) {
803
- const { scaleX, scaleY, transform, worldOrigin, editor } = e;
804
- const { app, list } = editor;
805
- app.lockLayout();
806
- list.forEach(target => {
807
- const resize = editor.getEditSize(target) === 'size';
808
- if (transform) {
809
- target.transform(transform, resize);
810
- }
811
- else {
812
- target.scaleOf(target.getInnerPoint(worldOrigin), scaleX, scaleY, resize);
813
- }
814
- });
815
- app.unlockLayout();
816
- }
817
- onRotate(e) {
818
- const { rotation, worldOrigin, editor } = e;
819
- const { app, list } = editor;
820
- app.lockLayout();
821
- list.forEach(target => {
822
- target.rotateOf(target.getInnerPoint(worldOrigin), rotation);
823
- });
824
- app.unlockLayout();
825
- }
826
- onSkew(e) {
827
- const { skewX, skewY, transform, worldOrigin, editor } = e;
828
- const { app, list } = editor;
829
- app.lockLayout();
830
- list.forEach(target => {
831
- const resize = editor.getEditSize(target) === 'size';
832
- if (transform) {
833
- target.transform(transform, resize);
834
- }
835
- else {
836
- target.skewOf(target.getInnerPoint(worldOrigin), skewX, skewY, resize);
837
- }
838
- });
839
- app.unlockLayout();
840
- }
841
- update(editor) {
842
- const { simulateTarget, element } = editor;
843
- if (editor.multiple)
844
- simulateTarget.parent.updateLayout();
845
- const { x, y, scaleX, scaleY, rotation, skewX, skewY, width, height } = element.getLayoutBounds('box', editor, true);
846
- editor.editBox.set({ x, y, scaleX, scaleY, rotation, skewX, skewY });
847
- editor.editBox.update({ x: 0, y: 0, width, height });
848
- }
849
- }
850
- EditTool.list = [];
851
-
852
- const { left, right } = IDirection8;
853
- class LineEditTool extends EditTool {
854
- constructor() {
855
- super(...arguments);
856
- this.tag = 'LineEditTool';
857
- this.scaleOfEvent = true;
858
- }
859
- onScaleWithDrag(e) {
860
- const { drag, direction, lockRatio, around } = e;
861
- const target = e.target;
862
- const fromPoint = { x: 0, y: 0 };
863
- const { toPoint } = target;
864
- target.rotation = 0;
865
- let { x, y } = drag.getInnerMove(target);
866
- if (lockRatio) {
867
- if (Math.abs(x) > Math.abs(y)) {
868
- y = 0;
869
- }
870
- else {
871
- x = 0;
872
- }
873
- }
874
- if (direction === left) {
875
- fromPoint.x += x;
876
- fromPoint.y += y;
877
- if (around) {
878
- toPoint.x -= x;
879
- toPoint.y -= y;
880
- }
881
- }
882
- else {
883
- if (around) {
884
- fromPoint.x -= x;
885
- fromPoint.y -= y;
886
- }
887
- toPoint.x += x;
888
- toPoint.y += y;
889
- }
890
- target.getLocalPointByInner(fromPoint, null, null, true);
891
- target.getLocalPointByInner(toPoint, null, null, true);
892
- target.x = fromPoint.x;
893
- target.y = fromPoint.y;
894
- target.getInnerPointByLocal(toPoint, null, null, true);
895
- target.toPoint = toPoint;
896
- }
897
- onSkew(_e) {
898
- }
899
- update(editor) {
900
- const { rotatePoints, resizeLines, resizePoints } = editor.editBox;
901
- super.update(editor);
902
- for (let i = 0; i < 8; i++) {
903
- if (i < 4)
904
- resizeLines[i].visible = false;
905
- resizePoints[i].visible = rotatePoints[i].visible = (i === left || i === right);
906
- }
907
- }
908
- }
909
-
910
- function getEditTool(list) {
911
- if (list.length === 1) {
912
- const leaf = list[0];
913
- if (leaf instanceof Line && !leaf.points) {
914
- return new LineEditTool();
915
- }
916
- else {
917
- return new EditTool();
918
- }
919
- }
920
- else {
921
- return new EditTool();
922
- }
923
- }
924
-
925
1168
  function simulate(editor) {
926
1169
  const { simulateTarget, leafList: targetList } = editor;
927
1170
  const { x, y, width, height } = new Bounds().setListWithFn(targetList.list, (leaf) => leaf.worldBoxBounds);
@@ -939,7 +1182,8 @@ function onTarget(editor, oldValue) {
939
1182
  editor.leafList.reset();
940
1183
  }
941
1184
  editor.emitEvent(new EditorEvent(EditorEvent.SELECT, { editor, value: target, oldValue }));
942
- if (editor.hasTarget) {
1185
+ editor.checkOpenedGroups();
1186
+ if (editor.editing) {
943
1187
  editor.waitLeafer(() => {
944
1188
  if (editor.multiple)
945
1189
  simulate(editor);
@@ -950,6 +1194,7 @@ function onTarget(editor, oldValue) {
950
1194
  });
951
1195
  }
952
1196
  else {
1197
+ editor.updateEditTool();
953
1198
  editor.removeTargetEvents();
954
1199
  }
955
1200
  }
@@ -960,11 +1205,16 @@ function onHover(editor, oldValue) {
960
1205
  const order = (a, b) => a.parent.children.indexOf(a) - b.parent.children.indexOf(b);
961
1206
  const reverseOrder = (a, b) => b.parent.children.indexOf(b) - a.parent.children.indexOf(a);
962
1207
  const EditorHelper = {
963
- group(list, element, group) {
1208
+ group(list, element, userGroup) {
964
1209
  list.sort(reverseOrder);
965
1210
  const { app, parent } = list[0];
966
- if (!group)
967
- group = new Group();
1211
+ let group;
1212
+ if (userGroup && userGroup.add) {
1213
+ group = userGroup;
1214
+ }
1215
+ else {
1216
+ group = new Group(userGroup);
1217
+ }
968
1218
  parent.addAt(group, parent.children.indexOf(list[0]));
969
1219
  list.sort(order);
970
1220
  const matrx = new Matrix(element.worldTransform);
@@ -1013,25 +1263,79 @@ const EditorHelper = {
1013
1263
  }
1014
1264
  };
1015
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
+
1016
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
+ }
1017
1311
  get list() { return this.leafList.list; }
1018
- get hasTarget() { return !!this.list.length; }
1312
+ get editing() { return !!this.list.length; }
1313
+ get groupOpening() { return !!this.openedGroupList.length; }
1019
1314
  get multiple() { return this.list.length > 1; }
1020
1315
  get single() { return this.list.length === 1; }
1316
+ get dragging() { return this.editBox.dragging; }
1021
1317
  get element() { return this.multiple ? this.simulateTarget : this.list[0]; }
1022
1318
  get buttons() { return this.editBox.buttons; }
1023
- get dragging() { return this.editBox.dragging; }
1024
1319
  constructor(userConfig, data) {
1025
1320
  super(data);
1026
1321
  this.config = config;
1027
1322
  this.leafList = new LeafList();
1323
+ this.openedGroupList = new LeafList();
1028
1324
  this.simulateTarget = new Rect({ visible: false });
1029
1325
  this.editBox = new EditBox(this);
1326
+ this.editToolList = {};
1030
1327
  this.selector = new EditSelect(this);
1328
+ this.editMask = new EditMask(this);
1031
1329
  this.targetEventIds = [];
1032
1330
  if (userConfig)
1033
1331
  this.config = DataHelper.default(userConfig, this.config);
1034
- 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;
1035
1339
  }
1036
1340
  hasItem(item) {
1037
1341
  return this.leafList.has(item);
@@ -1048,52 +1352,82 @@ class Editor extends Group {
1048
1352
  this.hasItem(item) ? this.removeItem(item) : this.addItem(item);
1049
1353
  }
1050
1354
  update() {
1051
- if (this.target) {
1052
- this.editTool.update(this);
1355
+ if (this.editing) {
1356
+ if (this.innerEditing)
1357
+ this.innerEditor.update();
1358
+ this.editTool.update();
1053
1359
  this.selector.update();
1054
1360
  }
1055
1361
  }
1362
+ updateEditBox() {
1363
+ if (this.multiple)
1364
+ simulate(this);
1365
+ this.update();
1366
+ }
1056
1367
  updateEditTool() {
1057
- 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
+ }
1058
1380
  }
1059
- getEditSize(ui) {
1060
- let { editSize } = this.config;
1061
- return editSize === 'auto' ? ui.editSize : editSize;
1381
+ getEditSize(_ui) {
1382
+ return this.mergeConfig.editSize;
1062
1383
  }
1063
1384
  onMove(e) {
1064
- const move = e.getLocalMove(this.element);
1385
+ const total = { x: e.totalX, y: e.totalY };
1065
1386
  if (e.shiftKey) {
1066
- if (Math.abs(move.x) > Math.abs(move.y))
1067
- move.y = 0;
1387
+ if (Math.abs(total.x) > Math.abs(total.y))
1388
+ total.y = 0;
1068
1389
  else
1069
- move.x = 0;
1390
+ total.x = 0;
1070
1391
  }
1071
- this.move(move.x, move.y);
1392
+ this.move(DragEvent.getValidMove(this.element, this.dragStartPoint, total));
1072
1393
  }
1073
1394
  onScale(e) {
1074
1395
  const { element } = this;
1075
- const { direction } = e.current;
1076
- let { around, lockRatio } = this.config;
1077
- if (e.shiftKey)
1078
- lockRatio = true;
1079
- const data = EditDataHelper.getScaleData(element.boxBounds, direction, e.getInnerMove(element), lockRatio, EditDataHelper.getAround(around, e.altKey));
1080
- if (this.editTool.onScaleWithDrag) {
1081
- data.drag = e;
1082
- 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
+ }
1083
1401
  }
1084
1402
  else {
1085
- 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
+ }
1086
1415
  }
1087
1416
  }
1088
1417
  onRotate(e) {
1089
- const { skewable, around, rotateGap } = this.config;
1418
+ const { skewable, around, rotateGap } = this.mergeConfig;
1090
1419
  const { direction, name } = e.current;
1091
1420
  if (skewable && name === 'resize-line')
1092
1421
  return this.onSkew(e);
1093
- const { element, editBox } = this;
1422
+ const { element } = this;
1094
1423
  let origin, rotation;
1095
1424
  if (e instanceof RotateEvent) {
1096
- 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;
1097
1431
  }
1098
1432
  else {
1099
1433
  const last = { x: e.x - e.moveX, y: e.y - e.moveY };
@@ -1104,21 +1438,23 @@ class Editor extends Group {
1104
1438
  rotation = MathHelper.getGapRotation(rotation, rotateGap, element.rotation);
1105
1439
  if (!rotation)
1106
1440
  return;
1107
- if (editBox.flippedOne)
1441
+ if (element.scaleX * element.scaleY < 0)
1108
1442
  rotation = -rotation;
1109
- this.rotateOf(origin, rotation);
1443
+ this.rotateOf(origin, MathHelper.float(rotation, 2));
1110
1444
  }
1111
1445
  onSkew(e) {
1112
1446
  const { element } = this;
1113
- const { around } = this.config;
1447
+ const { around } = this.mergeConfig;
1114
1448
  const { origin, skewX, skewY } = EditDataHelper.getSkewData(element.boxBounds, e.current.direction, e.getInnerMove(element), EditDataHelper.getAround(around, e.altKey));
1115
1449
  if (!skewX && !skewY)
1116
1450
  return;
1117
1451
  this.skewOf(origin, skewX, skewY);
1118
1452
  }
1119
- move(x, y) {
1453
+ move(x, y = 0) {
1454
+ if (!this.mergeConfig.moveable || this.element.locked)
1455
+ return;
1120
1456
  const { element } = this;
1121
- const world = element.getWorldPointByLocal({ x, y }, null, true);
1457
+ const world = element.getWorldPointByLocal(typeof x === 'object' ? Object.assign({}, x) : { x, y }, null, true);
1122
1458
  const event = new EditorMoveEvent(EditorMoveEvent.MOVE, { target: element, editor: this, moveX: world.x, moveY: world.y });
1123
1459
  this.editTool.onMove(event);
1124
1460
  this.emitEvent(event);
@@ -1126,6 +1462,8 @@ class Editor extends Group {
1126
1462
  element.move(x, y);
1127
1463
  }
1128
1464
  scaleWithDrag(data) {
1465
+ if (!this.mergeConfig.resizeable || this.element.locked)
1466
+ return;
1129
1467
  const { element } = this;
1130
1468
  const worldOrigin = element.getWorldPoint(data.origin);
1131
1469
  const event = new EditorScaleEvent(EditorScaleEvent.SCALE, Object.assign(Object.assign({}, data), { target: element, editor: this, worldOrigin }));
@@ -1133,35 +1471,45 @@ class Editor extends Group {
1133
1471
  this.emitEvent(event);
1134
1472
  }
1135
1473
  scaleOf(origin, scaleX, scaleY = scaleX, _resize) {
1474
+ if (!this.mergeConfig.resizeable || this.element.locked)
1475
+ return;
1136
1476
  const { element } = this;
1137
- const worldOrigin = element.getWorldPoint(origin);
1477
+ const worldOrigin = element.getWorldPoint(LeafHelper.getInnerOrigin(element, origin));
1138
1478
  let transform;
1139
1479
  if (this.multiple) {
1140
- const childMatrix = Object.assign({}, element.localTransform);
1480
+ const oldMatrix = new Matrix(element.worldTransform);
1141
1481
  element.scaleOf(origin, scaleX, scaleY);
1142
- transform = new Matrix(element.localTransform).divide(childMatrix);
1482
+ transform = new Matrix(element.worldTransform).divide(oldMatrix);
1143
1483
  }
1144
1484
  const event = new EditorScaleEvent(EditorScaleEvent.SCALE, { target: element, editor: this, worldOrigin, scaleX, scaleY, transform });
1145
1485
  this.editTool.onScale(event);
1146
1486
  this.emitEvent(event);
1147
1487
  }
1148
1488
  rotateOf(origin, rotation) {
1489
+ if (!this.mergeConfig.rotateable || this.element.locked)
1490
+ return;
1149
1491
  const { element } = this;
1150
- const worldOrigin = element.getWorldPoint(origin);
1151
- 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 });
1152
1500
  this.editTool.onRotate(event);
1153
1501
  this.emitEvent(event);
1154
- if (this.multiple)
1155
- element.rotateOf(origin, rotation);
1156
1502
  }
1157
1503
  skewOf(origin, skewX, skewY = 0, _resize) {
1504
+ if (!this.mergeConfig.skewable || this.element.locked)
1505
+ return;
1158
1506
  const { element } = this;
1159
- const worldOrigin = element.getWorldPoint(origin);
1507
+ const worldOrigin = element.getWorldPoint(LeafHelper.getInnerOrigin(element, origin));
1160
1508
  let transform;
1161
1509
  if (this.multiple) {
1162
- const childMatrix = Object.assign({}, element.localTransform);
1510
+ const oldMatrix = new Matrix(element.worldTransform);
1163
1511
  element.skewOf(origin, skewX, skewY);
1164
- transform = new Matrix(element.localTransform).divide(childMatrix);
1512
+ transform = new Matrix(element.worldTransform).divide(oldMatrix);
1165
1513
  }
1166
1514
  const event = new EditorSkewEvent(EditorSkewEvent.SKEW, {
1167
1515
  target: element, editor: this, skewX, skewY, transform, worldOrigin
@@ -1169,16 +1517,92 @@ class Editor extends Group {
1169
1517
  this.editTool.onSkew(event);
1170
1518
  this.emitEvent(event);
1171
1519
  }
1172
- group(group) {
1173
- if (this.multiple)
1174
- 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
+ }
1175
1525
  return this.target;
1176
1526
  }
1177
1527
  ungroup() {
1178
- if (this.list.length)
1179
- 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
+ }
1180
1534
  return this.list;
1181
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
+ }
1182
1606
  lock() {
1183
1607
  this.list.forEach(leaf => leaf.locked = true);
1184
1608
  this.update();
@@ -1219,7 +1643,9 @@ class Editor extends Group {
1219
1643
  destroy() {
1220
1644
  if (!this.destroyed) {
1221
1645
  this.simulateTarget.destroy();
1222
- 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;
1223
1649
  super.destroy();
1224
1650
  }
1225
1651
  }
@@ -1231,8 +1657,254 @@ __decorate([
1231
1657
  targetAttr(onTarget)
1232
1658
  ], Editor.prototype, "target", void 0);
1233
1659
 
1234
- Creator.editor = function (options) {
1235
- 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
+ });
1236
1908
  };
1237
1909
 
1238
- 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 };