@plait/core 0.1.1 → 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 +43 -12
- package/esm2020/plugins/with-viewport.mjs +11 -0
- package/esm2020/public-api.mjs +2 -1
- 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 +3 -1
- package/fesm2015/plait-core.mjs +548 -561
- package/fesm2015/plait-core.mjs.map +1 -1
- package/fesm2020/plait-core.mjs +548 -558
- 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 +4 -1
- package/plugins/with-viewport.d.ts +2 -0
- package/public-api.d.ts +1 -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 +2 -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) => {
|
|
@@ -356,19 +456,6 @@ const NodeTransforms = {
|
|
|
356
456
|
moveNode
|
|
357
457
|
};
|
|
358
458
|
|
|
359
|
-
// record richtext type status
|
|
360
|
-
const FLUSHING = new WeakMap();
|
|
361
|
-
const IS_TEXT_EDITABLE = new WeakMap();
|
|
362
|
-
const BOARD_TO_ON_CHANGE = new WeakMap();
|
|
363
|
-
const BOARD_TO_COMPONENT = new WeakMap();
|
|
364
|
-
const BOARD_TO_ROUGH_SVG = new WeakMap();
|
|
365
|
-
const BOARD_TO_HOST = new WeakMap();
|
|
366
|
-
const BOARD_TO_ELEMENT_HOST = new WeakMap();
|
|
367
|
-
const BOARD_TO_SELECTED_ELEMENT = new WeakMap();
|
|
368
|
-
const BOARD_TO_MOVING_POINT = new WeakMap();
|
|
369
|
-
// save no standard selected elements
|
|
370
|
-
const BOARD_TO_TEMPORARY_ELEMENTS = new WeakMap();
|
|
371
|
-
|
|
372
459
|
function setSelection(board, selection) {
|
|
373
460
|
const operation = { type: 'set_selection', properties: board.selection, newProperties: selection };
|
|
374
461
|
board.apply(operation);
|
|
@@ -384,80 +471,61 @@ function setSelectionWithTemporaryElements(board, elements) {
|
|
|
384
471
|
});
|
|
385
472
|
}
|
|
386
473
|
|
|
387
|
-
function setViewport(board, viewport) {
|
|
474
|
+
function setViewport$1(board, viewport) {
|
|
388
475
|
const operation = { type: 'set_viewport', properties: board.viewport, newProperties: viewport };
|
|
389
476
|
board.apply(operation);
|
|
390
477
|
}
|
|
391
478
|
const ViewportTransforms = {
|
|
392
|
-
setViewport
|
|
479
|
+
setViewport: setViewport$1
|
|
393
480
|
};
|
|
394
481
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
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);
|
|
401
511
|
}
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
right: Number.MIN_VALUE,
|
|
408
|
-
bottom: Number.MIN_VALUE
|
|
409
|
-
};
|
|
410
|
-
const calcRectangleClient = (node) => {
|
|
411
|
-
const nodeRectangle = board.getRectangle(node);
|
|
412
|
-
if (nodeRectangle) {
|
|
413
|
-
boundaryBox.left = Math.min(boundaryBox.left, nodeRectangle.x);
|
|
414
|
-
boundaryBox.top = Math.min(boundaryBox.top, nodeRectangle.y);
|
|
415
|
-
boundaryBox.right = Math.max(boundaryBox.right, nodeRectangle.x + nodeRectangle.width);
|
|
416
|
-
boundaryBox.bottom = Math.max(boundaryBox.bottom, nodeRectangle.y + nodeRectangle.height);
|
|
417
|
-
}
|
|
418
|
-
};
|
|
419
|
-
elements.forEach(element => {
|
|
420
|
-
if (recursion) {
|
|
421
|
-
depthFirstRecursion(element, node => calcRectangleClient(node));
|
|
422
|
-
}
|
|
423
|
-
else {
|
|
424
|
-
calcRectangleClient(element);
|
|
425
|
-
}
|
|
426
|
-
});
|
|
427
|
-
return {
|
|
428
|
-
x: boundaryBox.left,
|
|
429
|
-
y: boundaryBox.top,
|
|
430
|
-
width: boundaryBox.right - boundaryBox.left,
|
|
431
|
-
height: boundaryBox.bottom - boundaryBox.top
|
|
432
|
-
};
|
|
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];
|
|
433
517
|
}
|
|
434
|
-
function
|
|
435
|
-
|
|
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);
|
|
436
528
|
}
|
|
437
|
-
|
|
438
|
-
const PlaitBoard = {
|
|
439
|
-
getHost(board) {
|
|
440
|
-
return BOARD_TO_HOST.get(board);
|
|
441
|
-
},
|
|
442
|
-
getElementHost(board) {
|
|
443
|
-
return BOARD_TO_ELEMENT_HOST.get(board);
|
|
444
|
-
},
|
|
445
|
-
getRoughSVG(board) {
|
|
446
|
-
return BOARD_TO_ROUGH_SVG.get(board);
|
|
447
|
-
},
|
|
448
|
-
getComponent(board) {
|
|
449
|
-
return BOARD_TO_COMPONENT.get(board);
|
|
450
|
-
},
|
|
451
|
-
getBoardNativeElement(board) {
|
|
452
|
-
return PlaitBoard.getComponent(board).nativeElement;
|
|
453
|
-
},
|
|
454
|
-
getRectangle(board) {
|
|
455
|
-
return getRectangleByElements(board, board.children, true);
|
|
456
|
-
},
|
|
457
|
-
getViewportContainer(board) {
|
|
458
|
-
return PlaitBoard.getHost(board).parentElement;
|
|
459
|
-
}
|
|
460
|
-
};
|
|
461
529
|
|
|
462
530
|
function transformPoints(board, points) {
|
|
463
531
|
const newPoints = points.map(point => {
|
|
@@ -473,9 +541,11 @@ function transformPoint(board, point) {
|
|
|
473
541
|
const newPoint = [x, y];
|
|
474
542
|
return newPoint;
|
|
475
543
|
}
|
|
476
|
-
function
|
|
477
|
-
|
|
478
|
-
|
|
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;
|
|
479
549
|
}
|
|
480
550
|
|
|
481
551
|
const NS = 'http://www.w3.org/2000/svg';
|
|
@@ -796,222 +866,6 @@ function idCreator(length = 5) {
|
|
|
796
866
|
return key;
|
|
797
867
|
}
|
|
798
868
|
|
|
799
|
-
// https://stackoverflow.com/a/6853926/232122
|
|
800
|
-
function distanceBetweenPointAndSegment(x, y, x1, y1, x2, y2) {
|
|
801
|
-
const A = x - x1;
|
|
802
|
-
const B = y - y1;
|
|
803
|
-
const C = x2 - x1;
|
|
804
|
-
const D = y2 - y1;
|
|
805
|
-
const dot = A * C + B * D;
|
|
806
|
-
const lenSquare = C * C + D * D;
|
|
807
|
-
let param = -1;
|
|
808
|
-
if (lenSquare !== 0) {
|
|
809
|
-
// in case of 0 length line
|
|
810
|
-
param = dot / lenSquare;
|
|
811
|
-
}
|
|
812
|
-
let xx, yy;
|
|
813
|
-
if (param < 0) {
|
|
814
|
-
xx = x1;
|
|
815
|
-
yy = y1;
|
|
816
|
-
}
|
|
817
|
-
else if (param > 1) {
|
|
818
|
-
xx = x2;
|
|
819
|
-
yy = y2;
|
|
820
|
-
}
|
|
821
|
-
else {
|
|
822
|
-
xx = x1 + param * C;
|
|
823
|
-
yy = y1 + param * D;
|
|
824
|
-
}
|
|
825
|
-
const dx = x - xx;
|
|
826
|
-
const dy = y - yy;
|
|
827
|
-
return Math.hypot(dx, dy);
|
|
828
|
-
}
|
|
829
|
-
function rotate(x1, y1, x2, y2, angle) {
|
|
830
|
-
// 𝑎′𝑥=(𝑎𝑥−𝑐𝑥)cos𝜃−(𝑎𝑦−𝑐𝑦)sin𝜃+𝑐𝑥
|
|
831
|
-
// 𝑎′𝑦=(𝑎𝑥−𝑐𝑥)sin𝜃+(𝑎𝑦−𝑐𝑦)cos𝜃+𝑐𝑦.
|
|
832
|
-
// https://math.stackexchange.com/questions/2204520/how-do-i-rotate-a-line-segment-in-a-specific-point-on-the-line
|
|
833
|
-
return [(x1 - x2) * Math.cos(angle) - (y1 - y2) * Math.sin(angle) + x2, (x1 - x2) * Math.sin(angle) + (y1 - y2) * Math.cos(angle) + y2];
|
|
834
|
-
}
|
|
835
|
-
function distanceBetweenPointAndPoint(x1, y1, x2, y2) {
|
|
836
|
-
const dx = x1 - x2;
|
|
837
|
-
const dy = y1 - y2;
|
|
838
|
-
return Math.hypot(dx, dy);
|
|
839
|
-
}
|
|
840
|
-
// https://stackoverflow.com/questions/5254838/calculating-distance-between-a-point-and-a-rectangular-box-nearest-point
|
|
841
|
-
function distanceBetweenPointAndRectangle(x, y, rect) {
|
|
842
|
-
var dx = Math.max(rect.x - x, 0, x - (rect.x + rect.width));
|
|
843
|
-
var dy = Math.max(rect.y - y, 0, y - (rect.y + rect.height));
|
|
844
|
-
return Math.sqrt(dx * dx + dy * dy);
|
|
845
|
-
}
|
|
846
|
-
|
|
847
|
-
/**
|
|
848
|
-
* 逆矩阵
|
|
849
|
-
* [a c e]
|
|
850
|
-
* [b d f]
|
|
851
|
-
* [0 0 1]
|
|
852
|
-
* @param newMatrix 输出返回矩阵
|
|
853
|
-
* @param matrix 新矩阵
|
|
854
|
-
* @returns 逆矩阵
|
|
855
|
-
*/
|
|
856
|
-
function invertMatrix(newMatrix, matrix) {
|
|
857
|
-
const [n, r, a, i, o, c, l, s, u] = matrix;
|
|
858
|
-
const determinant = u * o - c * s;
|
|
859
|
-
const h = -u * i + c * l;
|
|
860
|
-
const f = s * i - o * l;
|
|
861
|
-
const product = n * determinant + r * h + a * f;
|
|
862
|
-
if (!product) {
|
|
863
|
-
return null;
|
|
864
|
-
}
|
|
865
|
-
const reciprocal = 1 / product;
|
|
866
|
-
newMatrix[0] = determinant * reciprocal;
|
|
867
|
-
newMatrix[1] = (-u * r + a * s) * reciprocal;
|
|
868
|
-
newMatrix[2] = (c * r - a * o) * reciprocal;
|
|
869
|
-
newMatrix[3] = h * reciprocal;
|
|
870
|
-
newMatrix[4] = (u * n - a * l) * reciprocal;
|
|
871
|
-
newMatrix[5] = (-c * n + a * i) * reciprocal;
|
|
872
|
-
newMatrix[6] = f * reciprocal;
|
|
873
|
-
newMatrix[7] = (-s * n + r * l) * reciprocal;
|
|
874
|
-
newMatrix[8] = (o * n - r * i) * reciprocal;
|
|
875
|
-
return newMatrix;
|
|
876
|
-
}
|
|
877
|
-
/**
|
|
878
|
-
* 将视图坐标与反转矩阵相乘,以得到原始坐标
|
|
879
|
-
* 使用给定的矩阵进行转换
|
|
880
|
-
* 矩阵与向量乘法,3 维向量与3x3矩阵的乘积
|
|
881
|
-
* [m11 m12 m13][v1]
|
|
882
|
-
* [m21 m22 m23][v2]
|
|
883
|
-
* [m31 m32 m33][v3]
|
|
884
|
-
* @param out 输出结果向量
|
|
885
|
-
* @param t 要转换的向量
|
|
886
|
-
* @param n 矩阵转换
|
|
887
|
-
* @returns [v1 * m11 + v2 * m12 + v3 * m13, v1 * m21 + v2 * m22 + v3 * m23, v1 * m31 + v2 * m32 + v3 * m33];
|
|
888
|
-
*/
|
|
889
|
-
function transformMat3(out, vector, matrix) {
|
|
890
|
-
out = [
|
|
891
|
-
vector[0] * matrix[0] + vector[1] * matrix[3] + vector[2] * matrix[6],
|
|
892
|
-
vector[0] * matrix[1] + vector[1] * matrix[4] + vector[2] * matrix[7],
|
|
893
|
-
vector[0] * matrix[2] + vector[1] * matrix[5] + vector[2] * matrix[8]
|
|
894
|
-
];
|
|
895
|
-
return out;
|
|
896
|
-
}
|
|
897
|
-
/**
|
|
898
|
-
* 规范 point
|
|
899
|
-
* @param point
|
|
900
|
-
* @returns point
|
|
901
|
-
*/
|
|
902
|
-
function normalizePoint(point) {
|
|
903
|
-
return Array.isArray(point)
|
|
904
|
-
? {
|
|
905
|
-
x: point[0],
|
|
906
|
-
y: point[1]
|
|
907
|
-
}
|
|
908
|
-
: point;
|
|
909
|
-
}
|
|
910
|
-
/**
|
|
911
|
-
* 将一个点坐标反转回它的原始坐标
|
|
912
|
-
* @param point 表示要反转的点的视图坐标,它是一个长度为 2 的数组,存储点的 x 和 y 坐标
|
|
913
|
-
* @param matrix 表示视图矩阵,是在视图中对图形进行缩放和平移时使用的矩阵
|
|
914
|
-
* @returns 最终结果是一个长度为 3 的数组,存储点的 x,y 和 w 坐标(w 坐标是点的齐次坐标)
|
|
915
|
-
*/
|
|
916
|
-
function invertViewportCoordinates(point, matrix) {
|
|
917
|
-
const { x, y } = normalizePoint(point);
|
|
918
|
-
const invertedMatrix = invertMatrix([], matrix);
|
|
919
|
-
return transformMat3([], [x, y, 1], invertedMatrix);
|
|
920
|
-
}
|
|
921
|
-
function convertToViewportCoordinates(point, matrix) {
|
|
922
|
-
const { x, y } = normalizePoint(point);
|
|
923
|
-
return transformMat3([], [x, y, 1], matrix);
|
|
924
|
-
}
|
|
925
|
-
/**
|
|
926
|
-
* 获取 contentContainer 的 clientBox
|
|
927
|
-
* @param board
|
|
928
|
-
* @returns
|
|
929
|
-
*/
|
|
930
|
-
function getViewportContainerBox(board) {
|
|
931
|
-
const { hideScrollbar } = board.options;
|
|
932
|
-
const scrollBarWidth = hideScrollbar ? SCROLL_BAR_WIDTH : 0;
|
|
933
|
-
const container = PlaitBoard.getViewportContainer(board);
|
|
934
|
-
const containerRect = container.getBoundingClientRect();
|
|
935
|
-
const x = containerRect.x || containerRect.left;
|
|
936
|
-
const y = containerRect.y || containerRect.top;
|
|
937
|
-
const width = containerRect.width - scrollBarWidth;
|
|
938
|
-
const height = containerRect.height - scrollBarWidth;
|
|
939
|
-
return {
|
|
940
|
-
minX: x,
|
|
941
|
-
minY: y,
|
|
942
|
-
maxX: x + width,
|
|
943
|
-
maxY: y + height,
|
|
944
|
-
x,
|
|
945
|
-
y,
|
|
946
|
-
width,
|
|
947
|
-
height
|
|
948
|
-
};
|
|
949
|
-
}
|
|
950
|
-
/**
|
|
951
|
-
* 获取 board.plait-board 的 clientBox
|
|
952
|
-
* @param board
|
|
953
|
-
* @returns
|
|
954
|
-
*/
|
|
955
|
-
function getBoardClientBox(board) {
|
|
956
|
-
const { hideScrollbar } = board.options;
|
|
957
|
-
const scrollBarWidth = hideScrollbar ? SCROLL_BAR_WIDTH : 0;
|
|
958
|
-
const viewportRect = PlaitBoard.getViewportContainer(board).getBoundingClientRect();
|
|
959
|
-
return {
|
|
960
|
-
width: viewportRect.width + scrollBarWidth,
|
|
961
|
-
height: viewportRect.height + scrollBarWidth
|
|
962
|
-
};
|
|
963
|
-
}
|
|
964
|
-
/**
|
|
965
|
-
* 获取 rootGroup 相对于当前 svg 空间的最小矩阵坐标
|
|
966
|
-
*/
|
|
967
|
-
function getRootGroupBBox(board, zoom) {
|
|
968
|
-
const elementHost = PlaitBoard.getElementHost(board);
|
|
969
|
-
const rootGroupBox = elementHost.getBBox();
|
|
970
|
-
const viewportContainerBox = getViewportContainerBox(board);
|
|
971
|
-
const containerWidth = viewportContainerBox.width / zoom;
|
|
972
|
-
const containerHeight = viewportContainerBox.height / zoom;
|
|
973
|
-
let left;
|
|
974
|
-
let right;
|
|
975
|
-
let top;
|
|
976
|
-
let bottom;
|
|
977
|
-
if (rootGroupBox.width < containerWidth) {
|
|
978
|
-
const offsetX = rootGroupBox.x + rootGroupBox.width / 2;
|
|
979
|
-
const containerX = containerWidth / 2;
|
|
980
|
-
left = offsetX - containerX;
|
|
981
|
-
right = offsetX + containerX;
|
|
982
|
-
}
|
|
983
|
-
else {
|
|
984
|
-
left = rootGroupBox.x;
|
|
985
|
-
right = rootGroupBox.x + rootGroupBox.width;
|
|
986
|
-
}
|
|
987
|
-
if (rootGroupBox.height < containerHeight) {
|
|
988
|
-
const offsetY = rootGroupBox.y + rootGroupBox.height / 2;
|
|
989
|
-
const containerY = containerHeight / 2;
|
|
990
|
-
top = offsetY - containerY;
|
|
991
|
-
bottom = offsetY + containerY;
|
|
992
|
-
}
|
|
993
|
-
else {
|
|
994
|
-
top = rootGroupBox.y;
|
|
995
|
-
bottom = rootGroupBox.y + rootGroupBox.height;
|
|
996
|
-
}
|
|
997
|
-
return {
|
|
998
|
-
left,
|
|
999
|
-
right,
|
|
1000
|
-
top,
|
|
1001
|
-
bottom
|
|
1002
|
-
};
|
|
1003
|
-
}
|
|
1004
|
-
/**
|
|
1005
|
-
* 验证缩放比是否符合限制,如果超出限制,则返回合适的缩放比
|
|
1006
|
-
* @param zoom 缩放比
|
|
1007
|
-
* @param minZoom 最小缩放比
|
|
1008
|
-
* @param maxZoom 最大缩放比
|
|
1009
|
-
* @returns 正确的缩放比
|
|
1010
|
-
*/
|
|
1011
|
-
function clampZoomLevel(zoom, minZoom = 0.2, maxZoom = 4) {
|
|
1012
|
-
return zoom < minZoom ? minZoom : zoom > maxZoom ? maxZoom : zoom;
|
|
1013
|
-
}
|
|
1014
|
-
|
|
1015
869
|
const calcElementIntersectionSelection = (board) => {
|
|
1016
870
|
const selectedElements = [];
|
|
1017
871
|
depthFirstRecursion(board, node => {
|
|
@@ -1025,6 +879,19 @@ const calcElementIntersectionSelection = (board) => {
|
|
|
1025
879
|
});
|
|
1026
880
|
return selectedElements;
|
|
1027
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
|
+
};
|
|
1028
895
|
const cacheSelectedElements = (board, selectedElements) => {
|
|
1029
896
|
BOARD_TO_SELECTED_ELEMENT.set(board, selectedElements);
|
|
1030
897
|
};
|
|
@@ -1045,6 +912,10 @@ const isSelectedElement = (board, element) => {
|
|
|
1045
912
|
return !!selectedElements.find(value => value === element);
|
|
1046
913
|
};
|
|
1047
914
|
|
|
915
|
+
const CLIP_BOARD_FORMAT_KEY = 'x-plait-fragment';
|
|
916
|
+
const SCROLL_BAR_WIDTH = 20;
|
|
917
|
+
const MAX_RADIUS = 16;
|
|
918
|
+
|
|
1048
919
|
/**
|
|
1049
920
|
* drawRoundRectangle
|
|
1050
921
|
* @param rs RoughSVG
|
|
@@ -1097,6 +968,196 @@ function drawArrow(rs, start, end, options, maxHypotenuseLength = 10, degree = 4
|
|
|
1097
968
|
return [arrowLineLeft, arrowLineRight];
|
|
1098
969
|
}
|
|
1099
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
|
+
|
|
1100
1161
|
const updatePointerType = (board, pointer) => {
|
|
1101
1162
|
board.pointer = pointer;
|
|
1102
1163
|
const boardComponent = BOARD_TO_COMPONENT.get(board);
|
|
@@ -1157,6 +1218,7 @@ function createBoard(children, options) {
|
|
|
1157
1218
|
destroyElement: (context) => { },
|
|
1158
1219
|
isWithinSelection: element => false,
|
|
1159
1220
|
isIntersectionSelection: element => false,
|
|
1221
|
+
isMovable: element => false,
|
|
1160
1222
|
getRectangle: element => null
|
|
1161
1223
|
};
|
|
1162
1224
|
return board;
|
|
@@ -1282,11 +1344,13 @@ function withHandPointer(board) {
|
|
|
1282
1344
|
};
|
|
1283
1345
|
board.mousemove = (event) => {
|
|
1284
1346
|
if (board.pointer === PlaitPointerType.hand && board.selection && isMoving) {
|
|
1285
|
-
const
|
|
1286
|
-
const left = event.x - plaitBoardMove.x;
|
|
1287
|
-
const top = event.y - plaitBoardMove.y;
|
|
1288
|
-
const
|
|
1289
|
-
|
|
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);
|
|
1290
1354
|
plaitBoardMove.x = event.x;
|
|
1291
1355
|
plaitBoardMove.y = event.y;
|
|
1292
1356
|
}
|
|
@@ -1319,6 +1383,8 @@ function withHandPointer(board) {
|
|
|
1319
1383
|
return board;
|
|
1320
1384
|
}
|
|
1321
1385
|
|
|
1386
|
+
const ATTACHED_ELEMENT_CLASS_NAME = 'plait-board-attached';
|
|
1387
|
+
|
|
1322
1388
|
function withSelection(board) {
|
|
1323
1389
|
const { mousedown, globalMousemove, globalMouseup, onChange } = board;
|
|
1324
1390
|
let start = null;
|
|
@@ -1326,12 +1392,22 @@ function withSelection(board) {
|
|
|
1326
1392
|
let selectionMovingG;
|
|
1327
1393
|
let selectionOuterG;
|
|
1328
1394
|
board.mousedown = (event) => {
|
|
1329
|
-
selectionOuterG === null || selectionOuterG === void 0 ? void 0 : selectionOuterG.remove();
|
|
1330
1395
|
if (event.button === 0) {
|
|
1331
1396
|
start = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
|
|
1332
1397
|
}
|
|
1333
1398
|
if (start) {
|
|
1334
|
-
|
|
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
|
+
}
|
|
1335
1411
|
}
|
|
1336
1412
|
mousedown(event);
|
|
1337
1413
|
};
|
|
@@ -1339,13 +1415,11 @@ function withSelection(board) {
|
|
|
1339
1415
|
if (start) {
|
|
1340
1416
|
const movedTarget = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
|
|
1341
1417
|
const { x, y, width, height } = RectangleClient.toRectangleClient([start, movedTarget]);
|
|
1418
|
+
selectionMovingG === null || selectionMovingG === void 0 ? void 0 : selectionMovingG.remove();
|
|
1342
1419
|
if (Math.hypot(width, height) > 5) {
|
|
1343
1420
|
end = movedTarget;
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
}
|
|
1347
|
-
PlaitBoard.getBoardNativeElement(board).classList.add('selection-moving');
|
|
1348
|
-
selectionMovingG === null || selectionMovingG === void 0 ? void 0 : selectionMovingG.remove();
|
|
1421
|
+
Transforms.setSelection(board, { ranges: [{ anchor: start, focus: end }] });
|
|
1422
|
+
setSelectionMoving(board);
|
|
1349
1423
|
const rough = PlaitBoard.getRoughSVG(board);
|
|
1350
1424
|
selectionMovingG = rough.rectangle(x, y, width, height, {
|
|
1351
1425
|
stroke: SELECTION_BORDER_COLOR,
|
|
@@ -1360,8 +1434,18 @@ function withSelection(board) {
|
|
|
1360
1434
|
};
|
|
1361
1435
|
board.globalMouseup = (event) => {
|
|
1362
1436
|
if (start && end) {
|
|
1363
|
-
PlaitBoard.getBoardNativeElement(board).classList.remove('selection-moving');
|
|
1364
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
|
+
}
|
|
1365
1449
|
}
|
|
1366
1450
|
start = null;
|
|
1367
1451
|
end = null;
|
|
@@ -1370,6 +1454,7 @@ function withSelection(board) {
|
|
|
1370
1454
|
board.onChange = () => {
|
|
1371
1455
|
// calc selected elements entry
|
|
1372
1456
|
try {
|
|
1457
|
+
selectionOuterG === null || selectionOuterG === void 0 ? void 0 : selectionOuterG.remove();
|
|
1373
1458
|
if (board.operations.find(value => value.type === 'set_selection')) {
|
|
1374
1459
|
const temporaryElements = getTemporaryElements(board);
|
|
1375
1460
|
const elements = temporaryElements ? temporaryElements : calcElementIntersectionSelection(board);
|
|
@@ -1377,12 +1462,12 @@ function withSelection(board) {
|
|
|
1377
1462
|
const { x, y, width, height } = getRectangleByElements(board, elements, false);
|
|
1378
1463
|
if (width > 0 && height > 0) {
|
|
1379
1464
|
const rough = PlaitBoard.getRoughSVG(board);
|
|
1380
|
-
selectionOuterG === null || selectionOuterG === void 0 ? void 0 : selectionOuterG.remove();
|
|
1381
1465
|
selectionOuterG = rough.rectangle(x - 2, y - 2, width + 4, height + 4, {
|
|
1382
1466
|
stroke: SELECTION_BORDER_COLOR,
|
|
1383
1467
|
strokeWidth: 1,
|
|
1384
1468
|
fillStyle: 'solid'
|
|
1385
1469
|
});
|
|
1470
|
+
selectionOuterG.classList.add('selection-outer');
|
|
1386
1471
|
PlaitBoard.getHost(board).append(selectionOuterG);
|
|
1387
1472
|
}
|
|
1388
1473
|
}
|
|
@@ -1401,6 +1486,27 @@ function getTemporaryElements(board) {
|
|
|
1401
1486
|
function deleteTemporaryElements(board) {
|
|
1402
1487
|
BOARD_TO_TEMPORARY_ELEMENTS.delete(board);
|
|
1403
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
|
+
}
|
|
1404
1510
|
|
|
1405
1511
|
class PlaitElementComponent {
|
|
1406
1512
|
constructor(renderer2, viewContainerRef) {
|
|
@@ -1454,7 +1560,7 @@ class PlaitElementComponent {
|
|
|
1454
1560
|
const current = {
|
|
1455
1561
|
element: this.element,
|
|
1456
1562
|
selection: this.selection,
|
|
1457
|
-
board: this.board
|
|
1563
|
+
board: this.board
|
|
1458
1564
|
};
|
|
1459
1565
|
if (this.context) {
|
|
1460
1566
|
const previous = Object.assign({}, this.context);
|
|
@@ -1555,10 +1661,6 @@ class PlaitBoardComponent {
|
|
|
1555
1661
|
this.elementRef = elementRef;
|
|
1556
1662
|
this.hasInitialized = false;
|
|
1557
1663
|
this.destroy$ = new Subject();
|
|
1558
|
-
this.viewportState = {
|
|
1559
|
-
zoom: 1,
|
|
1560
|
-
autoFitPadding: 8
|
|
1561
|
-
};
|
|
1562
1664
|
this.plaitValue = [];
|
|
1563
1665
|
this.plaitPlugins = [];
|
|
1564
1666
|
this.plaitChange = new EventEmitter();
|
|
@@ -1567,10 +1669,6 @@ class PlaitBoardComponent {
|
|
|
1567
1669
|
return index;
|
|
1568
1670
|
};
|
|
1569
1671
|
}
|
|
1570
|
-
get isFocused() {
|
|
1571
|
-
var _a;
|
|
1572
|
-
return (_a = this.board) === null || _a === void 0 ? void 0 : _a.selection;
|
|
1573
|
-
}
|
|
1574
1672
|
get host() {
|
|
1575
1673
|
return this.svg.nativeElement;
|
|
1576
1674
|
}
|
|
@@ -1580,8 +1678,8 @@ class PlaitBoardComponent {
|
|
|
1580
1678
|
get readonly() {
|
|
1581
1679
|
return this.board.options.readonly;
|
|
1582
1680
|
}
|
|
1583
|
-
get
|
|
1584
|
-
return this.
|
|
1681
|
+
get isFocused() {
|
|
1682
|
+
return PlaitBoard.isFocus(this.board);
|
|
1585
1683
|
}
|
|
1586
1684
|
get nativeElement() {
|
|
1587
1685
|
return this.elementRef.nativeElement;
|
|
@@ -1591,10 +1689,12 @@ class PlaitBoardComponent {
|
|
|
1591
1689
|
const roughSVG = rough.svg(this.host, {
|
|
1592
1690
|
options: { roughness: 0, strokeWidth: 1 }
|
|
1593
1691
|
});
|
|
1692
|
+
this.roughSVG = roughSVG;
|
|
1594
1693
|
this.initializePlugins();
|
|
1595
1694
|
this.initializeEvents();
|
|
1596
1695
|
this.viewportScrollListener();
|
|
1597
1696
|
this.elementResizeListener();
|
|
1697
|
+
this.mouseLeaveListener();
|
|
1598
1698
|
BOARD_TO_COMPONENT.set(this.board, this);
|
|
1599
1699
|
BOARD_TO_ROUGH_SVG.set(this.board, roughSVG);
|
|
1600
1700
|
BOARD_TO_HOST.set(this.board, this.host);
|
|
@@ -1611,13 +1711,19 @@ class PlaitBoardComponent {
|
|
|
1611
1711
|
});
|
|
1612
1712
|
this.hasInitialized = true;
|
|
1613
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
|
+
}
|
|
1614
1721
|
ngOnChanges(changes) {
|
|
1615
1722
|
if (this.hasInitialized) {
|
|
1616
1723
|
const valueChange = changes['plaitValue'];
|
|
1617
1724
|
const options = changes['plaitOptions'];
|
|
1618
|
-
if (valueChange)
|
|
1725
|
+
if (valueChange)
|
|
1619
1726
|
this.board.children = valueChange.currentValue;
|
|
1620
|
-
}
|
|
1621
1727
|
if (options)
|
|
1622
1728
|
this.board.options = options.currentValue;
|
|
1623
1729
|
this.cdr.markForCheck();
|
|
@@ -1626,21 +1732,17 @@ class PlaitBoardComponent {
|
|
|
1626
1732
|
ngAfterViewInit() {
|
|
1627
1733
|
this.plaitBoardInitialized.emit(this.board);
|
|
1628
1734
|
this.initViewportContainer();
|
|
1629
|
-
|
|
1630
|
-
this.
|
|
1735
|
+
initializeViewport(this.board);
|
|
1736
|
+
initializeViewportContainerOffset(this.board);
|
|
1631
1737
|
}
|
|
1632
1738
|
initializePlugins() {
|
|
1633
|
-
|
|
1634
|
-
let board = withHandPointer(withHistory(withSelection(withBoard(createBoard(this.plaitValue, this.plaitOptions)))));
|
|
1739
|
+
let board = withHandPointer(withHistory(withSelection(withBoard(withViewport(createBoard(this.plaitValue, this.plaitOptions))))));
|
|
1635
1740
|
this.plaitPlugins.forEach(plugin => {
|
|
1636
1741
|
board = plugin(board);
|
|
1637
1742
|
});
|
|
1638
1743
|
this.board = board;
|
|
1639
1744
|
if (this.plaitViewport) {
|
|
1640
1745
|
this.board.viewport = this.plaitViewport;
|
|
1641
|
-
this.updateViewportState({
|
|
1642
|
-
zoom: (_b = (_a = this.plaitViewport) === null || _a === void 0 ? void 0 : _a.zoom) !== null && _b !== void 0 ? _b : 1
|
|
1643
|
-
});
|
|
1644
1746
|
}
|
|
1645
1747
|
}
|
|
1646
1748
|
initializeEvents() {
|
|
@@ -1676,34 +1778,34 @@ class PlaitBoardComponent {
|
|
|
1676
1778
|
this.board.dblclick(event);
|
|
1677
1779
|
});
|
|
1678
1780
|
fromEvent(document, 'keydown')
|
|
1679
|
-
.pipe(takeUntil(this.destroy$), filter(() =>
|
|
1680
|
-
return !IS_TEXT_EDITABLE.get(this.board) && !!this.board.selection;
|
|
1681
|
-
}))
|
|
1781
|
+
.pipe(takeUntil(this.destroy$), filter(() => this.isFocused && !PlaitBoard.hasBeenTextEditing(this.board)))
|
|
1682
1782
|
.subscribe((event) => {
|
|
1683
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
|
+
}
|
|
1684
1792
|
(_a = this.board) === null || _a === void 0 ? void 0 : _a.keydown(event);
|
|
1685
1793
|
});
|
|
1686
1794
|
fromEvent(document, 'keyup')
|
|
1687
|
-
.pipe(takeUntil(this.destroy$), filter(() =>
|
|
1688
|
-
return !IS_TEXT_EDITABLE.get(this.board) && !!this.board.selection;
|
|
1689
|
-
}))
|
|
1795
|
+
.pipe(takeUntil(this.destroy$), filter(() => this.isFocused && !PlaitBoard.hasBeenTextEditing(this.board)))
|
|
1690
1796
|
.subscribe((event) => {
|
|
1691
1797
|
var _a;
|
|
1692
1798
|
(_a = this.board) === null || _a === void 0 ? void 0 : _a.keyup(event);
|
|
1693
1799
|
});
|
|
1694
1800
|
fromEvent(document, 'copy')
|
|
1695
|
-
.pipe(takeUntil(this.destroy$), filter(() =>
|
|
1696
|
-
return !IS_TEXT_EDITABLE.get(this.board) && !!this.board.selection;
|
|
1697
|
-
}))
|
|
1801
|
+
.pipe(takeUntil(this.destroy$), filter(() => this.isFocused && !PlaitBoard.hasBeenTextEditing(this.board)))
|
|
1698
1802
|
.subscribe((event) => {
|
|
1699
1803
|
var _a;
|
|
1700
1804
|
event.preventDefault();
|
|
1701
1805
|
(_a = this.board) === null || _a === void 0 ? void 0 : _a.setFragment(event.clipboardData);
|
|
1702
1806
|
});
|
|
1703
1807
|
fromEvent(document, 'paste')
|
|
1704
|
-
.pipe(takeUntil(this.destroy$), filter(() =>
|
|
1705
|
-
return !IS_TEXT_EDITABLE.get(this.board) && !!this.board.selection && !this.readonly;
|
|
1706
|
-
}))
|
|
1808
|
+
.pipe(takeUntil(this.destroy$), filter(() => this.isFocused && !PlaitBoard.isReadonly(this.board) && !PlaitBoard.hasBeenTextEditing(this.board)))
|
|
1707
1809
|
.subscribe((clipboardEvent) => {
|
|
1708
1810
|
const mousePoint = BOARD_TO_MOVING_POINT.get(this.board);
|
|
1709
1811
|
const rect = this.nativeElement.getBoundingClientRect();
|
|
@@ -1713,9 +1815,7 @@ class PlaitBoardComponent {
|
|
|
1713
1815
|
}
|
|
1714
1816
|
});
|
|
1715
1817
|
fromEvent(document, 'cut')
|
|
1716
|
-
.pipe(takeUntil(this.destroy$), filter(() =>
|
|
1717
|
-
return !IS_TEXT_EDITABLE.get(this.board) && !!this.board.selection;
|
|
1718
|
-
}))
|
|
1818
|
+
.pipe(takeUntil(this.destroy$), filter(() => this.isFocused && !PlaitBoard.isReadonly(this.board) && !PlaitBoard.hasBeenTextEditing(this.board)))
|
|
1719
1819
|
.subscribe((event) => {
|
|
1720
1820
|
var _a, _b;
|
|
1721
1821
|
event.preventDefault();
|
|
@@ -1725,206 +1825,43 @@ class PlaitBoardComponent {
|
|
|
1725
1825
|
}
|
|
1726
1826
|
viewportScrollListener() {
|
|
1727
1827
|
fromEvent(this.viewportContainer.nativeElement, 'scroll')
|
|
1728
|
-
.pipe(takeUntil(this.destroy$), filter(() =>
|
|
1729
|
-
return !!this.isFocused;
|
|
1730
|
-
}))
|
|
1828
|
+
.pipe(takeUntil(this.destroy$), filter(() => this.isFocused))
|
|
1731
1829
|
.subscribe((event) => {
|
|
1732
1830
|
const { scrollLeft, scrollTop } = event.target;
|
|
1733
|
-
const
|
|
1734
|
-
const
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
this.setScrollTop(scrollTop);
|
|
1738
|
-
this.setViewport();
|
|
1739
|
-
}
|
|
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);
|
|
1740
1835
|
});
|
|
1741
1836
|
}
|
|
1742
1837
|
elementResizeListener() {
|
|
1743
1838
|
this.resizeObserver = new ResizeObserver(() => {
|
|
1744
1839
|
this.initViewportContainer();
|
|
1745
|
-
this.calcViewBox(this.board.viewport.zoom);
|
|
1746
|
-
this.updateViewBoxStyles();
|
|
1747
|
-
this.updateViewportScrolling();
|
|
1748
|
-
this.setViewport();
|
|
1749
1840
|
});
|
|
1750
1841
|
this.resizeObserver.observe(this.nativeElement);
|
|
1751
1842
|
}
|
|
1752
|
-
updateViewportState(state) {
|
|
1753
|
-
this.viewportState = Object.assign(Object.assign({}, this.viewportState), state);
|
|
1754
|
-
}
|
|
1755
1843
|
initViewportContainer() {
|
|
1756
|
-
const { width, height } =
|
|
1844
|
+
const { width, height } = getViewportContainerRect(this.board);
|
|
1757
1845
|
this.renderer2.setStyle(this.viewportContainer.nativeElement, 'width', `${width}px`);
|
|
1758
1846
|
this.renderer2.setStyle(this.viewportContainer.nativeElement, 'height', `${height}px`);
|
|
1759
1847
|
}
|
|
1760
|
-
initViewport(viewport = this.board.viewport) {
|
|
1761
|
-
var _a;
|
|
1762
|
-
const originationCoord = viewport === null || viewport === void 0 ? void 0 : viewport.originationCoord;
|
|
1763
|
-
const zoom = (_a = viewport === null || viewport === void 0 ? void 0 : viewport.zoom) !== null && _a !== void 0 ? _a : this.viewportState.zoom;
|
|
1764
|
-
if (originationCoord) {
|
|
1765
|
-
const matrix = this.getMatrix();
|
|
1766
|
-
const [pointX, pointY] = invertViewportCoordinates([0, 0], matrix);
|
|
1767
|
-
const scrollLeft = this.viewportState.scrollLeft;
|
|
1768
|
-
const scrollTop = this.viewportState.scrollTop;
|
|
1769
|
-
const left = scrollLeft + (originationCoord[0] - pointX) * zoom;
|
|
1770
|
-
const top = scrollTop + (originationCoord[1] - pointY) * zoom;
|
|
1771
|
-
this.setScroll(left, top);
|
|
1772
|
-
}
|
|
1773
|
-
else {
|
|
1774
|
-
this.adaptHandle();
|
|
1775
|
-
}
|
|
1776
|
-
}
|
|
1777
|
-
calcViewBox(zoom = this.viewportState.zoom) {
|
|
1778
|
-
var _a;
|
|
1779
|
-
zoom = clampZoomLevel(zoom);
|
|
1780
|
-
const scrollBarWidth = ((_a = this.plaitOptions) === null || _a === void 0 ? void 0 : _a.hideScrollbar) ? SCROLL_BAR_WIDTH : 0;
|
|
1781
|
-
const viewportContainerBox = getViewportContainerBox(this.board);
|
|
1782
|
-
const groupBBox = getRootGroupBBox(this.board, zoom);
|
|
1783
|
-
const horizontalPadding = viewportContainerBox.width / 2;
|
|
1784
|
-
const verticalPadding = viewportContainerBox.height / 2;
|
|
1785
|
-
const viewportWidth = (groupBBox.right - groupBBox.left) * zoom + 2 * horizontalPadding + scrollBarWidth;
|
|
1786
|
-
const viewportHeight = (groupBBox.bottom - groupBBox.top) * zoom + 2 * verticalPadding + scrollBarWidth;
|
|
1787
|
-
const viewBox = [
|
|
1788
|
-
groupBBox.left - horizontalPadding / zoom,
|
|
1789
|
-
groupBBox.top - verticalPadding / zoom,
|
|
1790
|
-
viewportWidth / zoom,
|
|
1791
|
-
viewportHeight / zoom
|
|
1792
|
-
];
|
|
1793
|
-
const matrix = this.getMatrix();
|
|
1794
|
-
let scrollLeft;
|
|
1795
|
-
let scrollTop;
|
|
1796
|
-
if (matrix.length > 0) {
|
|
1797
|
-
// focusPoint
|
|
1798
|
-
const focusX = viewportContainerBox.x + viewportContainerBox.width / 2;
|
|
1799
|
-
const focusY = viewportContainerBox.y + viewportContainerBox.height / 2;
|
|
1800
|
-
const viewportContainerPoint = [focusX - viewportContainerBox.x, focusY - viewportContainerBox.y, 1];
|
|
1801
|
-
const point = invertViewportCoordinates([viewportContainerPoint[0], viewportContainerPoint[1]], matrix);
|
|
1802
|
-
const newMatrix = [zoom, 0, 0, 0, zoom, 0, -zoom * viewBox[0], -zoom * viewBox[1], 1];
|
|
1803
|
-
const newPoint = transformMat3([], point, newMatrix);
|
|
1804
|
-
scrollLeft = newPoint[0] - viewportContainerPoint[0];
|
|
1805
|
-
scrollTop = newPoint[1] - viewportContainerPoint[1];
|
|
1806
|
-
}
|
|
1807
|
-
else {
|
|
1808
|
-
scrollLeft = horizontalPadding;
|
|
1809
|
-
scrollTop = verticalPadding;
|
|
1810
|
-
}
|
|
1811
|
-
this.updateViewportState({
|
|
1812
|
-
viewportWidth,
|
|
1813
|
-
viewportHeight,
|
|
1814
|
-
zoom,
|
|
1815
|
-
viewBox
|
|
1816
|
-
});
|
|
1817
|
-
this.setScrollLeft(scrollLeft);
|
|
1818
|
-
this.setScrollTop(scrollTop);
|
|
1819
|
-
}
|
|
1820
|
-
getMatrix() {
|
|
1821
|
-
const { viewBox, zoom, scrollLeft, scrollTop } = this.viewportState;
|
|
1822
|
-
if (scrollLeft >= 0 && scrollTop >= 0) {
|
|
1823
|
-
return [zoom, 0, 0, 0, zoom, 0, -scrollLeft - zoom * viewBox[0], -scrollTop - zoom * viewBox[1], 1];
|
|
1824
|
-
}
|
|
1825
|
-
return [];
|
|
1826
|
-
}
|
|
1827
|
-
setScrollLeft(left) {
|
|
1828
|
-
var _a;
|
|
1829
|
-
const viewportContainerBox = getViewportContainerBox(this.board);
|
|
1830
|
-
const scrollBarWidth = ((_a = this.plaitOptions) === null || _a === void 0 ? void 0 : _a.hideScrollbar) ? SCROLL_BAR_WIDTH : 0;
|
|
1831
|
-
const { viewportWidth } = this.viewportState;
|
|
1832
|
-
const width = viewportWidth - viewportContainerBox.width + scrollBarWidth;
|
|
1833
|
-
this.viewportState.scrollLeft = left < 0 ? 0 : left > width ? width : left;
|
|
1834
|
-
}
|
|
1835
|
-
setScrollTop(top) {
|
|
1836
|
-
var _a;
|
|
1837
|
-
const viewportContainerBox = getViewportContainerBox(this.board);
|
|
1838
|
-
const scrollBarWidth = ((_a = this.plaitOptions) === null || _a === void 0 ? void 0 : _a.hideScrollbar) ? SCROLL_BAR_WIDTH : 0;
|
|
1839
|
-
const { viewportHeight } = this.viewportState;
|
|
1840
|
-
const height = viewportHeight - viewportContainerBox.height + scrollBarWidth;
|
|
1841
|
-
this.viewportState.scrollTop = top < 0 ? 0 : top > height ? height : top;
|
|
1842
|
-
}
|
|
1843
|
-
setScroll(left, top) {
|
|
1844
|
-
this.setScrollLeft(left);
|
|
1845
|
-
this.setScrollTop(top);
|
|
1846
|
-
this.updateViewBoxStyles();
|
|
1847
|
-
this.updateViewportScrolling();
|
|
1848
|
-
this.setViewport();
|
|
1849
|
-
}
|
|
1850
|
-
updateViewBoxStyles() {
|
|
1851
|
-
const { host, viewportState } = this;
|
|
1852
|
-
const { viewportWidth, viewportHeight, viewBox } = viewportState;
|
|
1853
|
-
this.renderer2.setStyle(host, 'display', 'block');
|
|
1854
|
-
this.renderer2.setStyle(host, 'width', `${viewportWidth}px`);
|
|
1855
|
-
this.renderer2.setStyle(host, 'height', `${viewportHeight}px`);
|
|
1856
|
-
if (viewBox && viewBox[2] > 0 && viewBox[3] > 0) {
|
|
1857
|
-
this.renderer2.setAttribute(host, 'viewBox', viewBox.join(' '));
|
|
1858
|
-
}
|
|
1859
|
-
}
|
|
1860
|
-
updateViewportScrolling() {
|
|
1861
|
-
const { viewportContainer, viewportState } = this;
|
|
1862
|
-
const { scrollLeft, scrollTop } = viewportState;
|
|
1863
|
-
viewportContainer.nativeElement.scrollLeft = scrollLeft;
|
|
1864
|
-
viewportContainer.nativeElement.scrollTop = scrollTop;
|
|
1865
|
-
}
|
|
1866
|
-
setViewport() {
|
|
1867
|
-
var _a, _b;
|
|
1868
|
-
const viewport = (_a = this.board) === null || _a === void 0 ? void 0 : _a.viewport;
|
|
1869
|
-
const oldOriginationCoord = (_b = viewport === null || viewport === void 0 ? void 0 : viewport.originationCoord) !== null && _b !== void 0 ? _b : [];
|
|
1870
|
-
const matrix = this.getMatrix();
|
|
1871
|
-
const originationCoord = invertViewportCoordinates([0, 0], matrix);
|
|
1872
|
-
if (!originationCoord.every((item, index) => item === oldOriginationCoord[index])) {
|
|
1873
|
-
Transforms.setViewport(this.board, Object.assign(Object.assign({}, viewport), { zoom: this.viewportState.zoom, originationCoord }));
|
|
1874
|
-
}
|
|
1875
|
-
}
|
|
1876
1848
|
adaptHandle() {
|
|
1877
|
-
|
|
1878
|
-
const rootGroup = this.host.firstChild;
|
|
1879
|
-
const matrix = this.getMatrix();
|
|
1880
|
-
const rootGroupBox = rootGroup.getBBox();
|
|
1881
|
-
const centerPoint = [containerBox.width / 2, containerBox.height / 2];
|
|
1882
|
-
const rootGroupCenterX = rootGroupBox.x + rootGroupBox.width / 2;
|
|
1883
|
-
const rootGroupCenterY = rootGroupBox.y + rootGroupBox.height / 2;
|
|
1884
|
-
const transformedPoint = transformMat3([], [rootGroupCenterX, rootGroupCenterY, 1], matrix);
|
|
1885
|
-
const offsetLeft = centerPoint[0] - transformedPoint[0];
|
|
1886
|
-
const offsetTop = centerPoint[1] - transformedPoint[1];
|
|
1887
|
-
const { autoFitPadding, zoom, scrollLeft, scrollTop } = this.viewportState;
|
|
1888
|
-
const viewportWidth = containerBox.width - 2 * autoFitPadding;
|
|
1889
|
-
const viewportHeight = containerBox.height - 2 * autoFitPadding;
|
|
1890
|
-
let newZoom = zoom;
|
|
1891
|
-
if (viewportWidth < rootGroupBox.width || viewportHeight < rootGroupBox.height) {
|
|
1892
|
-
newZoom = Math.min(viewportWidth / rootGroupBox.width, viewportHeight / rootGroupBox.height);
|
|
1893
|
-
}
|
|
1894
|
-
else {
|
|
1895
|
-
newZoom = 1;
|
|
1896
|
-
}
|
|
1897
|
-
this.setScrollLeft(scrollLeft - offsetLeft);
|
|
1898
|
-
this.setScrollTop(scrollTop - offsetTop);
|
|
1899
|
-
this.calcViewBox(newZoom);
|
|
1900
|
-
this.updateViewBoxStyles();
|
|
1901
|
-
this.updateViewportScrolling();
|
|
1902
|
-
this.setViewport();
|
|
1849
|
+
fitViewport(this.board);
|
|
1903
1850
|
}
|
|
1904
|
-
zoomInHandle() {
|
|
1905
|
-
this.
|
|
1906
|
-
this.updateViewBoxStyles();
|
|
1907
|
-
this.updateViewportScrolling();
|
|
1908
|
-
this.setViewport();
|
|
1851
|
+
zoomInHandle(isCenter = true) {
|
|
1852
|
+
changeZoom(this.board, this.board.viewport.zoom + 0.1, isCenter);
|
|
1909
1853
|
}
|
|
1910
1854
|
zoomOutHandle() {
|
|
1911
|
-
this.
|
|
1912
|
-
this.updateViewBoxStyles();
|
|
1913
|
-
this.updateViewportScrolling();
|
|
1914
|
-
this.setViewport();
|
|
1855
|
+
changeZoom(this.board, this.board.viewport.zoom - 0.1);
|
|
1915
1856
|
}
|
|
1916
1857
|
resetZoomHandel() {
|
|
1917
|
-
this.
|
|
1918
|
-
this.updateViewBoxStyles();
|
|
1919
|
-
this.updateViewportScrolling();
|
|
1920
|
-
this.setViewport();
|
|
1858
|
+
changeZoom(this.board, 1);
|
|
1921
1859
|
}
|
|
1922
1860
|
ngOnDestroy() {
|
|
1861
|
+
var _a;
|
|
1923
1862
|
this.destroy$.next();
|
|
1924
1863
|
this.destroy$.complete();
|
|
1925
|
-
|
|
1926
|
-
this.resizeObserver.disconnect();
|
|
1927
|
-
}
|
|
1864
|
+
this.resizeObserver && ((_a = this.resizeObserver) === null || _a === void 0 ? void 0 : _a.disconnect());
|
|
1928
1865
|
BOARD_TO_ROUGH_SVG.delete(this.board);
|
|
1929
1866
|
BOARD_TO_COMPONENT.delete(this.board);
|
|
1930
1867
|
BOARD_TO_ROUGH_SVG.delete(this.board);
|
|
@@ -1935,41 +1872,9 @@ class PlaitBoardComponent {
|
|
|
1935
1872
|
markForCheck() {
|
|
1936
1873
|
this.cdr.markForCheck();
|
|
1937
1874
|
}
|
|
1938
|
-
scrollToRectangle(client) {
|
|
1939
|
-
var _a;
|
|
1940
|
-
this.calcViewBox();
|
|
1941
|
-
this.updateViewBoxStyles();
|
|
1942
|
-
this.updateViewportScrolling();
|
|
1943
|
-
this.setViewport();
|
|
1944
|
-
const svgRect = this.host.getBoundingClientRect();
|
|
1945
|
-
const viewportContainerBox = getViewportContainerBox(this.board);
|
|
1946
|
-
if (svgRect.width > viewportContainerBox.width || svgRect.height > viewportContainerBox.height) {
|
|
1947
|
-
const scrollBarWidth = ((_a = this.plaitOptions) === null || _a === void 0 ? void 0 : _a.hideScrollbar) ? SCROLL_BAR_WIDTH : 0;
|
|
1948
|
-
const matrix = this.getMatrix();
|
|
1949
|
-
const [nodePointX, nodePointY] = convertToViewportCoordinates([client.x, client.y], matrix);
|
|
1950
|
-
const [fullNodePointX, fullNodePointY] = convertToViewportCoordinates([client.x + client.width, client.y + client.height], matrix);
|
|
1951
|
-
let newLeft = this.viewportState.scrollLeft;
|
|
1952
|
-
let newTop = this.viewportState.scrollTop;
|
|
1953
|
-
if (nodePointX < 0) {
|
|
1954
|
-
newLeft -= Math.abs(nodePointX);
|
|
1955
|
-
}
|
|
1956
|
-
if (nodePointX > 0 && fullNodePointX > viewportContainerBox.width) {
|
|
1957
|
-
newLeft += fullNodePointX - viewportContainerBox.width + scrollBarWidth;
|
|
1958
|
-
}
|
|
1959
|
-
if (nodePointY < 0) {
|
|
1960
|
-
newTop -= Math.abs(nodePointY);
|
|
1961
|
-
}
|
|
1962
|
-
if (nodePointY > 0 && fullNodePointY > viewportContainerBox.height) {
|
|
1963
|
-
newTop += fullNodePointY - viewportContainerBox.height + scrollBarWidth;
|
|
1964
|
-
}
|
|
1965
|
-
if (newLeft !== this.viewportState.scrollLeft || newTop !== this.viewportState.scrollTop) {
|
|
1966
|
-
this.setScroll(newLeft, newTop);
|
|
1967
|
-
}
|
|
1968
|
-
}
|
|
1969
|
-
}
|
|
1970
1875
|
}
|
|
1971
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 });
|
|
1972
|
-
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: `
|
|
1973
1878
|
<div class="viewport-container" #viewportContainer>
|
|
1974
1879
|
<svg #svg width="100%" height="100%" style="position: relative;"><g class="element-host"></g></svg>
|
|
1975
1880
|
<plait-element
|
|
@@ -2035,7 +1940,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImpo
|
|
|
2035
1940
|
}], readonly: [{
|
|
2036
1941
|
type: HostBinding,
|
|
2037
1942
|
args: ['class.readonly']
|
|
2038
|
-
}],
|
|
1943
|
+
}], isFocused: [{
|
|
2039
1944
|
type: HostBinding,
|
|
2040
1945
|
args: ['class.focused']
|
|
2041
1946
|
}], svg: [{
|
|
@@ -2133,6 +2038,88 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImpo
|
|
|
2133
2038
|
}]
|
|
2134
2039
|
}] });
|
|
2135
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
|
+
|
|
2136
2123
|
/*
|
|
2137
2124
|
* Public API Surface of plait
|
|
2138
2125
|
*/
|
|
@@ -2141,5 +2128,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImpo
|
|
|
2141
2128
|
* Generated bundle index. Do not edit.
|
|
2142
2129
|
*/
|
|
2143
2130
|
|
|
2144
|
-
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, 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, 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 };
|
|
2145
2132
|
//# sourceMappingURL=plait-core.mjs.map
|