@plait/core 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/board/board.component.d.ts +4 -17
- package/board/board.component.interface.d.ts +0 -2
- package/constants/selection.d.ts +1 -0
- package/esm2020/board/board.component.interface.mjs +1 -1
- package/esm2020/board/board.component.mjs +49 -248
- package/esm2020/constants/selection.mjs +2 -0
- package/esm2020/core/element/element.component.mjs +2 -2
- package/esm2020/interfaces/board.mjs +11 -2
- package/esm2020/interfaces/viewport.mjs +1 -1
- package/esm2020/plugins/create-board.mjs +2 -1
- package/esm2020/plugins/with-hand.mjs +9 -6
- package/esm2020/plugins/with-moving.mjs +91 -0
- package/esm2020/plugins/with-selection.mjs +54 -13
- package/esm2020/plugins/with-viewport.mjs +11 -0
- package/esm2020/public-api.mjs +3 -1
- package/esm2020/transforms/selection.mjs +10 -2
- package/esm2020/utils/board.mjs +7 -3
- package/esm2020/utils/common.mjs +15 -0
- package/esm2020/utils/element.mjs +3 -3
- package/esm2020/utils/helper.mjs +14 -1
- package/esm2020/utils/index.mjs +4 -2
- package/esm2020/utils/moving-element.mjs +15 -0
- package/esm2020/utils/selected-element.mjs +14 -1
- package/esm2020/utils/viewport.mjs +170 -0
- package/esm2020/utils/weak-maps.mjs +5 -1
- package/fesm2015/plait-core.mjs +567 -562
- package/fesm2015/plait-core.mjs.map +1 -1
- package/fesm2020/plait-core.mjs +567 -559
- package/fesm2020/plait-core.mjs.map +1 -1
- package/interfaces/board.d.ts +4 -10
- package/interfaces/viewport.d.ts +2 -2
- package/package.json +1 -1
- package/plugins/with-moving.d.ts +2 -0
- package/plugins/with-selection.d.ts +6 -1
- package/plugins/with-viewport.d.ts +2 -0
- package/public-api.d.ts +2 -0
- package/transforms/selection.d.ts +3 -0
- package/utils/board.d.ts +1 -1
- package/utils/common.d.ts +1 -0
- package/utils/helper.d.ts +9 -0
- package/utils/index.d.ts +3 -1
- package/utils/moving-element.d.ts +5 -0
- package/utils/selected-element.d.ts +2 -0
- package/utils/viewport.d.ts +29 -0
- package/utils/weak-maps.d.ts +3 -0
- package/esm2020/utils/matrix.mjs +0 -170
- package/utils/matrix.d.ts +0 -82
package/fesm2015/plait-core.mjs
CHANGED
|
@@ -4,13 +4,100 @@ import rough from 'roughjs/bin/rough';
|
|
|
4
4
|
import { Subject, fromEvent } from 'rxjs';
|
|
5
5
|
import { takeUntil, filter } from 'rxjs/operators';
|
|
6
6
|
import produce, { createDraft, finishDraft, isDraft } from 'immer';
|
|
7
|
-
import { isKeyHotkey, isHotkey } from 'is-hotkey';
|
|
7
|
+
import isHotkey$1, { isKeyHotkey, isHotkey } from 'is-hotkey';
|
|
8
8
|
import * as i1 from '@angular/common';
|
|
9
9
|
import { BrowserModule } from '@angular/platform-browser';
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
const
|
|
13
|
-
const
|
|
11
|
+
// record richtext type status
|
|
12
|
+
const FLUSHING = new WeakMap();
|
|
13
|
+
const IS_TEXT_EDITABLE = new WeakMap();
|
|
14
|
+
const BOARD_TO_ON_CHANGE = new WeakMap();
|
|
15
|
+
const BOARD_TO_COMPONENT = new WeakMap();
|
|
16
|
+
const BOARD_TO_ROUGH_SVG = new WeakMap();
|
|
17
|
+
const BOARD_TO_HOST = new WeakMap();
|
|
18
|
+
const BOARD_TO_ELEMENT_HOST = new WeakMap();
|
|
19
|
+
const BOARD_TO_SELECTED_ELEMENT = new WeakMap();
|
|
20
|
+
const BOARD_TO_MOVING_POINT = new WeakMap();
|
|
21
|
+
const BOARD_TO_IS_SELECTION_MOVING = new WeakMap();
|
|
22
|
+
// save no standard selected elements
|
|
23
|
+
const BOARD_TO_TEMPORARY_ELEMENTS = new WeakMap();
|
|
24
|
+
const BOARD_TO_MOVING_ELEMENT = new WeakMap();
|
|
25
|
+
|
|
26
|
+
function depthFirstRecursion(node, callback) {
|
|
27
|
+
var _a;
|
|
28
|
+
(_a = node.children) === null || _a === void 0 ? void 0 : _a.forEach(child => {
|
|
29
|
+
depthFirstRecursion(child, callback);
|
|
30
|
+
});
|
|
31
|
+
callback(node);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function getRectangleByElements(board, elements, recursion) {
|
|
35
|
+
const boundaryBox = {
|
|
36
|
+
left: Number.MAX_VALUE,
|
|
37
|
+
top: Number.MAX_VALUE,
|
|
38
|
+
right: Number.NEGATIVE_INFINITY,
|
|
39
|
+
bottom: Number.NEGATIVE_INFINITY
|
|
40
|
+
};
|
|
41
|
+
const calcRectangleClient = (node) => {
|
|
42
|
+
const nodeRectangle = board.getRectangle(node);
|
|
43
|
+
if (nodeRectangle) {
|
|
44
|
+
boundaryBox.left = Math.min(boundaryBox.left, nodeRectangle.x);
|
|
45
|
+
boundaryBox.top = Math.min(boundaryBox.top, nodeRectangle.y);
|
|
46
|
+
boundaryBox.right = Math.max(boundaryBox.right, nodeRectangle.x + nodeRectangle.width);
|
|
47
|
+
boundaryBox.bottom = Math.max(boundaryBox.bottom, nodeRectangle.y + nodeRectangle.height);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
elements.forEach(element => {
|
|
51
|
+
if (recursion) {
|
|
52
|
+
depthFirstRecursion(element, node => calcRectangleClient(node));
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
calcRectangleClient(element);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
return {
|
|
59
|
+
x: boundaryBox.left,
|
|
60
|
+
y: boundaryBox.top,
|
|
61
|
+
width: boundaryBox.right - boundaryBox.left,
|
|
62
|
+
height: boundaryBox.bottom - boundaryBox.top
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function getBoardRectangle(board) {
|
|
66
|
+
return getRectangleByElements(board, board.children, true);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const PlaitBoard = {
|
|
70
|
+
getHost(board) {
|
|
71
|
+
return BOARD_TO_HOST.get(board);
|
|
72
|
+
},
|
|
73
|
+
getElementHost(board) {
|
|
74
|
+
return BOARD_TO_ELEMENT_HOST.get(board);
|
|
75
|
+
},
|
|
76
|
+
getRoughSVG(board) {
|
|
77
|
+
return BOARD_TO_ROUGH_SVG.get(board);
|
|
78
|
+
},
|
|
79
|
+
getComponent(board) {
|
|
80
|
+
return BOARD_TO_COMPONENT.get(board);
|
|
81
|
+
},
|
|
82
|
+
getBoardNativeElement(board) {
|
|
83
|
+
return PlaitBoard.getComponent(board).nativeElement;
|
|
84
|
+
},
|
|
85
|
+
getRectangle(board) {
|
|
86
|
+
return getRectangleByElements(board, board.children, true);
|
|
87
|
+
},
|
|
88
|
+
getViewportContainer(board) {
|
|
89
|
+
return PlaitBoard.getHost(board).parentElement;
|
|
90
|
+
},
|
|
91
|
+
isFocus(board) {
|
|
92
|
+
return !!board.selection;
|
|
93
|
+
},
|
|
94
|
+
isReadonly(board) {
|
|
95
|
+
return board.options.readonly;
|
|
96
|
+
},
|
|
97
|
+
hasBeenTextEditing(board) {
|
|
98
|
+
return !!IS_TEXT_EDITABLE.get(board);
|
|
99
|
+
}
|
|
100
|
+
};
|
|
14
101
|
|
|
15
102
|
var PlaitPointerType;
|
|
16
103
|
(function (PlaitPointerType) {
|
|
@@ -21,6 +108,19 @@ var PlaitPointerType;
|
|
|
21
108
|
function isNullOrUndefined(value) {
|
|
22
109
|
return value === null || value === undefined;
|
|
23
110
|
}
|
|
111
|
+
/**
|
|
112
|
+
* 规范 point
|
|
113
|
+
* @param point
|
|
114
|
+
* @returns point
|
|
115
|
+
*/
|
|
116
|
+
function normalizePoint(point) {
|
|
117
|
+
return Array.isArray(point)
|
|
118
|
+
? {
|
|
119
|
+
x: point[0],
|
|
120
|
+
y: point[1]
|
|
121
|
+
}
|
|
122
|
+
: point;
|
|
123
|
+
}
|
|
24
124
|
|
|
25
125
|
const Viewport = {
|
|
26
126
|
isViewport: (value) => {
|
|
@@ -361,94 +461,71 @@ function setSelection(board, selection) {
|
|
|
361
461
|
board.apply(operation);
|
|
362
462
|
}
|
|
363
463
|
const SelectionTransforms = {
|
|
364
|
-
setSelection
|
|
464
|
+
setSelection,
|
|
465
|
+
setSelectionWithTemporaryElements
|
|
365
466
|
};
|
|
467
|
+
function setSelectionWithTemporaryElements(board, elements) {
|
|
468
|
+
setTimeout(() => {
|
|
469
|
+
BOARD_TO_TEMPORARY_ELEMENTS.set(board, elements);
|
|
470
|
+
setSelection(board, { ranges: [] });
|
|
471
|
+
});
|
|
472
|
+
}
|
|
366
473
|
|
|
367
|
-
function setViewport(board, viewport) {
|
|
474
|
+
function setViewport$1(board, viewport) {
|
|
368
475
|
const operation = { type: 'set_viewport', properties: board.viewport, newProperties: viewport };
|
|
369
476
|
board.apply(operation);
|
|
370
477
|
}
|
|
371
478
|
const ViewportTransforms = {
|
|
372
|
-
setViewport
|
|
479
|
+
setViewport: setViewport$1
|
|
373
480
|
};
|
|
374
481
|
|
|
375
|
-
//
|
|
376
|
-
|
|
377
|
-
const
|
|
378
|
-
const
|
|
379
|
-
const
|
|
380
|
-
const
|
|
381
|
-
const
|
|
382
|
-
const
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
482
|
+
// https://stackoverflow.com/a/6853926/232122
|
|
483
|
+
function distanceBetweenPointAndSegment(x, y, x1, y1, x2, y2) {
|
|
484
|
+
const A = x - x1;
|
|
485
|
+
const B = y - y1;
|
|
486
|
+
const C = x2 - x1;
|
|
487
|
+
const D = y2 - y1;
|
|
488
|
+
const dot = A * C + B * D;
|
|
489
|
+
const lenSquare = C * C + D * D;
|
|
490
|
+
let param = -1;
|
|
491
|
+
if (lenSquare !== 0) {
|
|
492
|
+
// in case of 0 length line
|
|
493
|
+
param = dot / lenSquare;
|
|
494
|
+
}
|
|
495
|
+
let xx, yy;
|
|
496
|
+
if (param < 0) {
|
|
497
|
+
xx = x1;
|
|
498
|
+
yy = y1;
|
|
499
|
+
}
|
|
500
|
+
else if (param > 1) {
|
|
501
|
+
xx = x2;
|
|
502
|
+
yy = y2;
|
|
503
|
+
}
|
|
504
|
+
else {
|
|
505
|
+
xx = x1 + param * C;
|
|
506
|
+
yy = y1 + param * D;
|
|
507
|
+
}
|
|
508
|
+
const dx = x - xx;
|
|
509
|
+
const dy = y - yy;
|
|
510
|
+
return Math.hypot(dx, dy);
|
|
392
511
|
}
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
right: Number.MIN_VALUE,
|
|
399
|
-
bottom: Number.MIN_VALUE
|
|
400
|
-
};
|
|
401
|
-
const calcRectangleClient = (node) => {
|
|
402
|
-
const nodeRectangle = board.getRectangle(node);
|
|
403
|
-
if (nodeRectangle) {
|
|
404
|
-
boundaryBox.left = Math.min(boundaryBox.left, nodeRectangle.x);
|
|
405
|
-
boundaryBox.top = Math.min(boundaryBox.top, nodeRectangle.y);
|
|
406
|
-
boundaryBox.right = Math.max(boundaryBox.right, nodeRectangle.x + nodeRectangle.width);
|
|
407
|
-
boundaryBox.bottom = Math.max(boundaryBox.bottom, nodeRectangle.y + nodeRectangle.height);
|
|
408
|
-
}
|
|
409
|
-
};
|
|
410
|
-
elements.forEach(element => {
|
|
411
|
-
if (recursion) {
|
|
412
|
-
depthFirstRecursion(element, node => calcRectangleClient(node));
|
|
413
|
-
}
|
|
414
|
-
else {
|
|
415
|
-
calcRectangleClient(element);
|
|
416
|
-
}
|
|
417
|
-
});
|
|
418
|
-
return {
|
|
419
|
-
x: boundaryBox.left,
|
|
420
|
-
y: boundaryBox.top,
|
|
421
|
-
width: boundaryBox.right - boundaryBox.left,
|
|
422
|
-
height: boundaryBox.bottom - boundaryBox.top
|
|
423
|
-
};
|
|
512
|
+
function rotate(x1, y1, x2, y2, angle) {
|
|
513
|
+
// 𝑎′𝑥=(𝑎𝑥−𝑐𝑥)cos𝜃−(𝑎𝑦−𝑐𝑦)sin𝜃+𝑐𝑥
|
|
514
|
+
// 𝑎′𝑦=(𝑎𝑥−𝑐𝑥)sin𝜃+(𝑎𝑦−𝑐𝑦)cos𝜃+𝑐𝑦.
|
|
515
|
+
// https://math.stackexchange.com/questions/2204520/how-do-i-rotate-a-line-segment-in-a-specific-point-on-the-line
|
|
516
|
+
return [(x1 - x2) * Math.cos(angle) - (y1 - y2) * Math.sin(angle) + x2, (x1 - x2) * Math.sin(angle) + (y1 - y2) * Math.cos(angle) + y2];
|
|
424
517
|
}
|
|
425
|
-
function
|
|
426
|
-
|
|
518
|
+
function distanceBetweenPointAndPoint(x1, y1, x2, y2) {
|
|
519
|
+
const dx = x1 - x2;
|
|
520
|
+
const dy = y1 - y2;
|
|
521
|
+
return Math.hypot(dx, dy);
|
|
522
|
+
}
|
|
523
|
+
// https://stackoverflow.com/questions/5254838/calculating-distance-between-a-point-and-a-rectangular-box-nearest-point
|
|
524
|
+
function distanceBetweenPointAndRectangle(x, y, rect) {
|
|
525
|
+
var dx = Math.max(rect.x - x, 0, x - (rect.x + rect.width));
|
|
526
|
+
var dy = Math.max(rect.y - y, 0, y - (rect.y + rect.height));
|
|
527
|
+
return Math.sqrt(dx * dx + dy * dy);
|
|
427
528
|
}
|
|
428
|
-
|
|
429
|
-
const PlaitBoard = {
|
|
430
|
-
getHost(board) {
|
|
431
|
-
return BOARD_TO_HOST.get(board);
|
|
432
|
-
},
|
|
433
|
-
getElementHost(board) {
|
|
434
|
-
return BOARD_TO_ELEMENT_HOST.get(board);
|
|
435
|
-
},
|
|
436
|
-
getRoughSVG(board) {
|
|
437
|
-
return BOARD_TO_ROUGH_SVG.get(board);
|
|
438
|
-
},
|
|
439
|
-
getComponent(board) {
|
|
440
|
-
return BOARD_TO_COMPONENT.get(board);
|
|
441
|
-
},
|
|
442
|
-
getBoardNativeElement(board) {
|
|
443
|
-
return PlaitBoard.getComponent(board).nativeElement;
|
|
444
|
-
},
|
|
445
|
-
getRectangle(board) {
|
|
446
|
-
return getRectangleByElements(board, board.children, true);
|
|
447
|
-
},
|
|
448
|
-
getViewportContainer(board) {
|
|
449
|
-
return PlaitBoard.getHost(board).parentElement;
|
|
450
|
-
}
|
|
451
|
-
};
|
|
452
529
|
|
|
453
530
|
function transformPoints(board, points) {
|
|
454
531
|
const newPoints = points.map(point => {
|
|
@@ -464,9 +541,11 @@ function transformPoint(board, point) {
|
|
|
464
541
|
const newPoint = [x, y];
|
|
465
542
|
return newPoint;
|
|
466
543
|
}
|
|
467
|
-
function
|
|
468
|
-
|
|
469
|
-
|
|
544
|
+
function isInPlaitBoard(board, x, y) {
|
|
545
|
+
const plaitBoardElement = PlaitBoard.getBoardNativeElement(board);
|
|
546
|
+
const plaitBoardRect = plaitBoardElement.getBoundingClientRect();
|
|
547
|
+
const distances = distanceBetweenPointAndRectangle(x, y, plaitBoardRect);
|
|
548
|
+
return distances === 0;
|
|
470
549
|
}
|
|
471
550
|
|
|
472
551
|
const NS = 'http://www.w3.org/2000/svg';
|
|
@@ -787,222 +866,6 @@ function idCreator(length = 5) {
|
|
|
787
866
|
return key;
|
|
788
867
|
}
|
|
789
868
|
|
|
790
|
-
// https://stackoverflow.com/a/6853926/232122
|
|
791
|
-
function distanceBetweenPointAndSegment(x, y, x1, y1, x2, y2) {
|
|
792
|
-
const A = x - x1;
|
|
793
|
-
const B = y - y1;
|
|
794
|
-
const C = x2 - x1;
|
|
795
|
-
const D = y2 - y1;
|
|
796
|
-
const dot = A * C + B * D;
|
|
797
|
-
const lenSquare = C * C + D * D;
|
|
798
|
-
let param = -1;
|
|
799
|
-
if (lenSquare !== 0) {
|
|
800
|
-
// in case of 0 length line
|
|
801
|
-
param = dot / lenSquare;
|
|
802
|
-
}
|
|
803
|
-
let xx, yy;
|
|
804
|
-
if (param < 0) {
|
|
805
|
-
xx = x1;
|
|
806
|
-
yy = y1;
|
|
807
|
-
}
|
|
808
|
-
else if (param > 1) {
|
|
809
|
-
xx = x2;
|
|
810
|
-
yy = y2;
|
|
811
|
-
}
|
|
812
|
-
else {
|
|
813
|
-
xx = x1 + param * C;
|
|
814
|
-
yy = y1 + param * D;
|
|
815
|
-
}
|
|
816
|
-
const dx = x - xx;
|
|
817
|
-
const dy = y - yy;
|
|
818
|
-
return Math.hypot(dx, dy);
|
|
819
|
-
}
|
|
820
|
-
function rotate(x1, y1, x2, y2, angle) {
|
|
821
|
-
// 𝑎′𝑥=(𝑎𝑥−𝑐𝑥)cos𝜃−(𝑎𝑦−𝑐𝑦)sin𝜃+𝑐𝑥
|
|
822
|
-
// 𝑎′𝑦=(𝑎𝑥−𝑐𝑥)sin𝜃+(𝑎𝑦−𝑐𝑦)cos𝜃+𝑐𝑦.
|
|
823
|
-
// https://math.stackexchange.com/questions/2204520/how-do-i-rotate-a-line-segment-in-a-specific-point-on-the-line
|
|
824
|
-
return [(x1 - x2) * Math.cos(angle) - (y1 - y2) * Math.sin(angle) + x2, (x1 - x2) * Math.sin(angle) + (y1 - y2) * Math.cos(angle) + y2];
|
|
825
|
-
}
|
|
826
|
-
function distanceBetweenPointAndPoint(x1, y1, x2, y2) {
|
|
827
|
-
const dx = x1 - x2;
|
|
828
|
-
const dy = y1 - y2;
|
|
829
|
-
return Math.hypot(dx, dy);
|
|
830
|
-
}
|
|
831
|
-
// https://stackoverflow.com/questions/5254838/calculating-distance-between-a-point-and-a-rectangular-box-nearest-point
|
|
832
|
-
function distanceBetweenPointAndRectangle(x, y, rect) {
|
|
833
|
-
var dx = Math.max(rect.x - x, 0, x - (rect.x + rect.width));
|
|
834
|
-
var dy = Math.max(rect.y - y, 0, y - (rect.y + rect.height));
|
|
835
|
-
return Math.sqrt(dx * dx + dy * dy);
|
|
836
|
-
}
|
|
837
|
-
|
|
838
|
-
/**
|
|
839
|
-
* 逆矩阵
|
|
840
|
-
* [a c e]
|
|
841
|
-
* [b d f]
|
|
842
|
-
* [0 0 1]
|
|
843
|
-
* @param newMatrix 输出返回矩阵
|
|
844
|
-
* @param matrix 新矩阵
|
|
845
|
-
* @returns 逆矩阵
|
|
846
|
-
*/
|
|
847
|
-
function invertMatrix(newMatrix, matrix) {
|
|
848
|
-
const [n, r, a, i, o, c, l, s, u] = matrix;
|
|
849
|
-
const determinant = u * o - c * s;
|
|
850
|
-
const h = -u * i + c * l;
|
|
851
|
-
const f = s * i - o * l;
|
|
852
|
-
const product = n * determinant + r * h + a * f;
|
|
853
|
-
if (!product) {
|
|
854
|
-
return null;
|
|
855
|
-
}
|
|
856
|
-
const reciprocal = 1 / product;
|
|
857
|
-
newMatrix[0] = determinant * reciprocal;
|
|
858
|
-
newMatrix[1] = (-u * r + a * s) * reciprocal;
|
|
859
|
-
newMatrix[2] = (c * r - a * o) * reciprocal;
|
|
860
|
-
newMatrix[3] = h * reciprocal;
|
|
861
|
-
newMatrix[4] = (u * n - a * l) * reciprocal;
|
|
862
|
-
newMatrix[5] = (-c * n + a * i) * reciprocal;
|
|
863
|
-
newMatrix[6] = f * reciprocal;
|
|
864
|
-
newMatrix[7] = (-s * n + r * l) * reciprocal;
|
|
865
|
-
newMatrix[8] = (o * n - r * i) * reciprocal;
|
|
866
|
-
return newMatrix;
|
|
867
|
-
}
|
|
868
|
-
/**
|
|
869
|
-
* 将视图坐标与反转矩阵相乘,以得到原始坐标
|
|
870
|
-
* 使用给定的矩阵进行转换
|
|
871
|
-
* 矩阵与向量乘法,3 维向量与3x3矩阵的乘积
|
|
872
|
-
* [m11 m12 m13][v1]
|
|
873
|
-
* [m21 m22 m23][v2]
|
|
874
|
-
* [m31 m32 m33][v3]
|
|
875
|
-
* @param out 输出结果向量
|
|
876
|
-
* @param t 要转换的向量
|
|
877
|
-
* @param n 矩阵转换
|
|
878
|
-
* @returns [v1 * m11 + v2 * m12 + v3 * m13, v1 * m21 + v2 * m22 + v3 * m23, v1 * m31 + v2 * m32 + v3 * m33];
|
|
879
|
-
*/
|
|
880
|
-
function transformMat3(out, vector, matrix) {
|
|
881
|
-
out = [
|
|
882
|
-
vector[0] * matrix[0] + vector[1] * matrix[3] + vector[2] * matrix[6],
|
|
883
|
-
vector[0] * matrix[1] + vector[1] * matrix[4] + vector[2] * matrix[7],
|
|
884
|
-
vector[0] * matrix[2] + vector[1] * matrix[5] + vector[2] * matrix[8]
|
|
885
|
-
];
|
|
886
|
-
return out;
|
|
887
|
-
}
|
|
888
|
-
/**
|
|
889
|
-
* 规范 point
|
|
890
|
-
* @param point
|
|
891
|
-
* @returns point
|
|
892
|
-
*/
|
|
893
|
-
function normalizePoint(point) {
|
|
894
|
-
return Array.isArray(point)
|
|
895
|
-
? {
|
|
896
|
-
x: point[0],
|
|
897
|
-
y: point[1]
|
|
898
|
-
}
|
|
899
|
-
: point;
|
|
900
|
-
}
|
|
901
|
-
/**
|
|
902
|
-
* 将一个点坐标反转回它的原始坐标
|
|
903
|
-
* @param point 表示要反转的点的视图坐标,它是一个长度为 2 的数组,存储点的 x 和 y 坐标
|
|
904
|
-
* @param matrix 表示视图矩阵,是在视图中对图形进行缩放和平移时使用的矩阵
|
|
905
|
-
* @returns 最终结果是一个长度为 3 的数组,存储点的 x,y 和 w 坐标(w 坐标是点的齐次坐标)
|
|
906
|
-
*/
|
|
907
|
-
function invertViewportCoordinates(point, matrix) {
|
|
908
|
-
const { x, y } = normalizePoint(point);
|
|
909
|
-
const invertedMatrix = invertMatrix([], matrix);
|
|
910
|
-
return transformMat3([], [x, y, 1], invertedMatrix);
|
|
911
|
-
}
|
|
912
|
-
function convertToViewportCoordinates(point, matrix) {
|
|
913
|
-
const { x, y } = normalizePoint(point);
|
|
914
|
-
return transformMat3([], [x, y, 1], matrix);
|
|
915
|
-
}
|
|
916
|
-
/**
|
|
917
|
-
* 获取 contentContainer 的 clientBox
|
|
918
|
-
* @param board
|
|
919
|
-
* @returns
|
|
920
|
-
*/
|
|
921
|
-
function getViewportContainerBox(board) {
|
|
922
|
-
const { hideScrollbar } = board.options;
|
|
923
|
-
const scrollBarWidth = hideScrollbar ? SCROLL_BAR_WIDTH : 0;
|
|
924
|
-
const container = PlaitBoard.getViewportContainer(board);
|
|
925
|
-
const containerRect = container.getBoundingClientRect();
|
|
926
|
-
const x = containerRect.x || containerRect.left;
|
|
927
|
-
const y = containerRect.y || containerRect.top;
|
|
928
|
-
const width = containerRect.width - scrollBarWidth;
|
|
929
|
-
const height = containerRect.height - scrollBarWidth;
|
|
930
|
-
return {
|
|
931
|
-
minX: x,
|
|
932
|
-
minY: y,
|
|
933
|
-
maxX: x + width,
|
|
934
|
-
maxY: y + height,
|
|
935
|
-
x,
|
|
936
|
-
y,
|
|
937
|
-
width,
|
|
938
|
-
height
|
|
939
|
-
};
|
|
940
|
-
}
|
|
941
|
-
/**
|
|
942
|
-
* 获取 board.plait-board 的 clientBox
|
|
943
|
-
* @param board
|
|
944
|
-
* @returns
|
|
945
|
-
*/
|
|
946
|
-
function getBoardClientBox(board) {
|
|
947
|
-
const { hideScrollbar } = board.options;
|
|
948
|
-
const scrollBarWidth = hideScrollbar ? SCROLL_BAR_WIDTH : 0;
|
|
949
|
-
const viewportRect = PlaitBoard.getViewportContainer(board).getBoundingClientRect();
|
|
950
|
-
return {
|
|
951
|
-
width: viewportRect.width + scrollBarWidth,
|
|
952
|
-
height: viewportRect.height + scrollBarWidth
|
|
953
|
-
};
|
|
954
|
-
}
|
|
955
|
-
/**
|
|
956
|
-
* 获取 rootGroup 相对于当前 svg 空间的最小矩阵坐标
|
|
957
|
-
*/
|
|
958
|
-
function getRootGroupBBox(board, zoom) {
|
|
959
|
-
const elementHost = PlaitBoard.getElementHost(board);
|
|
960
|
-
const rootGroupBox = elementHost.getBBox();
|
|
961
|
-
const viewportContainerBox = getViewportContainerBox(board);
|
|
962
|
-
const containerWidth = viewportContainerBox.width / zoom;
|
|
963
|
-
const containerHeight = viewportContainerBox.height / zoom;
|
|
964
|
-
let left;
|
|
965
|
-
let right;
|
|
966
|
-
let top;
|
|
967
|
-
let bottom;
|
|
968
|
-
if (rootGroupBox.width < containerWidth) {
|
|
969
|
-
const offsetX = rootGroupBox.x + rootGroupBox.width / 2;
|
|
970
|
-
const containerX = containerWidth / 2;
|
|
971
|
-
left = offsetX - containerX;
|
|
972
|
-
right = offsetX + containerX;
|
|
973
|
-
}
|
|
974
|
-
else {
|
|
975
|
-
left = rootGroupBox.x;
|
|
976
|
-
right = rootGroupBox.x + rootGroupBox.width;
|
|
977
|
-
}
|
|
978
|
-
if (rootGroupBox.height < containerHeight) {
|
|
979
|
-
const offsetY = rootGroupBox.y + rootGroupBox.height / 2;
|
|
980
|
-
const containerY = containerHeight / 2;
|
|
981
|
-
top = offsetY - containerY;
|
|
982
|
-
bottom = offsetY + containerY;
|
|
983
|
-
}
|
|
984
|
-
else {
|
|
985
|
-
top = rootGroupBox.y;
|
|
986
|
-
bottom = rootGroupBox.y + rootGroupBox.height;
|
|
987
|
-
}
|
|
988
|
-
return {
|
|
989
|
-
left,
|
|
990
|
-
right,
|
|
991
|
-
top,
|
|
992
|
-
bottom
|
|
993
|
-
};
|
|
994
|
-
}
|
|
995
|
-
/**
|
|
996
|
-
* 验证缩放比是否符合限制,如果超出限制,则返回合适的缩放比
|
|
997
|
-
* @param zoom 缩放比
|
|
998
|
-
* @param minZoom 最小缩放比
|
|
999
|
-
* @param maxZoom 最大缩放比
|
|
1000
|
-
* @returns 正确的缩放比
|
|
1001
|
-
*/
|
|
1002
|
-
function clampZoomLevel(zoom, minZoom = 0.2, maxZoom = 4) {
|
|
1003
|
-
return zoom < minZoom ? minZoom : zoom > maxZoom ? maxZoom : zoom;
|
|
1004
|
-
}
|
|
1005
|
-
|
|
1006
869
|
const calcElementIntersectionSelection = (board) => {
|
|
1007
870
|
const selectedElements = [];
|
|
1008
871
|
depthFirstRecursion(board, node => {
|
|
@@ -1016,6 +879,19 @@ const calcElementIntersectionSelection = (board) => {
|
|
|
1016
879
|
});
|
|
1017
880
|
return selectedElements;
|
|
1018
881
|
};
|
|
882
|
+
const isIntersectionElements = (board, elements, ranges) => {
|
|
883
|
+
let isIntersectionElements = false;
|
|
884
|
+
if (elements.length) {
|
|
885
|
+
elements.map(item => {
|
|
886
|
+
if (!isIntersectionElements) {
|
|
887
|
+
isIntersectionElements = ranges.some(range => {
|
|
888
|
+
return board.isIntersectionSelection(item, range);
|
|
889
|
+
});
|
|
890
|
+
}
|
|
891
|
+
});
|
|
892
|
+
}
|
|
893
|
+
return isIntersectionElements;
|
|
894
|
+
};
|
|
1019
895
|
const cacheSelectedElements = (board, selectedElements) => {
|
|
1020
896
|
BOARD_TO_SELECTED_ELEMENT.set(board, selectedElements);
|
|
1021
897
|
};
|
|
@@ -1036,6 +912,10 @@ const isSelectedElement = (board, element) => {
|
|
|
1036
912
|
return !!selectedElements.find(value => value === element);
|
|
1037
913
|
};
|
|
1038
914
|
|
|
915
|
+
const CLIP_BOARD_FORMAT_KEY = 'x-plait-fragment';
|
|
916
|
+
const SCROLL_BAR_WIDTH = 20;
|
|
917
|
+
const MAX_RADIUS = 16;
|
|
918
|
+
|
|
1039
919
|
/**
|
|
1040
920
|
* drawRoundRectangle
|
|
1041
921
|
* @param rs RoughSVG
|
|
@@ -1088,6 +968,196 @@ function drawArrow(rs, start, end, options, maxHypotenuseLength = 10, degree = 4
|
|
|
1088
968
|
return [arrowLineLeft, arrowLineRight];
|
|
1089
969
|
}
|
|
1090
970
|
|
|
971
|
+
function getViewportContainerRect(board) {
|
|
972
|
+
const { hideScrollbar } = board.options;
|
|
973
|
+
const scrollBarWidth = hideScrollbar ? SCROLL_BAR_WIDTH : 0;
|
|
974
|
+
const viewportRect = PlaitBoard.getBoardNativeElement(board).getBoundingClientRect();
|
|
975
|
+
return {
|
|
976
|
+
width: viewportRect.width + scrollBarWidth,
|
|
977
|
+
height: viewportRect.height + scrollBarWidth
|
|
978
|
+
};
|
|
979
|
+
}
|
|
980
|
+
function getElementHostBBox(board, zoom) {
|
|
981
|
+
const childrenRect = getRectangleByElements(board, board.children, true);
|
|
982
|
+
const viewportContainerRect = getViewportContainerRect(board);
|
|
983
|
+
const containerWidth = viewportContainerRect.width / zoom;
|
|
984
|
+
const containerHeight = viewportContainerRect.height / zoom;
|
|
985
|
+
let left;
|
|
986
|
+
let right;
|
|
987
|
+
let top;
|
|
988
|
+
let bottom;
|
|
989
|
+
if (childrenRect.width < containerWidth) {
|
|
990
|
+
const centerX = Math.ceil(childrenRect.x + childrenRect.width / 2);
|
|
991
|
+
const halfContainerWidth = Math.ceil(containerWidth / 2);
|
|
992
|
+
left = centerX - halfContainerWidth;
|
|
993
|
+
right = centerX + halfContainerWidth;
|
|
994
|
+
}
|
|
995
|
+
else {
|
|
996
|
+
left = childrenRect.x;
|
|
997
|
+
right = childrenRect.x + childrenRect.width;
|
|
998
|
+
}
|
|
999
|
+
if (childrenRect.height < containerHeight) {
|
|
1000
|
+
const centerY = Math.ceil(childrenRect.y + childrenRect.height / 2);
|
|
1001
|
+
const halfContainerHeight = Math.ceil(containerHeight / 2);
|
|
1002
|
+
top = centerY - halfContainerHeight;
|
|
1003
|
+
bottom = centerY + halfContainerHeight;
|
|
1004
|
+
}
|
|
1005
|
+
else {
|
|
1006
|
+
top = childrenRect.y;
|
|
1007
|
+
bottom = childrenRect.y + childrenRect.height;
|
|
1008
|
+
}
|
|
1009
|
+
return {
|
|
1010
|
+
left,
|
|
1011
|
+
right,
|
|
1012
|
+
top,
|
|
1013
|
+
bottom
|
|
1014
|
+
};
|
|
1015
|
+
}
|
|
1016
|
+
/**
|
|
1017
|
+
* 验证缩放比是否符合限制,如果超出限制,则返回合适的缩放比
|
|
1018
|
+
* @param zoom 缩放比
|
|
1019
|
+
* @param minZoom 最小缩放比
|
|
1020
|
+
* @param maxZoom 最大缩放比
|
|
1021
|
+
* @returns 正确的缩放比
|
|
1022
|
+
*/
|
|
1023
|
+
function clampZoomLevel(zoom, minZoom = 0.2, maxZoom = 4) {
|
|
1024
|
+
return zoom < minZoom ? minZoom : zoom > maxZoom ? maxZoom : zoom;
|
|
1025
|
+
}
|
|
1026
|
+
function getViewBox(board, zoom) {
|
|
1027
|
+
const { hideScrollbar } = board.options;
|
|
1028
|
+
const scrollBarWidth = hideScrollbar ? SCROLL_BAR_WIDTH : 0;
|
|
1029
|
+
const viewportContainerRect = getViewportContainerRect(board);
|
|
1030
|
+
const elementHostBBox = getElementHostBBox(board, zoom);
|
|
1031
|
+
const horizontalPadding = viewportContainerRect.width / 2;
|
|
1032
|
+
const verticalPadding = viewportContainerRect.height / 2;
|
|
1033
|
+
const viewportWidth = (elementHostBBox.right - elementHostBBox.left) * zoom + 2 * horizontalPadding + scrollBarWidth;
|
|
1034
|
+
const viewportHeight = (elementHostBBox.bottom - elementHostBBox.top) * zoom + 2 * verticalPadding + scrollBarWidth;
|
|
1035
|
+
const viewBox = [
|
|
1036
|
+
elementHostBBox.left - horizontalPadding / zoom,
|
|
1037
|
+
elementHostBBox.top - verticalPadding / zoom,
|
|
1038
|
+
viewportWidth / zoom,
|
|
1039
|
+
viewportHeight / zoom
|
|
1040
|
+
];
|
|
1041
|
+
return viewBox;
|
|
1042
|
+
}
|
|
1043
|
+
function setSVGViewBox(board, viewBox) {
|
|
1044
|
+
const zoom = board.viewport.zoom;
|
|
1045
|
+
const hostElement = PlaitBoard.getHost(board);
|
|
1046
|
+
hostElement.style.display = 'block';
|
|
1047
|
+
hostElement.style.width = `${viewBox[2] * zoom}px`;
|
|
1048
|
+
hostElement.style.height = `${viewBox[3] * zoom}px`;
|
|
1049
|
+
if (viewBox && viewBox[2] > 0 && viewBox[3] > 0) {
|
|
1050
|
+
hostElement.setAttribute('viewBox', viewBox.join(' '));
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
function updateViewportContainerOffset(board, origination) {
|
|
1054
|
+
origination = origination !== null && origination !== void 0 ? origination : board.viewport.origination;
|
|
1055
|
+
if (!origination)
|
|
1056
|
+
return;
|
|
1057
|
+
const { zoom } = board.viewport;
|
|
1058
|
+
const viewBox = getViewBox(board, zoom);
|
|
1059
|
+
const scrollLeft = (origination[0] - viewBox[0]) * zoom;
|
|
1060
|
+
const scrollTop = (origination[1] - viewBox[1]) * zoom;
|
|
1061
|
+
setViewportContainerScroll(board, scrollLeft, scrollTop);
|
|
1062
|
+
}
|
|
1063
|
+
function setViewportContainerScroll(board, left, top) {
|
|
1064
|
+
const viewportContainer = PlaitBoard.getViewportContainer(board);
|
|
1065
|
+
viewportContainer.scrollLeft = Math.floor(left);
|
|
1066
|
+
viewportContainer.scrollTop = Math.floor(top);
|
|
1067
|
+
}
|
|
1068
|
+
function initializeViewport(board) {
|
|
1069
|
+
const zoom = board.viewport.zoom;
|
|
1070
|
+
const viewBox = getViewBox(board, zoom);
|
|
1071
|
+
setSVGViewBox(board, viewBox);
|
|
1072
|
+
}
|
|
1073
|
+
function initializeViewportContainerOffset(board) {
|
|
1074
|
+
var _a;
|
|
1075
|
+
if (!((_a = board.viewport) === null || _a === void 0 ? void 0 : _a.origination)) {
|
|
1076
|
+
const zoom = board.viewport.zoom;
|
|
1077
|
+
const viewportContainerBox = PlaitBoard.getBoardNativeElement(board).getBoundingClientRect();
|
|
1078
|
+
const viewBox = getViewBox(board, zoom);
|
|
1079
|
+
const centerX = viewBox[0] + viewBox[2] / 2;
|
|
1080
|
+
const centerY = viewBox[1] + viewBox[3] / 2;
|
|
1081
|
+
const origination = [centerX - viewportContainerBox.width / 2 / zoom, centerY - viewportContainerBox.height / 2 / zoom];
|
|
1082
|
+
updateViewportContainerOffset(board, origination);
|
|
1083
|
+
return;
|
|
1084
|
+
}
|
|
1085
|
+
updateViewportContainerOffset(board);
|
|
1086
|
+
}
|
|
1087
|
+
function setViewport(board, origination, zoom) {
|
|
1088
|
+
zoom = zoom !== null && zoom !== void 0 ? zoom : board.viewport.zoom;
|
|
1089
|
+
Transforms.setViewport(board, Object.assign(Object.assign({}, board.viewport), { zoom,
|
|
1090
|
+
origination }));
|
|
1091
|
+
}
|
|
1092
|
+
function changeZoom(board, newZoom, isCenter = true) {
|
|
1093
|
+
newZoom = clampZoomLevel(newZoom);
|
|
1094
|
+
const mousePoint = BOARD_TO_MOVING_POINT.get(board);
|
|
1095
|
+
const nativeElement = PlaitBoard.getBoardNativeElement(board);
|
|
1096
|
+
const rect = nativeElement.getBoundingClientRect();
|
|
1097
|
+
const viewportContainerRect = getViewportContainerRect(board);
|
|
1098
|
+
let focusPoint = [viewportContainerRect.width / 2, viewportContainerRect.height / 2];
|
|
1099
|
+
if (!isCenter && mousePoint && distanceBetweenPointAndRectangle(mousePoint[0], mousePoint[1], rect) === 0) {
|
|
1100
|
+
focusPoint = toPoint(mousePoint[0], mousePoint[1], nativeElement);
|
|
1101
|
+
}
|
|
1102
|
+
const { origination, zoom } = board.viewport;
|
|
1103
|
+
const centerX = origination[0] + focusPoint[0] / zoom;
|
|
1104
|
+
const centerY = origination[1] + focusPoint[1] / zoom;
|
|
1105
|
+
const viewBox = getViewBox(board, newZoom);
|
|
1106
|
+
const newOrigination = [centerX - focusPoint[0] / newZoom, centerY - focusPoint[1] / newZoom];
|
|
1107
|
+
setSVGViewBox(board, viewBox);
|
|
1108
|
+
setViewport(board, newOrigination, newZoom);
|
|
1109
|
+
}
|
|
1110
|
+
function fitViewport(board) {
|
|
1111
|
+
const viewportContainerRect = getViewportContainerRect(board);
|
|
1112
|
+
const rootGroupBox = getRectangleByElements(board, board.children, true);
|
|
1113
|
+
const zoom = board.viewport.zoom;
|
|
1114
|
+
const autoFitPadding = 8;
|
|
1115
|
+
const viewportWidth = viewportContainerRect.width - 2 * autoFitPadding;
|
|
1116
|
+
const viewportHeight = viewportContainerRect.height - 2 * autoFitPadding;
|
|
1117
|
+
let newZoom = zoom;
|
|
1118
|
+
if (viewportWidth < rootGroupBox.width || viewportHeight < rootGroupBox.height) {
|
|
1119
|
+
newZoom = Math.min(viewportWidth / rootGroupBox.width, viewportHeight / rootGroupBox.height);
|
|
1120
|
+
}
|
|
1121
|
+
else {
|
|
1122
|
+
newZoom = 1;
|
|
1123
|
+
}
|
|
1124
|
+
const viewBox = getViewBox(board, newZoom);
|
|
1125
|
+
const centerX = viewBox[0] + viewBox[2] / 2;
|
|
1126
|
+
const centerY = viewBox[1] + viewBox[3] / 2;
|
|
1127
|
+
const newOrigination = [centerX - viewportContainerRect.width / 2 / newZoom, centerY - viewportContainerRect.height / 2 / newZoom];
|
|
1128
|
+
setViewport(board, newOrigination, newZoom);
|
|
1129
|
+
}
|
|
1130
|
+
function scrollToRectangle(board, client) { }
|
|
1131
|
+
|
|
1132
|
+
let timerId = null;
|
|
1133
|
+
const throttleRAF = (fn) => {
|
|
1134
|
+
const scheduleFunc = () => {
|
|
1135
|
+
timerId = requestAnimationFrame(() => {
|
|
1136
|
+
timerId = null;
|
|
1137
|
+
fn();
|
|
1138
|
+
});
|
|
1139
|
+
};
|
|
1140
|
+
if (timerId !== null) {
|
|
1141
|
+
cancelAnimationFrame(timerId);
|
|
1142
|
+
timerId = null;
|
|
1143
|
+
}
|
|
1144
|
+
scheduleFunc();
|
|
1145
|
+
};
|
|
1146
|
+
|
|
1147
|
+
const getMovingElements = (board) => {
|
|
1148
|
+
return BOARD_TO_MOVING_ELEMENT.get(board) || [];
|
|
1149
|
+
};
|
|
1150
|
+
const addMovingElements = (board, elements) => {
|
|
1151
|
+
const movingElements = getMovingElements(board);
|
|
1152
|
+
cacheMovingElements(board, [...movingElements, ...elements]);
|
|
1153
|
+
};
|
|
1154
|
+
const removeMovingElements = (board) => {
|
|
1155
|
+
BOARD_TO_MOVING_ELEMENT.delete(board);
|
|
1156
|
+
};
|
|
1157
|
+
const cacheMovingElements = (board, elements) => {
|
|
1158
|
+
BOARD_TO_MOVING_ELEMENT.set(board, elements);
|
|
1159
|
+
};
|
|
1160
|
+
|
|
1091
1161
|
const updatePointerType = (board, pointer) => {
|
|
1092
1162
|
board.pointer = pointer;
|
|
1093
1163
|
const boardComponent = BOARD_TO_COMPONENT.get(board);
|
|
@@ -1148,6 +1218,7 @@ function createBoard(children, options) {
|
|
|
1148
1218
|
destroyElement: (context) => { },
|
|
1149
1219
|
isWithinSelection: element => false,
|
|
1150
1220
|
isIntersectionSelection: element => false,
|
|
1221
|
+
isMovable: element => false,
|
|
1151
1222
|
getRectangle: element => null
|
|
1152
1223
|
};
|
|
1153
1224
|
return board;
|
|
@@ -1273,11 +1344,13 @@ function withHandPointer(board) {
|
|
|
1273
1344
|
};
|
|
1274
1345
|
board.mousemove = (event) => {
|
|
1275
1346
|
if (board.pointer === PlaitPointerType.hand && board.selection && isMoving) {
|
|
1276
|
-
const
|
|
1277
|
-
const left = event.x - plaitBoardMove.x;
|
|
1278
|
-
const top = event.y - plaitBoardMove.y;
|
|
1279
|
-
const
|
|
1280
|
-
|
|
1347
|
+
const viewportContainer = PlaitBoard.getViewportContainer(board);
|
|
1348
|
+
const left = viewportContainer.scrollLeft + (event.x - plaitBoardMove.x);
|
|
1349
|
+
const top = viewportContainer.scrollTop + (event.y - plaitBoardMove.y);
|
|
1350
|
+
const zoom = board.viewport.zoom;
|
|
1351
|
+
const viewBox = getViewBox(board, zoom);
|
|
1352
|
+
const origination = [left / zoom + viewBox[0], top / zoom + viewBox[1]];
|
|
1353
|
+
setViewport(board, origination);
|
|
1281
1354
|
plaitBoardMove.x = event.x;
|
|
1282
1355
|
plaitBoardMove.y = event.y;
|
|
1283
1356
|
}
|
|
@@ -1310,6 +1383,8 @@ function withHandPointer(board) {
|
|
|
1310
1383
|
return board;
|
|
1311
1384
|
}
|
|
1312
1385
|
|
|
1386
|
+
const ATTACHED_ELEMENT_CLASS_NAME = 'plait-board-attached';
|
|
1387
|
+
|
|
1313
1388
|
function withSelection(board) {
|
|
1314
1389
|
const { mousedown, globalMousemove, globalMouseup, onChange } = board;
|
|
1315
1390
|
let start = null;
|
|
@@ -1317,12 +1392,22 @@ function withSelection(board) {
|
|
|
1317
1392
|
let selectionMovingG;
|
|
1318
1393
|
let selectionOuterG;
|
|
1319
1394
|
board.mousedown = (event) => {
|
|
1320
|
-
selectionOuterG === null || selectionOuterG === void 0 ? void 0 : selectionOuterG.remove();
|
|
1321
1395
|
if (event.button === 0) {
|
|
1322
1396
|
start = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
|
|
1323
1397
|
}
|
|
1324
1398
|
if (start) {
|
|
1325
|
-
|
|
1399
|
+
const ranges = [{ anchor: start, focus: start }];
|
|
1400
|
+
const selectedElements = getSelectedElements(board);
|
|
1401
|
+
const intersectionSelectedElement = isIntersectionElements(board, selectedElements, ranges);
|
|
1402
|
+
if (intersectionSelectedElement) {
|
|
1403
|
+
start = null;
|
|
1404
|
+
}
|
|
1405
|
+
else {
|
|
1406
|
+
Transforms.setSelection(board, { ranges: ranges });
|
|
1407
|
+
if (calcElementIntersectionSelection(board).length) {
|
|
1408
|
+
start = null;
|
|
1409
|
+
}
|
|
1410
|
+
}
|
|
1326
1411
|
}
|
|
1327
1412
|
mousedown(event);
|
|
1328
1413
|
};
|
|
@@ -1330,13 +1415,11 @@ function withSelection(board) {
|
|
|
1330
1415
|
if (start) {
|
|
1331
1416
|
const movedTarget = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
|
|
1332
1417
|
const { x, y, width, height } = RectangleClient.toRectangleClient([start, movedTarget]);
|
|
1418
|
+
selectionMovingG === null || selectionMovingG === void 0 ? void 0 : selectionMovingG.remove();
|
|
1333
1419
|
if (Math.hypot(width, height) > 5) {
|
|
1334
1420
|
end = movedTarget;
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
}
|
|
1338
|
-
PlaitBoard.getBoardNativeElement(board).classList.add('selection-moving');
|
|
1339
|
-
selectionMovingG === null || selectionMovingG === void 0 ? void 0 : selectionMovingG.remove();
|
|
1421
|
+
Transforms.setSelection(board, { ranges: [{ anchor: start, focus: end }] });
|
|
1422
|
+
setSelectionMoving(board);
|
|
1340
1423
|
const rough = PlaitBoard.getRoughSVG(board);
|
|
1341
1424
|
selectionMovingG = rough.rectangle(x, y, width, height, {
|
|
1342
1425
|
stroke: SELECTION_BORDER_COLOR,
|
|
@@ -1351,8 +1434,18 @@ function withSelection(board) {
|
|
|
1351
1434
|
};
|
|
1352
1435
|
board.globalMouseup = (event) => {
|
|
1353
1436
|
if (start && end) {
|
|
1354
|
-
PlaitBoard.getBoardNativeElement(board).classList.remove('selection-moving');
|
|
1355
1437
|
selectionMovingG === null || selectionMovingG === void 0 ? void 0 : selectionMovingG.remove();
|
|
1438
|
+
clearSelectionMoving(board);
|
|
1439
|
+
Transforms.setSelection(board, { ranges: [{ anchor: start, focus: end }] });
|
|
1440
|
+
}
|
|
1441
|
+
if (PlaitBoard.isFocus(board)) {
|
|
1442
|
+
const isInBoard = event.target instanceof Node && PlaitBoard.getBoardNativeElement(board).contains(event.target);
|
|
1443
|
+
const isAttachedElement = event.target instanceof HTMLElement && event.target.closest(`.${ATTACHED_ELEMENT_CLASS_NAME}`);
|
|
1444
|
+
// Clear selection when mouse board outside area
|
|
1445
|
+
// The framework needs to determine whether the board is focused through selection
|
|
1446
|
+
if (!isInBoard && !start && !isAttachedElement) {
|
|
1447
|
+
Transforms.setSelection(board, null);
|
|
1448
|
+
}
|
|
1356
1449
|
}
|
|
1357
1450
|
start = null;
|
|
1358
1451
|
end = null;
|
|
@@ -1361,10 +1454,12 @@ function withSelection(board) {
|
|
|
1361
1454
|
board.onChange = () => {
|
|
1362
1455
|
// calc selected elements entry
|
|
1363
1456
|
try {
|
|
1457
|
+
selectionOuterG === null || selectionOuterG === void 0 ? void 0 : selectionOuterG.remove();
|
|
1364
1458
|
if (board.operations.find(value => value.type === 'set_selection')) {
|
|
1365
|
-
const
|
|
1366
|
-
|
|
1367
|
-
|
|
1459
|
+
const temporaryElements = getTemporaryElements(board);
|
|
1460
|
+
const elements = temporaryElements ? temporaryElements : calcElementIntersectionSelection(board);
|
|
1461
|
+
cacheSelectedElements(board, elements);
|
|
1462
|
+
const { x, y, width, height } = getRectangleByElements(board, elements, false);
|
|
1368
1463
|
if (width > 0 && height > 0) {
|
|
1369
1464
|
const rough = PlaitBoard.getRoughSVG(board);
|
|
1370
1465
|
selectionOuterG = rough.rectangle(x - 2, y - 2, width + 4, height + 4, {
|
|
@@ -1372,9 +1467,11 @@ function withSelection(board) {
|
|
|
1372
1467
|
strokeWidth: 1,
|
|
1373
1468
|
fillStyle: 'solid'
|
|
1374
1469
|
});
|
|
1470
|
+
selectionOuterG.classList.add('selection-outer');
|
|
1375
1471
|
PlaitBoard.getHost(board).append(selectionOuterG);
|
|
1376
1472
|
}
|
|
1377
1473
|
}
|
|
1474
|
+
deleteTemporaryElements(board);
|
|
1378
1475
|
}
|
|
1379
1476
|
catch (error) {
|
|
1380
1477
|
console.error(error);
|
|
@@ -1383,6 +1480,33 @@ function withSelection(board) {
|
|
|
1383
1480
|
};
|
|
1384
1481
|
return board;
|
|
1385
1482
|
}
|
|
1483
|
+
function getTemporaryElements(board) {
|
|
1484
|
+
return BOARD_TO_TEMPORARY_ELEMENTS.get(board);
|
|
1485
|
+
}
|
|
1486
|
+
function deleteTemporaryElements(board) {
|
|
1487
|
+
BOARD_TO_TEMPORARY_ELEMENTS.delete(board);
|
|
1488
|
+
}
|
|
1489
|
+
function isSelectionMoving(board) {
|
|
1490
|
+
return !!BOARD_TO_IS_SELECTION_MOVING.get(board);
|
|
1491
|
+
}
|
|
1492
|
+
function setSelectionMoving(board) {
|
|
1493
|
+
PlaitBoard.getBoardNativeElement(board).classList.add('selection-moving');
|
|
1494
|
+
BOARD_TO_IS_SELECTION_MOVING.set(board, true);
|
|
1495
|
+
}
|
|
1496
|
+
function clearSelectionMoving(board) {
|
|
1497
|
+
PlaitBoard.getBoardNativeElement(board).classList.remove('selection-moving');
|
|
1498
|
+
BOARD_TO_IS_SELECTION_MOVING.delete(board);
|
|
1499
|
+
}
|
|
1500
|
+
|
|
1501
|
+
function withViewport(board) {
|
|
1502
|
+
const { onChange } = board;
|
|
1503
|
+
board.onChange = () => {
|
|
1504
|
+
initializeViewport(board);
|
|
1505
|
+
updateViewportContainerOffset(board);
|
|
1506
|
+
onChange();
|
|
1507
|
+
};
|
|
1508
|
+
return board;
|
|
1509
|
+
}
|
|
1386
1510
|
|
|
1387
1511
|
class PlaitElementComponent {
|
|
1388
1512
|
constructor(renderer2, viewContainerRef) {
|
|
@@ -1436,7 +1560,7 @@ class PlaitElementComponent {
|
|
|
1436
1560
|
const current = {
|
|
1437
1561
|
element: this.element,
|
|
1438
1562
|
selection: this.selection,
|
|
1439
|
-
board: this.board
|
|
1563
|
+
board: this.board
|
|
1440
1564
|
};
|
|
1441
1565
|
if (this.context) {
|
|
1442
1566
|
const previous = Object.assign({}, this.context);
|
|
@@ -1537,10 +1661,6 @@ class PlaitBoardComponent {
|
|
|
1537
1661
|
this.elementRef = elementRef;
|
|
1538
1662
|
this.hasInitialized = false;
|
|
1539
1663
|
this.destroy$ = new Subject();
|
|
1540
|
-
this.viewportState = {
|
|
1541
|
-
zoom: 1,
|
|
1542
|
-
autoFitPadding: 8
|
|
1543
|
-
};
|
|
1544
1664
|
this.plaitValue = [];
|
|
1545
1665
|
this.plaitPlugins = [];
|
|
1546
1666
|
this.plaitChange = new EventEmitter();
|
|
@@ -1549,10 +1669,6 @@ class PlaitBoardComponent {
|
|
|
1549
1669
|
return index;
|
|
1550
1670
|
};
|
|
1551
1671
|
}
|
|
1552
|
-
get isFocused() {
|
|
1553
|
-
var _a;
|
|
1554
|
-
return (_a = this.board) === null || _a === void 0 ? void 0 : _a.selection;
|
|
1555
|
-
}
|
|
1556
1672
|
get host() {
|
|
1557
1673
|
return this.svg.nativeElement;
|
|
1558
1674
|
}
|
|
@@ -1562,8 +1678,8 @@ class PlaitBoardComponent {
|
|
|
1562
1678
|
get readonly() {
|
|
1563
1679
|
return this.board.options.readonly;
|
|
1564
1680
|
}
|
|
1565
|
-
get
|
|
1566
|
-
return this.
|
|
1681
|
+
get isFocused() {
|
|
1682
|
+
return PlaitBoard.isFocus(this.board);
|
|
1567
1683
|
}
|
|
1568
1684
|
get nativeElement() {
|
|
1569
1685
|
return this.elementRef.nativeElement;
|
|
@@ -1573,10 +1689,12 @@ class PlaitBoardComponent {
|
|
|
1573
1689
|
const roughSVG = rough.svg(this.host, {
|
|
1574
1690
|
options: { roughness: 0, strokeWidth: 1 }
|
|
1575
1691
|
});
|
|
1692
|
+
this.roughSVG = roughSVG;
|
|
1576
1693
|
this.initializePlugins();
|
|
1577
1694
|
this.initializeEvents();
|
|
1578
1695
|
this.viewportScrollListener();
|
|
1579
1696
|
this.elementResizeListener();
|
|
1697
|
+
this.mouseLeaveListener();
|
|
1580
1698
|
BOARD_TO_COMPONENT.set(this.board, this);
|
|
1581
1699
|
BOARD_TO_ROUGH_SVG.set(this.board, roughSVG);
|
|
1582
1700
|
BOARD_TO_HOST.set(this.board, this.host);
|
|
@@ -1593,13 +1711,19 @@ class PlaitBoardComponent {
|
|
|
1593
1711
|
});
|
|
1594
1712
|
this.hasInitialized = true;
|
|
1595
1713
|
}
|
|
1714
|
+
mouseLeaveListener() {
|
|
1715
|
+
fromEvent(this.host, 'mouseleave')
|
|
1716
|
+
.pipe(takeUntil(this.destroy$))
|
|
1717
|
+
.subscribe((event) => {
|
|
1718
|
+
BOARD_TO_MOVING_POINT.delete(this.board);
|
|
1719
|
+
});
|
|
1720
|
+
}
|
|
1596
1721
|
ngOnChanges(changes) {
|
|
1597
1722
|
if (this.hasInitialized) {
|
|
1598
1723
|
const valueChange = changes['plaitValue'];
|
|
1599
1724
|
const options = changes['plaitOptions'];
|
|
1600
|
-
if (valueChange)
|
|
1725
|
+
if (valueChange)
|
|
1601
1726
|
this.board.children = valueChange.currentValue;
|
|
1602
|
-
}
|
|
1603
1727
|
if (options)
|
|
1604
1728
|
this.board.options = options.currentValue;
|
|
1605
1729
|
this.cdr.markForCheck();
|
|
@@ -1608,21 +1732,17 @@ class PlaitBoardComponent {
|
|
|
1608
1732
|
ngAfterViewInit() {
|
|
1609
1733
|
this.plaitBoardInitialized.emit(this.board);
|
|
1610
1734
|
this.initViewportContainer();
|
|
1611
|
-
|
|
1612
|
-
this.
|
|
1735
|
+
initializeViewport(this.board);
|
|
1736
|
+
initializeViewportContainerOffset(this.board);
|
|
1613
1737
|
}
|
|
1614
1738
|
initializePlugins() {
|
|
1615
|
-
|
|
1616
|
-
let board = withHandPointer(withHistory(withSelection(withBoard(createBoard(this.plaitValue, this.plaitOptions)))));
|
|
1739
|
+
let board = withHandPointer(withHistory(withSelection(withBoard(withViewport(createBoard(this.plaitValue, this.plaitOptions))))));
|
|
1617
1740
|
this.plaitPlugins.forEach(plugin => {
|
|
1618
1741
|
board = plugin(board);
|
|
1619
1742
|
});
|
|
1620
1743
|
this.board = board;
|
|
1621
1744
|
if (this.plaitViewport) {
|
|
1622
1745
|
this.board.viewport = this.plaitViewport;
|
|
1623
|
-
this.updateViewportState({
|
|
1624
|
-
zoom: (_b = (_a = this.plaitViewport) === null || _a === void 0 ? void 0 : _a.zoom) !== null && _b !== void 0 ? _b : 1
|
|
1625
|
-
});
|
|
1626
1746
|
}
|
|
1627
1747
|
}
|
|
1628
1748
|
initializeEvents() {
|
|
@@ -1658,34 +1778,34 @@ class PlaitBoardComponent {
|
|
|
1658
1778
|
this.board.dblclick(event);
|
|
1659
1779
|
});
|
|
1660
1780
|
fromEvent(document, 'keydown')
|
|
1661
|
-
.pipe(takeUntil(this.destroy$), filter(() =>
|
|
1662
|
-
return !IS_TEXT_EDITABLE.get(this.board) && !!this.board.selection;
|
|
1663
|
-
}))
|
|
1781
|
+
.pipe(takeUntil(this.destroy$), filter(() => this.isFocused && !PlaitBoard.hasBeenTextEditing(this.board)))
|
|
1664
1782
|
.subscribe((event) => {
|
|
1665
1783
|
var _a;
|
|
1784
|
+
if (isHotkey$1(['mod+=', 'mod++'], { byKey: true })(event)) {
|
|
1785
|
+
event.preventDefault();
|
|
1786
|
+
this.zoomInHandle(false);
|
|
1787
|
+
}
|
|
1788
|
+
if (isHotkey$1('mod+-', { byKey: true })(event)) {
|
|
1789
|
+
this.zoomOutHandle();
|
|
1790
|
+
event.preventDefault();
|
|
1791
|
+
}
|
|
1666
1792
|
(_a = this.board) === null || _a === void 0 ? void 0 : _a.keydown(event);
|
|
1667
1793
|
});
|
|
1668
1794
|
fromEvent(document, 'keyup')
|
|
1669
|
-
.pipe(takeUntil(this.destroy$), filter(() =>
|
|
1670
|
-
return !IS_TEXT_EDITABLE.get(this.board) && !!this.board.selection;
|
|
1671
|
-
}))
|
|
1795
|
+
.pipe(takeUntil(this.destroy$), filter(() => this.isFocused && !PlaitBoard.hasBeenTextEditing(this.board)))
|
|
1672
1796
|
.subscribe((event) => {
|
|
1673
1797
|
var _a;
|
|
1674
1798
|
(_a = this.board) === null || _a === void 0 ? void 0 : _a.keyup(event);
|
|
1675
1799
|
});
|
|
1676
1800
|
fromEvent(document, 'copy')
|
|
1677
|
-
.pipe(takeUntil(this.destroy$), filter(() =>
|
|
1678
|
-
return !IS_TEXT_EDITABLE.get(this.board) && !!this.board.selection;
|
|
1679
|
-
}))
|
|
1801
|
+
.pipe(takeUntil(this.destroy$), filter(() => this.isFocused && !PlaitBoard.hasBeenTextEditing(this.board)))
|
|
1680
1802
|
.subscribe((event) => {
|
|
1681
1803
|
var _a;
|
|
1682
1804
|
event.preventDefault();
|
|
1683
1805
|
(_a = this.board) === null || _a === void 0 ? void 0 : _a.setFragment(event.clipboardData);
|
|
1684
1806
|
});
|
|
1685
1807
|
fromEvent(document, 'paste')
|
|
1686
|
-
.pipe(takeUntil(this.destroy$), filter(() =>
|
|
1687
|
-
return !IS_TEXT_EDITABLE.get(this.board) && !!this.board.selection && !this.readonly;
|
|
1688
|
-
}))
|
|
1808
|
+
.pipe(takeUntil(this.destroy$), filter(() => this.isFocused && !PlaitBoard.isReadonly(this.board) && !PlaitBoard.hasBeenTextEditing(this.board)))
|
|
1689
1809
|
.subscribe((clipboardEvent) => {
|
|
1690
1810
|
const mousePoint = BOARD_TO_MOVING_POINT.get(this.board);
|
|
1691
1811
|
const rect = this.nativeElement.getBoundingClientRect();
|
|
@@ -1695,9 +1815,7 @@ class PlaitBoardComponent {
|
|
|
1695
1815
|
}
|
|
1696
1816
|
});
|
|
1697
1817
|
fromEvent(document, 'cut')
|
|
1698
|
-
.pipe(takeUntil(this.destroy$), filter(() =>
|
|
1699
|
-
return !IS_TEXT_EDITABLE.get(this.board) && !!this.board.selection;
|
|
1700
|
-
}))
|
|
1818
|
+
.pipe(takeUntil(this.destroy$), filter(() => this.isFocused && !PlaitBoard.isReadonly(this.board) && !PlaitBoard.hasBeenTextEditing(this.board)))
|
|
1701
1819
|
.subscribe((event) => {
|
|
1702
1820
|
var _a, _b;
|
|
1703
1821
|
event.preventDefault();
|
|
@@ -1707,206 +1825,43 @@ class PlaitBoardComponent {
|
|
|
1707
1825
|
}
|
|
1708
1826
|
viewportScrollListener() {
|
|
1709
1827
|
fromEvent(this.viewportContainer.nativeElement, 'scroll')
|
|
1710
|
-
.pipe(takeUntil(this.destroy$), filter(() =>
|
|
1711
|
-
return !!this.isFocused;
|
|
1712
|
-
}))
|
|
1828
|
+
.pipe(takeUntil(this.destroy$), filter(() => this.isFocused))
|
|
1713
1829
|
.subscribe((event) => {
|
|
1714
1830
|
const { scrollLeft, scrollTop } = event.target;
|
|
1715
|
-
const
|
|
1716
|
-
const
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
this.setScrollTop(scrollTop);
|
|
1720
|
-
this.setViewport();
|
|
1721
|
-
}
|
|
1831
|
+
const zoom = this.board.viewport.zoom;
|
|
1832
|
+
const viewBox = getViewBox(this.board, zoom);
|
|
1833
|
+
const origination = [scrollLeft / zoom + viewBox[0], scrollTop / zoom + viewBox[1]];
|
|
1834
|
+
setViewport(this.board, origination);
|
|
1722
1835
|
});
|
|
1723
1836
|
}
|
|
1724
1837
|
elementResizeListener() {
|
|
1725
1838
|
this.resizeObserver = new ResizeObserver(() => {
|
|
1726
1839
|
this.initViewportContainer();
|
|
1727
|
-
this.calcViewBox(this.board.viewport.zoom);
|
|
1728
|
-
this.updateViewBoxStyles();
|
|
1729
|
-
this.updateViewportScrolling();
|
|
1730
|
-
this.setViewport();
|
|
1731
1840
|
});
|
|
1732
1841
|
this.resizeObserver.observe(this.nativeElement);
|
|
1733
1842
|
}
|
|
1734
|
-
updateViewportState(state) {
|
|
1735
|
-
this.viewportState = Object.assign(Object.assign({}, this.viewportState), state);
|
|
1736
|
-
}
|
|
1737
1843
|
initViewportContainer() {
|
|
1738
|
-
const { width, height } =
|
|
1844
|
+
const { width, height } = getViewportContainerRect(this.board);
|
|
1739
1845
|
this.renderer2.setStyle(this.viewportContainer.nativeElement, 'width', `${width}px`);
|
|
1740
1846
|
this.renderer2.setStyle(this.viewportContainer.nativeElement, 'height', `${height}px`);
|
|
1741
1847
|
}
|
|
1742
|
-
initViewport(viewport = this.board.viewport) {
|
|
1743
|
-
var _a;
|
|
1744
|
-
const originationCoord = viewport === null || viewport === void 0 ? void 0 : viewport.originationCoord;
|
|
1745
|
-
const zoom = (_a = viewport === null || viewport === void 0 ? void 0 : viewport.zoom) !== null && _a !== void 0 ? _a : this.viewportState.zoom;
|
|
1746
|
-
if (originationCoord) {
|
|
1747
|
-
const matrix = this.getMatrix();
|
|
1748
|
-
const [pointX, pointY] = invertViewportCoordinates([0, 0], matrix);
|
|
1749
|
-
const scrollLeft = this.viewportState.scrollLeft;
|
|
1750
|
-
const scrollTop = this.viewportState.scrollTop;
|
|
1751
|
-
const left = scrollLeft + (originationCoord[0] - pointX) * zoom;
|
|
1752
|
-
const top = scrollTop + (originationCoord[1] - pointY) * zoom;
|
|
1753
|
-
this.setScroll(left, top);
|
|
1754
|
-
}
|
|
1755
|
-
else {
|
|
1756
|
-
this.adaptHandle();
|
|
1757
|
-
}
|
|
1758
|
-
}
|
|
1759
|
-
calcViewBox(zoom = this.viewportState.zoom) {
|
|
1760
|
-
var _a;
|
|
1761
|
-
zoom = clampZoomLevel(zoom);
|
|
1762
|
-
const scrollBarWidth = ((_a = this.plaitOptions) === null || _a === void 0 ? void 0 : _a.hideScrollbar) ? SCROLL_BAR_WIDTH : 0;
|
|
1763
|
-
const viewportContainerBox = getViewportContainerBox(this.board);
|
|
1764
|
-
const groupBBox = getRootGroupBBox(this.board, zoom);
|
|
1765
|
-
const horizontalPadding = viewportContainerBox.width / 2;
|
|
1766
|
-
const verticalPadding = viewportContainerBox.height / 2;
|
|
1767
|
-
const viewportWidth = (groupBBox.right - groupBBox.left) * zoom + 2 * horizontalPadding + scrollBarWidth;
|
|
1768
|
-
const viewportHeight = (groupBBox.bottom - groupBBox.top) * zoom + 2 * verticalPadding + scrollBarWidth;
|
|
1769
|
-
const viewBox = [
|
|
1770
|
-
groupBBox.left - horizontalPadding / zoom,
|
|
1771
|
-
groupBBox.top - verticalPadding / zoom,
|
|
1772
|
-
viewportWidth / zoom,
|
|
1773
|
-
viewportHeight / zoom
|
|
1774
|
-
];
|
|
1775
|
-
const matrix = this.getMatrix();
|
|
1776
|
-
let scrollLeft;
|
|
1777
|
-
let scrollTop;
|
|
1778
|
-
if (matrix.length > 0) {
|
|
1779
|
-
// focusPoint
|
|
1780
|
-
const focusX = viewportContainerBox.x + viewportContainerBox.width / 2;
|
|
1781
|
-
const focusY = viewportContainerBox.y + viewportContainerBox.height / 2;
|
|
1782
|
-
const viewportContainerPoint = [focusX - viewportContainerBox.x, focusY - viewportContainerBox.y, 1];
|
|
1783
|
-
const point = invertViewportCoordinates([viewportContainerPoint[0], viewportContainerPoint[1]], matrix);
|
|
1784
|
-
const newMatrix = [zoom, 0, 0, 0, zoom, 0, -zoom * viewBox[0], -zoom * viewBox[1], 1];
|
|
1785
|
-
const newPoint = transformMat3([], point, newMatrix);
|
|
1786
|
-
scrollLeft = newPoint[0] - viewportContainerPoint[0];
|
|
1787
|
-
scrollTop = newPoint[1] - viewportContainerPoint[1];
|
|
1788
|
-
}
|
|
1789
|
-
else {
|
|
1790
|
-
scrollLeft = horizontalPadding;
|
|
1791
|
-
scrollTop = verticalPadding;
|
|
1792
|
-
}
|
|
1793
|
-
this.updateViewportState({
|
|
1794
|
-
viewportWidth,
|
|
1795
|
-
viewportHeight,
|
|
1796
|
-
zoom,
|
|
1797
|
-
viewBox
|
|
1798
|
-
});
|
|
1799
|
-
this.setScrollLeft(scrollLeft);
|
|
1800
|
-
this.setScrollTop(scrollTop);
|
|
1801
|
-
}
|
|
1802
|
-
getMatrix() {
|
|
1803
|
-
const { viewBox, zoom, scrollLeft, scrollTop } = this.viewportState;
|
|
1804
|
-
if (scrollLeft >= 0 && scrollTop >= 0) {
|
|
1805
|
-
return [zoom, 0, 0, 0, zoom, 0, -scrollLeft - zoom * viewBox[0], -scrollTop - zoom * viewBox[1], 1];
|
|
1806
|
-
}
|
|
1807
|
-
return [];
|
|
1808
|
-
}
|
|
1809
|
-
setScrollLeft(left) {
|
|
1810
|
-
var _a;
|
|
1811
|
-
const viewportContainerBox = getViewportContainerBox(this.board);
|
|
1812
|
-
const scrollBarWidth = ((_a = this.plaitOptions) === null || _a === void 0 ? void 0 : _a.hideScrollbar) ? SCROLL_BAR_WIDTH : 0;
|
|
1813
|
-
const { viewportWidth } = this.viewportState;
|
|
1814
|
-
const width = viewportWidth - viewportContainerBox.width + scrollBarWidth;
|
|
1815
|
-
this.viewportState.scrollLeft = left < 0 ? 0 : left > width ? width : left;
|
|
1816
|
-
}
|
|
1817
|
-
setScrollTop(top) {
|
|
1818
|
-
var _a;
|
|
1819
|
-
const viewportContainerBox = getViewportContainerBox(this.board);
|
|
1820
|
-
const scrollBarWidth = ((_a = this.plaitOptions) === null || _a === void 0 ? void 0 : _a.hideScrollbar) ? SCROLL_BAR_WIDTH : 0;
|
|
1821
|
-
const { viewportHeight } = this.viewportState;
|
|
1822
|
-
const height = viewportHeight - viewportContainerBox.height + scrollBarWidth;
|
|
1823
|
-
this.viewportState.scrollTop = top < 0 ? 0 : top > height ? height : top;
|
|
1824
|
-
}
|
|
1825
|
-
setScroll(left, top) {
|
|
1826
|
-
this.setScrollLeft(left);
|
|
1827
|
-
this.setScrollTop(top);
|
|
1828
|
-
this.updateViewBoxStyles();
|
|
1829
|
-
this.updateViewportScrolling();
|
|
1830
|
-
this.setViewport();
|
|
1831
|
-
}
|
|
1832
|
-
updateViewBoxStyles() {
|
|
1833
|
-
const { host, viewportState } = this;
|
|
1834
|
-
const { viewportWidth, viewportHeight, viewBox } = viewportState;
|
|
1835
|
-
this.renderer2.setStyle(host, 'display', 'block');
|
|
1836
|
-
this.renderer2.setStyle(host, 'width', `${viewportWidth}px`);
|
|
1837
|
-
this.renderer2.setStyle(host, 'height', `${viewportHeight}px`);
|
|
1838
|
-
if (viewBox && viewBox[2] > 0 && viewBox[3] > 0) {
|
|
1839
|
-
this.renderer2.setAttribute(host, 'viewBox', viewBox.join(' '));
|
|
1840
|
-
}
|
|
1841
|
-
}
|
|
1842
|
-
updateViewportScrolling() {
|
|
1843
|
-
const { viewportContainer, viewportState } = this;
|
|
1844
|
-
const { scrollLeft, scrollTop } = viewportState;
|
|
1845
|
-
viewportContainer.nativeElement.scrollLeft = scrollLeft;
|
|
1846
|
-
viewportContainer.nativeElement.scrollTop = scrollTop;
|
|
1847
|
-
}
|
|
1848
|
-
setViewport() {
|
|
1849
|
-
var _a, _b;
|
|
1850
|
-
const viewport = (_a = this.board) === null || _a === void 0 ? void 0 : _a.viewport;
|
|
1851
|
-
const oldOriginationCoord = (_b = viewport === null || viewport === void 0 ? void 0 : viewport.originationCoord) !== null && _b !== void 0 ? _b : [];
|
|
1852
|
-
const matrix = this.getMatrix();
|
|
1853
|
-
const originationCoord = invertViewportCoordinates([0, 0], matrix);
|
|
1854
|
-
if (!originationCoord.every((item, index) => item === oldOriginationCoord[index])) {
|
|
1855
|
-
Transforms.setViewport(this.board, Object.assign(Object.assign({}, viewport), { zoom: this.viewportState.zoom, originationCoord }));
|
|
1856
|
-
}
|
|
1857
|
-
}
|
|
1858
1848
|
adaptHandle() {
|
|
1859
|
-
|
|
1860
|
-
const rootGroup = this.host.firstChild;
|
|
1861
|
-
const matrix = this.getMatrix();
|
|
1862
|
-
const rootGroupBox = rootGroup.getBBox();
|
|
1863
|
-
const centerPoint = [containerBox.width / 2, containerBox.height / 2];
|
|
1864
|
-
const rootGroupCenterX = rootGroupBox.x + rootGroupBox.width / 2;
|
|
1865
|
-
const rootGroupCenterY = rootGroupBox.y + rootGroupBox.height / 2;
|
|
1866
|
-
const transformedPoint = transformMat3([], [rootGroupCenterX, rootGroupCenterY, 1], matrix);
|
|
1867
|
-
const offsetLeft = centerPoint[0] - transformedPoint[0];
|
|
1868
|
-
const offsetTop = centerPoint[1] - transformedPoint[1];
|
|
1869
|
-
const { autoFitPadding, zoom, scrollLeft, scrollTop } = this.viewportState;
|
|
1870
|
-
const viewportWidth = containerBox.width - 2 * autoFitPadding;
|
|
1871
|
-
const viewportHeight = containerBox.height - 2 * autoFitPadding;
|
|
1872
|
-
let newZoom = zoom;
|
|
1873
|
-
if (viewportWidth < rootGroupBox.width || viewportHeight < rootGroupBox.height) {
|
|
1874
|
-
newZoom = Math.min(viewportWidth / rootGroupBox.width, viewportHeight / rootGroupBox.height);
|
|
1875
|
-
}
|
|
1876
|
-
else {
|
|
1877
|
-
newZoom = 1;
|
|
1878
|
-
}
|
|
1879
|
-
this.setScrollLeft(scrollLeft - offsetLeft);
|
|
1880
|
-
this.setScrollTop(scrollTop - offsetTop);
|
|
1881
|
-
this.calcViewBox(newZoom);
|
|
1882
|
-
this.updateViewBoxStyles();
|
|
1883
|
-
this.updateViewportScrolling();
|
|
1884
|
-
this.setViewport();
|
|
1849
|
+
fitViewport(this.board);
|
|
1885
1850
|
}
|
|
1886
|
-
zoomInHandle() {
|
|
1887
|
-
this.
|
|
1888
|
-
this.updateViewBoxStyles();
|
|
1889
|
-
this.updateViewportScrolling();
|
|
1890
|
-
this.setViewport();
|
|
1851
|
+
zoomInHandle(isCenter = true) {
|
|
1852
|
+
changeZoom(this.board, this.board.viewport.zoom + 0.1, isCenter);
|
|
1891
1853
|
}
|
|
1892
1854
|
zoomOutHandle() {
|
|
1893
|
-
this.
|
|
1894
|
-
this.updateViewBoxStyles();
|
|
1895
|
-
this.updateViewportScrolling();
|
|
1896
|
-
this.setViewport();
|
|
1855
|
+
changeZoom(this.board, this.board.viewport.zoom - 0.1);
|
|
1897
1856
|
}
|
|
1898
1857
|
resetZoomHandel() {
|
|
1899
|
-
this.
|
|
1900
|
-
this.updateViewBoxStyles();
|
|
1901
|
-
this.updateViewportScrolling();
|
|
1902
|
-
this.setViewport();
|
|
1858
|
+
changeZoom(this.board, 1);
|
|
1903
1859
|
}
|
|
1904
1860
|
ngOnDestroy() {
|
|
1861
|
+
var _a;
|
|
1905
1862
|
this.destroy$.next();
|
|
1906
1863
|
this.destroy$.complete();
|
|
1907
|
-
|
|
1908
|
-
this.resizeObserver.disconnect();
|
|
1909
|
-
}
|
|
1864
|
+
this.resizeObserver && ((_a = this.resizeObserver) === null || _a === void 0 ? void 0 : _a.disconnect());
|
|
1910
1865
|
BOARD_TO_ROUGH_SVG.delete(this.board);
|
|
1911
1866
|
BOARD_TO_COMPONENT.delete(this.board);
|
|
1912
1867
|
BOARD_TO_ROUGH_SVG.delete(this.board);
|
|
@@ -1917,41 +1872,9 @@ class PlaitBoardComponent {
|
|
|
1917
1872
|
markForCheck() {
|
|
1918
1873
|
this.cdr.markForCheck();
|
|
1919
1874
|
}
|
|
1920
|
-
scrollToRectangle(client) {
|
|
1921
|
-
var _a;
|
|
1922
|
-
this.calcViewBox();
|
|
1923
|
-
this.updateViewBoxStyles();
|
|
1924
|
-
this.updateViewportScrolling();
|
|
1925
|
-
this.setViewport();
|
|
1926
|
-
const svgRect = this.host.getBoundingClientRect();
|
|
1927
|
-
const viewportContainerBox = getViewportContainerBox(this.board);
|
|
1928
|
-
if (svgRect.width > viewportContainerBox.width || svgRect.height > viewportContainerBox.height) {
|
|
1929
|
-
const scrollBarWidth = ((_a = this.plaitOptions) === null || _a === void 0 ? void 0 : _a.hideScrollbar) ? SCROLL_BAR_WIDTH : 0;
|
|
1930
|
-
const matrix = this.getMatrix();
|
|
1931
|
-
const [nodePointX, nodePointY] = convertToViewportCoordinates([client.x, client.y], matrix);
|
|
1932
|
-
const [fullNodePointX, fullNodePointY] = convertToViewportCoordinates([client.x + client.width, client.y + client.height], matrix);
|
|
1933
|
-
let newLeft = this.viewportState.scrollLeft;
|
|
1934
|
-
let newTop = this.viewportState.scrollTop;
|
|
1935
|
-
if (nodePointX < 0) {
|
|
1936
|
-
newLeft -= Math.abs(nodePointX);
|
|
1937
|
-
}
|
|
1938
|
-
if (nodePointX > 0 && fullNodePointX > viewportContainerBox.width) {
|
|
1939
|
-
newLeft += fullNodePointX - viewportContainerBox.width + scrollBarWidth;
|
|
1940
|
-
}
|
|
1941
|
-
if (nodePointY < 0) {
|
|
1942
|
-
newTop -= Math.abs(nodePointY);
|
|
1943
|
-
}
|
|
1944
|
-
if (nodePointY > 0 && fullNodePointY > viewportContainerBox.height) {
|
|
1945
|
-
newTop += fullNodePointY - viewportContainerBox.height + scrollBarWidth;
|
|
1946
|
-
}
|
|
1947
|
-
if (newLeft !== this.viewportState.scrollLeft || newTop !== this.viewportState.scrollTop) {
|
|
1948
|
-
this.setScroll(newLeft, newTop);
|
|
1949
|
-
}
|
|
1950
|
-
}
|
|
1951
|
-
}
|
|
1952
1875
|
}
|
|
1953
1876
|
PlaitBoardComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: PlaitBoardComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i0.Renderer2 }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
1954
|
-
PlaitBoardComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.11", type: PlaitBoardComponent, selector: "plait-board", inputs: { plaitValue: "plaitValue", plaitViewport: "plaitViewport", plaitPlugins: "plaitPlugins", plaitOptions: "plaitOptions" }, outputs: { plaitChange: "plaitChange", plaitBoardInitialized: "plaitBoardInitialized" }, host: { properties: { "class": "this.hostClass", "class.readonly": "this.readonly", "class.focused": "this.
|
|
1877
|
+
PlaitBoardComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.11", type: PlaitBoardComponent, selector: "plait-board", inputs: { plaitValue: "plaitValue", plaitViewport: "plaitViewport", plaitPlugins: "plaitPlugins", plaitOptions: "plaitOptions" }, outputs: { plaitChange: "plaitChange", plaitBoardInitialized: "plaitBoardInitialized" }, host: { properties: { "class": "this.hostClass", "class.readonly": "this.readonly", "class.focused": "this.isFocused" } }, queries: [{ propertyName: "toolbarTemplateRef", first: true, predicate: ["plaitToolbar"], descendants: true }], viewQueries: [{ propertyName: "svg", first: true, predicate: ["svg"], descendants: true, static: true }, { propertyName: "viewportContainer", first: true, predicate: ["viewportContainer"], descendants: true, read: ElementRef, static: true }], usesOnChanges: true, ngImport: i0, template: `
|
|
1955
1878
|
<div class="viewport-container" #viewportContainer>
|
|
1956
1879
|
<svg #svg width="100%" height="100%" style="position: relative;"><g class="element-host"></g></svg>
|
|
1957
1880
|
<plait-element
|
|
@@ -2017,7 +1940,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImpo
|
|
|
2017
1940
|
}], readonly: [{
|
|
2018
1941
|
type: HostBinding,
|
|
2019
1942
|
args: ['class.readonly']
|
|
2020
|
-
}],
|
|
1943
|
+
}], isFocused: [{
|
|
2021
1944
|
type: HostBinding,
|
|
2022
1945
|
args: ['class.focused']
|
|
2023
1946
|
}], svg: [{
|
|
@@ -2115,6 +2038,88 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImpo
|
|
|
2115
2038
|
}]
|
|
2116
2039
|
}] });
|
|
2117
2040
|
|
|
2041
|
+
function withMoving(board) {
|
|
2042
|
+
const { mousedown, mousemove, globalMouseup, globalMousemove } = board;
|
|
2043
|
+
let offsetX = 0;
|
|
2044
|
+
let offsetY = 0;
|
|
2045
|
+
let isPreventDefault = false;
|
|
2046
|
+
let startPoint;
|
|
2047
|
+
let activeElements = [];
|
|
2048
|
+
board.mousedown = event => {
|
|
2049
|
+
const host = BOARD_TO_HOST.get(board);
|
|
2050
|
+
const point = transformPoint(board, toPoint(event.x, event.y, host));
|
|
2051
|
+
const ranges = [{ anchor: point, focus: point }];
|
|
2052
|
+
let movableElements = board.children.filter(item => PlaitElement.isElement(item) && board.isMovable(item));
|
|
2053
|
+
if (movableElements.length) {
|
|
2054
|
+
startPoint = point;
|
|
2055
|
+
const selectedRootElements = getSelectedElements(board).filter(item => movableElements.includes(item));
|
|
2056
|
+
const intersectionSelectedElement = isIntersectionElements(board, selectedRootElements, ranges);
|
|
2057
|
+
if (intersectionSelectedElement) {
|
|
2058
|
+
activeElements = selectedRootElements;
|
|
2059
|
+
}
|
|
2060
|
+
else {
|
|
2061
|
+
activeElements = movableElements.filter(item => ranges.some(range => {
|
|
2062
|
+
return board.isIntersectionSelection(item, range);
|
|
2063
|
+
}));
|
|
2064
|
+
}
|
|
2065
|
+
}
|
|
2066
|
+
mousedown(event);
|
|
2067
|
+
};
|
|
2068
|
+
board.mousemove = event => {
|
|
2069
|
+
if (startPoint && (activeElements === null || activeElements === void 0 ? void 0 : activeElements.length)) {
|
|
2070
|
+
if (!isPreventDefault) {
|
|
2071
|
+
isPreventDefault = true;
|
|
2072
|
+
}
|
|
2073
|
+
const host = BOARD_TO_HOST.get(board);
|
|
2074
|
+
const endPoint = transformPoint(board, toPoint(event.x, event.y, host));
|
|
2075
|
+
offsetX = endPoint[0] - startPoint[0];
|
|
2076
|
+
offsetY = endPoint[1] - startPoint[1];
|
|
2077
|
+
throttleRAF(() => {
|
|
2078
|
+
const currentElements = activeElements.map(activeElement => {
|
|
2079
|
+
const [x, y] = activeElement === null || activeElement === void 0 ? void 0 : activeElement.points[0];
|
|
2080
|
+
const index = board.children.findIndex(item => item.id === activeElement.id);
|
|
2081
|
+
Transforms.setNode(board, {
|
|
2082
|
+
points: [[x + offsetX, y + offsetY]]
|
|
2083
|
+
}, [index]);
|
|
2084
|
+
MERGING.set(board, true);
|
|
2085
|
+
return PlaitNode.get(board, [index]);
|
|
2086
|
+
});
|
|
2087
|
+
addMovingElements(board, currentElements);
|
|
2088
|
+
});
|
|
2089
|
+
}
|
|
2090
|
+
if (isPreventDefault) {
|
|
2091
|
+
// 阻止 move 过程中触发画布滚动行为
|
|
2092
|
+
event.preventDefault();
|
|
2093
|
+
}
|
|
2094
|
+
mousemove(event);
|
|
2095
|
+
};
|
|
2096
|
+
board.globalMousemove = event => {
|
|
2097
|
+
if (startPoint) {
|
|
2098
|
+
const inPliatBordElement = isInPlaitBoard(board, event.x, event.y);
|
|
2099
|
+
if (!inPliatBordElement) {
|
|
2100
|
+
cancelMove(board);
|
|
2101
|
+
}
|
|
2102
|
+
}
|
|
2103
|
+
globalMousemove(event);
|
|
2104
|
+
};
|
|
2105
|
+
board.globalMouseup = event => {
|
|
2106
|
+
isPreventDefault = false;
|
|
2107
|
+
if (startPoint) {
|
|
2108
|
+
cancelMove(board);
|
|
2109
|
+
}
|
|
2110
|
+
globalMouseup(event);
|
|
2111
|
+
};
|
|
2112
|
+
function cancelMove(board) {
|
|
2113
|
+
startPoint = null;
|
|
2114
|
+
offsetX = 0;
|
|
2115
|
+
offsetY = 0;
|
|
2116
|
+
activeElements = [];
|
|
2117
|
+
removeMovingElements(board);
|
|
2118
|
+
MERGING.set(board, false);
|
|
2119
|
+
}
|
|
2120
|
+
return board;
|
|
2121
|
+
}
|
|
2122
|
+
|
|
2118
2123
|
/*
|
|
2119
2124
|
* Public API Surface of plait
|
|
2120
2125
|
*/
|
|
@@ -2123,5 +2128,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImpo
|
|
|
2123
2128
|
* Generated bundle index. Do not edit.
|
|
2124
2129
|
*/
|
|
2125
2130
|
|
|
2126
|
-
export { BOARD_TO_COMPONENT, BOARD_TO_ELEMENT_HOST, BOARD_TO_HOST, BOARD_TO_MOVING_POINT, BOARD_TO_ON_CHANGE, BOARD_TO_ROUGH_SVG, BOARD_TO_SELECTED_ELEMENT, BoardTransforms, CLIP_BOARD_FORMAT_KEY, ELEMENT_TO_PLUGIN_COMPONENT, FLUSHING, IS_APPLE, IS_CHROME, IS_CHROME_LEGACY, IS_EDGE_LEGACY, IS_FIREFOX, IS_IOS, IS_SAFARI, IS_TEXT_EDITABLE, MAX_RADIUS, MERGING, NS, Path, PlaitBoard, PlaitBoardComponent, PlaitElement, PlaitElementComponent, PlaitHistoryBoard, PlaitModule, PlaitNode, PlaitOperation, PlaitPluginElementComponent, PlaitPointerType, PlaitToolbarComponent, RectangleClient, SAVING, SCROLL_BAR_WIDTH, SELECTION_BORDER_COLOR, SELECTION_FILL_COLOR, Selection, Transforms, Viewport, addSelectedElement, arrowPoints, cacheSelectedElements, calcElementIntersectionSelection, clampZoomLevel,
|
|
2131
|
+
export { BOARD_TO_COMPONENT, BOARD_TO_ELEMENT_HOST, BOARD_TO_HOST, BOARD_TO_IS_SELECTION_MOVING, BOARD_TO_MOVING_ELEMENT, BOARD_TO_MOVING_POINT, BOARD_TO_ON_CHANGE, BOARD_TO_ROUGH_SVG, BOARD_TO_SELECTED_ELEMENT, BOARD_TO_TEMPORARY_ELEMENTS, BoardTransforms, CLIP_BOARD_FORMAT_KEY, ELEMENT_TO_PLUGIN_COMPONENT, FLUSHING, IS_APPLE, IS_CHROME, IS_CHROME_LEGACY, IS_EDGE_LEGACY, IS_FIREFOX, IS_IOS, IS_SAFARI, IS_TEXT_EDITABLE, MAX_RADIUS, MERGING, NS, Path, PlaitBoard, PlaitBoardComponent, PlaitElement, PlaitElementComponent, PlaitHistoryBoard, PlaitModule, PlaitNode, PlaitOperation, PlaitPluginElementComponent, PlaitPointerType, PlaitToolbarComponent, RectangleClient, SAVING, SCROLL_BAR_WIDTH, SELECTION_BORDER_COLOR, SELECTION_FILL_COLOR, Selection, Transforms, Viewport, addMovingElements, addSelectedElement, arrowPoints, cacheMovingElements, cacheSelectedElements, calcElementIntersectionSelection, changeZoom, clampZoomLevel, clearSelectionMoving, createG, createSVG, createText, deleteTemporaryElements, depthFirstRecursion, distanceBetweenPointAndPoint, distanceBetweenPointAndRectangle, distanceBetweenPointAndSegment, drawArrow, drawRoundRectangle, fitViewport, getBoardRectangle, getElementHostBBox, getMovingElements, getRectangleByElements, getSelectedElements, getTemporaryElements, getViewBox, getViewportContainerRect, hasBeforeContextChange, hotkeys, idCreator, initializeViewport, initializeViewportContainerOffset, inverse, isInPlaitBoard, isIntersectionElements, isNullOrUndefined, isSelectedElement, isSelectionMoving, isSetViewportOperation, normalizePoint, removeMovingElements, removeSelectedElement, rotate, scrollToRectangle, setSVGViewBox, setSelectionMoving, setViewport, setViewportContainerScroll, shouldClear, shouldMerge, shouldSave, throttleRAF, toPoint, transformPoint, transformPoints, updateViewportContainerOffset, withMoving, withSelection };
|
|
2127
2132
|
//# sourceMappingURL=plait-core.mjs.map
|