@leafer-in/editor 1.0.0-rc.6 → 1.0.0-rc.7

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,375 @@
1
- import { MatrixHelper, Bounds, Matrix, Event, Group, Rect, Polygon, DataHelper, RotateEvent, PointHelper, MathHelper, DragEvent, PointerEvent, RenderEvent, KeyEvent } from '@leafer-ui/core';
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';
2
+
3
+ /******************************************************************************
4
+ Copyright (c) Microsoft Corporation.
5
+
6
+ Permission to use, copy, modify, and/or distribute this software for any
7
+ purpose with or without fee is hereby granted.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
10
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
12
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
14
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15
+ PERFORMANCE OF THIS SOFTWARE.
16
+ ***************************************************************************** */
17
+ /* global Reflect, Promise, SuppressedError, Symbol */
18
+
19
+
20
+ function __decorate(decorators, target, key, desc) {
21
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
22
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
23
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
24
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
25
+ }
26
+
27
+ typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
28
+ var e = new Error(message);
29
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
30
+ };
31
+
32
+ class EditorEvent extends Event {
33
+ constructor(type, data) {
34
+ super(type);
35
+ if (data)
36
+ Object.assign(this, data);
37
+ }
38
+ }
39
+ EditorEvent.SELECT = 'editor.select';
40
+ EditorEvent.HOVER = 'editor.hover';
41
+
42
+ class EditorMoveEvent extends EditorEvent {
43
+ constructor(type, data) {
44
+ super(type, data);
45
+ }
46
+ }
47
+ EditorMoveEvent.MOVE = 'editor.move';
48
+
49
+ class EditorScaleEvent extends EditorEvent {
50
+ constructor(type, data) {
51
+ super(type, data);
52
+ }
53
+ }
54
+ EditorScaleEvent.SCALE = 'editor.scale';
55
+
56
+ class EditorRotateEvent extends EditorEvent {
57
+ constructor(type, data) {
58
+ super(type, data);
59
+ }
60
+ }
61
+ EditorRotateEvent.ROTATE = 'editor.rotate';
62
+
63
+ class EditorSkewEvent extends EditorEvent {
64
+ constructor(type, data) {
65
+ super(type, data);
66
+ }
67
+ }
68
+ EditorSkewEvent.SKEW = 'editor.skew';
69
+
70
+ function targetAttr(fn) {
71
+ return (target, key) => {
72
+ const privateKey = '_' + key;
73
+ defineKey(target, key, {
74
+ get() { return this[privateKey]; },
75
+ set(value) { if (this[privateKey] !== value)
76
+ this[privateKey] = value, fn(this); }
77
+ });
78
+ };
79
+ }
80
+
81
+ const matrix = MatrixHelper.get();
82
+ const { abs } = Math;
83
+ const { copy, scale } = MatrixHelper;
84
+ class Stroker extends UI {
85
+ constructor() {
86
+ super();
87
+ this.list = [];
88
+ this.hittable = false;
89
+ this.strokeAlign = 'center';
90
+ }
91
+ setTarget(target, style) {
92
+ const { stroke, strokeWidth } = style;
93
+ this.set({ stroke, strokeWidth });
94
+ this.target = target;
95
+ }
96
+ __draw(canvas, options) {
97
+ const { list } = this;
98
+ if (list.length) {
99
+ let leaf;
100
+ const { stroke, strokeWidth } = this.__;
101
+ const { bounds } = options;
102
+ for (let i = 0; i < list.length; i++) {
103
+ leaf = list[i];
104
+ if (bounds && bounds.hit(leaf.__world, options.matrix)) {
105
+ let drewPath;
106
+ if (leaf.__.editSize === 'scale') {
107
+ const aScaleX = abs(leaf.__world.scaleX), aScaleY = abs(leaf.__world.scaleY);
108
+ if (aScaleX !== aScaleY) {
109
+ copy(matrix, leaf.__world);
110
+ scale(matrix, 1 / aScaleX, 1 / aScaleY);
111
+ canvas.setWorld(matrix, options.matrix);
112
+ canvas.beginPath();
113
+ this.__.strokeWidth = strokeWidth;
114
+ const { x, y, width, height } = leaf.__layout.boxBounds;
115
+ canvas.rect(x * aScaleX, y * aScaleY, width * aScaleX, height * aScaleY);
116
+ drewPath = true;
117
+ }
118
+ }
119
+ if (!drewPath) {
120
+ canvas.setWorld(leaf.__world, options.matrix);
121
+ canvas.beginPath();
122
+ leaf.__.__pathForRender ? leaf.__drawRenderPath(canvas) : leaf.__drawPathByBox(canvas);
123
+ this.__.strokeWidth = strokeWidth / abs(leaf.__world.scaleX);
124
+ }
125
+ typeof stroke === 'string' ? Paint.stroke(stroke, this, canvas, options) : Paint.strokes(stroke, this, canvas, options);
126
+ }
127
+ }
128
+ this.__.strokeWidth = strokeWidth;
129
+ }
130
+ }
131
+ destroy() {
132
+ this.target = null;
133
+ super.destroy();
134
+ }
135
+ }
136
+ __decorate([
137
+ targetAttr(onTarget$1)
138
+ ], Stroker.prototype, "target", void 0);
139
+ function onTarget$1(stroker) {
140
+ const value = stroker.target;
141
+ stroker.list = value ? (value instanceof Array ? value : [value]) : [];
142
+ stroker.forceUpdate();
143
+ }
144
+
145
+ class SelectArea extends Group {
146
+ constructor(data) {
147
+ super(data);
148
+ this.strokeArea = new Rect({ strokeAlign: 'center' });
149
+ this.fillArea = new Rect();
150
+ this.visible = this.hittable = false;
151
+ this.addMany(this.fillArea, this.strokeArea);
152
+ }
153
+ setStyle(style, userStyle) {
154
+ const { visible, stroke, strokeWidth } = style;
155
+ this.visible = visible;
156
+ this.strokeArea.reset(Object.assign({ stroke, strokeWidth }, (userStyle || {})));
157
+ this.fillArea.reset({ visible: userStyle ? false : true, fill: stroke, opacity: 0.2 });
158
+ }
159
+ setBounds(bounds) {
160
+ this.strokeArea.set(bounds);
161
+ this.fillArea.set(bounds);
162
+ }
163
+ }
164
+
165
+ var AnswerType;
166
+ (function (AnswerType) {
167
+ AnswerType[AnswerType["No"] = 0] = "No";
168
+ AnswerType[AnswerType["Yes"] = 1] = "Yes";
169
+ AnswerType[AnswerType["NoAndSkip"] = 2] = "NoAndSkip";
170
+ AnswerType[AnswerType["YesAndSkip"] = 3] = "YesAndSkip";
171
+ })(AnswerType || (AnswerType = {}));
172
+
173
+ const { No, Yes, NoAndSkip, YesAndSkip } = AnswerType;
174
+ const EditSelectHelper = {
175
+ findOne(path) {
176
+ return path.list.find((leaf) => leaf.editable);
177
+ },
178
+ findBounds(leaf, bounds) {
179
+ if (leaf.__.hittable && !leaf.__.locked && bounds.hit(leaf.__world)) {
180
+ if (leaf.__.editable) {
181
+ if (leaf.isBranch && !leaf.__.hitChildren) {
182
+ return leaf.__.hitSelf ? YesAndSkip : NoAndSkip;
183
+ }
184
+ else if (leaf.isFrame) {
185
+ return bounds.includes(leaf.__layout.boxBounds, leaf.__world) ? YesAndSkip : No;
186
+ }
187
+ else {
188
+ if (bounds.hit(leaf.__layout.boxBounds, leaf.__world) && leaf.__.hitSelf)
189
+ return Yes;
190
+ }
191
+ }
192
+ return No;
193
+ }
194
+ else {
195
+ return leaf.isBranch ? NoAndSkip : No;
196
+ }
197
+ }
198
+ };
199
+
200
+ const { findOne } = EditSelectHelper;
201
+ class EditSelect extends Group {
202
+ get dragging() { return !!this.originList; }
203
+ get running() { return this.editor.hittable && this.editor.config.selector; }
204
+ get isMoveMode() { return this.app && this.app.interaction.moveMode; }
205
+ constructor(editor) {
206
+ super();
207
+ this.hoverStroker = new Stroker();
208
+ this.targetStroker = new Stroker();
209
+ this.bounds = new Bounds();
210
+ this.selectArea = new SelectArea();
211
+ this.__eventIds = [];
212
+ this.editor = editor;
213
+ this.addMany(this.targetStroker, this.hoverStroker, this.selectArea);
214
+ this.__listenEvents();
215
+ }
216
+ onHover() {
217
+ const { editor } = this;
218
+ if (this.running && !this.dragging && !editor.dragging) {
219
+ const { stroke, strokeWidth, hover } = editor.config;
220
+ this.hoverStroker.setTarget(hover ? this.editor.hoverTarget : null, { stroke, strokeWidth });
221
+ }
222
+ else {
223
+ this.hoverStroker.target = null;
224
+ }
225
+ }
226
+ onSelect() {
227
+ if (this.running) {
228
+ const { config, list } = this.editor;
229
+ const { stroke, strokeWidth } = config;
230
+ this.targetStroker.setTarget(list, { stroke, strokeWidth: Math.max(1, strokeWidth / 2) });
231
+ this.hoverStroker.target = null;
232
+ }
233
+ }
234
+ update() {
235
+ if (this.running)
236
+ this.targetStroker.forceUpdate();
237
+ }
238
+ onPointerMove(e) {
239
+ if (this.running && !this.isMoveMode) {
240
+ const find = e.shiftKey ? this.findDeepOne(e) : findOne(e.path);
241
+ this.editor.hoverTarget = this.editor.hasItem(find) ? null : find;
242
+ }
243
+ if (this.isMoveMode) {
244
+ this.editor.hoverTarget = null;
245
+ }
246
+ }
247
+ onBeforeDown(e) {
248
+ if (this.running && !this.isMoveMode && !e.middle) {
249
+ const find = this.lastDownLeaf = findOne(e.path);
250
+ if (find) {
251
+ if (e.shiftKey) {
252
+ this.editor.shiftItem(find);
253
+ }
254
+ else {
255
+ this.editor.target = find;
256
+ }
257
+ this.editor.updateLayout();
258
+ find.leafer.interaction.updateDownData();
259
+ }
260
+ else if (this.allow(e.target)) {
261
+ if (!e.shiftKey)
262
+ this.editor.target = null;
263
+ }
264
+ }
265
+ }
266
+ onTap(e) {
267
+ if (this.running && e.shiftKey && !e.middle && !this.lastDownLeaf) {
268
+ const find = this.findDeepOne(e);
269
+ if (find)
270
+ this.editor.shiftItem(find);
271
+ }
272
+ else if (this.isMoveMode) {
273
+ this.editor.target = null;
274
+ }
275
+ this.lastDownLeaf = null;
276
+ }
277
+ onDragStart(e) {
278
+ if (this.running && this.allowDrag(e)) {
279
+ const { editor } = this;
280
+ const { stroke, strokeWidth, area } = editor.config;
281
+ const { x, y } = e.getInner(this);
282
+ this.bounds.set(x, y);
283
+ this.selectArea.setStyle({ visible: true, stroke, strokeWidth, x, y }, area);
284
+ this.selectArea.setBounds(this.bounds.get());
285
+ this.originList = editor.leafList.clone();
286
+ }
287
+ }
288
+ onDrag(e) {
289
+ if (this.editor.dragging) {
290
+ this.onDragEnd();
291
+ return;
292
+ }
293
+ if (this.dragging) {
294
+ const { editor } = this;
295
+ const total = e.getInnerTotal(this);
296
+ const dragBounds = this.bounds.clone().unsign();
297
+ const list = new LeafList(editor.app.find(EditSelectHelper.findBounds, dragBounds));
298
+ this.bounds.width = total.x;
299
+ this.bounds.height = total.y;
300
+ this.selectArea.setBounds(dragBounds.get());
301
+ if (list.length) {
302
+ const selectList = [];
303
+ this.originList.forEach(item => { if (!list.has(item))
304
+ selectList.push(item); });
305
+ list.forEach(item => { if (!this.originList.has(item))
306
+ selectList.push(item); });
307
+ editor.target = selectList;
308
+ }
309
+ else {
310
+ editor.target = this.originList;
311
+ if (editor.leafList.length)
312
+ editor.update();
313
+ }
314
+ }
315
+ }
316
+ onDragEnd() {
317
+ if (this.dragging)
318
+ this.originList = null, this.selectArea.visible = false;
319
+ }
320
+ onAutoMove(e) {
321
+ if (this.dragging) {
322
+ const { x, y } = e.getLocalMove(this);
323
+ this.bounds.x += x;
324
+ this.bounds.y += y;
325
+ }
326
+ }
327
+ allow(target) {
328
+ return target.leafer !== this.editor.leafer;
329
+ }
330
+ allowDrag(e) {
331
+ if (this.editor.config.boxSelect && !e.target.draggable) {
332
+ return (!this.editor.hasTarget && this.allow(e.target)) || (e.shiftKey && !findOne(e.path));
333
+ }
334
+ else {
335
+ return false;
336
+ }
337
+ }
338
+ findDeepOne(e) {
339
+ const options = { exclude: new LeafList(this.editor.editBox.rect) };
340
+ return findOne(e.target.leafer.interaction.findPath(e, options));
341
+ }
342
+ __listenEvents() {
343
+ const { editor } = this;
344
+ editor.waitLeafer(() => {
345
+ const { app } = editor;
346
+ app.selector.proxy = editor;
347
+ this.__eventIds = [
348
+ editor.on_(EditorEvent.HOVER, this.onHover, this),
349
+ editor.on_(EditorEvent.SELECT, this.onSelect, this),
350
+ app.on_(PointerEvent.MOVE, this.onPointerMove, this),
351
+ app.on_(PointerEvent.BEFORE_DOWN, this.onBeforeDown, this),
352
+ app.on_(PointerEvent.TAP, this.onTap, this),
353
+ app.on_(DragEvent.START, this.onDragStart, this),
354
+ app.on_(DragEvent.DRAG, this.onDrag, this),
355
+ app.on_(DragEvent.END, this.onDragEnd, this),
356
+ app.on_(MoveEvent.MOVE, this.onAutoMove, this),
357
+ app.on_([ZoomEvent.ZOOM, MoveEvent.MOVE], () => { this.editor.hoverTarget = null; }),
358
+ ];
359
+ });
360
+ }
361
+ __removeListenEvents() {
362
+ if (this.__eventIds) {
363
+ this.off_(this.__eventIds);
364
+ this.__eventIds.length = 0;
365
+ }
366
+ }
367
+ destroy() {
368
+ this.editor = this.originList = this.lastDownLeaf = null;
369
+ this.__removeListenEvents();
370
+ super.destroy();
371
+ }
372
+ }
2
373
 
3
374
  var IDirection8;
4
375
  (function (IDirection8) {
@@ -12,110 +383,154 @@ var IDirection8;
12
383
  IDirection8[IDirection8["left"] = 7] = "left";
13
384
  })(IDirection8 || (IDirection8 = {}));
14
385
 
15
- const { scaleOfOuter, reset } = MatrixHelper;
16
386
  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;
17
- const matrix = {};
18
- function getResizeData(old, direction, move, lockRatio, around) {
19
- if (around) {
20
- move.x *= 2;
21
- move.y *= 2;
22
- }
23
- let origin, scaleX = 1, scaleY = 1;
24
- const { x, y, width, height } = old;
25
- const topScale = (-move.y + height) / height;
26
- const rightScale = (move.x + width) / width;
27
- const bottomScale = (move.y + height) / height;
28
- const leftScale = (-move.x + width) / width;
29
- switch (direction) {
30
- case top$1:
31
- scaleY = topScale;
32
- if (lockRatio)
33
- scaleX = scaleY;
34
- origin = { x: x + width / 2, y: y + height };
35
- break;
36
- case right$2:
37
- scaleX = rightScale;
38
- if (lockRatio)
39
- scaleY = scaleX;
40
- origin = { x, y: y + height / 2 };
41
- break;
42
- case bottom$1:
43
- scaleY = bottomScale;
44
- if (lockRatio)
45
- scaleX = scaleY;
46
- origin = { x: x + width / 2, y };
47
- break;
48
- case left$2:
49
- scaleX = leftScale;
50
- if (lockRatio)
387
+ const { toPoint } = AroundHelper;
388
+ const EditDataHelper = {
389
+ getScaleData(bounds, direction, pointMove, lockRatio, around) {
390
+ let origin, scaleX = 1, scaleY = 1;
391
+ const { width, height } = bounds;
392
+ if (around) {
393
+ pointMove.x *= 2;
394
+ pointMove.y *= 2;
395
+ }
396
+ const topScale = (-pointMove.y + height) / height;
397
+ const rightScale = (pointMove.x + width) / width;
398
+ const bottomScale = (pointMove.y + height) / height;
399
+ const leftScale = (-pointMove.x + width) / width;
400
+ switch (direction) {
401
+ case top$1:
402
+ scaleY = topScale;
403
+ origin = { x: 0.5, y: 1 };
404
+ break;
405
+ case right$2:
406
+ scaleX = rightScale;
407
+ origin = { x: 0, y: 0.5 };
408
+ break;
409
+ case bottom$1:
410
+ scaleY = bottomScale;
411
+ origin = { x: 0.5, y: 0 };
412
+ break;
413
+ case left$2:
414
+ scaleX = leftScale;
415
+ origin = { x: 1, y: 0.5 };
416
+ break;
417
+ case topLeft$1:
418
+ scaleY = topScale;
419
+ scaleX = leftScale;
420
+ origin = { x: 1, y: 1 };
421
+ break;
422
+ case topRight$1:
423
+ scaleY = topScale;
424
+ scaleX = rightScale;
425
+ origin = { x: 0, y: 1 };
426
+ break;
427
+ case bottomRight$1:
428
+ scaleY = bottomScale;
429
+ scaleX = rightScale;
430
+ origin = { x: 0, y: 0 };
431
+ break;
432
+ case bottomLeft$1:
433
+ scaleY = bottomScale;
434
+ scaleX = leftScale;
435
+ origin = { x: 1, y: 0 };
436
+ }
437
+ if (lockRatio) {
438
+ if (scaleX !== 1)
51
439
  scaleY = scaleX;
52
- origin = { x: x + width, y: y + height / 2 };
53
- break;
54
- case topLeft$1:
55
- scaleY = topScale;
56
- scaleX = leftScale;
57
- if (lockRatio)
58
- scaleX = scaleY;
59
- origin = { x: x + width, y: y + height };
60
- break;
61
- case topRight$1:
62
- scaleY = topScale;
63
- scaleX = rightScale;
64
- if (lockRatio)
65
- scaleX = scaleY;
66
- origin = { x, y: y + height };
67
- break;
68
- case bottomRight$1:
69
- scaleY = bottomScale;
70
- scaleX = rightScale;
71
- if (lockRatio)
440
+ else
72
441
  scaleX = scaleY;
73
- origin = { x, y };
74
- break;
75
- case bottomLeft$1:
76
- scaleY = bottomScale;
77
- scaleX = leftScale;
78
- if (lockRatio)
79
- scaleX = scaleY;
80
- origin = { x: x + width, y };
81
- break;
82
- }
83
- if (around) {
84
- if (typeof around === 'object') {
85
- origin = { x: x + width / around.x, y: y + height / around.y };
86
442
  }
87
- else {
88
- origin = { x: x + width / 2, y: y + height / 2 };
443
+ toPoint(around || origin, bounds, origin);
444
+ return { origin, scaleX, scaleY, direction, lockRatio, around };
445
+ },
446
+ getRotateData(bounds, direction, current, last, around) {
447
+ let origin;
448
+ switch (direction) {
449
+ case topLeft$1:
450
+ origin = { x: 1, y: 1 };
451
+ break;
452
+ case topRight$1:
453
+ origin = { x: 0, y: 1 };
454
+ break;
455
+ case bottomRight$1:
456
+ origin = { x: 0, y: 0 };
457
+ break;
458
+ case bottomLeft$1:
459
+ origin = { x: 1, y: 0 };
460
+ break;
461
+ default:
462
+ origin = { x: 0.5, y: 0.5 };
463
+ }
464
+ toPoint(around || origin, bounds, origin);
465
+ return { origin, rotation: PointHelper.getRotation(last, origin, current) };
466
+ },
467
+ getSkewData(bounds, direction, move, around) {
468
+ let origin, skewX = 0, skewY = 0;
469
+ let last;
470
+ switch (direction) {
471
+ case top$1:
472
+ last = { x: 0.5, y: 0 };
473
+ origin = { x: 0.5, y: 1 };
474
+ skewX = 1;
475
+ break;
476
+ case bottom$1:
477
+ last = { x: 0.5, y: 1 };
478
+ origin = { x: 0.5, y: 0 };
479
+ skewX = 1;
480
+ break;
481
+ case left$2:
482
+ last = { x: 0, y: 0.5 };
483
+ origin = { x: 1, y: 0.5 };
484
+ skewY = 1;
485
+ break;
486
+ case right$2:
487
+ last = { x: 1, y: 0.5 };
488
+ origin = { x: 0, y: 0.5 };
489
+ skewY = 1;
89
490
  }
491
+ const { x, y, width, height } = bounds;
492
+ last.x = x + last.x * width;
493
+ last.y = y + last.y * height;
494
+ toPoint(around || origin, bounds, origin);
495
+ const rotation = PointHelper.getRotation(last, origin, { x: last.x + (skewX ? move.x : 0), y: last.y + (skewY ? move.y : 0) });
496
+ skewX ? skewX = -rotation : skewY = rotation;
497
+ return { origin, skewX, skewY };
498
+ },
499
+ getAround(around, altKey) {
500
+ return (altKey && !around) ? AroundHelper.center : around;
501
+ },
502
+ getRotateDirection(direction, rotation, totalDirection = 8) {
503
+ direction = (direction + Math.round(rotation / (360 / totalDirection))) % totalDirection;
504
+ if (direction < 0)
505
+ direction += totalDirection;
506
+ return direction;
90
507
  }
91
- reset(matrix);
92
- scaleOfOuter(matrix, origin, scaleX, scaleY);
93
- const bounds = { x: old.x + matrix.e, y: old.y + matrix.f, width: width * scaleX, height: height * scaleY };
94
- return { bounds, old, origin, scaleX, scaleY, direction, lockRatio, around, };
95
- }
508
+ };
96
509
 
97
510
  const { topLeft, top, topRight, right: right$1, bottomRight, bottom, bottomLeft, left: left$1 } = IDirection8;
98
511
  function updateCursor(editor, e) {
99
- const point = editor.enterPoint;
100
- if (!point || !editor.target || !editor.visible)
512
+ const { editBox } = editor, point = editBox.enterPoint;
513
+ if (!point || !editor.hasTarget || !editBox.visible)
101
514
  return;
102
- let { rotation } = editor;
103
- let { resizeCursor, rotateCursor, resizeable } = editor.config;
104
- const mirror = editor.tool.getMirrorData(editor);
105
- const { __direction, __isResizePoint } = point.__;
106
- editor.enterPoint = point;
107
- if (__isResizePoint && (e.metaKey || e.ctrlKey || !resizeable))
515
+ let { rotation } = editBox;
516
+ let { resizeCursor, rotateCursor, resizeable, rotateable } = editor.config;
517
+ const { direction, pointType } = point;
518
+ editBox.enterPoint = point;
519
+ const isResizePoint = pointType === 'resize';
520
+ if (isResizePoint && rotateable && (e.metaKey || e.ctrlKey || !resizeable))
108
521
  resizeCursor = rotateCursor;
109
- if (mirror.x || mirror.y) {
110
- mirrorCursors(resizeCursor = [...resizeCursor], mirror.x, mirror.y);
111
- mirrorCursors(rotateCursor = [...rotateCursor], mirror.y, mirror.x);
112
- if (mirror.x + mirror.y === 1)
522
+ if (editBox.flipped) {
523
+ const { flippedX, flippedY } = editBox;
524
+ mirrorCursors(resizeCursor = [...resizeCursor], flippedX, flippedY);
525
+ mirrorCursors(rotateCursor = [...rotateCursor], flippedY, flippedX);
526
+ if (editBox.flippedOne)
113
527
  rotation = -rotation;
114
528
  }
115
- let index = (__direction + Math.round(rotation / 45)) % 8;
116
- if (index < 0)
117
- index += 8;
118
- point.cursor = __isResizePoint ? resizeCursor[index] : rotateCursor[index];
529
+ const index = EditDataHelper.getRotateDirection(direction, rotation);
530
+ point.cursor = isResizePoint ? resizeCursor[index] : rotateCursor[index];
531
+ }
532
+ function updateMoveCursor(editor) {
533
+ editor.editBox.rect.cursor = editor.config.moveCursor;
119
534
  }
120
535
  function mirrorCursors(mirror, mirrorX, mirrorY) {
121
536
  if (mirrorX) {
@@ -138,133 +553,324 @@ function mirrorCursors(mirror, mirrorX, mirrorY) {
138
553
  }
139
554
  }
140
555
 
141
- const RectTool = {
142
- name: 'RectTool',
143
- getMirrorData(editor) {
144
- const { scaleX, scaleY } = editor.target;
145
- return {
146
- x: scaleX < 0 ? 1 : 0,
147
- y: scaleY < 0 ? 1 : 0
148
- };
149
- },
150
- resize(e) {
151
- const { target, bounds, resizeType, old } = e;
152
- const { x, y, width, height } = bounds;
153
- const point = { x: x - old.x, y: y - old.y };
154
- target.innerToWorld(point, null, true, target.parent);
155
- target.x += point.x;
156
- target.y += point.y;
157
- if (resizeType === 'scale') {
158
- target.scaleX *= width / old.width;
159
- target.scaleY *= height / old.height;
160
- }
161
- else {
162
- if (width < 0) {
163
- target.width = -width;
164
- target.scaleX *= -1;
165
- }
166
- else {
167
- if (target.width !== width)
168
- target.width = width;
169
- }
170
- if (height < 0) {
171
- target.height = -height;
172
- target.scaleY *= -1;
173
- }
174
- else {
175
- if (target.height !== height)
176
- target.height = height;
556
+ class EditPoint extends Box {
557
+ }
558
+
559
+ const fourDirection = ['top', 'right', 'bottom', 'left'];
560
+ class EditBox extends Group {
561
+ get flipped() { return this.flippedX || this.flippedY; }
562
+ get flippedX() { return this.scaleX < 0; }
563
+ get flippedY() { return this.scaleY < 0; }
564
+ get flippedOne() { return this.scaleX * this.scaleY < 0; }
565
+ constructor(editor) {
566
+ super();
567
+ this.rect = new Box({ name: 'rect', hitFill: 'all', hitStroke: 'none', strokeAlign: 'center', hitRadius: 5 });
568
+ this.circle = new EditPoint({ name: 'circle', strokeAlign: 'outside', around: 'center', cursor: 'crosshair', hitRadius: 5 });
569
+ this.buttons = new Group({ around: 'center', hitSelf: false });
570
+ this.resizePoints = [];
571
+ this.rotatePoints = [];
572
+ this.resizeLines = [];
573
+ this.__eventIds = [];
574
+ this.editor = editor;
575
+ this.visible = false;
576
+ this.create();
577
+ this.__listenEvents();
578
+ }
579
+ create() {
580
+ let rotatePoint, resizeLine, resizePoint;
581
+ const { resizePoints, rotatePoints, resizeLines, rect, circle, buttons } = this;
582
+ 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 }];
583
+ for (let i = 0; i < 8; i++) {
584
+ rotatePoint = new EditPoint({ around: arounds[i], width: 15, height: 15, hitFill: "all" });
585
+ rotatePoints.push(rotatePoint);
586
+ this.listenPointEvents(rotatePoint, 'rotate', i);
587
+ if (i % 2) {
588
+ resizeLine = new EditPoint({ name: 'resize-line', around: 'center', width: 10, height: 10, hitFill: "all" });
589
+ resizeLines.push(resizeLine);
590
+ this.listenPointEvents(resizeLine, 'resize', i);
177
591
  }
592
+ resizePoint = new EditPoint({ name: 'resize-point', around: 'center', strokeAlign: 'outside', hitRadius: 5 });
593
+ resizePoints.push(resizePoint);
594
+ this.listenPointEvents(resizePoint, 'resize', i);
178
595
  }
179
- },
180
- rotate(e) {
181
- const { target, rotation, origin } = e;
182
- target.rotateOf(origin, rotation);
183
- },
184
- update(editor) {
185
- const { target, config, rotatePoints, targetRect, rect, circle, resizeLines, resizePoints } = editor;
186
- const { type, resizeable, rotateable, stroke, pointFill, pointSize, pointRadius } = config;
187
- const defaultStyle = { fill: pointFill, stroke, width: pointSize, height: pointSize, cornerRadius: pointRadius };
188
- const pointStyles = config.point instanceof Array ? config.point : [config.point || defaultStyle];
189
- const box = new Bounds(target.boxBounds);
190
- const w = target.worldTransform, pw = editor.parent.worldTransform;
191
- const matrix = new Matrix(w);
192
- matrix.divide(pw);
193
- const worldX = matrix.e, worldY = matrix.f;
194
- let { scaleX, scaleY, rotation, skewX, skewY } = w;
195
- scaleX /= pw.scaleX, scaleY /= pw.scaleY, rotation -= pw.rotation, skewX -= pw.skewX, skewY -= pw.skewY;
196
- const { x, y, width, height } = box.scale(scaleX, scaleY);
197
- editor.set({ x: worldX, y: worldY, rotation, skewX, skewY });
198
- targetRect.set({ x, y, width: box.width / scaleX, height: box.height / scaleY, scaleX, scaleY, visible: true });
199
- const points = [
200
- { x, y },
201
- { x: x + width / 2, y },
202
- { x: x + width, y },
203
- { x: x + width, y: y + height / 2 },
204
- { x: x + width, y: y + height },
205
- { x: x + width / 2, y: y + height },
206
- { x, y: y + height },
207
- { x, y: y + height / 2 }
208
- ];
209
- const rectPoints = [];
596
+ buttons.add(circle);
597
+ this.listenPointEvents(circle, 'rotate', 2);
598
+ this.addMany(...rotatePoints, rect, buttons, ...resizeLines, ...resizePoints);
599
+ }
600
+ update(bounds) {
601
+ const { config, list } = this.editor;
602
+ const { width, height } = bounds;
603
+ const { rect, circle, resizePoints, rotatePoints, resizeLines } = this;
604
+ const { middlePoint, resizeable, rotateable, stroke, strokeWidth } = config;
605
+ const points = this.getDirection8Points(bounds);
606
+ const pointsStyle = this.getPointsStyle();
607
+ const middlePointsStyle = this.getMiddlePointsStyle();
608
+ this.visible = list[0] && !list[0].locked;
210
609
  let point, style, rotateP, resizeP, resizeL;
211
610
  for (let i = 0; i < 8; i++) {
212
- point = points[i];
213
- style = pointStyles[i % pointStyles.length];
214
- resizeP = resizePoints[i];
215
- resizeL = resizeLines[Math.floor(i / 2)];
216
- rotateP = rotatePoints[i];
611
+ point = points[i], style = this.getPointStyle((i % 2) ? middlePointsStyle[((i - 1) / 2) % middlePointsStyle.length] : pointsStyle[(i / 2) % pointsStyle.length]);
612
+ resizeP = resizePoints[i], rotateP = rotatePoints[i], resizeL = resizeLines[Math.floor(i / 2)];
217
613
  resizeP.set(style);
218
- resizeP.x = rotateP.x = resizeL.x = point.x;
219
- resizeP.y = rotateP.y = resizeL.y = point.y;
614
+ resizeP.set(point), rotateP.set(point), resizeL.set(point);
220
615
  resizeP.visible = resizeL.visible = resizeable || rotateable;
221
616
  rotateP.visible = rotateable && resizeable;
222
617
  if (i % 2) {
618
+ resizeP.visible = rotateP.visible = !!middlePoint;
223
619
  if (((i + 1) / 2) % 2) {
224
- resizeL.width = Math.abs(width);
225
- rotateP.width = Math.max(10, Math.abs(width) - 30);
620
+ resizeL.width = width;
621
+ if (resizeP.width > width - 30)
622
+ resizeP.visible = false;
226
623
  }
227
624
  else {
228
- resizeL.height = Math.abs(height);
229
- rotateP.height = Math.max(10, Math.abs(height) - 30);
625
+ resizeL.height = height;
626
+ resizeP.rotation = 90;
627
+ if (resizeP.width > height - 30)
628
+ resizeP.visible = false;
230
629
  }
231
- resizeP.rotation = 90;
232
- resizeP.visible = type === 'mobile';
233
- rotateP.visible = false;
234
630
  }
235
631
  else {
236
- rotateP.visible = type !== 'mobile';
237
- rectPoints.push(point.x, point.y);
632
+ resizeP.rotation = (i / 2) * 90;
633
+ }
634
+ }
635
+ circle.visible = rotateable && !!config.rotatePoint;
636
+ circle.set(this.getPointStyle(config.rotatePoint || pointsStyle[0]));
637
+ rect.set(Object.assign({ stroke, strokeWidth }, (config.rect || {})));
638
+ rect.set(Object.assign(Object.assign({}, bounds), { visible: true }));
639
+ this.layoutButtons();
640
+ }
641
+ layoutButtons() {
642
+ const { buttons, resizePoints } = this;
643
+ const { buttonsDirection, buttonsFixed, buttonsMargin, middlePoint } = this.editor.config;
644
+ const { flippedX, flippedY } = this;
645
+ let index = fourDirection.indexOf(buttonsDirection);
646
+ if ((index % 2 && flippedX) || ((index + 1) % 2 && flippedY)) {
647
+ if (buttonsFixed)
648
+ index = (index + 2) % 4;
649
+ }
650
+ const direction = buttonsFixed ? EditDataHelper.getRotateDirection(index, this.flippedOne ? this.rotation : -this.rotation, 4) : index;
651
+ const point = resizePoints[direction * 2 + 1];
652
+ const useX = direction % 2;
653
+ const sign = (!direction || direction === 3) ? -1 : 1;
654
+ const useWidth = index % 2;
655
+ const margin = (buttonsMargin + (useWidth ? ((middlePoint ? point.width : 0) + buttons.boxBounds.width) : ((middlePoint ? point.height : 0) + buttons.boxBounds.height)) / 2) * sign;
656
+ if (useX) {
657
+ buttons.x = point.x + margin;
658
+ buttons.y = point.y;
659
+ }
660
+ else {
661
+ buttons.x = point.x;
662
+ buttons.y = point.y + margin;
663
+ }
664
+ if (buttonsFixed) {
665
+ buttons.rotation = (direction - index) * 90;
666
+ buttons.scaleX = flippedX ? -1 : 1;
667
+ buttons.scaleY = flippedY ? -1 : 1;
668
+ }
669
+ }
670
+ getPointStyle(userStyle) {
671
+ const { stroke, strokeWidth, pointFill, pointSize, pointRadius } = this.editor.config;
672
+ const defaultStyle = { fill: pointFill, stroke, strokeWidth, width: pointSize, height: pointSize, cornerRadius: pointRadius };
673
+ return userStyle ? Object.assign(defaultStyle, userStyle) : defaultStyle;
674
+ }
675
+ getPointsStyle() {
676
+ const { point } = this.editor.config;
677
+ return point instanceof Array ? point : [point];
678
+ }
679
+ getMiddlePointsStyle() {
680
+ const { middlePoint } = this.editor.config;
681
+ return middlePoint instanceof Array ? middlePoint : (middlePoint ? [middlePoint] : this.getPointsStyle());
682
+ }
683
+ getDirection8Points(bounds) {
684
+ const { x, y, width, height } = bounds;
685
+ return [
686
+ { x, y },
687
+ { x: x + width / 2, y },
688
+ { x: x + width, y },
689
+ { x: x + width, y: y + height / 2 },
690
+ { x: x + width, y: y + height },
691
+ { x: x + width / 2, y: y + height },
692
+ { x, y: y + height },
693
+ { x, y: y + height / 2 }
694
+ ];
695
+ }
696
+ onDragStart(e) {
697
+ this.dragging = true;
698
+ if (e.target.name === 'rect')
699
+ this.editor.opacity = this.editor.config.hideOnMove ? 0 : 1;
700
+ }
701
+ onDragEnd(e) {
702
+ this.dragging = false;
703
+ if (e.target.name === 'rect')
704
+ this.editor.opacity = 1;
705
+ }
706
+ onDrag(e) {
707
+ const { editor } = this;
708
+ const point = e.current;
709
+ if (point.pointType === 'rotate' || e.metaKey || e.ctrlKey || !editor.config.resizeable) {
710
+ if (editor.config.rotateable)
711
+ editor.onRotate(e);
712
+ }
713
+ else {
714
+ editor.onScale(e);
715
+ }
716
+ }
717
+ onArrow(e) {
718
+ if (this.editor.hasTarget) {
719
+ const move = { x: 0, y: 0 };
720
+ const distance = e.shiftKey ? 10 : 1;
721
+ switch (e.code) {
722
+ case 'ArrowDown':
723
+ move.y = distance;
724
+ break;
725
+ case 'ArrowUp':
726
+ move.y = -distance;
727
+ break;
728
+ case 'ArrowLeft':
729
+ move.x = -distance;
730
+ break;
731
+ case 'ArrowRight':
732
+ move.x = distance;
238
733
  }
734
+ if (move.x || move.y)
735
+ this.editor.move(move.x, move.y);
239
736
  }
240
- style = config.rotatePoint || style;
241
- circle.set(style);
242
- circle.x = x + width / 2;
243
- if (!style.y)
244
- circle.y = y - (10 + (resizeP.height + circle.height) / 2) * (this.getMirrorData(editor).y ? -1 : 1);
245
- circle.visible = rotateable && type === 'mobile';
246
- rect.set(config.rect || { stroke });
247
- rect.points = rectPoints;
248
- rect.visible = true;
249
737
  }
738
+ onDoubleClick() {
739
+ const { editor } = this;
740
+ if (editor.single && editor.element.isBranch) ;
741
+ }
742
+ listenPointEvents(point, type, direction) {
743
+ const { editor } = this;
744
+ point.direction = direction;
745
+ point.pointType = type;
746
+ point.on_(DragEvent.START, this.onDragStart, this);
747
+ point.on_(DragEvent.DRAG, this.onDrag, this);
748
+ point.on_(DragEvent.END, this.onDragEnd, this);
749
+ point.on_(PointerEvent.LEAVE, () => this.enterPoint = null);
750
+ if (point.name !== 'circle')
751
+ point.on_(PointerEvent.ENTER, (e) => { this.enterPoint = point, updateCursor(editor, e); });
752
+ }
753
+ __listenEvents() {
754
+ const { rect, editor } = this;
755
+ this.__eventIds = [
756
+ editor.on_(EditorEvent.SELECT, () => { this.visible = editor.hasTarget; }),
757
+ rect.on_(DragEvent.START, this.onDragStart, this),
758
+ rect.on_(DragEvent.DRAG, editor.onMove, editor),
759
+ rect.on_(DragEvent.END, this.onDragEnd, this),
760
+ rect.on_(PointerEvent.ENTER, () => updateMoveCursor(editor)),
761
+ rect.on_(PointerEvent.DOUBLE_CLICK, this.onDoubleClick, this)
762
+ ];
763
+ }
764
+ __removeListenEvents() {
765
+ this.off_(this.__eventIds);
766
+ this.__eventIds.length = 0;
767
+ }
768
+ destroy() {
769
+ this.editor = null;
770
+ this.__removeListenEvents();
771
+ super.destroy();
772
+ }
773
+ }
774
+
775
+ const config = {
776
+ editSize: 'auto',
777
+ stroke: '#836DFF',
778
+ strokeWidth: 2,
779
+ pointFill: '#FFFFFF',
780
+ pointSize: 8,
781
+ pointRadius: 16,
782
+ rotateGap: 45,
783
+ buttonsDirection: 'bottom',
784
+ buttonsMargin: 12,
785
+ moveCursor: 'move',
786
+ resizeCursor: ['nwse-resize', 'ns-resize', 'nesw-resize', 'ew-resize', 'nwse-resize', 'ns-resize', 'nesw-resize', 'ew-resize'],
787
+ rotateCursor: ['ne-resize', 'e-resize', 'se-resize', 's-resize', 'sw-resize', 'w-resize', 'nw-resize', 'n-resize'],
788
+ selector: true,
789
+ hover: true,
790
+ boxSelect: true,
791
+ resizeable: true,
792
+ rotateable: true,
793
+ skewable: true
250
794
  };
251
795
 
796
+ class EditTool {
797
+ constructor() {
798
+ this.tag = 'EditTool';
799
+ }
800
+ onMove(e) {
801
+ const { moveX, moveY, editor } = e;
802
+ const { app, list } = editor;
803
+ app.lockLayout();
804
+ list.forEach(target => {
805
+ const move = target.getLocalPoint({ x: moveX, y: moveY }, null, true);
806
+ target.move(move.x, move.y);
807
+ });
808
+ app.unlockLayout();
809
+ }
810
+ onScale(e) {
811
+ const { scaleX, scaleY, transform, worldOrigin, editor } = e;
812
+ const { app, list } = editor;
813
+ app.lockLayout();
814
+ list.forEach(target => {
815
+ const resize = editor.getEditSize(target) === 'size';
816
+ if (transform) {
817
+ target.transform(transform, resize);
818
+ }
819
+ else {
820
+ target.scaleOf(target.getInnerPoint(worldOrigin), scaleX, scaleY, resize);
821
+ }
822
+ });
823
+ app.unlockLayout();
824
+ }
825
+ onRotate(e) {
826
+ const { rotation, worldOrigin, editor } = e;
827
+ const { app, list } = editor;
828
+ app.lockLayout();
829
+ list.forEach(target => {
830
+ target.rotateOf(target.getInnerPoint(worldOrigin), rotation);
831
+ });
832
+ app.unlockLayout();
833
+ }
834
+ onSkew(e) {
835
+ const { skewX, skewY, transform, worldOrigin, editor } = e;
836
+ const { app, list } = editor;
837
+ app.lockLayout();
838
+ list.forEach(target => {
839
+ const resize = editor.getEditSize(target) === 'size';
840
+ if (transform) {
841
+ target.transform(transform, resize);
842
+ }
843
+ else {
844
+ target.skewOf(target.getInnerPoint(worldOrigin), skewX, skewY, resize);
845
+ }
846
+ });
847
+ app.unlockLayout();
848
+ }
849
+ update(editor) {
850
+ const { simulateTarget, element } = editor;
851
+ if (editor.multiple)
852
+ simulateTarget.parent.updateLayout();
853
+ const { x, y, scaleX, scaleY, rotation, skewX, skewY, width, height } = element.getLayoutBounds('box', editor, true);
854
+ editor.editBox.set({ x, y, scaleX, scaleY, rotation, skewX, skewY });
855
+ editor.editBox.update({ x: 0, y: 0, width, height });
856
+ }
857
+ }
858
+ EditTool.list = [];
859
+
252
860
  const { left, right } = IDirection8;
253
- const LineTool = {
254
- name: 'LineTool',
255
- getMirrorData(_editor) {
256
- return {
257
- x: 0,
258
- y: 0
259
- };
260
- },
261
- resize(e) {
262
- const { direction, dragEvent, lockRatio, around } = e;
861
+ class LineEditTool extends EditTool {
862
+ constructor() {
863
+ super(...arguments);
864
+ this.tag = 'LineEditTool';
865
+ this.scaleOfEvent = true;
866
+ }
867
+ onScaleWithDrag(e) {
868
+ const { drag, direction, lockRatio, around } = e;
263
869
  const target = e.target;
264
870
  const fromPoint = { x: 0, y: 0 };
265
871
  const { toPoint } = target;
266
872
  target.rotation = 0;
267
- let { x, y } = dragEvent.getInnerMove(target);
873
+ let { x, y } = drag.getInnerMove(target);
268
874
  if (lockRatio) {
269
875
  if (Math.abs(x) > Math.abs(y)) {
270
876
  y = 0;
@@ -295,219 +901,373 @@ const LineTool = {
295
901
  target.y = fromPoint.y;
296
902
  target.getInnerPointByLocal(toPoint, null, null, true);
297
903
  target.toPoint = toPoint;
298
- },
299
- rotate(e) {
300
- RectTool.rotate(e);
301
- },
904
+ }
905
+ onSkew(_e) {
906
+ }
302
907
  update(editor) {
303
- const { rotatePoints, circle, resizeLines, resizePoints } = editor;
304
- RectTool.update(editor);
908
+ const { rotatePoints, resizeLines, resizePoints } = editor.editBox;
909
+ super.update(editor);
305
910
  for (let i = 0; i < 8; i++) {
306
911
  if (i < 4)
307
912
  resizeLines[i].visible = false;
308
- resizePoints[i].visible = rotatePoints[i].visible = i === left || i === right;
913
+ resizePoints[i].visible = rotatePoints[i].visible = (i === left || i === right);
309
914
  }
310
- circle.visible = false;
311
915
  }
312
- };
916
+ }
313
917
 
314
- class EditorResizeEvent extends Event {
315
- constructor(type, data) {
316
- super(type);
317
- if (data)
318
- Object.assign(this, data);
918
+ function getEditTool(list) {
919
+ if (list.length === 1) {
920
+ const leaf = list[0];
921
+ if (leaf instanceof Line && !leaf.points) {
922
+ return new LineEditTool();
923
+ }
924
+ else {
925
+ return new EditTool();
926
+ }
927
+ }
928
+ else {
929
+ return new EditTool();
319
930
  }
320
931
  }
321
- EditorResizeEvent.RESIZE = 'editor.resize';
322
932
 
323
- class EditorRotateEvent extends Event {
324
- constructor(type, data) {
325
- super(type);
326
- if (data)
327
- Object.assign(this, data);
933
+ function simulate(editor) {
934
+ const { simulateTarget, leafList: targetList } = editor;
935
+ const { x, y, width, height } = new Bounds().setListWithFn(targetList.list, (leaf) => leaf.worldBoxBounds);
936
+ const parent = simulateTarget.parent = targetList.list[0].leafer.zoomLayer;
937
+ const { scaleX, scaleY, e: worldX, f: worldY } = parent.__world;
938
+ simulateTarget.reset({ x: (x - worldX) / scaleX, y: (y - worldY) / scaleY, width: width / scaleX, height: height / scaleY });
939
+ }
940
+
941
+ function onTarget(editor) {
942
+ const { target } = editor;
943
+ if (target) {
944
+ editor.leafList = target instanceof LeafList ? target : new LeafList(target instanceof Array ? target : target);
945
+ }
946
+ else {
947
+ editor.leafList.reset();
948
+ }
949
+ editor.emitEvent(new EditorEvent(EditorEvent.SELECT, { editor }));
950
+ if (editor.hasTarget) {
951
+ editor.waitLeafer(() => {
952
+ if (editor.multiple)
953
+ simulate(editor);
954
+ updateMoveCursor(editor);
955
+ editor.updateEditTool();
956
+ editor.update();
957
+ editor.listenTargetEvents();
958
+ });
959
+ }
960
+ else {
961
+ editor.removeTargetEvents();
328
962
  }
329
963
  }
330
- EditorRotateEvent.ROTATE = 'editor.rotate';
964
+ function onHover(editor) {
965
+ editor.emitEvent(new EditorEvent(EditorEvent.HOVER, { editor }));
966
+ }
331
967
 
332
- class Editor extends Group {
333
- get target() { return this._target; }
334
- set target(value) {
335
- this.__removeTargetEvents();
336
- this.visible = !!value;
337
- this._target = value;
338
- if (value)
339
- this.onTarget();
968
+ const order = (a, b) => a.parent.children.indexOf(a) - b.parent.children.indexOf(b);
969
+ const reverseOrder = (a, b) => b.parent.children.indexOf(b) - a.parent.children.indexOf(a);
970
+ const EditorHelper = {
971
+ group(list, element, group) {
972
+ list.sort(reverseOrder);
973
+ const { app, parent } = list[0];
974
+ if (!group)
975
+ group = new Group();
976
+ parent.addAt(group, parent.children.indexOf(list[0]));
977
+ list.sort(order);
978
+ const matrx = new Matrix(element.worldTransform);
979
+ matrx.divideParent(parent.worldTransform);
980
+ group.setTransform(matrx);
981
+ group.editable = true;
982
+ group.hitChildren = false;
983
+ app.lockLayout();
984
+ list.forEach(child => child.dropTo(group));
985
+ app.unlockLayout();
986
+ return group;
987
+ },
988
+ ungroup(list) {
989
+ const { app } = list[0];
990
+ const ungroupList = [];
991
+ app.lockLayout();
992
+ list.forEach(leaf => {
993
+ if (leaf.isBranch) {
994
+ const { parent, children } = leaf;
995
+ while (children.length) {
996
+ ungroupList.push(children[0]);
997
+ children[0].dropTo(parent, parent.children.indexOf(leaf));
998
+ }
999
+ leaf.remove();
1000
+ }
1001
+ else {
1002
+ ungroupList.push(leaf);
1003
+ }
1004
+ });
1005
+ app.unlockLayout();
1006
+ return ungroupList;
1007
+ },
1008
+ toTop(list) {
1009
+ list.sort(order);
1010
+ list.forEach(leaf => {
1011
+ let zIndex;
1012
+ const { parent } = leaf;
1013
+ if (parent) {
1014
+ const { children } = parent;
1015
+ const top = children.length - 1;
1016
+ const zIndexOfTop = children[top].__.zIndex;
1017
+ const current = children.indexOf(leaf);
1018
+ if (current !== top) {
1019
+ children.splice(current, 1);
1020
+ children.push(leaf);
1021
+ zIndex = zIndexOfTop + 1;
1022
+ }
1023
+ else {
1024
+ zIndex = zIndexOfTop;
1025
+ }
1026
+ leaf.zIndex = zIndex;
1027
+ }
1028
+ });
1029
+ },
1030
+ toBottom(list) {
1031
+ list.sort(reverseOrder);
1032
+ list.forEach(leaf => {
1033
+ let zIndex;
1034
+ const { parent } = leaf;
1035
+ if (parent) {
1036
+ const { children } = parent;
1037
+ const zIndexOfBottom = children[0].__.zIndex;
1038
+ const current = children.indexOf(leaf);
1039
+ if (current !== 0) {
1040
+ children.splice(current, 1);
1041
+ children.unshift(leaf);
1042
+ zIndex = zIndexOfBottom - 1;
1043
+ }
1044
+ else {
1045
+ zIndex = zIndexOfBottom;
1046
+ }
1047
+ leaf.zIndex = zIndex;
1048
+ }
1049
+ });
340
1050
  }
1051
+ };
1052
+
1053
+ class Editor extends Group {
1054
+ get list() { return this.leafList.list; }
1055
+ get hasTarget() { return !!this.list.length; }
1056
+ get multiple() { return this.list.length > 1; }
1057
+ get single() { return this.list.length === 1; }
1058
+ get element() { return this.multiple ? this.simulateTarget : this.list[0]; }
1059
+ get buttons() { return this.editBox.buttons; }
1060
+ get dragging() { return this.editBox.dragging; }
341
1061
  constructor(userConfig, data) {
342
1062
  super(data);
343
- this.config = {
344
- type: 'pc',
345
- stroke: '#836DFF',
346
- pointFill: '#FFFFFF',
347
- pointSize: 10,
348
- pointRadius: 10,
349
- rotateGap: 90,
350
- hideOnMove: false,
351
- moveCursor: 'move',
352
- resizeType: 'auto',
353
- resizeCursor: ['nwse-resize', 'ns-resize', 'nesw-resize', 'ew-resize', 'nwse-resize', 'ns-resize', 'nesw-resize', 'ew-resize'],
354
- rotateCursor: ['ne-resize', 'e-resize', 'se-resize', 's-resize', 'sw-resize', 'w-resize', 'nw-resize', 'n-resize'],
355
- resizeable: true,
356
- rotateable: true
357
- };
358
- this.resizePoints = [];
359
- this.rotatePoints = [];
360
- this.resizeLines = [];
361
- this.targetRect = new Rect({ hitFill: 'all', hitRadius: 5 });
362
- this.rect = new Polygon({ hittable: false, strokeAlign: 'center' });
363
- this.circle = new Rect({ around: 'center', hitRadius: 10 });
364
- this.__eventIds = [];
365
- this.__targetEventIds = [];
1063
+ this.config = config;
1064
+ this.leafList = new LeafList();
1065
+ this.simulateTarget = new Rect({ visible: false });
1066
+ this.editBox = new EditBox(this);
1067
+ this.selector = new EditSelect(this);
1068
+ this.targetEventIds = [];
366
1069
  if (userConfig)
367
1070
  this.config = DataHelper.default(userConfig, this.config);
368
- this.init();
1071
+ this.addMany(this.selector, this.editBox);
369
1072
  }
370
- init() {
371
- let rotatePoint, resizeLine, resizePoint;
372
- const { resizePoints, rotatePoints, resizeLines } = this;
373
- const arounds = [{ x: 1, y: 1 }, 'center', { x: 0, y: 1 }, 'center', { x: 0, y: 0 }, 'center', { x: 1, y: 0 }, 'center'];
374
- for (let i = 0; i < 8; i++) {
375
- rotatePoint = new Rect({ around: arounds[i], width: 15, height: 15, hitFill: "all" });
376
- rotatePoints.push(rotatePoint);
377
- this.__listenPointEvents(rotatePoint, 'rotate', i);
378
- if (i % 2) {
379
- resizeLine = new Rect({ around: 'center', width: 10, height: 10, hitFill: "all" });
380
- resizeLines.push(resizeLine);
381
- this.__listenPointEvents(resizeLine, 'resize', i);
382
- }
383
- resizePoint = new Rect({ around: 'center', hitRadius: 5 });
384
- resizePoints.push(resizePoint);
385
- this.__listenPointEvents(resizePoint, 'resize', i);
386
- }
387
- this.__listenPointEvents(this.circle, 'rotate', 1);
388
- this.addMany(...rotatePoints, this.targetRect, this.rect, this.circle, ...resizeLines, ...resizePoints);
389
- this.__listenEvents();
1073
+ hasItem(item) {
1074
+ return this.leafList.has(item);
390
1075
  }
391
- onTarget() {
392
- this.tool = this.getTool(this.target);
393
- this.waitLeafer(() => {
394
- this.update();
395
- this.updateMoveCursor();
396
- this.__listenTargetEvents();
397
- });
1076
+ addItem(item) {
1077
+ if (!this.hasItem(item) && !item.locked)
1078
+ this.leafList.add(item), this.target = this.leafList.list;
398
1079
  }
399
- getTool(value) {
400
- return (value.tag === 'Line' && value.resizeable) ? LineTool : RectTool;
1080
+ removeItem(item) {
1081
+ if (this.hasItem(item))
1082
+ this.leafList.remove(item), this.target = this.leafList.list;
401
1083
  }
402
- update() {
403
- if (!this.target)
404
- return;
405
- this.tool.update(this);
1084
+ shiftItem(item) {
1085
+ this.hasItem(item) ? this.removeItem(item) : this.addItem(item);
406
1086
  }
407
- onDrag(e) {
408
- const { resizeable, rotateable } = this.config;
409
- if (e.metaKey || e.ctrlKey || !resizeable) {
410
- if (rotateable)
411
- this.onRotate(e);
412
- }
413
- else {
414
- this.onResize(e);
1087
+ update() {
1088
+ if (this.target) {
1089
+ this.editTool.update(this);
1090
+ this.selector.update();
415
1091
  }
416
1092
  }
1093
+ updateEditTool() {
1094
+ this.editTool = getEditTool(this.list);
1095
+ }
1096
+ getEditSize(ui) {
1097
+ let { editSize } = this.config;
1098
+ return editSize === 'auto' ? ui.editSize : editSize;
1099
+ }
417
1100
  onMove(e) {
418
- const { target } = this;
419
- const { x, y } = e.getLocalMove(target);
1101
+ const move = e.getLocalMove(this.element);
420
1102
  if (e.shiftKey) {
421
- if (Math.abs(x) > Math.abs(y)) {
422
- target.x += x;
423
- }
424
- else {
425
- target.y += y;
426
- }
1103
+ if (Math.abs(move.x) > Math.abs(move.y))
1104
+ move.y = 0;
1105
+ else
1106
+ move.x = 0;
1107
+ }
1108
+ this.move(move.x, move.y);
1109
+ }
1110
+ onScale(e) {
1111
+ const { element } = this;
1112
+ const { direction } = e.current;
1113
+ let { around, lockRatio } = this.config;
1114
+ if (e.shiftKey)
1115
+ lockRatio = true;
1116
+ const data = EditDataHelper.getScaleData(element.boxBounds, direction, e.getInnerMove(element), lockRatio, EditDataHelper.getAround(around, e.altKey));
1117
+ if (this.editTool.onScaleWithDrag) {
1118
+ data.drag = e;
1119
+ this.scaleWithDrag(data);
427
1120
  }
428
1121
  else {
429
- target.x += x;
430
- target.y += y;
1122
+ this.scaleOf(data.origin, data.scaleX, data.scaleY);
431
1123
  }
432
1124
  }
433
1125
  onRotate(e) {
434
- const { target } = this;
435
- const { rotateGap } = this.config;
436
- const { x, y, width, height } = target.boxBounds;
437
- const origin = { x: x + width / 2, y: y + height / 2 };
438
- let rotation;
1126
+ const { skewable, around, rotateGap } = this.config;
1127
+ const { direction, name } = e.current;
1128
+ if (skewable && name === 'resize-line')
1129
+ return this.onSkew(e);
1130
+ const { element, editBox } = this;
1131
+ let origin, rotation;
439
1132
  if (e instanceof RotateEvent) {
440
- rotation = e.rotation;
1133
+ rotation = e.rotation, origin = element.getInnerPoint(e);
441
1134
  }
442
1135
  else {
443
- const point = e;
444
- const last = { x: point.x - e.moveX, y: point.y - e.moveY };
445
- rotation = PointHelper.getChangeAngle(last, target.getWorldPoint(origin), point);
446
- }
447
- rotation = MathHelper.getGapRotation(target.rotation + rotation, rotateGap) - target.rotation;
448
- const event = new EditorRotateEvent(EditorRotateEvent.ROTATE, { editor: this, target, origin, rotation });
449
- this.tool.rotate(event);
450
- target.emitEvent(event);
451
- }
452
- onResize(e) {
453
- const { target } = this;
454
- const { __direction } = e.current.__;
455
- let { resizeType, around, lockRatio } = this.config;
456
- if (e.shiftKey)
457
- lockRatio = true;
458
- if (e.altKey && !around)
459
- around = 'center';
460
- if (resizeType === 'auto')
461
- resizeType = target.resizeable ? 'size' : 'scale';
462
- const data = getResizeData(target.boxBounds, __direction, e.getInnerMove(this.targetRect), lockRatio, around);
463
- const event = new EditorResizeEvent(EditorResizeEvent.RESIZE, Object.assign(Object.assign({}, data), { target, editor: this, dragEvent: e, resizeType }));
464
- this.tool.resize(event);
465
- target.emitEvent(event);
466
- }
467
- updateMoveCursor() {
468
- this.targetRect.cursor = this.config.moveCursor;
1136
+ const last = { x: e.x - e.moveX, y: e.y - e.moveY };
1137
+ const data = EditDataHelper.getRotateData(element.boxBounds, direction, e.getInner(element), element.getInnerPoint(last), e.shiftKey ? null : (around || 'center'));
1138
+ rotation = data.rotation;
1139
+ origin = data.origin;
1140
+ }
1141
+ rotation = MathHelper.getGapRotation(rotation, rotateGap, element.rotation);
1142
+ if (!rotation)
1143
+ return;
1144
+ if (editBox.flippedOne)
1145
+ rotation = -rotation;
1146
+ this.rotateOf(origin, rotation);
469
1147
  }
470
- __listenEvents() {
471
- this.__eventIds = [
472
- this.targetRect.on_(DragEvent.START, () => { this.opacity = this.config.hideOnMove ? 0 : 1; }),
473
- this.targetRect.on_(DragEvent.DRAG, this.onMove, this),
474
- this.targetRect.on_(DragEvent.END, () => { this.opacity = 1; }),
475
- this.targetRect.on_(PointerEvent.ENTER, this.updateMoveCursor, this)
476
- ];
1148
+ onSkew(e) {
1149
+ const { element } = this;
1150
+ const { around } = this.config;
1151
+ const { origin, skewX, skewY } = EditDataHelper.getSkewData(element.boxBounds, e.current.direction, e.getInnerMove(element), EditDataHelper.getAround(around, e.altKey));
1152
+ if (!skewX && !skewY)
1153
+ return;
1154
+ this.skewOf(origin, skewX, skewY);
477
1155
  }
478
- __removeListenEvents() {
479
- this.targetRect.off_(this.__eventIds);
480
- this.__eventIds.length = 0;
1156
+ move(x, y) {
1157
+ const { element } = this;
1158
+ const world = element.getWorldPointByLocal({ x, y }, null, true);
1159
+ const event = new EditorMoveEvent(EditorMoveEvent.MOVE, { target: element, editor: this, moveX: world.x, moveY: world.y });
1160
+ this.editTool.onMove(event);
1161
+ this.emitEvent(event);
1162
+ if (this.multiple)
1163
+ element.move(x, y);
481
1164
  }
482
- __listenPointEvents(point, type, direction) {
483
- point.__.__direction = direction;
484
- const resize = point.__.__isResizePoint = type === 'resize';
485
- point.on_(DragEvent.DRAG, resize ? this.onDrag : this.onRotate, this);
486
- point.on_(PointerEvent.LEAVE, () => this.enterPoint = null);
487
- point.on_(PointerEvent.ENTER, (e) => { this.enterPoint = point; updateCursor(this, e); });
1165
+ scaleWithDrag(data) {
1166
+ const { element } = this;
1167
+ const worldOrigin = element.getWorldPoint(data.origin);
1168
+ const event = new EditorScaleEvent(EditorScaleEvent.SCALE, Object.assign(Object.assign({}, data), { target: element, editor: this, worldOrigin }));
1169
+ this.editTool.onScaleWithDrag(event);
1170
+ this.emitEvent(event);
488
1171
  }
489
- __listenTargetEvents() {
490
- if (this.target) {
491
- const { leafer } = this.target;
492
- this.__targetEventIds = [
1172
+ scaleOf(origin, scaleX, scaleY = scaleX, _resize) {
1173
+ const { element } = this;
1174
+ const worldOrigin = element.getWorldPoint(origin);
1175
+ let transform;
1176
+ if (this.multiple) {
1177
+ const childMatrix = Object.assign({}, element.localTransform);
1178
+ element.scaleOf(origin, scaleX, scaleY);
1179
+ transform = new Matrix(element.localTransform).divide(childMatrix);
1180
+ }
1181
+ const event = new EditorScaleEvent(EditorScaleEvent.SCALE, { target: element, editor: this, worldOrigin, scaleX, scaleY, transform });
1182
+ this.editTool.onScale(event);
1183
+ this.emitEvent(event);
1184
+ }
1185
+ rotateOf(origin, rotation) {
1186
+ const { element } = this;
1187
+ const worldOrigin = element.getWorldPoint(origin);
1188
+ const event = new EditorRotateEvent(EditorRotateEvent.ROTATE, { target: element, editor: this, worldOrigin, rotation });
1189
+ this.editTool.onRotate(event);
1190
+ this.emitEvent(event);
1191
+ if (this.multiple)
1192
+ element.rotateOf(origin, rotation);
1193
+ }
1194
+ skewOf(origin, skewX, skewY = 0, _resize) {
1195
+ const { element } = this;
1196
+ const worldOrigin = element.getWorldPoint(origin);
1197
+ let transform;
1198
+ if (this.multiple) {
1199
+ const childMatrix = Object.assign({}, element.localTransform);
1200
+ element.skewOf(origin, skewX, skewY);
1201
+ transform = new Matrix(element.localTransform).divide(childMatrix);
1202
+ }
1203
+ const event = new EditorSkewEvent(EditorSkewEvent.SKEW, {
1204
+ target: element, editor: this, skewX, skewY, transform, worldOrigin
1205
+ });
1206
+ this.editTool.onSkew(event);
1207
+ this.emitEvent(event);
1208
+ }
1209
+ group() {
1210
+ if (this.multiple)
1211
+ this.target = EditorHelper.group(this.list, this.element);
1212
+ }
1213
+ ungroup() {
1214
+ if (this.list.length)
1215
+ this.target = EditorHelper.ungroup(this.list);
1216
+ }
1217
+ lock() {
1218
+ this.list.forEach(leaf => leaf.locked = true);
1219
+ this.update();
1220
+ }
1221
+ unlock() {
1222
+ this.list.forEach(leaf => leaf.locked = false);
1223
+ this.update();
1224
+ }
1225
+ toTop() {
1226
+ if (this.list.length) {
1227
+ EditorHelper.toTop(this.list);
1228
+ this.leafList.update();
1229
+ }
1230
+ }
1231
+ toBottom() {
1232
+ if (this.list.length) {
1233
+ EditorHelper.toBottom(this.list);
1234
+ this.leafList.update();
1235
+ }
1236
+ }
1237
+ listenTargetEvents() {
1238
+ if (!this.targetEventIds.length) {
1239
+ const { leafer } = this.list[0];
1240
+ this.targetEventIds = [
493
1241
  leafer.on_(RenderEvent.START, this.update, this),
494
- leafer.on_([KeyEvent.HOLD, KeyEvent.UP], (e) => { updateCursor(this, e); })
1242
+ leafer.on_([KeyEvent.HOLD, KeyEvent.UP], (e) => { updateCursor(this, e); }),
1243
+ leafer.on_(KeyEvent.DOWN, this.editBox.onArrow, this.editBox)
495
1244
  ];
496
1245
  }
497
1246
  }
498
- __removeTargetEvents() {
499
- if (this.__targetEventIds.length) {
500
- const { leafer } = this.target;
501
- if (leafer)
502
- leafer.off_(this.__targetEventIds);
503
- this.__targetEventIds.length = 0;
1247
+ removeTargetEvents() {
1248
+ const { targetEventIds } = this;
1249
+ if (targetEventIds.length) {
1250
+ this.off_(targetEventIds);
1251
+ targetEventIds.length = 0;
504
1252
  }
505
1253
  }
506
1254
  destroy() {
507
- this.__removeListenEvents();
508
- this._target = null;
509
- super.destroy();
1255
+ if (!this.destroyed) {
1256
+ this.simulateTarget.destroy();
1257
+ this.target = this.hoverTarget = this.simulateTarget = null;
1258
+ super.destroy();
1259
+ }
510
1260
  }
511
1261
  }
1262
+ __decorate([
1263
+ targetAttr(onHover)
1264
+ ], Editor.prototype, "hoverTarget", void 0);
1265
+ __decorate([
1266
+ targetAttr(onTarget)
1267
+ ], Editor.prototype, "target", void 0);
1268
+
1269
+ Creator.editor = function (options) {
1270
+ return new Editor(options);
1271
+ };
512
1272
 
513
- export { Editor, EditorResizeEvent, EditorRotateEvent, LineTool, RectTool };
1273
+ export { EditBox, EditDataHelper, EditPoint, EditSelect, EditSelectHelper, EditTool, Editor, EditorEvent, EditorHelper, EditorMoveEvent, EditorRotateEvent, EditorScaleEvent, EditorSkewEvent, LineEditTool, SelectArea, Stroker };