@plait/core 0.56.2 → 0.58.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/core/element/element-flavour.d.ts +30 -0
- package/core/list-render.d.ts +2 -4
- package/esm2022/board/board.component.mjs +10 -5
- package/esm2022/core/element/element-flavour.mjs +136 -0
- package/esm2022/core/island/island-base.component.mjs +6 -6
- package/esm2022/core/list-render.mjs +27 -27
- package/esm2022/interfaces/board.mjs +7 -1
- package/esm2022/interfaces/element.mjs +1 -5
- package/esm2022/plugins/with-moving.mjs +2 -2
- package/esm2022/plugins/with-selection.mjs +3 -6
- package/esm2022/public-api.mjs +2 -2
- package/esm2022/services/context.service.mjs +3 -3
- package/esm2022/utils/angle.mjs +6 -8
- package/esm2022/utils/element.mjs +7 -2
- package/esm2022/utils/selected-element.mjs +9 -1
- package/esm2022/utils/snap/snap.mjs +5 -2
- package/esm2022/utils/weak-maps.mjs +1 -1
- package/fesm2022/plait-core.mjs +1033 -1027
- package/fesm2022/plait-core.mjs.map +1 -1
- package/interfaces/board.d.ts +4 -2
- package/interfaces/element.d.ts +1 -3
- package/package.json +1 -1
- package/public-api.d.ts +1 -1
- package/utils/angle.d.ts +5 -5
- package/utils/element.d.ts +1 -0
- package/utils/selected-element.d.ts +2 -0
- package/utils/weak-maps.d.ts +1 -0
- package/core/element/plugin-element.d.ts +0 -34
- package/esm2022/core/element/plugin-element.mjs +0 -151
package/fesm2022/plait-core.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import {
|
|
2
|
+
import { Directive, Input, Injectable, IterableDiffers, EventEmitter, inject, ElementRef, Component, ChangeDetectionStrategy, Output, HostBinding, ViewChild, ContentChildren } from '@angular/core';
|
|
3
3
|
import rough from 'roughjs/bin/rough';
|
|
4
4
|
import { timer, Subject, fromEvent } from 'rxjs';
|
|
5
5
|
import { takeUntil, filter, tap } from 'rxjs/operators';
|
|
@@ -42,51 +42,6 @@ var PlaitPointerType;
|
|
|
42
42
|
* Extendable Custom Types Interface
|
|
43
43
|
*/
|
|
44
44
|
|
|
45
|
-
function depthFirstRecursion(node, callback, recursion, isReverse) {
|
|
46
|
-
if (!recursion || recursion(node)) {
|
|
47
|
-
let children = [];
|
|
48
|
-
if (node.children) {
|
|
49
|
-
children = [...node.children];
|
|
50
|
-
}
|
|
51
|
-
children = isReverse ? children.reverse() : children;
|
|
52
|
-
children.forEach(child => {
|
|
53
|
-
depthFirstRecursion(child, callback, recursion);
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
callback(node);
|
|
57
|
-
}
|
|
58
|
-
const getIsRecursionFunc = (board) => {
|
|
59
|
-
return (element) => {
|
|
60
|
-
if (PlaitBoard.isBoard(element) || board.isRecursion(element)) {
|
|
61
|
-
return true;
|
|
62
|
-
}
|
|
63
|
-
else {
|
|
64
|
-
return false;
|
|
65
|
-
}
|
|
66
|
-
};
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
const SELECTION_BORDER_COLOR = '#6698FF';
|
|
70
|
-
const SELECTION_FILL_COLOR = '#6698FF25'; // opacity 0.25
|
|
71
|
-
const Selection = {
|
|
72
|
-
isCollapsed(selection) {
|
|
73
|
-
if (selection.anchor[0] == selection.focus[0] && selection.anchor[1] === selection.focus[1]) {
|
|
74
|
-
return true;
|
|
75
|
-
}
|
|
76
|
-
else {
|
|
77
|
-
return false;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
const sortElements = (board, elements, ascendingOrder = true) => {
|
|
83
|
-
return [...elements].sort((a, b) => {
|
|
84
|
-
const pathA = PlaitBoard.findPath(board, a);
|
|
85
|
-
const pathB = PlaitBoard.findPath(board, b);
|
|
86
|
-
return ascendingOrder ? pathA[0] - pathB[0] : pathB[0] - pathA[0];
|
|
87
|
-
});
|
|
88
|
-
};
|
|
89
|
-
|
|
90
45
|
const RectangleClient = {
|
|
91
46
|
isHit: (origin, target) => {
|
|
92
47
|
return RectangleClient.isHitX(origin, target) && RectangleClient.isHitY(origin, target);
|
|
@@ -244,122 +199,371 @@ const RectangleClient = {
|
|
|
244
199
|
}
|
|
245
200
|
};
|
|
246
201
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
const
|
|
253
|
-
const
|
|
254
|
-
const
|
|
255
|
-
|
|
256
|
-
|
|
202
|
+
// https://stackoverflow.com/a/6853926/232122
|
|
203
|
+
function distanceBetweenPointAndSegment(x, y, x1, y1, x2, y2) {
|
|
204
|
+
const A = x - x1;
|
|
205
|
+
const B = y - y1;
|
|
206
|
+
const C = x2 - x1;
|
|
207
|
+
const D = y2 - y1;
|
|
208
|
+
const dot = A * C + B * D;
|
|
209
|
+
const lenSquare = C * C + D * D;
|
|
210
|
+
let param = -1;
|
|
211
|
+
if (lenSquare !== 0) {
|
|
212
|
+
// in case of 0 length line
|
|
213
|
+
param = dot / lenSquare;
|
|
257
214
|
}
|
|
258
|
-
|
|
259
|
-
if (
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
return [hitElement];
|
|
263
|
-
}
|
|
264
|
-
else {
|
|
265
|
-
return [];
|
|
266
|
-
}
|
|
215
|
+
let xx, yy;
|
|
216
|
+
if (param < 0) {
|
|
217
|
+
xx = x1;
|
|
218
|
+
yy = y1;
|
|
267
219
|
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
}
|
|
272
|
-
}, getIsRecursionFunc(board), true);
|
|
273
|
-
return rectangleHitElements;
|
|
274
|
-
};
|
|
275
|
-
const getHitElementByPoint = (board, point, match = () => true) => {
|
|
276
|
-
let hitElement = undefined;
|
|
277
|
-
let hitInsideElement = undefined;
|
|
278
|
-
depthFirstRecursion(board, node => {
|
|
279
|
-
if (hitElement) {
|
|
280
|
-
return;
|
|
281
|
-
}
|
|
282
|
-
if (PlaitBoard.isBoard(node) || !match(node) || !PlaitElement.hasMounted(node)) {
|
|
283
|
-
return;
|
|
284
|
-
}
|
|
285
|
-
if (board.isHit(node, point)) {
|
|
286
|
-
hitElement = node;
|
|
287
|
-
return;
|
|
288
|
-
}
|
|
289
|
-
/**
|
|
290
|
-
* 需要增加场景测试
|
|
291
|
-
* hitInsideElement 存的是第一个符合 isInsidePoint 的元素
|
|
292
|
-
* 当有元素符合 isHit 时结束遍历,并返回 hitElement
|
|
293
|
-
* 当所有元素都不符合 isHit ,则返回第一个符合 isInsidePoint 的元素
|
|
294
|
-
* 这样保证最上面的元素优先被探测到;
|
|
295
|
-
*/
|
|
296
|
-
if (!hitInsideElement && board.isInsidePoint(node, point)) {
|
|
297
|
-
hitInsideElement = node;
|
|
298
|
-
}
|
|
299
|
-
}, getIsRecursionFunc(board), true);
|
|
300
|
-
return hitElement || hitInsideElement;
|
|
301
|
-
};
|
|
302
|
-
const getHitSelectedElements = (board, point) => {
|
|
303
|
-
const selectedElements = getSelectedElements(board);
|
|
304
|
-
const targetRectangle = selectedElements.length > 0 && getRectangleByElements(board, selectedElements, false);
|
|
305
|
-
const isInTargetRectangle = targetRectangle && RectangleClient.isPointInRectangle(targetRectangle, point);
|
|
306
|
-
if (isInTargetRectangle) {
|
|
307
|
-
return selectedElements;
|
|
220
|
+
else if (param > 1) {
|
|
221
|
+
xx = x2;
|
|
222
|
+
yy = y2;
|
|
308
223
|
}
|
|
309
224
|
else {
|
|
310
|
-
|
|
225
|
+
xx = x1 + param * C;
|
|
226
|
+
yy = y1 + param * D;
|
|
311
227
|
}
|
|
312
|
-
|
|
313
|
-
const
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
const
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
const
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
228
|
+
const dx = x - xx;
|
|
229
|
+
const dy = y - yy;
|
|
230
|
+
return Math.hypot(dx, dy);
|
|
231
|
+
}
|
|
232
|
+
function getNearestPointBetweenPointAndSegment(point, linePoints) {
|
|
233
|
+
const x = point[0], y = point[1], x1 = linePoints[0][0], y1 = linePoints[0][1], x2 = linePoints[1][0], y2 = linePoints[1][1];
|
|
234
|
+
const A = x - x1;
|
|
235
|
+
const B = y - y1;
|
|
236
|
+
const C = x2 - x1;
|
|
237
|
+
const D = y2 - y1;
|
|
238
|
+
const dot = A * C + B * D;
|
|
239
|
+
const lenSquare = C * C + D * D;
|
|
240
|
+
let param = -1;
|
|
241
|
+
if (lenSquare !== 0) {
|
|
242
|
+
// in case of 0 length line
|
|
243
|
+
param = dot / lenSquare;
|
|
244
|
+
}
|
|
245
|
+
let xx, yy;
|
|
246
|
+
if (param < 0) {
|
|
247
|
+
xx = x1;
|
|
248
|
+
yy = y1;
|
|
249
|
+
}
|
|
250
|
+
else if (param > 1) {
|
|
251
|
+
xx = x2;
|
|
252
|
+
yy = y2;
|
|
324
253
|
}
|
|
325
254
|
else {
|
|
326
|
-
|
|
255
|
+
xx = x1 + param * C;
|
|
256
|
+
yy = y1 + param * D;
|
|
327
257
|
}
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
const
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
const
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
258
|
+
return [xx, yy];
|
|
259
|
+
}
|
|
260
|
+
function distanceBetweenPointAndSegments(points, point) {
|
|
261
|
+
const len = points.length;
|
|
262
|
+
let distance = Infinity;
|
|
263
|
+
for (let i = 0; i < len - 1; i++) {
|
|
264
|
+
const p = points[i];
|
|
265
|
+
const p2 = points[i + 1];
|
|
266
|
+
const currentDistance = distanceBetweenPointAndSegment(point[0], point[1], p[0], p[1], p2[0], p2[1]);
|
|
267
|
+
if (currentDistance < distance) {
|
|
268
|
+
distance = currentDistance;
|
|
339
269
|
}
|
|
340
|
-
|
|
341
|
-
|
|
270
|
+
}
|
|
271
|
+
return distance;
|
|
272
|
+
}
|
|
273
|
+
function getNearestPointBetweenPointAndSegments(point, points, isClose = true) {
|
|
274
|
+
const len = points.length;
|
|
275
|
+
let distance = Infinity;
|
|
276
|
+
let result = point;
|
|
277
|
+
for (let i = 0; i < len; i++) {
|
|
278
|
+
const p = points[i];
|
|
279
|
+
if (i === len - 1 && !isClose)
|
|
280
|
+
continue;
|
|
281
|
+
const p2 = i === len - 1 ? points[0] : points[i + 1];
|
|
282
|
+
const currentDistance = distanceBetweenPointAndSegment(point[0], point[1], p[0], p[1], p2[0], p2[1]);
|
|
283
|
+
if (currentDistance < distance) {
|
|
284
|
+
distance = currentDistance;
|
|
285
|
+
result = getNearestPointBetweenPointAndSegment(point, [p, p2]);
|
|
342
286
|
}
|
|
343
|
-
const newSelectedElements = selectedElements.filter(value => !targetElements.includes(value));
|
|
344
|
-
cacheSelectedElements(board, newSelectedElements);
|
|
345
287
|
}
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
288
|
+
return result;
|
|
289
|
+
}
|
|
290
|
+
function getNearestPointBetweenPointAndEllipse(point, center, rx, ry, rotation = 0) {
|
|
291
|
+
const rectangleClient = {
|
|
292
|
+
x: center[0] - rx,
|
|
293
|
+
y: center[1] - ry,
|
|
294
|
+
height: ry * 2,
|
|
295
|
+
width: rx * 2
|
|
296
|
+
};
|
|
297
|
+
// https://stackoverflow.com/a/46007540/232122
|
|
298
|
+
const px = Math.abs(point[0] - rectangleClient.x - rectangleClient.width / 2);
|
|
299
|
+
const py = Math.abs(point[1] - rectangleClient.y - rectangleClient.height / 2);
|
|
300
|
+
let tx = 0.707;
|
|
301
|
+
let ty = 0.707;
|
|
302
|
+
const a = Math.abs(rectangleClient.width) / 2;
|
|
303
|
+
const b = Math.abs(rectangleClient.height) / 2;
|
|
304
|
+
[0, 1, 2, 3].forEach(x => {
|
|
305
|
+
const xx = a * tx;
|
|
306
|
+
const yy = b * ty;
|
|
307
|
+
const ex = ((a * a - b * b) * tx ** 3) / a;
|
|
308
|
+
const ey = ((b * b - a * a) * ty ** 3) / b;
|
|
309
|
+
const rx = xx - ex;
|
|
310
|
+
const ry = yy - ey;
|
|
311
|
+
const qx = px - ex;
|
|
312
|
+
const qy = py - ey;
|
|
313
|
+
const r = Math.hypot(ry, rx);
|
|
314
|
+
const q = Math.hypot(qy, qx);
|
|
315
|
+
tx = Math.min(1, Math.max(0, ((qx * r) / q + ex) / a));
|
|
316
|
+
ty = Math.min(1, Math.max(0, ((qy * r) / q + ey) / b));
|
|
317
|
+
const t = Math.hypot(ty, tx);
|
|
318
|
+
tx /= t;
|
|
319
|
+
ty /= t;
|
|
358
320
|
});
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
}
|
|
321
|
+
const signX = point[0] > center[0] ? 1 : -1;
|
|
322
|
+
const signY = point[1] > center[1] ? 1 : -1;
|
|
323
|
+
return [center[0] + a * tx * signX, center[1] + b * ty * signY];
|
|
324
|
+
}
|
|
325
|
+
function rotate(x1, y1, x2, y2, angle) {
|
|
326
|
+
// 𝑎′𝑥=(𝑎𝑥−𝑐𝑥)cos𝜃−(𝑎𝑦−𝑐𝑦)sin𝜃+𝑐𝑥
|
|
327
|
+
// 𝑎′𝑦=(𝑎𝑥−𝑐𝑥)sin𝜃+(𝑎𝑦−𝑐𝑦)cos𝜃+𝑐𝑦.
|
|
328
|
+
// https://math.stackexchange.com/questions/2204520/how-do-i-rotate-a-line-segment-in-a-specific-point-on-the-line
|
|
329
|
+
return [(x1 - x2) * Math.cos(angle) - (y1 - y2) * Math.sin(angle) + x2, (x1 - x2) * Math.sin(angle) + (y1 - y2) * Math.cos(angle) + y2];
|
|
330
|
+
}
|
|
331
|
+
function distanceBetweenPointAndPoint(x1, y1, x2, y2) {
|
|
332
|
+
const dx = x1 - x2;
|
|
333
|
+
const dy = y1 - y2;
|
|
334
|
+
return Math.hypot(dx, dy);
|
|
335
|
+
}
|
|
336
|
+
// https://stackoverflow.com/questions/5254838/calculating-distance-between-a-point-and-a-rectangular-box-nearest-point
|
|
337
|
+
function distanceBetweenPointAndRectangle(x, y, rect) {
|
|
338
|
+
var dx = Math.max(rect.x - x, 0, x - (rect.x + rect.width));
|
|
339
|
+
var dy = Math.max(rect.y - y, 0, y - (rect.y + rect.height));
|
|
340
|
+
return Math.sqrt(dx * dx + dy * dy);
|
|
341
|
+
}
|
|
342
|
+
const isLineHitLine = (a, b, c, d) => {
|
|
343
|
+
const crossProduct = (v1, v2) => v1[0] * v2[1] - v1[1] * v2[0];
|
|
344
|
+
const ab = [b[0] - a[0], b[1] - a[1]];
|
|
345
|
+
const ac = [c[0] - a[0], c[1] - a[1]];
|
|
346
|
+
const ad = [d[0] - a[0], d[1] - a[1]];
|
|
347
|
+
const ca = [a[0] - c[0], a[1] - c[1]];
|
|
348
|
+
const cb = [b[0] - c[0], b[1] - c[1]];
|
|
349
|
+
const cd = [d[0] - c[0], d[1] - c[1]];
|
|
350
|
+
return crossProduct(ab, ac) * crossProduct(ab, ad) <= 0 && crossProduct(cd, ca) * crossProduct(cd, cb) <= 0;
|
|
351
|
+
};
|
|
352
|
+
const isPolylineHitRectangle = (points, rectangle, isClose = true) => {
|
|
353
|
+
const rectanglePoints = RectangleClient.getCornerPoints(rectangle);
|
|
354
|
+
const len = points.length;
|
|
355
|
+
for (let i = 0; i < len; i++) {
|
|
356
|
+
if (i === len - 1 && !isClose)
|
|
357
|
+
continue;
|
|
358
|
+
const p1 = points[i];
|
|
359
|
+
const p2 = points[(i + 1) % len];
|
|
360
|
+
const isHit = isLineHitLine(p1, p2, rectanglePoints[0], rectanglePoints[1]) ||
|
|
361
|
+
isLineHitLine(p1, p2, rectanglePoints[1], rectanglePoints[2]) ||
|
|
362
|
+
isLineHitLine(p1, p2, rectanglePoints[2], rectanglePoints[3]) ||
|
|
363
|
+
isLineHitLine(p1, p2, rectanglePoints[3], rectanglePoints[0]);
|
|
364
|
+
if (isHit || isPointInPolygon(p1, rectanglePoints) || isPointInPolygon(p2, rectanglePoints)) {
|
|
365
|
+
return true;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
return false;
|
|
369
|
+
};
|
|
370
|
+
//https://stackoverflow.com/questions/22521982/check-if-point-is-inside-a-polygon
|
|
371
|
+
const isPointInPolygon = (point, points) => {
|
|
372
|
+
// ray-casting algorithm based on
|
|
373
|
+
// https://wrf.ecse.rpi.edu/Research/Short_Notes/pnpoly.html
|
|
374
|
+
const x = point[0], y = point[1];
|
|
375
|
+
let inside = false;
|
|
376
|
+
for (var i = 0, j = points.length - 1; i < points.length; j = i++) {
|
|
377
|
+
let xi = points[i][0], yi = points[i][1];
|
|
378
|
+
let xj = points[j][0], yj = points[j][1];
|
|
379
|
+
let intersect = yi > y != yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi) + xi;
|
|
380
|
+
if (intersect)
|
|
381
|
+
inside = !inside;
|
|
382
|
+
}
|
|
383
|
+
return inside;
|
|
384
|
+
};
|
|
385
|
+
const isPointInEllipse = (point, center, rx, ry, angle = 0) => {
|
|
386
|
+
const cosAngle = Math.cos(angle);
|
|
387
|
+
const sinAngle = Math.sin(angle);
|
|
388
|
+
const x1 = (point[0] - center[0]) * cosAngle + (point[1] - center[1]) * sinAngle;
|
|
389
|
+
const y1 = (point[1] - center[1]) * cosAngle - (point[0] - center[0]) * sinAngle;
|
|
390
|
+
return (x1 * x1) / (rx * rx) + (y1 * y1) / (ry * ry) <= 1;
|
|
391
|
+
};
|
|
392
|
+
const isPointInRoundRectangle = (point, rectangle, radius, angle = 0) => {
|
|
393
|
+
const { x: rectX, y: rectY, width, height } = rectangle;
|
|
394
|
+
const isInRectangle = point[0] >= rectX && point[0] <= rectX + width && point[1] >= rectY && point[1] <= rectY + height;
|
|
395
|
+
const handleLeftTop = point[0] >= rectX &&
|
|
396
|
+
point[0] <= rectX + radius &&
|
|
397
|
+
point[1] >= rectY &&
|
|
398
|
+
point[1] <= rectY + radius &&
|
|
399
|
+
Math.hypot(point[0] - (rectX + radius), point[1] - (rectY + radius)) > radius;
|
|
400
|
+
const handleLeftBottom = point[0] >= rectX &&
|
|
401
|
+
point[0] <= rectX + radius &&
|
|
402
|
+
point[1] >= rectY + height &&
|
|
403
|
+
point[1] <= rectY + height - radius &&
|
|
404
|
+
Math.hypot(point[0] - (rectX + radius), point[1] - (rectY + height - radius)) > radius;
|
|
405
|
+
const handleRightTop = point[0] >= rectX + width - radius &&
|
|
406
|
+
point[0] <= rectX + width &&
|
|
407
|
+
point[1] >= rectY &&
|
|
408
|
+
point[1] <= rectY + radius &&
|
|
409
|
+
Math.hypot(point[0] - (rectX + width - radius), point[1] - (rectY + radius)) > radius;
|
|
410
|
+
const handleRightBottom = point[0] >= rectX + width - radius &&
|
|
411
|
+
point[0] <= rectX + width &&
|
|
412
|
+
point[1] >= rectY + height - radius &&
|
|
413
|
+
point[1] <= rectY + height &&
|
|
414
|
+
Math.hypot(point[0] - (rectX + width - radius), point[1] - (rectY + height - radius)) > radius;
|
|
415
|
+
const isInCorner = handleLeftTop || handleLeftBottom || handleRightTop || handleRightBottom;
|
|
416
|
+
return isInRectangle && !isInCorner;
|
|
417
|
+
};
|
|
418
|
+
// https://gist.github.com/nicholaswmin/c2661eb11cad5671d816
|
|
419
|
+
const catmullRomFitting = function (points) {
|
|
420
|
+
const alpha = 0.5;
|
|
421
|
+
let p0, p1, p2, p3, bp1, bp2, d1, d2, d3, A, B, N, M;
|
|
422
|
+
var d3powA, d2powA, d3pow2A, d2pow2A, d1pow2A, d1powA;
|
|
423
|
+
const result = [];
|
|
424
|
+
result.push([Math.round(points[0][0]), Math.round(points[0][1])]);
|
|
425
|
+
var length = points.length;
|
|
426
|
+
for (var i = 0; i < length - 1; i++) {
|
|
427
|
+
p0 = i == 0 ? points[0] : points[i - 1];
|
|
428
|
+
p1 = points[i];
|
|
429
|
+
p2 = points[i + 1];
|
|
430
|
+
p3 = i + 2 < length ? points[i + 2] : p2;
|
|
431
|
+
d1 = Math.sqrt(Math.pow(p0[0] - p1[0], 2) + Math.pow(p0[1] - p1[1], 2));
|
|
432
|
+
d2 = Math.sqrt(Math.pow(p1[0] - p2[0], 2) + Math.pow(p1[1] - p2[1], 2));
|
|
433
|
+
d3 = Math.sqrt(Math.pow(p2[0] - p3[0], 2) + Math.pow(p2[1] - p3[1], 2));
|
|
434
|
+
// Catmull-Rom to Cubic Bezier conversion matrix
|
|
435
|
+
// A = 2d1^2a + 3d1^a * d2^a + d3^2a
|
|
436
|
+
// B = 2d3^2a + 3d3^a * d2^a + d2^2a
|
|
437
|
+
// [ 0 1 0 0 ]
|
|
438
|
+
// [ -d2^2a /N A/N d1^2a /N 0 ]
|
|
439
|
+
// [ 0 d3^2a /M B/M -d2^2a /M ]
|
|
440
|
+
// [ 0 0 1 0 ]
|
|
441
|
+
d3powA = Math.pow(d3, alpha);
|
|
442
|
+
d3pow2A = Math.pow(d3, 2 * alpha);
|
|
443
|
+
d2powA = Math.pow(d2, alpha);
|
|
444
|
+
d2pow2A = Math.pow(d2, 2 * alpha);
|
|
445
|
+
d1powA = Math.pow(d1, alpha);
|
|
446
|
+
d1pow2A = Math.pow(d1, 2 * alpha);
|
|
447
|
+
A = 2 * d1pow2A + 3 * d1powA * d2powA + d2pow2A;
|
|
448
|
+
B = 2 * d3pow2A + 3 * d3powA * d2powA + d2pow2A;
|
|
449
|
+
N = 3 * d1powA * (d1powA + d2powA);
|
|
450
|
+
if (N > 0) {
|
|
451
|
+
N = 1 / N;
|
|
452
|
+
}
|
|
453
|
+
M = 3 * d3powA * (d3powA + d2powA);
|
|
454
|
+
if (M > 0) {
|
|
455
|
+
M = 1 / M;
|
|
456
|
+
}
|
|
457
|
+
bp1 = [(-d2pow2A * p0[0] + A * p1[0] + d1pow2A * p2[0]) * N, (-d2pow2A * p0[1] + A * p1[1] + d1pow2A * p2[1]) * N];
|
|
458
|
+
bp2 = [(d3pow2A * p1[0] + B * p2[0] - d2pow2A * p3[0]) * M, (d3pow2A * p1[1] + B * p2[1] - d2pow2A * p3[1]) * M];
|
|
459
|
+
if (bp1[0] == 0 && bp1[1] == 0) {
|
|
460
|
+
bp1 = p1;
|
|
461
|
+
}
|
|
462
|
+
if (bp2[0] == 0 && bp2[1] == 0) {
|
|
463
|
+
bp2 = p2;
|
|
464
|
+
}
|
|
465
|
+
result.push(bp1, bp2, p2);
|
|
466
|
+
}
|
|
467
|
+
return result;
|
|
468
|
+
};
|
|
469
|
+
/**
|
|
470
|
+
* the result of slope is based on Cartesian coordinate system
|
|
471
|
+
* x, y are based on the position in the Cartesian coordinate system
|
|
472
|
+
*/
|
|
473
|
+
function getEllipseTangentSlope(x, y, a, b) {
|
|
474
|
+
if (Math.abs(y) === 0) {
|
|
475
|
+
return x > 0 ? -Infinity : Infinity;
|
|
476
|
+
}
|
|
477
|
+
const k = (-b * b * x) / (a * a * y);
|
|
478
|
+
return k;
|
|
479
|
+
}
|
|
480
|
+
/**
|
|
481
|
+
* x, y are based on the position in the Cartesian coordinate system
|
|
482
|
+
*/
|
|
483
|
+
function getVectorFromPointAndSlope(x, y, slope) {
|
|
484
|
+
if (slope === Infinity) {
|
|
485
|
+
return [0, -1];
|
|
486
|
+
}
|
|
487
|
+
else if (slope === -Infinity) {
|
|
488
|
+
return [0, 1];
|
|
489
|
+
}
|
|
490
|
+
let vector = [1, -slope];
|
|
491
|
+
if (y < 0) {
|
|
492
|
+
vector = [-vector[0], -vector[1]];
|
|
493
|
+
}
|
|
494
|
+
return vector;
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* The DOM likes values to be fixed to 3 decimal places
|
|
498
|
+
*/
|
|
499
|
+
function toDomPrecision(v) {
|
|
500
|
+
return +v.toFixed(4);
|
|
501
|
+
}
|
|
502
|
+
function toFixed(v) {
|
|
503
|
+
return +v.toFixed(2);
|
|
504
|
+
}
|
|
505
|
+
/**
|
|
506
|
+
* Whether two numbers numbers a and b are approximately equal.
|
|
507
|
+
*
|
|
508
|
+
* @param a - The first point.
|
|
509
|
+
* @param b - The second point.
|
|
510
|
+
* @public
|
|
511
|
+
*/
|
|
512
|
+
function approximately(a, b, precision = 0.000001) {
|
|
513
|
+
return Math.abs(a - b) <= precision;
|
|
514
|
+
}
|
|
515
|
+
// https://medium.com/@steveruiz/find-the-points-where-a-line-segment-intercepts-an-angled-ellipse-in-javascript-typescript-e451524beece
|
|
516
|
+
function getCrossingPointsBetweenEllipseAndSegment(startPoint, endPoint, cx, cy, rx, ry, segment_only = true) {
|
|
517
|
+
// If the ellipse or line segment are empty, return no tValues.
|
|
518
|
+
if (rx === 0 || ry === 0 || (startPoint[0] === endPoint[0] && startPoint[1] === endPoint[1])) {
|
|
519
|
+
return [];
|
|
520
|
+
}
|
|
521
|
+
rx = rx < 0 ? rx : -rx;
|
|
522
|
+
ry = ry < 0 ? ry : -ry;
|
|
523
|
+
startPoint[0] -= cx;
|
|
524
|
+
startPoint[1] -= cy;
|
|
525
|
+
endPoint[0] -= cx;
|
|
526
|
+
endPoint[1] -= cy;
|
|
527
|
+
// Calculate the quadratic parameters.
|
|
528
|
+
var A = ((endPoint[0] - startPoint[0]) * (endPoint[0] - startPoint[0])) / rx / rx +
|
|
529
|
+
((endPoint[1] - startPoint[1]) * (endPoint[1] - startPoint[1])) / ry / ry;
|
|
530
|
+
var B = (2 * startPoint[0] * (endPoint[0] - startPoint[0])) / rx / rx + (2 * startPoint[1] * (endPoint[1] - startPoint[1])) / ry / ry;
|
|
531
|
+
var C = (startPoint[0] * startPoint[0]) / rx / rx + (startPoint[1] * startPoint[1]) / ry / ry - 1;
|
|
532
|
+
// Make a list of t values (normalized points on the line where intersections occur).
|
|
533
|
+
var tValues = [];
|
|
534
|
+
// Calculate the discriminant.
|
|
535
|
+
var discriminant = B * B - 4 * A * C;
|
|
536
|
+
if (discriminant === 0) {
|
|
537
|
+
// One real solution.
|
|
538
|
+
tValues.push(-B / 2 / A);
|
|
539
|
+
}
|
|
540
|
+
else if (discriminant > 0) {
|
|
541
|
+
// Two real solutions.
|
|
542
|
+
tValues.push((-B + Math.sqrt(discriminant)) / 2 / A);
|
|
543
|
+
tValues.push((-B - Math.sqrt(discriminant)) / 2 / A);
|
|
544
|
+
}
|
|
545
|
+
return (tValues
|
|
546
|
+
// Filter to only points that are on the segment.
|
|
547
|
+
.filter(t => !segment_only || (t >= 0 && t <= 1))
|
|
548
|
+
// Solve for points.
|
|
549
|
+
.map(t => [startPoint[0] + (endPoint[0] - startPoint[0]) * t + cx, startPoint[1] + (endPoint[1] - startPoint[1]) * t + cy]));
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
function isInPlaitBoard(board, x, y) {
|
|
553
|
+
const plaitBoardElement = PlaitBoard.getBoardContainer(board);
|
|
554
|
+
const plaitBoardRect = plaitBoardElement.getBoundingClientRect();
|
|
555
|
+
const distances = distanceBetweenPointAndRectangle(x, y, plaitBoardRect);
|
|
556
|
+
return distances === 0;
|
|
557
|
+
}
|
|
558
|
+
function getRealScrollBarWidth(board) {
|
|
559
|
+
const { hideScrollbar } = board.options;
|
|
560
|
+
let scrollBarWidth = 0;
|
|
561
|
+
if (!hideScrollbar) {
|
|
562
|
+
const viewportContainer = PlaitBoard.getViewportContainer(board);
|
|
563
|
+
scrollBarWidth = viewportContainer.offsetWidth - viewportContainer.clientWidth;
|
|
564
|
+
}
|
|
565
|
+
return scrollBarWidth;
|
|
566
|
+
}
|
|
363
567
|
|
|
364
568
|
/**
|
|
365
569
|
* @license
|
|
@@ -540,785 +744,57 @@ function createRect(rectangle, options) {
|
|
|
540
744
|
const optionKey = key;
|
|
541
745
|
rect.setAttribute(key, `${options[optionKey]}`);
|
|
542
746
|
}
|
|
543
|
-
return rect;
|
|
544
|
-
}
|
|
545
|
-
const setStrokeLinecap = (g, value) => {
|
|
546
|
-
g.setAttribute('stroke-linecap', value);
|
|
547
|
-
};
|
|
548
|
-
const setPathStrokeLinecap = (g, value) => {
|
|
549
|
-
g.querySelectorAll('path').forEach(path => {
|
|
550
|
-
path.setAttribute('stroke-linecap', value);
|
|
551
|
-
});
|
|
552
|
-
};
|
|
553
|
-
function createMask() {
|
|
554
|
-
return document.createElementNS(NS, 'mask');
|
|
555
|
-
}
|
|
556
|
-
function createSVG() {
|
|
557
|
-
const svg = document.createElementNS(NS, 'svg');
|
|
558
|
-
return svg;
|
|
559
|
-
}
|
|
560
|
-
function createText(x, y, fill, textContent) {
|
|
561
|
-
var text = document.createElementNS(NS, 'text');
|
|
562
|
-
text.setAttribute('x', `${x}`);
|
|
563
|
-
text.setAttribute('y', `${y}`);
|
|
564
|
-
text.setAttribute('fill', fill);
|
|
565
|
-
text.textContent = textContent;
|
|
566
|
-
return text;
|
|
567
|
-
}
|
|
568
|
-
/**
|
|
569
|
-
* Check if a DOM node is an element node.
|
|
570
|
-
*/
|
|
571
|
-
const isDOMElement = (value) => {
|
|
572
|
-
return isDOMNode(value) && value.nodeType === 1;
|
|
573
|
-
};
|
|
574
|
-
/**
|
|
575
|
-
* Check if a value is a DOM node.
|
|
576
|
-
*/
|
|
577
|
-
const isDOMNode = (value) => {
|
|
578
|
-
return value instanceof window.Node;
|
|
579
|
-
};
|
|
580
|
-
const hasInputOrTextareaTarget = (target) => {
|
|
581
|
-
if (isDOMElement(target)) {
|
|
582
|
-
if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA') {
|
|
583
|
-
return true;
|
|
584
|
-
}
|
|
585
|
-
}
|
|
586
|
-
return false;
|
|
587
|
-
};
|
|
588
|
-
const isSecondaryPointer = (event) => {
|
|
589
|
-
return event.button === POINTER_BUTTON.SECONDARY;
|
|
590
|
-
};
|
|
591
|
-
const isMainPointer = (event) => {
|
|
592
|
-
return event.button === POINTER_BUTTON.MAIN;
|
|
593
|
-
};
|
|
594
|
-
|
|
595
|
-
function hasBeforeContextChange(value) {
|
|
596
|
-
if (value.beforeContextChange) {
|
|
597
|
-
return true;
|
|
598
|
-
}
|
|
599
|
-
return false;
|
|
600
|
-
}
|
|
601
|
-
function hasOnContextChanged(value) {
|
|
602
|
-
if (value.onContextChanged) {
|
|
603
|
-
return true;
|
|
604
|
-
}
|
|
605
|
-
return false;
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
class ListRender {
|
|
609
|
-
constructor(board, viewContainerRef) {
|
|
610
|
-
this.board = board;
|
|
611
|
-
this.viewContainerRef = viewContainerRef;
|
|
612
|
-
this.children = [];
|
|
613
|
-
this.componentRefs = [];
|
|
614
|
-
this.contexts = [];
|
|
615
|
-
this.differ = null;
|
|
616
|
-
this.initialized = false;
|
|
617
|
-
}
|
|
618
|
-
initialize(children, childrenContext) {
|
|
619
|
-
this.initialized = true;
|
|
620
|
-
this.children = children;
|
|
621
|
-
children.forEach((descendant, index) => {
|
|
622
|
-
NODE_TO_INDEX.set(descendant, index);
|
|
623
|
-
NODE_TO_PARENT.set(descendant, childrenContext.parent);
|
|
624
|
-
const context = getContext(this.board, descendant, index, childrenContext.parent);
|
|
625
|
-
const componentType = getComponentType(this.board, context);
|
|
626
|
-
const componentRef = createPluginComponent(componentType, context, this.viewContainerRef, childrenContext);
|
|
627
|
-
this.componentRefs.push(componentRef);
|
|
628
|
-
this.contexts.push(context);
|
|
629
|
-
});
|
|
630
|
-
const newDiffers = this.viewContainerRef.injector.get(IterableDiffers);
|
|
631
|
-
this.differ = newDiffers.find(children).create(trackBy);
|
|
632
|
-
this.differ.diff(children);
|
|
633
|
-
}
|
|
634
|
-
update(children, childrenContext) {
|
|
635
|
-
if (!this.initialized) {
|
|
636
|
-
this.initialize(children, childrenContext);
|
|
637
|
-
return;
|
|
638
|
-
}
|
|
639
|
-
if (!this.differ) {
|
|
640
|
-
throw new Error('Exception: Can not find differ ');
|
|
641
|
-
}
|
|
642
|
-
const { board, parent } = childrenContext;
|
|
643
|
-
const diffResult = this.differ.diff(children);
|
|
644
|
-
if (diffResult) {
|
|
645
|
-
const newContexts = [];
|
|
646
|
-
const newComponentRefs = [];
|
|
647
|
-
let currentIndexForFirstElement = null;
|
|
648
|
-
diffResult.forEachItem((record) => {
|
|
649
|
-
NODE_TO_INDEX.set(record.item, record.currentIndex);
|
|
650
|
-
NODE_TO_PARENT.set(record.item, childrenContext.parent);
|
|
651
|
-
const previousContext = record.previousIndex === null ? undefined : this.contexts[record.previousIndex];
|
|
652
|
-
const context = getContext(board, record.item, record.currentIndex, parent, previousContext);
|
|
653
|
-
if (record.previousIndex === null) {
|
|
654
|
-
const componentType = getComponentType(board, context);
|
|
655
|
-
const componentRef = createPluginComponent(componentType, context, this.viewContainerRef, childrenContext);
|
|
656
|
-
newContexts.push(context);
|
|
657
|
-
newComponentRefs.push(componentRef);
|
|
658
|
-
}
|
|
659
|
-
else {
|
|
660
|
-
const componentRef = this.componentRefs[record.previousIndex];
|
|
661
|
-
componentRef.instance.context = context;
|
|
662
|
-
newComponentRefs.push(componentRef);
|
|
663
|
-
newContexts.push(context);
|
|
664
|
-
}
|
|
665
|
-
// item might has been changed, so need to compare the id
|
|
666
|
-
if (record.item === this.children[0] || record.item.id === this.children[0]?.id) {
|
|
667
|
-
currentIndexForFirstElement = record.currentIndex;
|
|
668
|
-
}
|
|
669
|
-
});
|
|
670
|
-
diffResult.forEachOperation(record => {
|
|
671
|
-
// removed
|
|
672
|
-
if (record.currentIndex === null) {
|
|
673
|
-
const componentRef = this.componentRefs[record.previousIndex];
|
|
674
|
-
componentRef?.destroy();
|
|
675
|
-
}
|
|
676
|
-
// moved
|
|
677
|
-
if (record.previousIndex !== null && record.currentIndex !== null) {
|
|
678
|
-
mountOnItemMove(record.item, record.currentIndex, childrenContext, currentIndexForFirstElement);
|
|
679
|
-
}
|
|
680
|
-
});
|
|
681
|
-
this.componentRefs = newComponentRefs;
|
|
682
|
-
this.contexts = newContexts;
|
|
683
|
-
this.children = children;
|
|
684
|
-
}
|
|
685
|
-
else {
|
|
686
|
-
const newContexts = [];
|
|
687
|
-
this.children.forEach((element, index) => {
|
|
688
|
-
NODE_TO_INDEX.set(element, index);
|
|
689
|
-
NODE_TO_PARENT.set(element, childrenContext.parent);
|
|
690
|
-
const previousContext = this.contexts[index];
|
|
691
|
-
const previousComponentRef = this.componentRefs[index];
|
|
692
|
-
const context = getContext(board, element, index, parent, previousContext);
|
|
693
|
-
previousComponentRef.instance.context = context;
|
|
694
|
-
newContexts.push(context);
|
|
695
|
-
});
|
|
696
|
-
this.contexts = newContexts;
|
|
697
|
-
}
|
|
698
|
-
}
|
|
699
|
-
destroy() {
|
|
700
|
-
this.children.forEach((element, index) => {
|
|
701
|
-
if (this.componentRefs[index]) {
|
|
702
|
-
this.componentRefs[index].destroy();
|
|
703
|
-
}
|
|
704
|
-
});
|
|
705
|
-
this.componentRefs = [];
|
|
706
|
-
this.children = [];
|
|
707
|
-
this.contexts = [];
|
|
708
|
-
this.initialized = false;
|
|
709
|
-
this.differ = null;
|
|
710
|
-
}
|
|
711
|
-
}
|
|
712
|
-
const trackBy = (index, element) => {
|
|
713
|
-
return element.id;
|
|
714
|
-
};
|
|
715
|
-
const createPluginComponent = (componentType, context, viewContainerRef, childrenContext) => {
|
|
716
|
-
const componentRef = viewContainerRef.createComponent(componentType, { injector: viewContainerRef.injector });
|
|
717
|
-
const instance = componentRef.instance;
|
|
718
|
-
instance.context = context;
|
|
719
|
-
componentRef.changeDetectorRef.detectChanges();
|
|
720
|
-
const g = componentRef.instance.getContainerG();
|
|
721
|
-
mountElementG(context.index, g, childrenContext);
|
|
722
|
-
componentRef.instance.initializeListRender();
|
|
723
|
-
return componentRef;
|
|
724
|
-
};
|
|
725
|
-
const getComponentType = (board, context) => {
|
|
726
|
-
const result = board.drawElement(context);
|
|
727
|
-
return result;
|
|
728
|
-
};
|
|
729
|
-
const getContext = (board, element, index, parent, previousContext) => {
|
|
730
|
-
let isSelected = isSelectedElement(board, element);
|
|
731
|
-
const previousElement = previousContext && previousContext.element;
|
|
732
|
-
if (previousElement && previousElement !== element && isSelectedElement(board, previousElement)) {
|
|
733
|
-
isSelected = true;
|
|
734
|
-
removeSelectedElement(board, previousElement);
|
|
735
|
-
addSelectedElement(board, element);
|
|
736
|
-
}
|
|
737
|
-
const context = {
|
|
738
|
-
element: element,
|
|
739
|
-
parent: parent,
|
|
740
|
-
board: board,
|
|
741
|
-
selected: isSelected,
|
|
742
|
-
index
|
|
743
|
-
};
|
|
744
|
-
return context;
|
|
745
|
-
};
|
|
746
|
-
// the g depth of root element:[1]-[2]-[3]-[4]
|
|
747
|
-
// the g depth of root element and children element(the [2] element has children):
|
|
748
|
-
// [1]-
|
|
749
|
-
// [2]([2-1-1][2-1-2][2-1][2-2][2-3-1][2-3-2][2-3][2])-
|
|
750
|
-
// [3]-
|
|
751
|
-
// [4]
|
|
752
|
-
const mountElementG = (index, g, childrenContext,
|
|
753
|
-
// for moving scene: the current index for first element before moving
|
|
754
|
-
currentIndexForFirstElement = null) => {
|
|
755
|
-
const { parent, parentG } = childrenContext;
|
|
756
|
-
if (PlaitBoard.isBoard(parent)) {
|
|
757
|
-
if (index > 0) {
|
|
758
|
-
const previousElement = parent.children[index - 1];
|
|
759
|
-
const previousContainerG = PlaitElement.getContainerG(previousElement, { suppressThrow: false });
|
|
760
|
-
previousContainerG.insertAdjacentElement('afterend', g);
|
|
761
|
-
}
|
|
762
|
-
else {
|
|
763
|
-
if (currentIndexForFirstElement !== null) {
|
|
764
|
-
const firstElement = parent.children[currentIndexForFirstElement];
|
|
765
|
-
const firstContainerG = firstElement && PlaitElement.getContainerG(firstElement, { suppressThrow: true });
|
|
766
|
-
if (firstElement && firstContainerG) {
|
|
767
|
-
parentG.insertBefore(g, firstContainerG);
|
|
768
|
-
}
|
|
769
|
-
else {
|
|
770
|
-
throw new Error('fail to mount container on moving');
|
|
771
|
-
}
|
|
772
|
-
}
|
|
773
|
-
else {
|
|
774
|
-
parentG.append(g);
|
|
775
|
-
}
|
|
776
|
-
}
|
|
777
|
-
}
|
|
778
|
-
else {
|
|
779
|
-
if (index > 0) {
|
|
780
|
-
const previousElement = parent.children[index - 1];
|
|
781
|
-
const previousElementG = PlaitElement.getElementG(previousElement);
|
|
782
|
-
previousElementG.insertAdjacentElement('afterend', g);
|
|
783
|
-
}
|
|
784
|
-
else {
|
|
785
|
-
if (currentIndexForFirstElement) {
|
|
786
|
-
const nextElement = parent.children[currentIndexForFirstElement];
|
|
787
|
-
const nextPath = nextElement && PlaitBoard.findPath(childrenContext.board, nextElement);
|
|
788
|
-
const first = nextPath && PlaitNode.first(childrenContext.board, nextPath);
|
|
789
|
-
const firstContainerG = first && PlaitElement.getContainerG(first, { suppressThrow: false });
|
|
790
|
-
if (firstContainerG) {
|
|
791
|
-
parentG.insertBefore(g, firstContainerG);
|
|
792
|
-
}
|
|
793
|
-
else {
|
|
794
|
-
throw new Error('fail to mount container on moving');
|
|
795
|
-
}
|
|
796
|
-
}
|
|
797
|
-
else {
|
|
798
|
-
let parentElementG = PlaitElement.getElementG(parent);
|
|
799
|
-
parentG.insertBefore(g, parentElementG);
|
|
800
|
-
}
|
|
801
|
-
}
|
|
802
|
-
}
|
|
803
|
-
};
|
|
804
|
-
const mountOnItemMove = (element, index, childrenContext, currentIndexForFirstElement) => {
|
|
805
|
-
const containerG = PlaitElement.getContainerG(element, { suppressThrow: false });
|
|
806
|
-
mountElementG(index, containerG, childrenContext, currentIndexForFirstElement);
|
|
807
|
-
if (element.children && !PlaitElement.isRootElement(element)) {
|
|
808
|
-
element.children.forEach((child, index) => {
|
|
809
|
-
mountOnItemMove(child, index, { ...childrenContext, parent: element }, null);
|
|
810
|
-
});
|
|
811
|
-
}
|
|
812
|
-
};
|
|
813
|
-
|
|
814
|
-
class PlaitPluginElementComponent {
|
|
815
|
-
get hasChildren() {
|
|
816
|
-
return !!this.element.children;
|
|
817
|
-
}
|
|
818
|
-
set context(value) {
|
|
819
|
-
if (hasBeforeContextChange(this)) {
|
|
820
|
-
this.beforeContextChange(value);
|
|
821
|
-
}
|
|
822
|
-
const previousContext = this._context;
|
|
823
|
-
this._context = value;
|
|
824
|
-
if (this.element) {
|
|
825
|
-
ELEMENT_TO_COMPONENT.set(this.element, this);
|
|
826
|
-
}
|
|
827
|
-
if (this.initialized) {
|
|
828
|
-
const elementG = this.getElementG();
|
|
829
|
-
const containerG = this.getContainerG();
|
|
830
|
-
NODE_TO_G.set(this.element, elementG);
|
|
831
|
-
NODE_TO_CONTAINER_G.set(this.element, containerG);
|
|
832
|
-
ELEMENT_TO_REF.set(this.element, this.ref);
|
|
833
|
-
this.updateListRender();
|
|
834
|
-
this.cdr.markForCheck();
|
|
835
|
-
if (hasOnContextChanged(this)) {
|
|
836
|
-
this.onContextChanged(value, previousContext);
|
|
837
|
-
}
|
|
838
|
-
}
|
|
839
|
-
else {
|
|
840
|
-
if (PlaitElement.isRootElement(this.element) && this.hasChildren) {
|
|
841
|
-
this._g = createG();
|
|
842
|
-
this._containerG = createG();
|
|
843
|
-
this._containerG.append(this._g);
|
|
844
|
-
}
|
|
845
|
-
else {
|
|
846
|
-
this._g = createG();
|
|
847
|
-
this._containerG = this._g;
|
|
848
|
-
}
|
|
849
|
-
NODE_TO_G.set(this.element, this._g);
|
|
850
|
-
NODE_TO_CONTAINER_G.set(this.element, this._containerG);
|
|
851
|
-
ELEMENT_TO_REF.set(this.element, this.ref);
|
|
852
|
-
}
|
|
853
|
-
}
|
|
854
|
-
get context() {
|
|
855
|
-
return this._context;
|
|
856
|
-
}
|
|
857
|
-
get element() {
|
|
858
|
-
return this.context && this.context.element;
|
|
859
|
-
}
|
|
860
|
-
get board() {
|
|
861
|
-
return this.context && this.context.board;
|
|
862
|
-
}
|
|
863
|
-
get selected() {
|
|
864
|
-
return this.context && this.context.selected;
|
|
865
|
-
}
|
|
866
|
-
getContainerG() {
|
|
867
|
-
return this._containerG;
|
|
868
|
-
}
|
|
869
|
-
getElementG() {
|
|
870
|
-
return this._g;
|
|
871
|
-
}
|
|
872
|
-
constructor(ref) {
|
|
873
|
-
this.ref = ref;
|
|
874
|
-
this.viewContainerRef = inject(ViewContainerRef);
|
|
875
|
-
this.cdr = inject(ChangeDetectorRef);
|
|
876
|
-
this.initialized = false;
|
|
877
|
-
}
|
|
878
|
-
ngOnInit() {
|
|
879
|
-
if (this.element.type) {
|
|
880
|
-
this.getContainerG().setAttribute(`plait-${this.element.type}`, 'true');
|
|
881
|
-
}
|
|
882
|
-
if (this.hasChildren) {
|
|
883
|
-
if (PlaitElement.isRootElement(this.element)) {
|
|
884
|
-
this._rootContainerG = this._containerG;
|
|
885
|
-
}
|
|
886
|
-
else {
|
|
887
|
-
const path = PlaitBoard.findPath(this.board, this.element);
|
|
888
|
-
const rootNode = PlaitNode.get(this.board, path.slice(0, 1));
|
|
889
|
-
this._rootContainerG = PlaitElement.getContainerG(rootNode, { suppressThrow: false });
|
|
890
|
-
}
|
|
891
|
-
}
|
|
892
|
-
this.getContainerG().setAttribute('plait-data-id', this.element.id);
|
|
893
|
-
this.initialized = true;
|
|
894
|
-
}
|
|
895
|
-
initializeListRender() {
|
|
896
|
-
if (this.hasChildren) {
|
|
897
|
-
this.listRender = new ListRender(this.board, this.viewContainerRef);
|
|
898
|
-
if (this.board.isExpanded(this.element)) {
|
|
899
|
-
this.listRender.initialize(this.element.children, this.initializeChildrenContext());
|
|
900
|
-
}
|
|
901
|
-
}
|
|
902
|
-
}
|
|
903
|
-
getRef() {
|
|
904
|
-
return this.ref;
|
|
905
|
-
}
|
|
906
|
-
updateListRender() {
|
|
907
|
-
if (this.hasChildren) {
|
|
908
|
-
if (!this.listRender) {
|
|
909
|
-
throw new Error('incorrectly initialize list render');
|
|
910
|
-
}
|
|
911
|
-
if (this.board.isExpanded(this.element)) {
|
|
912
|
-
this.listRender.update(this.element.children, this.initializeChildrenContext());
|
|
913
|
-
}
|
|
914
|
-
else {
|
|
915
|
-
if (this.listRender.initialized) {
|
|
916
|
-
this.listRender.destroy();
|
|
917
|
-
}
|
|
918
|
-
}
|
|
919
|
-
}
|
|
920
|
-
}
|
|
921
|
-
initializeChildrenContext() {
|
|
922
|
-
if (!this._rootContainerG) {
|
|
923
|
-
throw new Error('can not resolve root container g');
|
|
924
|
-
}
|
|
925
|
-
return {
|
|
926
|
-
board: this.board,
|
|
927
|
-
parent: this.element,
|
|
928
|
-
parentG: this._rootContainerG
|
|
929
|
-
};
|
|
930
|
-
}
|
|
931
|
-
ngOnDestroy() {
|
|
932
|
-
if (ELEMENT_TO_COMPONENT.get(this.element) === this) {
|
|
933
|
-
ELEMENT_TO_COMPONENT.delete(this.element);
|
|
934
|
-
}
|
|
935
|
-
if (NODE_TO_G.get(this.element) === this._g) {
|
|
936
|
-
NODE_TO_G.delete(this.element);
|
|
937
|
-
}
|
|
938
|
-
if (NODE_TO_CONTAINER_G.get(this.element) === this._containerG) {
|
|
939
|
-
NODE_TO_CONTAINER_G.delete(this.element);
|
|
940
|
-
}
|
|
941
|
-
if (ELEMENT_TO_REF.get(this.element) === this.ref) {
|
|
942
|
-
ELEMENT_TO_REF.set(this.element, this.ref);
|
|
943
|
-
}
|
|
944
|
-
removeSelectedElement(this.board, this.element);
|
|
945
|
-
this.getContainerG().remove();
|
|
946
|
-
}
|
|
947
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.2.4", ngImport: i0, type: PlaitPluginElementComponent, deps: "invalid", target: i0.ɵɵFactoryTarget.Directive }); }
|
|
948
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.2.4", type: PlaitPluginElementComponent, inputs: { context: "context" }, ngImport: i0 }); }
|
|
949
|
-
}
|
|
950
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.2.4", ngImport: i0, type: PlaitPluginElementComponent, decorators: [{
|
|
951
|
-
type: Directive
|
|
952
|
-
}], ctorParameters: () => [{ type: undefined }], propDecorators: { context: [{
|
|
953
|
-
type: Input
|
|
954
|
-
}] } });
|
|
955
|
-
const ELEMENT_TO_COMPONENT = new WeakMap();
|
|
956
|
-
|
|
957
|
-
// https://stackoverflow.com/a/6853926/232122
|
|
958
|
-
function distanceBetweenPointAndSegment(x, y, x1, y1, x2, y2) {
|
|
959
|
-
const A = x - x1;
|
|
960
|
-
const B = y - y1;
|
|
961
|
-
const C = x2 - x1;
|
|
962
|
-
const D = y2 - y1;
|
|
963
|
-
const dot = A * C + B * D;
|
|
964
|
-
const lenSquare = C * C + D * D;
|
|
965
|
-
let param = -1;
|
|
966
|
-
if (lenSquare !== 0) {
|
|
967
|
-
// in case of 0 length line
|
|
968
|
-
param = dot / lenSquare;
|
|
969
|
-
}
|
|
970
|
-
let xx, yy;
|
|
971
|
-
if (param < 0) {
|
|
972
|
-
xx = x1;
|
|
973
|
-
yy = y1;
|
|
974
|
-
}
|
|
975
|
-
else if (param > 1) {
|
|
976
|
-
xx = x2;
|
|
977
|
-
yy = y2;
|
|
978
|
-
}
|
|
979
|
-
else {
|
|
980
|
-
xx = x1 + param * C;
|
|
981
|
-
yy = y1 + param * D;
|
|
982
|
-
}
|
|
983
|
-
const dx = x - xx;
|
|
984
|
-
const dy = y - yy;
|
|
985
|
-
return Math.hypot(dx, dy);
|
|
986
|
-
}
|
|
987
|
-
function getNearestPointBetweenPointAndSegment(point, linePoints) {
|
|
988
|
-
const x = point[0], y = point[1], x1 = linePoints[0][0], y1 = linePoints[0][1], x2 = linePoints[1][0], y2 = linePoints[1][1];
|
|
989
|
-
const A = x - x1;
|
|
990
|
-
const B = y - y1;
|
|
991
|
-
const C = x2 - x1;
|
|
992
|
-
const D = y2 - y1;
|
|
993
|
-
const dot = A * C + B * D;
|
|
994
|
-
const lenSquare = C * C + D * D;
|
|
995
|
-
let param = -1;
|
|
996
|
-
if (lenSquare !== 0) {
|
|
997
|
-
// in case of 0 length line
|
|
998
|
-
param = dot / lenSquare;
|
|
999
|
-
}
|
|
1000
|
-
let xx, yy;
|
|
1001
|
-
if (param < 0) {
|
|
1002
|
-
xx = x1;
|
|
1003
|
-
yy = y1;
|
|
1004
|
-
}
|
|
1005
|
-
else if (param > 1) {
|
|
1006
|
-
xx = x2;
|
|
1007
|
-
yy = y2;
|
|
1008
|
-
}
|
|
1009
|
-
else {
|
|
1010
|
-
xx = x1 + param * C;
|
|
1011
|
-
yy = y1 + param * D;
|
|
1012
|
-
}
|
|
1013
|
-
return [xx, yy];
|
|
1014
|
-
}
|
|
1015
|
-
function distanceBetweenPointAndSegments(points, point) {
|
|
1016
|
-
const len = points.length;
|
|
1017
|
-
let distance = Infinity;
|
|
1018
|
-
for (let i = 0; i < len - 1; i++) {
|
|
1019
|
-
const p = points[i];
|
|
1020
|
-
const p2 = points[i + 1];
|
|
1021
|
-
const currentDistance = distanceBetweenPointAndSegment(point[0], point[1], p[0], p[1], p2[0], p2[1]);
|
|
1022
|
-
if (currentDistance < distance) {
|
|
1023
|
-
distance = currentDistance;
|
|
1024
|
-
}
|
|
1025
|
-
}
|
|
1026
|
-
return distance;
|
|
1027
|
-
}
|
|
1028
|
-
function getNearestPointBetweenPointAndSegments(point, points, isClose = true) {
|
|
1029
|
-
const len = points.length;
|
|
1030
|
-
let distance = Infinity;
|
|
1031
|
-
let result = point;
|
|
1032
|
-
for (let i = 0; i < len; i++) {
|
|
1033
|
-
const p = points[i];
|
|
1034
|
-
if (i === len - 1 && !isClose)
|
|
1035
|
-
continue;
|
|
1036
|
-
const p2 = i === len - 1 ? points[0] : points[i + 1];
|
|
1037
|
-
const currentDistance = distanceBetweenPointAndSegment(point[0], point[1], p[0], p[1], p2[0], p2[1]);
|
|
1038
|
-
if (currentDistance < distance) {
|
|
1039
|
-
distance = currentDistance;
|
|
1040
|
-
result = getNearestPointBetweenPointAndSegment(point, [p, p2]);
|
|
1041
|
-
}
|
|
1042
|
-
}
|
|
1043
|
-
return result;
|
|
1044
|
-
}
|
|
1045
|
-
function getNearestPointBetweenPointAndEllipse(point, center, rx, ry, rotation = 0) {
|
|
1046
|
-
const rectangleClient = {
|
|
1047
|
-
x: center[0] - rx,
|
|
1048
|
-
y: center[1] - ry,
|
|
1049
|
-
height: ry * 2,
|
|
1050
|
-
width: rx * 2
|
|
1051
|
-
};
|
|
1052
|
-
// https://stackoverflow.com/a/46007540/232122
|
|
1053
|
-
const px = Math.abs(point[0] - rectangleClient.x - rectangleClient.width / 2);
|
|
1054
|
-
const py = Math.abs(point[1] - rectangleClient.y - rectangleClient.height / 2);
|
|
1055
|
-
let tx = 0.707;
|
|
1056
|
-
let ty = 0.707;
|
|
1057
|
-
const a = Math.abs(rectangleClient.width) / 2;
|
|
1058
|
-
const b = Math.abs(rectangleClient.height) / 2;
|
|
1059
|
-
[0, 1, 2, 3].forEach(x => {
|
|
1060
|
-
const xx = a * tx;
|
|
1061
|
-
const yy = b * ty;
|
|
1062
|
-
const ex = ((a * a - b * b) * tx ** 3) / a;
|
|
1063
|
-
const ey = ((b * b - a * a) * ty ** 3) / b;
|
|
1064
|
-
const rx = xx - ex;
|
|
1065
|
-
const ry = yy - ey;
|
|
1066
|
-
const qx = px - ex;
|
|
1067
|
-
const qy = py - ey;
|
|
1068
|
-
const r = Math.hypot(ry, rx);
|
|
1069
|
-
const q = Math.hypot(qy, qx);
|
|
1070
|
-
tx = Math.min(1, Math.max(0, ((qx * r) / q + ex) / a));
|
|
1071
|
-
ty = Math.min(1, Math.max(0, ((qy * r) / q + ey) / b));
|
|
1072
|
-
const t = Math.hypot(ty, tx);
|
|
1073
|
-
tx /= t;
|
|
1074
|
-
ty /= t;
|
|
1075
|
-
});
|
|
1076
|
-
const signX = point[0] > center[0] ? 1 : -1;
|
|
1077
|
-
const signY = point[1] > center[1] ? 1 : -1;
|
|
1078
|
-
return [center[0] + a * tx * signX, center[1] + b * ty * signY];
|
|
1079
|
-
}
|
|
1080
|
-
function rotate(x1, y1, x2, y2, angle) {
|
|
1081
|
-
// 𝑎′𝑥=(𝑎𝑥−𝑐𝑥)cos𝜃−(𝑎𝑦−𝑐𝑦)sin𝜃+𝑐𝑥
|
|
1082
|
-
// 𝑎′𝑦=(𝑎𝑥−𝑐𝑥)sin𝜃+(𝑎𝑦−𝑐𝑦)cos𝜃+𝑐𝑦.
|
|
1083
|
-
// https://math.stackexchange.com/questions/2204520/how-do-i-rotate-a-line-segment-in-a-specific-point-on-the-line
|
|
1084
|
-
return [(x1 - x2) * Math.cos(angle) - (y1 - y2) * Math.sin(angle) + x2, (x1 - x2) * Math.sin(angle) + (y1 - y2) * Math.cos(angle) + y2];
|
|
1085
|
-
}
|
|
1086
|
-
function distanceBetweenPointAndPoint(x1, y1, x2, y2) {
|
|
1087
|
-
const dx = x1 - x2;
|
|
1088
|
-
const dy = y1 - y2;
|
|
1089
|
-
return Math.hypot(dx, dy);
|
|
1090
|
-
}
|
|
1091
|
-
// https://stackoverflow.com/questions/5254838/calculating-distance-between-a-point-and-a-rectangular-box-nearest-point
|
|
1092
|
-
function distanceBetweenPointAndRectangle(x, y, rect) {
|
|
1093
|
-
var dx = Math.max(rect.x - x, 0, x - (rect.x + rect.width));
|
|
1094
|
-
var dy = Math.max(rect.y - y, 0, y - (rect.y + rect.height));
|
|
1095
|
-
return Math.sqrt(dx * dx + dy * dy);
|
|
1096
|
-
}
|
|
1097
|
-
const isLineHitLine = (a, b, c, d) => {
|
|
1098
|
-
const crossProduct = (v1, v2) => v1[0] * v2[1] - v1[1] * v2[0];
|
|
1099
|
-
const ab = [b[0] - a[0], b[1] - a[1]];
|
|
1100
|
-
const ac = [c[0] - a[0], c[1] - a[1]];
|
|
1101
|
-
const ad = [d[0] - a[0], d[1] - a[1]];
|
|
1102
|
-
const ca = [a[0] - c[0], a[1] - c[1]];
|
|
1103
|
-
const cb = [b[0] - c[0], b[1] - c[1]];
|
|
1104
|
-
const cd = [d[0] - c[0], d[1] - c[1]];
|
|
1105
|
-
return crossProduct(ab, ac) * crossProduct(ab, ad) <= 0 && crossProduct(cd, ca) * crossProduct(cd, cb) <= 0;
|
|
1106
|
-
};
|
|
1107
|
-
const isPolylineHitRectangle = (points, rectangle, isClose = true) => {
|
|
1108
|
-
const rectanglePoints = RectangleClient.getCornerPoints(rectangle);
|
|
1109
|
-
const len = points.length;
|
|
1110
|
-
for (let i = 0; i < len; i++) {
|
|
1111
|
-
if (i === len - 1 && !isClose)
|
|
1112
|
-
continue;
|
|
1113
|
-
const p1 = points[i];
|
|
1114
|
-
const p2 = points[(i + 1) % len];
|
|
1115
|
-
const isHit = isLineHitLine(p1, p2, rectanglePoints[0], rectanglePoints[1]) ||
|
|
1116
|
-
isLineHitLine(p1, p2, rectanglePoints[1], rectanglePoints[2]) ||
|
|
1117
|
-
isLineHitLine(p1, p2, rectanglePoints[2], rectanglePoints[3]) ||
|
|
1118
|
-
isLineHitLine(p1, p2, rectanglePoints[3], rectanglePoints[0]);
|
|
1119
|
-
if (isHit || isPointInPolygon(p1, rectanglePoints) || isPointInPolygon(p2, rectanglePoints)) {
|
|
1120
|
-
return true;
|
|
1121
|
-
}
|
|
1122
|
-
}
|
|
1123
|
-
return false;
|
|
1124
|
-
};
|
|
1125
|
-
//https://stackoverflow.com/questions/22521982/check-if-point-is-inside-a-polygon
|
|
1126
|
-
const isPointInPolygon = (point, points) => {
|
|
1127
|
-
// ray-casting algorithm based on
|
|
1128
|
-
// https://wrf.ecse.rpi.edu/Research/Short_Notes/pnpoly.html
|
|
1129
|
-
const x = point[0], y = point[1];
|
|
1130
|
-
let inside = false;
|
|
1131
|
-
for (var i = 0, j = points.length - 1; i < points.length; j = i++) {
|
|
1132
|
-
let xi = points[i][0], yi = points[i][1];
|
|
1133
|
-
let xj = points[j][0], yj = points[j][1];
|
|
1134
|
-
let intersect = yi > y != yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi) + xi;
|
|
1135
|
-
if (intersect)
|
|
1136
|
-
inside = !inside;
|
|
1137
|
-
}
|
|
1138
|
-
return inside;
|
|
1139
|
-
};
|
|
1140
|
-
const isPointInEllipse = (point, center, rx, ry, angle = 0) => {
|
|
1141
|
-
const cosAngle = Math.cos(angle);
|
|
1142
|
-
const sinAngle = Math.sin(angle);
|
|
1143
|
-
const x1 = (point[0] - center[0]) * cosAngle + (point[1] - center[1]) * sinAngle;
|
|
1144
|
-
const y1 = (point[1] - center[1]) * cosAngle - (point[0] - center[0]) * sinAngle;
|
|
1145
|
-
return (x1 * x1) / (rx * rx) + (y1 * y1) / (ry * ry) <= 1;
|
|
1146
|
-
};
|
|
1147
|
-
const isPointInRoundRectangle = (point, rectangle, radius, angle = 0) => {
|
|
1148
|
-
const { x: rectX, y: rectY, width, height } = rectangle;
|
|
1149
|
-
const isInRectangle = point[0] >= rectX && point[0] <= rectX + width && point[1] >= rectY && point[1] <= rectY + height;
|
|
1150
|
-
const handleLeftTop = point[0] >= rectX &&
|
|
1151
|
-
point[0] <= rectX + radius &&
|
|
1152
|
-
point[1] >= rectY &&
|
|
1153
|
-
point[1] <= rectY + radius &&
|
|
1154
|
-
Math.hypot(point[0] - (rectX + radius), point[1] - (rectY + radius)) > radius;
|
|
1155
|
-
const handleLeftBottom = point[0] >= rectX &&
|
|
1156
|
-
point[0] <= rectX + radius &&
|
|
1157
|
-
point[1] >= rectY + height &&
|
|
1158
|
-
point[1] <= rectY + height - radius &&
|
|
1159
|
-
Math.hypot(point[0] - (rectX + radius), point[1] - (rectY + height - radius)) > radius;
|
|
1160
|
-
const handleRightTop = point[0] >= rectX + width - radius &&
|
|
1161
|
-
point[0] <= rectX + width &&
|
|
1162
|
-
point[1] >= rectY &&
|
|
1163
|
-
point[1] <= rectY + radius &&
|
|
1164
|
-
Math.hypot(point[0] - (rectX + width - radius), point[1] - (rectY + radius)) > radius;
|
|
1165
|
-
const handleRightBottom = point[0] >= rectX + width - radius &&
|
|
1166
|
-
point[0] <= rectX + width &&
|
|
1167
|
-
point[1] >= rectY + height - radius &&
|
|
1168
|
-
point[1] <= rectY + height &&
|
|
1169
|
-
Math.hypot(point[0] - (rectX + width - radius), point[1] - (rectY + height - radius)) > radius;
|
|
1170
|
-
const isInCorner = handleLeftTop || handleLeftBottom || handleRightTop || handleRightBottom;
|
|
1171
|
-
return isInRectangle && !isInCorner;
|
|
1172
|
-
};
|
|
1173
|
-
// https://gist.github.com/nicholaswmin/c2661eb11cad5671d816
|
|
1174
|
-
const catmullRomFitting = function (points) {
|
|
1175
|
-
const alpha = 0.5;
|
|
1176
|
-
let p0, p1, p2, p3, bp1, bp2, d1, d2, d3, A, B, N, M;
|
|
1177
|
-
var d3powA, d2powA, d3pow2A, d2pow2A, d1pow2A, d1powA;
|
|
1178
|
-
const result = [];
|
|
1179
|
-
result.push([Math.round(points[0][0]), Math.round(points[0][1])]);
|
|
1180
|
-
var length = points.length;
|
|
1181
|
-
for (var i = 0; i < length - 1; i++) {
|
|
1182
|
-
p0 = i == 0 ? points[0] : points[i - 1];
|
|
1183
|
-
p1 = points[i];
|
|
1184
|
-
p2 = points[i + 1];
|
|
1185
|
-
p3 = i + 2 < length ? points[i + 2] : p2;
|
|
1186
|
-
d1 = Math.sqrt(Math.pow(p0[0] - p1[0], 2) + Math.pow(p0[1] - p1[1], 2));
|
|
1187
|
-
d2 = Math.sqrt(Math.pow(p1[0] - p2[0], 2) + Math.pow(p1[1] - p2[1], 2));
|
|
1188
|
-
d3 = Math.sqrt(Math.pow(p2[0] - p3[0], 2) + Math.pow(p2[1] - p3[1], 2));
|
|
1189
|
-
// Catmull-Rom to Cubic Bezier conversion matrix
|
|
1190
|
-
// A = 2d1^2a + 3d1^a * d2^a + d3^2a
|
|
1191
|
-
// B = 2d3^2a + 3d3^a * d2^a + d2^2a
|
|
1192
|
-
// [ 0 1 0 0 ]
|
|
1193
|
-
// [ -d2^2a /N A/N d1^2a /N 0 ]
|
|
1194
|
-
// [ 0 d3^2a /M B/M -d2^2a /M ]
|
|
1195
|
-
// [ 0 0 1 0 ]
|
|
1196
|
-
d3powA = Math.pow(d3, alpha);
|
|
1197
|
-
d3pow2A = Math.pow(d3, 2 * alpha);
|
|
1198
|
-
d2powA = Math.pow(d2, alpha);
|
|
1199
|
-
d2pow2A = Math.pow(d2, 2 * alpha);
|
|
1200
|
-
d1powA = Math.pow(d1, alpha);
|
|
1201
|
-
d1pow2A = Math.pow(d1, 2 * alpha);
|
|
1202
|
-
A = 2 * d1pow2A + 3 * d1powA * d2powA + d2pow2A;
|
|
1203
|
-
B = 2 * d3pow2A + 3 * d3powA * d2powA + d2pow2A;
|
|
1204
|
-
N = 3 * d1powA * (d1powA + d2powA);
|
|
1205
|
-
if (N > 0) {
|
|
1206
|
-
N = 1 / N;
|
|
1207
|
-
}
|
|
1208
|
-
M = 3 * d3powA * (d3powA + d2powA);
|
|
1209
|
-
if (M > 0) {
|
|
1210
|
-
M = 1 / M;
|
|
1211
|
-
}
|
|
1212
|
-
bp1 = [(-d2pow2A * p0[0] + A * p1[0] + d1pow2A * p2[0]) * N, (-d2pow2A * p0[1] + A * p1[1] + d1pow2A * p2[1]) * N];
|
|
1213
|
-
bp2 = [(d3pow2A * p1[0] + B * p2[0] - d2pow2A * p3[0]) * M, (d3pow2A * p1[1] + B * p2[1] - d2pow2A * p3[1]) * M];
|
|
1214
|
-
if (bp1[0] == 0 && bp1[1] == 0) {
|
|
1215
|
-
bp1 = p1;
|
|
1216
|
-
}
|
|
1217
|
-
if (bp2[0] == 0 && bp2[1] == 0) {
|
|
1218
|
-
bp2 = p2;
|
|
1219
|
-
}
|
|
1220
|
-
result.push(bp1, bp2, p2);
|
|
1221
|
-
}
|
|
1222
|
-
return result;
|
|
1223
|
-
};
|
|
1224
|
-
/**
|
|
1225
|
-
* the result of slope is based on Cartesian coordinate system
|
|
1226
|
-
* x, y are based on the position in the Cartesian coordinate system
|
|
1227
|
-
*/
|
|
1228
|
-
function getEllipseTangentSlope(x, y, a, b) {
|
|
1229
|
-
if (Math.abs(y) === 0) {
|
|
1230
|
-
return x > 0 ? -Infinity : Infinity;
|
|
1231
|
-
}
|
|
1232
|
-
const k = (-b * b * x) / (a * a * y);
|
|
1233
|
-
return k;
|
|
747
|
+
return rect;
|
|
1234
748
|
}
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
}
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
let vector = [1, -slope];
|
|
1246
|
-
if (y < 0) {
|
|
1247
|
-
vector = [-vector[0], -vector[1]];
|
|
1248
|
-
}
|
|
1249
|
-
return vector;
|
|
749
|
+
const setStrokeLinecap = (g, value) => {
|
|
750
|
+
g.setAttribute('stroke-linecap', value);
|
|
751
|
+
};
|
|
752
|
+
const setPathStrokeLinecap = (g, value) => {
|
|
753
|
+
g.querySelectorAll('path').forEach(path => {
|
|
754
|
+
path.setAttribute('stroke-linecap', value);
|
|
755
|
+
});
|
|
756
|
+
};
|
|
757
|
+
function createMask() {
|
|
758
|
+
return document.createElementNS(NS, 'mask');
|
|
1250
759
|
}
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
function toDomPrecision(v) {
|
|
1255
|
-
return +v.toFixed(4);
|
|
760
|
+
function createSVG() {
|
|
761
|
+
const svg = document.createElementNS(NS, 'svg');
|
|
762
|
+
return svg;
|
|
1256
763
|
}
|
|
1257
|
-
function
|
|
1258
|
-
|
|
764
|
+
function createText(x, y, fill, textContent) {
|
|
765
|
+
var text = document.createElementNS(NS, 'text');
|
|
766
|
+
text.setAttribute('x', `${x}`);
|
|
767
|
+
text.setAttribute('y', `${y}`);
|
|
768
|
+
text.setAttribute('fill', fill);
|
|
769
|
+
text.textContent = textContent;
|
|
770
|
+
return text;
|
|
1259
771
|
}
|
|
1260
772
|
/**
|
|
1261
|
-
*
|
|
1262
|
-
*
|
|
1263
|
-
* @param a - The first point.
|
|
1264
|
-
* @param b - The second point.
|
|
1265
|
-
* @public
|
|
773
|
+
* Check if a DOM node is an element node.
|
|
1266
774
|
*/
|
|
1267
|
-
|
|
1268
|
-
return
|
|
1269
|
-
}
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
endPoint[1] -= cy;
|
|
1282
|
-
// Calculate the quadratic parameters.
|
|
1283
|
-
var A = ((endPoint[0] - startPoint[0]) * (endPoint[0] - startPoint[0])) / rx / rx +
|
|
1284
|
-
((endPoint[1] - startPoint[1]) * (endPoint[1] - startPoint[1])) / ry / ry;
|
|
1285
|
-
var B = (2 * startPoint[0] * (endPoint[0] - startPoint[0])) / rx / rx + (2 * startPoint[1] * (endPoint[1] - startPoint[1])) / ry / ry;
|
|
1286
|
-
var C = (startPoint[0] * startPoint[0]) / rx / rx + (startPoint[1] * startPoint[1]) / ry / ry - 1;
|
|
1287
|
-
// Make a list of t values (normalized points on the line where intersections occur).
|
|
1288
|
-
var tValues = [];
|
|
1289
|
-
// Calculate the discriminant.
|
|
1290
|
-
var discriminant = B * B - 4 * A * C;
|
|
1291
|
-
if (discriminant === 0) {
|
|
1292
|
-
// One real solution.
|
|
1293
|
-
tValues.push(-B / 2 / A);
|
|
1294
|
-
}
|
|
1295
|
-
else if (discriminant > 0) {
|
|
1296
|
-
// Two real solutions.
|
|
1297
|
-
tValues.push((-B + Math.sqrt(discriminant)) / 2 / A);
|
|
1298
|
-
tValues.push((-B - Math.sqrt(discriminant)) / 2 / A);
|
|
1299
|
-
}
|
|
1300
|
-
return (tValues
|
|
1301
|
-
// Filter to only points that are on the segment.
|
|
1302
|
-
.filter(t => !segment_only || (t >= 0 && t <= 1))
|
|
1303
|
-
// Solve for points.
|
|
1304
|
-
.map(t => [startPoint[0] + (endPoint[0] - startPoint[0]) * t + cx, startPoint[1] + (endPoint[1] - startPoint[1]) * t + cy]));
|
|
1305
|
-
}
|
|
1306
|
-
|
|
1307
|
-
function isInPlaitBoard(board, x, y) {
|
|
1308
|
-
const plaitBoardElement = PlaitBoard.getBoardContainer(board);
|
|
1309
|
-
const plaitBoardRect = plaitBoardElement.getBoundingClientRect();
|
|
1310
|
-
const distances = distanceBetweenPointAndRectangle(x, y, plaitBoardRect);
|
|
1311
|
-
return distances === 0;
|
|
1312
|
-
}
|
|
1313
|
-
function getRealScrollBarWidth(board) {
|
|
1314
|
-
const { hideScrollbar } = board.options;
|
|
1315
|
-
let scrollBarWidth = 0;
|
|
1316
|
-
if (!hideScrollbar) {
|
|
1317
|
-
const viewportContainer = PlaitBoard.getViewportContainer(board);
|
|
1318
|
-
scrollBarWidth = viewportContainer.offsetWidth - viewportContainer.clientWidth;
|
|
775
|
+
const isDOMElement = (value) => {
|
|
776
|
+
return isDOMNode(value) && value.nodeType === 1;
|
|
777
|
+
};
|
|
778
|
+
/**
|
|
779
|
+
* Check if a value is a DOM node.
|
|
780
|
+
*/
|
|
781
|
+
const isDOMNode = (value) => {
|
|
782
|
+
return value instanceof window.Node;
|
|
783
|
+
};
|
|
784
|
+
const hasInputOrTextareaTarget = (target) => {
|
|
785
|
+
if (isDOMElement(target)) {
|
|
786
|
+
if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA') {
|
|
787
|
+
return true;
|
|
788
|
+
}
|
|
1319
789
|
}
|
|
1320
|
-
return
|
|
1321
|
-
}
|
|
790
|
+
return false;
|
|
791
|
+
};
|
|
792
|
+
const isSecondaryPointer = (event) => {
|
|
793
|
+
return event.button === POINTER_BUTTON.SECONDARY;
|
|
794
|
+
};
|
|
795
|
+
const isMainPointer = (event) => {
|
|
796
|
+
return event.button === POINTER_BUTTON.MAIN;
|
|
797
|
+
};
|
|
1322
798
|
|
|
1323
799
|
function createForeignObject(x, y, width, height) {
|
|
1324
800
|
var newForeignObject = document.createElementNS(NS, 'foreignObject');
|
|
@@ -1602,8 +1078,178 @@ function idCreator(length = 5) {
|
|
|
1602
1078
|
for (let i = 0; i < length; i++) {
|
|
1603
1079
|
key += $chars.charAt(Math.floor(Math.random() * maxPosition));
|
|
1604
1080
|
}
|
|
1605
|
-
return key;
|
|
1606
|
-
}
|
|
1081
|
+
return key;
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
function depthFirstRecursion(node, callback, recursion, isReverse) {
|
|
1085
|
+
if (!recursion || recursion(node)) {
|
|
1086
|
+
let children = [];
|
|
1087
|
+
if (node.children) {
|
|
1088
|
+
children = [...node.children];
|
|
1089
|
+
}
|
|
1090
|
+
children = isReverse ? children.reverse() : children;
|
|
1091
|
+
children.forEach(child => {
|
|
1092
|
+
depthFirstRecursion(child, callback, recursion);
|
|
1093
|
+
});
|
|
1094
|
+
}
|
|
1095
|
+
callback(node);
|
|
1096
|
+
}
|
|
1097
|
+
const getIsRecursionFunc = (board) => {
|
|
1098
|
+
return (element) => {
|
|
1099
|
+
if (PlaitBoard.isBoard(element) || board.isRecursion(element)) {
|
|
1100
|
+
return true;
|
|
1101
|
+
}
|
|
1102
|
+
else {
|
|
1103
|
+
return false;
|
|
1104
|
+
}
|
|
1105
|
+
};
|
|
1106
|
+
};
|
|
1107
|
+
|
|
1108
|
+
const SELECTION_BORDER_COLOR = '#6698FF';
|
|
1109
|
+
const SELECTION_FILL_COLOR = '#6698FF25'; // opacity 0.25
|
|
1110
|
+
const Selection = {
|
|
1111
|
+
isCollapsed(selection) {
|
|
1112
|
+
if (selection.anchor[0] == selection.focus[0] && selection.anchor[1] === selection.focus[1]) {
|
|
1113
|
+
return true;
|
|
1114
|
+
}
|
|
1115
|
+
else {
|
|
1116
|
+
return false;
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
};
|
|
1120
|
+
|
|
1121
|
+
const sortElements = (board, elements, ascendingOrder = true) => {
|
|
1122
|
+
return [...elements].sort((a, b) => {
|
|
1123
|
+
const pathA = PlaitBoard.findPath(board, a);
|
|
1124
|
+
const pathB = PlaitBoard.findPath(board, b);
|
|
1125
|
+
return ascendingOrder ? pathA[0] - pathB[0] : pathB[0] - pathA[0];
|
|
1126
|
+
});
|
|
1127
|
+
};
|
|
1128
|
+
|
|
1129
|
+
var PlaitPluginKey;
|
|
1130
|
+
(function (PlaitPluginKey) {
|
|
1131
|
+
PlaitPluginKey["withSelection"] = "withSelection";
|
|
1132
|
+
})(PlaitPluginKey || (PlaitPluginKey = {}));
|
|
1133
|
+
|
|
1134
|
+
const getHitElementsBySelection = (board, selection, match = () => true) => {
|
|
1135
|
+
const newSelection = selection || board.selection;
|
|
1136
|
+
const rectangleHitElements = [];
|
|
1137
|
+
if (!newSelection) {
|
|
1138
|
+
return [];
|
|
1139
|
+
}
|
|
1140
|
+
const isCollapsed = Selection.isCollapsed(newSelection);
|
|
1141
|
+
if (isCollapsed) {
|
|
1142
|
+
const hitElement = getHitElementByPoint(board, newSelection.anchor, match);
|
|
1143
|
+
if (hitElement) {
|
|
1144
|
+
return [hitElement];
|
|
1145
|
+
}
|
|
1146
|
+
else {
|
|
1147
|
+
return [];
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
depthFirstRecursion(board, node => {
|
|
1151
|
+
if (!PlaitBoard.isBoard(node) && match(node) && board.isRectangleHit(node, newSelection)) {
|
|
1152
|
+
rectangleHitElements.push(node);
|
|
1153
|
+
}
|
|
1154
|
+
}, getIsRecursionFunc(board), true);
|
|
1155
|
+
return rectangleHitElements;
|
|
1156
|
+
};
|
|
1157
|
+
const getHitElementByPoint = (board, point, match = () => true) => {
|
|
1158
|
+
let hitElement = undefined;
|
|
1159
|
+
let hitInsideElement = undefined;
|
|
1160
|
+
depthFirstRecursion(board, node => {
|
|
1161
|
+
if (hitElement) {
|
|
1162
|
+
return;
|
|
1163
|
+
}
|
|
1164
|
+
if (PlaitBoard.isBoard(node) || !match(node) || !PlaitElement.hasMounted(node)) {
|
|
1165
|
+
return;
|
|
1166
|
+
}
|
|
1167
|
+
if (board.isHit(node, point)) {
|
|
1168
|
+
hitElement = node;
|
|
1169
|
+
return;
|
|
1170
|
+
}
|
|
1171
|
+
/**
|
|
1172
|
+
* 需要增加场景测试
|
|
1173
|
+
* hitInsideElement 存的是第一个符合 isInsidePoint 的元素
|
|
1174
|
+
* 当有元素符合 isHit 时结束遍历,并返回 hitElement
|
|
1175
|
+
* 当所有元素都不符合 isHit ,则返回第一个符合 isInsidePoint 的元素
|
|
1176
|
+
* 这样保证最上面的元素优先被探测到;
|
|
1177
|
+
*/
|
|
1178
|
+
if (!hitInsideElement && board.isInsidePoint(node, point)) {
|
|
1179
|
+
hitInsideElement = node;
|
|
1180
|
+
}
|
|
1181
|
+
}, getIsRecursionFunc(board), true);
|
|
1182
|
+
return hitElement || hitInsideElement;
|
|
1183
|
+
};
|
|
1184
|
+
const getHitSelectedElements = (board, point) => {
|
|
1185
|
+
const selectedElements = getSelectedElements(board);
|
|
1186
|
+
const targetRectangle = selectedElements.length > 0 && getRectangleByElements(board, selectedElements, false);
|
|
1187
|
+
const isInTargetRectangle = targetRectangle && RectangleClient.isPointInRectangle(targetRectangle, point);
|
|
1188
|
+
if (isInTargetRectangle) {
|
|
1189
|
+
return selectedElements;
|
|
1190
|
+
}
|
|
1191
|
+
else {
|
|
1192
|
+
return [];
|
|
1193
|
+
}
|
|
1194
|
+
};
|
|
1195
|
+
const cacheSelectedElements = (board, selectedElements) => {
|
|
1196
|
+
const sortedElements = sortElements(board, selectedElements);
|
|
1197
|
+
BOARD_TO_SELECTED_ELEMENT.set(board, sortedElements);
|
|
1198
|
+
};
|
|
1199
|
+
const getSelectedElements = (board) => {
|
|
1200
|
+
return BOARD_TO_SELECTED_ELEMENT.get(board) || [];
|
|
1201
|
+
};
|
|
1202
|
+
const addSelectedElement = (board, element) => {
|
|
1203
|
+
let elements = [];
|
|
1204
|
+
if (Array.isArray(element)) {
|
|
1205
|
+
elements.push(...element);
|
|
1206
|
+
}
|
|
1207
|
+
else {
|
|
1208
|
+
elements.push(element);
|
|
1209
|
+
}
|
|
1210
|
+
const selectedElements = getSelectedElements(board);
|
|
1211
|
+
cacheSelectedElements(board, [...selectedElements, ...elements]);
|
|
1212
|
+
};
|
|
1213
|
+
const removeSelectedElement = (board, element, isRemoveChildren = false) => {
|
|
1214
|
+
const selectedElements = getSelectedElements(board);
|
|
1215
|
+
if (selectedElements.includes(element)) {
|
|
1216
|
+
const targetElements = [];
|
|
1217
|
+
if (board.isRecursion(element) && isRemoveChildren) {
|
|
1218
|
+
depthFirstRecursion(element, node => {
|
|
1219
|
+
targetElements.push(node);
|
|
1220
|
+
}, node => board.isRecursion(node));
|
|
1221
|
+
}
|
|
1222
|
+
else {
|
|
1223
|
+
targetElements.push(element);
|
|
1224
|
+
}
|
|
1225
|
+
const newSelectedElements = selectedElements.filter(value => !targetElements.includes(value));
|
|
1226
|
+
cacheSelectedElements(board, newSelectedElements);
|
|
1227
|
+
}
|
|
1228
|
+
};
|
|
1229
|
+
const clearSelectedElement = (board) => {
|
|
1230
|
+
cacheSelectedElements(board, []);
|
|
1231
|
+
};
|
|
1232
|
+
const isSelectedElement = (board, element) => {
|
|
1233
|
+
const selectedElements = getSelectedElements(board);
|
|
1234
|
+
return !!selectedElements.find(value => value === element);
|
|
1235
|
+
};
|
|
1236
|
+
const temporaryDisableSelection = (board) => {
|
|
1237
|
+
const currentOptions = board.getPluginOptions(PlaitPluginKey.withSelection);
|
|
1238
|
+
board.setPluginOptions(PlaitPluginKey.withSelection, {
|
|
1239
|
+
isDisabledSelect: true
|
|
1240
|
+
});
|
|
1241
|
+
setTimeout(() => {
|
|
1242
|
+
board.setPluginOptions(PlaitPluginKey.withSelection, { ...currentOptions });
|
|
1243
|
+
}, 0);
|
|
1244
|
+
};
|
|
1245
|
+
const isHitSelectedRectangle = (board, point) => {
|
|
1246
|
+
const hitSelectedElements = getHitSelectedElements(board, point);
|
|
1247
|
+
return hitSelectedElements.length > 0;
|
|
1248
|
+
};
|
|
1249
|
+
const isHitElement = (board, point) => {
|
|
1250
|
+
const hitElement = getHitElementByPoint(board, point);
|
|
1251
|
+
return !!hitElement || isHitSelectedRectangle(board, point);
|
|
1252
|
+
};
|
|
1607
1253
|
|
|
1608
1254
|
/**
|
|
1609
1255
|
* drawRoundRectangle
|
|
@@ -3344,14 +2990,14 @@ const rotatePoints = (points, centerPoint, angle) => {
|
|
|
3344
2990
|
}
|
|
3345
2991
|
else {
|
|
3346
2992
|
return points.map(point => {
|
|
3347
|
-
return rotate(point[0], point[1], centerPoint[0], centerPoint[1], angle);
|
|
2993
|
+
return rotate(point[0], point[1], centerPoint[0], centerPoint[1], angle || 0);
|
|
3348
2994
|
});
|
|
3349
2995
|
}
|
|
3350
2996
|
};
|
|
3351
2997
|
const getSelectionAngle = (elements) => {
|
|
3352
2998
|
let angle = elements[0]?.angle || 0;
|
|
3353
2999
|
elements.forEach(item => {
|
|
3354
|
-
if (item.angle !== angle && !approximately((item.angle % (Math.PI / 2)) - (angle % (Math.PI / 2)), 0)) {
|
|
3000
|
+
if (item.angle !== angle && !approximately(((item.angle || 0) % (Math.PI / 2)) - (angle % (Math.PI / 2)), 0)) {
|
|
3355
3001
|
angle = 0;
|
|
3356
3002
|
}
|
|
3357
3003
|
});
|
|
@@ -3408,7 +3054,7 @@ const rotateAntiPointsByElement = (points, element) => {
|
|
|
3408
3054
|
if (hasValidAngle(element)) {
|
|
3409
3055
|
let rectangle = RectangleClient.getRectangleByPoints(element.points);
|
|
3410
3056
|
const centerPoint = RectangleClient.getCenterPoint(rectangle);
|
|
3411
|
-
return rotatePoints(points, centerPoint, -element.angle);
|
|
3057
|
+
return rotatePoints(points, centerPoint, element.angle ? -element.angle : 0);
|
|
3412
3058
|
}
|
|
3413
3059
|
else {
|
|
3414
3060
|
return null;
|
|
@@ -3420,9 +3066,7 @@ const getRectangleByAngle = (rectangle, angle) => {
|
|
|
3420
3066
|
const centerPoint = RectangleClient.getCenterPoint(rectangle);
|
|
3421
3067
|
return RectangleClient.getRectangleByPoints(rotatePoints(cornerPoints, centerPoint, angle));
|
|
3422
3068
|
}
|
|
3423
|
-
|
|
3424
|
-
return null;
|
|
3425
|
-
}
|
|
3069
|
+
return rectangle;
|
|
3426
3070
|
};
|
|
3427
3071
|
const isAxisChangedByAngle = (angle) => {
|
|
3428
3072
|
const unitAngle = Math.abs(angle) % Math.PI;
|
|
@@ -3441,7 +3085,7 @@ function rotateElements(board, elements, angle) {
|
|
|
3441
3085
|
const originAngle = item.angle;
|
|
3442
3086
|
const points = rotatedDataPoints(item.points, selectionCenterPoint, normalizeAngle(angle));
|
|
3443
3087
|
const path = PlaitBoard.findPath(board, item);
|
|
3444
|
-
Transforms.setNode(board, { points, angle: normalizeAngle(originAngle + angle) }, path);
|
|
3088
|
+
Transforms.setNode(board, { points, angle: normalizeAngle((originAngle || 0) + angle) }, path);
|
|
3445
3089
|
});
|
|
3446
3090
|
}
|
|
3447
3091
|
const normalizeAngle = (angle) => {
|
|
@@ -3871,7 +3515,10 @@ function getSnapRectangles(board, activeElements) {
|
|
|
3871
3515
|
recursion: () => true,
|
|
3872
3516
|
isReverse: false
|
|
3873
3517
|
});
|
|
3874
|
-
return elements.map(item =>
|
|
3518
|
+
return elements.map(item => {
|
|
3519
|
+
const rectangle = board.getRectangle(item);
|
|
3520
|
+
return getRectangleByAngle(rectangle, item.angle || 0);
|
|
3521
|
+
});
|
|
3875
3522
|
}
|
|
3876
3523
|
function getBarPoint(point, isHorizontal) {
|
|
3877
3524
|
return isHorizontal
|
|
@@ -4077,9 +3724,6 @@ const PlaitElement = {
|
|
|
4077
3724
|
return false;
|
|
4078
3725
|
}
|
|
4079
3726
|
},
|
|
4080
|
-
getComponent(value) {
|
|
4081
|
-
return ELEMENT_TO_COMPONENT.get(value);
|
|
4082
|
-
},
|
|
4083
3727
|
getElementRef(value) {
|
|
4084
3728
|
return ELEMENT_TO_REF.get(value);
|
|
4085
3729
|
},
|
|
@@ -4332,6 +3976,11 @@ function getRectangleByElements(board, elements, recursion) {
|
|
|
4332
3976
|
};
|
|
4333
3977
|
}
|
|
4334
3978
|
}
|
|
3979
|
+
function getBoundingRectangleByElements(board, elements, recursion) {
|
|
3980
|
+
const rectangle = getRectangleByElements(board, elements, recursion);
|
|
3981
|
+
const angle = getSelectionAngle(elements);
|
|
3982
|
+
return getRectangleByAngle(rectangle, angle);
|
|
3983
|
+
}
|
|
4335
3984
|
function getBoardRectangle(board) {
|
|
4336
3985
|
return getRectangleByElements(board, board.children, true);
|
|
4337
3986
|
}
|
|
@@ -4399,6 +4048,9 @@ const PlaitBoard = {
|
|
|
4399
4048
|
getHost(board) {
|
|
4400
4049
|
return BOARD_TO_HOST.get(board);
|
|
4401
4050
|
},
|
|
4051
|
+
getElementLowerHost(board) {
|
|
4052
|
+
return BOARD_TO_ELEMENT_HOST.get(board)?.lowerHost;
|
|
4053
|
+
},
|
|
4402
4054
|
getElementHost(board) {
|
|
4403
4055
|
return BOARD_TO_ELEMENT_HOST.get(board)?.host;
|
|
4404
4056
|
},
|
|
@@ -4414,6 +4066,9 @@ const PlaitBoard = {
|
|
|
4414
4066
|
getComponent(board) {
|
|
4415
4067
|
return BOARD_TO_COMPONENT.get(board);
|
|
4416
4068
|
},
|
|
4069
|
+
getViewContainerRef(board) {
|
|
4070
|
+
return BOARD_TO_COMPONENT.get(board).viewContainerRef;
|
|
4071
|
+
},
|
|
4417
4072
|
getBoardContainer(board) {
|
|
4418
4073
|
return BOARD_TO_ELEMENT_HOST.get(board)?.container;
|
|
4419
4074
|
},
|
|
@@ -4764,10 +4419,7 @@ function withSelection(board) {
|
|
|
4764
4419
|
event.preventDefault();
|
|
4765
4420
|
}
|
|
4766
4421
|
const point = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
|
|
4767
|
-
const
|
|
4768
|
-
const hitElement = getHitElementByPoint(board, point);
|
|
4769
|
-
const hitSelectedElements = selectedElements.length > 1 ? getHitSelectedElements(board, point) : [];
|
|
4770
|
-
const isHitTarget = hitElement || hitSelectedElements.length > 0;
|
|
4422
|
+
const isHitTarget = isHitElement(board, point);
|
|
4771
4423
|
const options = board.getPluginOptions(PlaitPluginKey.withSelection);
|
|
4772
4424
|
if (PlaitBoard.isPointer(board, PlaitPointerType.selection) && !isHitTarget && options.isMultiple && !options.isDisabledSelect) {
|
|
4773
4425
|
preventTouchMove(board, event, true);
|
|
@@ -5272,7 +4924,7 @@ function withMoving(board) {
|
|
|
5272
4924
|
x: activeElementsRectangle.x + offsetX,
|
|
5273
4925
|
y: activeElementsRectangle.y + offsetY
|
|
5274
4926
|
};
|
|
5275
|
-
const activeRectangle = getRectangleByAngle(newRectangle, getSelectionAngle(activeElements))
|
|
4927
|
+
const activeRectangle = getRectangleByAngle(newRectangle, getSelectionAngle(activeElements));
|
|
5276
4928
|
const ref = getSnapMovingRef(board, activeRectangle, activeElements);
|
|
5277
4929
|
offsetX += ref.deltaX;
|
|
5278
4930
|
offsetY += ref.deltaY;
|
|
@@ -5467,10 +5119,10 @@ class PlaitIslandBaseComponent {
|
|
|
5467
5119
|
markForCheck() {
|
|
5468
5120
|
this.cdr.markForCheck();
|
|
5469
5121
|
}
|
|
5470
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.
|
|
5471
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.
|
|
5122
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.1", ngImport: i0, type: PlaitIslandBaseComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
5123
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.1", type: PlaitIslandBaseComponent, host: { classAttribute: "plait-island-container" }, ngImport: i0 }); }
|
|
5472
5124
|
}
|
|
5473
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.
|
|
5125
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.1", ngImport: i0, type: PlaitIslandBaseComponent, decorators: [{
|
|
5474
5126
|
type: Directive,
|
|
5475
5127
|
args: [{
|
|
5476
5128
|
host: {
|
|
@@ -5503,10 +5155,10 @@ class PlaitIslandPopoverBaseComponent {
|
|
|
5503
5155
|
this.subscription?.unsubscribe();
|
|
5504
5156
|
this.islandOnDestroy();
|
|
5505
5157
|
}
|
|
5506
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.
|
|
5507
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.
|
|
5158
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.1", ngImport: i0, type: PlaitIslandPopoverBaseComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
5159
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.1", type: PlaitIslandPopoverBaseComponent, inputs: { board: "board" }, host: { classAttribute: "plait-island-popover-container" }, ngImport: i0 }); }
|
|
5508
5160
|
}
|
|
5509
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.
|
|
5161
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.1", ngImport: i0, type: PlaitIslandPopoverBaseComponent, decorators: [{
|
|
5510
5162
|
type: Directive,
|
|
5511
5163
|
args: [{
|
|
5512
5164
|
host: {
|
|
@@ -5584,92 +5236,299 @@ const withHotkey = (board) => {
|
|
|
5584
5236
|
event.preventDefault();
|
|
5585
5237
|
deleteFragment(board);
|
|
5586
5238
|
}
|
|
5587
|
-
keyDown(event);
|
|
5588
|
-
};
|
|
5589
|
-
board.keyUp = (event) => {
|
|
5590
|
-
keyUp(event);
|
|
5591
|
-
};
|
|
5592
|
-
board.globalKeyDown = (event) => {
|
|
5593
|
-
if (PlaitBoard.getMovingPointInBoard(board) || PlaitBoard.isMovingPointInBoard(board)) {
|
|
5594
|
-
if (isHotkey(['mod+=', 'mod++'], { byKey: true })(event)) {
|
|
5595
|
-
event.preventDefault();
|
|
5596
|
-
BoardTransforms.updateZoom(board, board.viewport.zoom + 0.1, false);
|
|
5597
|
-
return;
|
|
5598
|
-
}
|
|
5599
|
-
if (isHotkey(['mod+shift+=', 'mod+shift++'], { byKey: true })(event)) {
|
|
5600
|
-
event.preventDefault();
|
|
5601
|
-
BoardTransforms.fitViewport(board);
|
|
5602
|
-
return;
|
|
5603
|
-
}
|
|
5604
|
-
if (isHotkey(['mod+-', 'mod+shift+-'])(event)) {
|
|
5605
|
-
event.preventDefault();
|
|
5606
|
-
BoardTransforms.updateZoom(board, board.viewport.zoom - 0.1);
|
|
5607
|
-
return;
|
|
5239
|
+
keyDown(event);
|
|
5240
|
+
};
|
|
5241
|
+
board.keyUp = (event) => {
|
|
5242
|
+
keyUp(event);
|
|
5243
|
+
};
|
|
5244
|
+
board.globalKeyDown = (event) => {
|
|
5245
|
+
if (PlaitBoard.getMovingPointInBoard(board) || PlaitBoard.isMovingPointInBoard(board)) {
|
|
5246
|
+
if (isHotkey(['mod+=', 'mod++'], { byKey: true })(event)) {
|
|
5247
|
+
event.preventDefault();
|
|
5248
|
+
BoardTransforms.updateZoom(board, board.viewport.zoom + 0.1, false);
|
|
5249
|
+
return;
|
|
5250
|
+
}
|
|
5251
|
+
if (isHotkey(['mod+shift+=', 'mod+shift++'], { byKey: true })(event)) {
|
|
5252
|
+
event.preventDefault();
|
|
5253
|
+
BoardTransforms.fitViewport(board);
|
|
5254
|
+
return;
|
|
5255
|
+
}
|
|
5256
|
+
if (isHotkey(['mod+-', 'mod+shift+-'])(event)) {
|
|
5257
|
+
event.preventDefault();
|
|
5258
|
+
BoardTransforms.updateZoom(board, board.viewport.zoom - 0.1);
|
|
5259
|
+
return;
|
|
5260
|
+
}
|
|
5261
|
+
if (isHotkey(['mod+0', 'mod+shift+0'], { byKey: true })(event)) {
|
|
5262
|
+
event.preventDefault();
|
|
5263
|
+
BoardTransforms.updateZoom(board, 1);
|
|
5264
|
+
return;
|
|
5265
|
+
}
|
|
5266
|
+
}
|
|
5267
|
+
globalKeyDown(event);
|
|
5268
|
+
};
|
|
5269
|
+
return board;
|
|
5270
|
+
};
|
|
5271
|
+
|
|
5272
|
+
class PlaitContextService {
|
|
5273
|
+
constructor() {
|
|
5274
|
+
this._stable = new Subject();
|
|
5275
|
+
this.uploadingFiles = [];
|
|
5276
|
+
}
|
|
5277
|
+
getUploadingFile(url) {
|
|
5278
|
+
return this.uploadingFiles.find(file => file.url === url);
|
|
5279
|
+
}
|
|
5280
|
+
setUploadingFile(file) {
|
|
5281
|
+
return this.uploadingFiles.push(file);
|
|
5282
|
+
}
|
|
5283
|
+
removeUploadingFile(fileEntry) {
|
|
5284
|
+
this.uploadingFiles = this.uploadingFiles.filter(file => file.url !== fileEntry.url);
|
|
5285
|
+
}
|
|
5286
|
+
onStable() {
|
|
5287
|
+
return this._stable.asObservable();
|
|
5288
|
+
}
|
|
5289
|
+
nextStable() {
|
|
5290
|
+
this._stable.next('');
|
|
5291
|
+
}
|
|
5292
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.1", ngImport: i0, type: PlaitContextService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
5293
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.1", ngImport: i0, type: PlaitContextService }); }
|
|
5294
|
+
}
|
|
5295
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.1", ngImport: i0, type: PlaitContextService, decorators: [{
|
|
5296
|
+
type: Injectable
|
|
5297
|
+
}] });
|
|
5298
|
+
|
|
5299
|
+
function withRelatedFragment(board) {
|
|
5300
|
+
const { buildFragment } = board;
|
|
5301
|
+
board.buildFragment = (clipboardContext, rectangle, operationType, originData) => {
|
|
5302
|
+
let relatedFragment = board.getRelatedFragment(originData || []);
|
|
5303
|
+
if (relatedFragment) {
|
|
5304
|
+
if (originData?.length) {
|
|
5305
|
+
relatedFragment = relatedFragment.filter(item => !originData.map(element => element.id).includes(item.id));
|
|
5306
|
+
}
|
|
5307
|
+
if (relatedFragment.length) {
|
|
5308
|
+
if (!clipboardContext) {
|
|
5309
|
+
clipboardContext = createClipboardContext(WritableClipboardType.elements, relatedFragment, '');
|
|
5310
|
+
}
|
|
5311
|
+
else {
|
|
5312
|
+
clipboardContext = addClipboardContext(clipboardContext, {
|
|
5313
|
+
text: '',
|
|
5314
|
+
type: WritableClipboardType.elements,
|
|
5315
|
+
elements: relatedFragment
|
|
5316
|
+
});
|
|
5317
|
+
}
|
|
5318
|
+
}
|
|
5319
|
+
}
|
|
5320
|
+
return buildFragment(clipboardContext, rectangle, operationType, originData);
|
|
5321
|
+
};
|
|
5322
|
+
return board;
|
|
5323
|
+
}
|
|
5324
|
+
|
|
5325
|
+
class ListRender {
|
|
5326
|
+
constructor(board) {
|
|
5327
|
+
this.board = board;
|
|
5328
|
+
this.children = [];
|
|
5329
|
+
this.instances = [];
|
|
5330
|
+
this.contexts = [];
|
|
5331
|
+
this.differ = null;
|
|
5332
|
+
this.initialized = false;
|
|
5333
|
+
}
|
|
5334
|
+
initialize(children, childrenContext) {
|
|
5335
|
+
this.initialized = true;
|
|
5336
|
+
this.children = children;
|
|
5337
|
+
children.forEach((descendant, index) => {
|
|
5338
|
+
NODE_TO_INDEX.set(descendant, index);
|
|
5339
|
+
NODE_TO_PARENT.set(descendant, childrenContext.parent);
|
|
5340
|
+
const context = getContext(this.board, descendant, index, childrenContext.parent);
|
|
5341
|
+
const componentType = getComponentType(this.board, context);
|
|
5342
|
+
const instance = createPluginComponent(this.board, componentType, context, childrenContext);
|
|
5343
|
+
this.instances.push(instance);
|
|
5344
|
+
this.contexts.push(context);
|
|
5345
|
+
});
|
|
5346
|
+
const newDiffers = PlaitBoard.getViewContainerRef(this.board).injector.get(IterableDiffers);
|
|
5347
|
+
this.differ = newDiffers.find(children).create(trackBy);
|
|
5348
|
+
this.differ.diff(children);
|
|
5349
|
+
}
|
|
5350
|
+
update(children, childrenContext) {
|
|
5351
|
+
if (!this.initialized) {
|
|
5352
|
+
this.initialize(children, childrenContext);
|
|
5353
|
+
return;
|
|
5354
|
+
}
|
|
5355
|
+
if (!this.differ) {
|
|
5356
|
+
throw new Error('Exception: Can not find differ ');
|
|
5357
|
+
}
|
|
5358
|
+
const { board, parent } = childrenContext;
|
|
5359
|
+
const diffResult = this.differ.diff(children);
|
|
5360
|
+
if (diffResult) {
|
|
5361
|
+
const newContexts = [];
|
|
5362
|
+
const newInstances = [];
|
|
5363
|
+
let currentIndexForFirstElement = null;
|
|
5364
|
+
diffResult.forEachItem((record) => {
|
|
5365
|
+
NODE_TO_INDEX.set(record.item, record.currentIndex);
|
|
5366
|
+
NODE_TO_PARENT.set(record.item, childrenContext.parent);
|
|
5367
|
+
const previousContext = record.previousIndex === null ? undefined : this.contexts[record.previousIndex];
|
|
5368
|
+
const context = getContext(board, record.item, record.currentIndex, parent, previousContext);
|
|
5369
|
+
if (record.previousIndex === null) {
|
|
5370
|
+
const componentType = getComponentType(board, context);
|
|
5371
|
+
const componentRef = createPluginComponent(board, componentType, context, childrenContext);
|
|
5372
|
+
newContexts.push(context);
|
|
5373
|
+
newInstances.push(componentRef);
|
|
5374
|
+
}
|
|
5375
|
+
else {
|
|
5376
|
+
const instance = this.instances[record.previousIndex];
|
|
5377
|
+
instance.context = context;
|
|
5378
|
+
newInstances.push(instance);
|
|
5379
|
+
newContexts.push(context);
|
|
5380
|
+
}
|
|
5381
|
+
// item might has been changed, so need to compare the id
|
|
5382
|
+
if (record.item === this.children[0] || record.item.id === this.children[0]?.id) {
|
|
5383
|
+
currentIndexForFirstElement = record.currentIndex;
|
|
5384
|
+
}
|
|
5385
|
+
});
|
|
5386
|
+
diffResult.forEachOperation(record => {
|
|
5387
|
+
// removed
|
|
5388
|
+
if (record.currentIndex === null) {
|
|
5389
|
+
const componentRef = this.instances[record.previousIndex];
|
|
5390
|
+
componentRef?.destroy();
|
|
5391
|
+
}
|
|
5392
|
+
// moved
|
|
5393
|
+
if (record.previousIndex !== null && record.currentIndex !== null) {
|
|
5394
|
+
mountOnItemMove(record.item, record.currentIndex, childrenContext, currentIndexForFirstElement);
|
|
5395
|
+
}
|
|
5396
|
+
});
|
|
5397
|
+
this.instances = newInstances;
|
|
5398
|
+
this.contexts = newContexts;
|
|
5399
|
+
this.children = children;
|
|
5400
|
+
}
|
|
5401
|
+
else {
|
|
5402
|
+
const newContexts = [];
|
|
5403
|
+
this.children.forEach((element, index) => {
|
|
5404
|
+
NODE_TO_INDEX.set(element, index);
|
|
5405
|
+
NODE_TO_PARENT.set(element, childrenContext.parent);
|
|
5406
|
+
const previousContext = this.contexts[index];
|
|
5407
|
+
const previousInstance = this.instances[index];
|
|
5408
|
+
const context = getContext(board, element, index, parent, previousContext);
|
|
5409
|
+
previousInstance.context = context;
|
|
5410
|
+
newContexts.push(context);
|
|
5411
|
+
});
|
|
5412
|
+
this.contexts = newContexts;
|
|
5413
|
+
}
|
|
5414
|
+
}
|
|
5415
|
+
destroy() {
|
|
5416
|
+
this.children.forEach((element, index) => {
|
|
5417
|
+
if (this.instances[index]) {
|
|
5418
|
+
this.instances[index].destroy();
|
|
5419
|
+
}
|
|
5420
|
+
});
|
|
5421
|
+
this.instances = [];
|
|
5422
|
+
this.children = [];
|
|
5423
|
+
this.contexts = [];
|
|
5424
|
+
this.initialized = false;
|
|
5425
|
+
this.differ = null;
|
|
5426
|
+
}
|
|
5427
|
+
}
|
|
5428
|
+
const trackBy = (index, element) => {
|
|
5429
|
+
return element.id;
|
|
5430
|
+
};
|
|
5431
|
+
const createPluginComponent = (board, componentType, context, childrenContext) => {
|
|
5432
|
+
// const componentRef = PlaitBoard.getViewContainerRef(board).createComponent(componentType, { injector: PlaitBoard.getViewContainerRef(board).injector });
|
|
5433
|
+
// const instance = componentRef.instance;
|
|
5434
|
+
const instance = new componentType();
|
|
5435
|
+
instance.context = context;
|
|
5436
|
+
instance.initialize();
|
|
5437
|
+
const g = instance.getContainerG();
|
|
5438
|
+
mountElementG(context.index, g, childrenContext);
|
|
5439
|
+
instance.initializeListRender();
|
|
5440
|
+
return instance;
|
|
5441
|
+
};
|
|
5442
|
+
const getComponentType = (board, context) => {
|
|
5443
|
+
const result = board.drawElement(context);
|
|
5444
|
+
return result;
|
|
5445
|
+
};
|
|
5446
|
+
const getContext = (board, element, index, parent, previousContext) => {
|
|
5447
|
+
let isSelected = isSelectedElement(board, element);
|
|
5448
|
+
const previousElement = previousContext && previousContext.element;
|
|
5449
|
+
if (previousElement && previousElement !== element && isSelectedElement(board, previousElement)) {
|
|
5450
|
+
isSelected = true;
|
|
5451
|
+
removeSelectedElement(board, previousElement);
|
|
5452
|
+
addSelectedElement(board, element);
|
|
5453
|
+
}
|
|
5454
|
+
const context = {
|
|
5455
|
+
element: element,
|
|
5456
|
+
parent: parent,
|
|
5457
|
+
board: board,
|
|
5458
|
+
selected: isSelected,
|
|
5459
|
+
index
|
|
5460
|
+
};
|
|
5461
|
+
return context;
|
|
5462
|
+
};
|
|
5463
|
+
// the g depth of root element:[1]-[2]-[3]-[4]
|
|
5464
|
+
// the g depth of root element and children element(the [2] element has children):
|
|
5465
|
+
// [1]-
|
|
5466
|
+
// [2]([2-1-1][2-1-2][2-1][2-2][2-3-1][2-3-2][2-3][2])-
|
|
5467
|
+
// [3]-
|
|
5468
|
+
// [4]
|
|
5469
|
+
const mountElementG = (index, g, childrenContext,
|
|
5470
|
+
// for moving scene: the current index for first element before moving
|
|
5471
|
+
currentIndexForFirstElement = null) => {
|
|
5472
|
+
const { parent, parentG } = childrenContext;
|
|
5473
|
+
if (PlaitBoard.isBoard(parent)) {
|
|
5474
|
+
if (index > 0) {
|
|
5475
|
+
const previousElement = parent.children[index - 1];
|
|
5476
|
+
const previousContainerG = PlaitElement.getContainerG(previousElement, { suppressThrow: false });
|
|
5477
|
+
previousContainerG.insertAdjacentElement('afterend', g);
|
|
5478
|
+
}
|
|
5479
|
+
else {
|
|
5480
|
+
if (currentIndexForFirstElement !== null) {
|
|
5481
|
+
const firstElement = parent.children[currentIndexForFirstElement];
|
|
5482
|
+
const firstContainerG = firstElement && PlaitElement.getContainerG(firstElement, { suppressThrow: true });
|
|
5483
|
+
if (firstElement && firstContainerG) {
|
|
5484
|
+
parentG.insertBefore(g, firstContainerG);
|
|
5485
|
+
}
|
|
5486
|
+
else {
|
|
5487
|
+
throw new Error('fail to mount container on moving');
|
|
5488
|
+
}
|
|
5608
5489
|
}
|
|
5609
|
-
|
|
5610
|
-
|
|
5611
|
-
BoardTransforms.updateZoom(board, 1);
|
|
5612
|
-
return;
|
|
5490
|
+
else {
|
|
5491
|
+
parentG.append(g);
|
|
5613
5492
|
}
|
|
5614
5493
|
}
|
|
5615
|
-
globalKeyDown(event);
|
|
5616
|
-
};
|
|
5617
|
-
return board;
|
|
5618
|
-
};
|
|
5619
|
-
|
|
5620
|
-
class PlaitContextService {
|
|
5621
|
-
constructor() {
|
|
5622
|
-
this._stable = new Subject();
|
|
5623
|
-
this.uploadingFiles = [];
|
|
5624
|
-
}
|
|
5625
|
-
getUploadingFile(url) {
|
|
5626
|
-
return this.uploadingFiles.find(file => file.url === url);
|
|
5627
|
-
}
|
|
5628
|
-
setUploadingFile(file) {
|
|
5629
|
-
return this.uploadingFiles.push(file);
|
|
5630
|
-
}
|
|
5631
|
-
removeUploadingFile(fileEntry) {
|
|
5632
|
-
this.uploadingFiles = this.uploadingFiles.filter(file => file.url !== fileEntry.url);
|
|
5633
|
-
}
|
|
5634
|
-
onStable() {
|
|
5635
|
-
return this._stable.asObservable();
|
|
5636
|
-
}
|
|
5637
|
-
nextStable() {
|
|
5638
|
-
this._stable.next('');
|
|
5639
5494
|
}
|
|
5640
|
-
|
|
5641
|
-
|
|
5642
|
-
|
|
5643
|
-
|
|
5644
|
-
|
|
5645
|
-
}
|
|
5646
|
-
|
|
5647
|
-
|
|
5648
|
-
|
|
5649
|
-
|
|
5650
|
-
|
|
5651
|
-
|
|
5652
|
-
|
|
5653
|
-
|
|
5654
|
-
}
|
|
5655
|
-
if (relatedFragment.length) {
|
|
5656
|
-
if (!clipboardContext) {
|
|
5657
|
-
clipboardContext = createClipboardContext(WritableClipboardType.elements, relatedFragment, '');
|
|
5495
|
+
else {
|
|
5496
|
+
if (index > 0) {
|
|
5497
|
+
const previousElement = parent.children[index - 1];
|
|
5498
|
+
const previousElementG = PlaitElement.getElementG(previousElement);
|
|
5499
|
+
previousElementG.insertAdjacentElement('afterend', g);
|
|
5500
|
+
}
|
|
5501
|
+
else {
|
|
5502
|
+
if (currentIndexForFirstElement) {
|
|
5503
|
+
const nextElement = parent.children[currentIndexForFirstElement];
|
|
5504
|
+
const nextPath = nextElement && PlaitBoard.findPath(childrenContext.board, nextElement);
|
|
5505
|
+
const first = nextPath && PlaitNode.first(childrenContext.board, nextPath);
|
|
5506
|
+
const firstContainerG = first && PlaitElement.getContainerG(first, { suppressThrow: false });
|
|
5507
|
+
if (firstContainerG) {
|
|
5508
|
+
parentG.insertBefore(g, firstContainerG);
|
|
5658
5509
|
}
|
|
5659
5510
|
else {
|
|
5660
|
-
|
|
5661
|
-
text: '',
|
|
5662
|
-
type: WritableClipboardType.elements,
|
|
5663
|
-
elements: relatedFragment
|
|
5664
|
-
});
|
|
5511
|
+
throw new Error('fail to mount container on moving');
|
|
5665
5512
|
}
|
|
5666
5513
|
}
|
|
5514
|
+
else {
|
|
5515
|
+
let parentElementG = PlaitElement.getElementG(parent);
|
|
5516
|
+
parentG.insertBefore(g, parentElementG);
|
|
5517
|
+
}
|
|
5667
5518
|
}
|
|
5668
|
-
|
|
5669
|
-
|
|
5670
|
-
|
|
5671
|
-
}
|
|
5519
|
+
}
|
|
5520
|
+
};
|
|
5521
|
+
const mountOnItemMove = (element, index, childrenContext, currentIndexForFirstElement) => {
|
|
5522
|
+
const containerG = PlaitElement.getContainerG(element, { suppressThrow: false });
|
|
5523
|
+
mountElementG(index, containerG, childrenContext, currentIndexForFirstElement);
|
|
5524
|
+
if (element.children && !PlaitElement.isRootElement(element)) {
|
|
5525
|
+
element.children.forEach((child, index) => {
|
|
5526
|
+
mountOnItemMove(child, index, { ...childrenContext, parent: element }, null);
|
|
5527
|
+
});
|
|
5528
|
+
}
|
|
5529
|
+
};
|
|
5672
5530
|
|
|
5531
|
+
const ElementLowerHostClass = 'element-lower-host';
|
|
5673
5532
|
const ElementHostClass = 'element-host';
|
|
5674
5533
|
const ElementUpperHostClass = 'element-upper-host';
|
|
5675
5534
|
const ElementActiveHostClass = 'element-active-host';
|
|
@@ -5721,6 +5580,7 @@ class PlaitBoardComponent {
|
|
|
5721
5580
|
};
|
|
5722
5581
|
}
|
|
5723
5582
|
ngOnInit() {
|
|
5583
|
+
const elementLowerHost = this.host.querySelector(`.${ElementLowerHostClass}`);
|
|
5724
5584
|
const elementHost = this.host.querySelector(`.${ElementHostClass}`);
|
|
5725
5585
|
const elementUpperHost = this.host.querySelector(`.${ElementUpperHostClass}`);
|
|
5726
5586
|
const elementActiveHost = this.host.querySelector(`.${ElementActiveHostClass}`);
|
|
@@ -5745,6 +5605,7 @@ class PlaitBoardComponent {
|
|
|
5745
5605
|
BOARD_TO_HOST.set(this.board, this.host);
|
|
5746
5606
|
IS_BOARD_ALIVE.set(this.board, true);
|
|
5747
5607
|
BOARD_TO_ELEMENT_HOST.set(this.board, {
|
|
5608
|
+
lowerHost: elementLowerHost,
|
|
5748
5609
|
host: elementHost,
|
|
5749
5610
|
upperHost: elementUpperHost,
|
|
5750
5611
|
activeHost: elementActiveHost,
|
|
@@ -5917,7 +5778,7 @@ class PlaitBoardComponent {
|
|
|
5917
5778
|
});
|
|
5918
5779
|
}
|
|
5919
5780
|
initializeListRender() {
|
|
5920
|
-
this.listRender = new ListRender(this.board
|
|
5781
|
+
this.listRender = new ListRender(this.board);
|
|
5921
5782
|
this.listRender.initialize(this.board.children, this.initializeChildrenContext());
|
|
5922
5783
|
}
|
|
5923
5784
|
updateListRender() {
|
|
@@ -6020,10 +5881,11 @@ class PlaitBoardComponent {
|
|
|
6020
5881
|
this.updateIslands();
|
|
6021
5882
|
});
|
|
6022
5883
|
}
|
|
6023
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.
|
|
6024
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.
|
|
5884
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.1", ngImport: i0, type: PlaitBoardComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i0.ViewContainerRef }, { token: i0.ElementRef }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
5885
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.1", type: PlaitBoardComponent, isStandalone: true, selector: "plait-board", inputs: { plaitValue: "plaitValue", plaitViewport: "plaitViewport", plaitPlugins: "plaitPlugins", plaitOptions: "plaitOptions", plaitTheme: "plaitTheme" }, outputs: { plaitChange: "plaitChange", plaitBoardInitialized: "plaitBoardInitialized" }, host: { properties: { "class": "this.hostClass", "class.readonly": "this.readonly", "class.focused": "this.isFocused", "class.disabled-scroll": "this.disabledScrollOnNonFocus" } }, providers: [PlaitContextService], queries: [{ propertyName: "islands", predicate: PlaitIslandBaseComponent, 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: `
|
|
6025
5886
|
<div class="viewport-container" #viewportContainer>
|
|
6026
5887
|
<svg #svg width="100%" height="100%" style="position: relative;" class="board-host-svg">
|
|
5888
|
+
<g class="element-lower-host"></g>
|
|
6027
5889
|
<g class="element-host"></g>
|
|
6028
5890
|
<g class="element-upper-host"></g>
|
|
6029
5891
|
<g class="element-active-host"></g>
|
|
@@ -6032,13 +5894,14 @@ class PlaitBoardComponent {
|
|
|
6032
5894
|
<ng-content></ng-content>
|
|
6033
5895
|
`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
6034
5896
|
}
|
|
6035
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.
|
|
5897
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.1", ngImport: i0, type: PlaitBoardComponent, decorators: [{
|
|
6036
5898
|
type: Component,
|
|
6037
5899
|
args: [{
|
|
6038
5900
|
selector: 'plait-board',
|
|
6039
5901
|
template: `
|
|
6040
5902
|
<div class="viewport-container" #viewportContainer>
|
|
6041
5903
|
<svg #svg width="100%" height="100%" style="position: relative;" class="board-host-svg">
|
|
5904
|
+
<g class="element-lower-host"></g>
|
|
6042
5905
|
<g class="element-host"></g>
|
|
6043
5906
|
<g class="element-upper-host"></g>
|
|
6044
5907
|
<g class="element-active-host"></g>
|
|
@@ -6087,6 +5950,149 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.2.4", ngImpor
|
|
|
6087
5950
|
args: [PlaitIslandBaseComponent, { descendants: true }]
|
|
6088
5951
|
}] } });
|
|
6089
5952
|
|
|
5953
|
+
function hasBeforeContextChange(value) {
|
|
5954
|
+
if (value.beforeContextChange) {
|
|
5955
|
+
return true;
|
|
5956
|
+
}
|
|
5957
|
+
return false;
|
|
5958
|
+
}
|
|
5959
|
+
function hasOnContextChanged(value) {
|
|
5960
|
+
if (value.onContextChanged) {
|
|
5961
|
+
return true;
|
|
5962
|
+
}
|
|
5963
|
+
return false;
|
|
5964
|
+
}
|
|
5965
|
+
|
|
5966
|
+
/**
|
|
5967
|
+
* 基于 element-flavour 实现元素的绘制,取代 Angular 组件
|
|
5968
|
+
*/
|
|
5969
|
+
class ElementFlavour {
|
|
5970
|
+
get hasChildren() {
|
|
5971
|
+
return !!this.element.children;
|
|
5972
|
+
}
|
|
5973
|
+
set context(value) {
|
|
5974
|
+
if (hasBeforeContextChange(this)) {
|
|
5975
|
+
this.beforeContextChange(value);
|
|
5976
|
+
}
|
|
5977
|
+
const previousContext = this._context;
|
|
5978
|
+
this._context = value;
|
|
5979
|
+
if (this.initialized) {
|
|
5980
|
+
const elementG = this.getElementG();
|
|
5981
|
+
const containerG = this.getContainerG();
|
|
5982
|
+
NODE_TO_G.set(this.element, elementG);
|
|
5983
|
+
NODE_TO_CONTAINER_G.set(this.element, containerG);
|
|
5984
|
+
ELEMENT_TO_REF.set(this.element, this.ref);
|
|
5985
|
+
this.updateListRender();
|
|
5986
|
+
if (hasOnContextChanged(this)) {
|
|
5987
|
+
this.onContextChanged(value, previousContext);
|
|
5988
|
+
}
|
|
5989
|
+
}
|
|
5990
|
+
else {
|
|
5991
|
+
if (PlaitElement.isRootElement(this.element) && this.hasChildren) {
|
|
5992
|
+
this._g = createG();
|
|
5993
|
+
this._containerG = createG();
|
|
5994
|
+
this._containerG.append(this._g);
|
|
5995
|
+
}
|
|
5996
|
+
else {
|
|
5997
|
+
this._g = createG();
|
|
5998
|
+
this._containerG = this._g;
|
|
5999
|
+
}
|
|
6000
|
+
NODE_TO_G.set(this.element, this._g);
|
|
6001
|
+
NODE_TO_CONTAINER_G.set(this.element, this._containerG);
|
|
6002
|
+
ELEMENT_TO_REF.set(this.element, this.ref);
|
|
6003
|
+
}
|
|
6004
|
+
}
|
|
6005
|
+
get context() {
|
|
6006
|
+
return this._context;
|
|
6007
|
+
}
|
|
6008
|
+
get element() {
|
|
6009
|
+
return this.context && this.context.element;
|
|
6010
|
+
}
|
|
6011
|
+
get board() {
|
|
6012
|
+
return this.context && this.context.board;
|
|
6013
|
+
}
|
|
6014
|
+
get selected() {
|
|
6015
|
+
return this.context && this.context.selected;
|
|
6016
|
+
}
|
|
6017
|
+
getContainerG() {
|
|
6018
|
+
return this._containerG;
|
|
6019
|
+
}
|
|
6020
|
+
getElementG() {
|
|
6021
|
+
return this._g;
|
|
6022
|
+
}
|
|
6023
|
+
constructor(ref) {
|
|
6024
|
+
this.ref = ref;
|
|
6025
|
+
this.initialized = false;
|
|
6026
|
+
}
|
|
6027
|
+
initialize() {
|
|
6028
|
+
if (this.element.type) {
|
|
6029
|
+
this.getContainerG().setAttribute(`plait-${this.element.type}`, 'true');
|
|
6030
|
+
}
|
|
6031
|
+
if (this.hasChildren) {
|
|
6032
|
+
if (PlaitElement.isRootElement(this.element)) {
|
|
6033
|
+
this._rootContainerG = this._containerG;
|
|
6034
|
+
}
|
|
6035
|
+
else {
|
|
6036
|
+
const path = PlaitBoard.findPath(this.board, this.element);
|
|
6037
|
+
const rootNode = PlaitNode.get(this.board, path.slice(0, 1));
|
|
6038
|
+
this._rootContainerG = PlaitElement.getContainerG(rootNode, { suppressThrow: false });
|
|
6039
|
+
}
|
|
6040
|
+
}
|
|
6041
|
+
this.getContainerG().setAttribute('plait-data-id', this.element.id);
|
|
6042
|
+
this.initialized = true;
|
|
6043
|
+
}
|
|
6044
|
+
initializeListRender() {
|
|
6045
|
+
if (this.hasChildren) {
|
|
6046
|
+
this.listRender = new ListRender(this.board);
|
|
6047
|
+
if (this.board.isExpanded(this.element)) {
|
|
6048
|
+
this.listRender.initialize(this.element.children, this.initializeChildrenContext());
|
|
6049
|
+
}
|
|
6050
|
+
}
|
|
6051
|
+
}
|
|
6052
|
+
getRef() {
|
|
6053
|
+
return this.ref;
|
|
6054
|
+
}
|
|
6055
|
+
updateListRender() {
|
|
6056
|
+
if (this.hasChildren) {
|
|
6057
|
+
if (!this.listRender) {
|
|
6058
|
+
throw new Error('incorrectly initialize list render');
|
|
6059
|
+
}
|
|
6060
|
+
if (this.board.isExpanded(this.element)) {
|
|
6061
|
+
this.listRender.update(this.element.children, this.initializeChildrenContext());
|
|
6062
|
+
}
|
|
6063
|
+
else {
|
|
6064
|
+
if (this.listRender.initialized) {
|
|
6065
|
+
this.listRender.destroy();
|
|
6066
|
+
}
|
|
6067
|
+
}
|
|
6068
|
+
}
|
|
6069
|
+
}
|
|
6070
|
+
initializeChildrenContext() {
|
|
6071
|
+
if (!this._rootContainerG) {
|
|
6072
|
+
throw new Error('can not resolve root container g');
|
|
6073
|
+
}
|
|
6074
|
+
return {
|
|
6075
|
+
board: this.board,
|
|
6076
|
+
parent: this.element,
|
|
6077
|
+
parentG: this._rootContainerG
|
|
6078
|
+
};
|
|
6079
|
+
}
|
|
6080
|
+
destroy() {
|
|
6081
|
+
if (NODE_TO_G.get(this.element) === this._g) {
|
|
6082
|
+
NODE_TO_G.delete(this.element);
|
|
6083
|
+
}
|
|
6084
|
+
if (NODE_TO_CONTAINER_G.get(this.element) === this._containerG) {
|
|
6085
|
+
NODE_TO_CONTAINER_G.delete(this.element);
|
|
6086
|
+
}
|
|
6087
|
+
if (ELEMENT_TO_REF.get(this.element) === this.ref) {
|
|
6088
|
+
ELEMENT_TO_REF.set(this.element, this.ref);
|
|
6089
|
+
}
|
|
6090
|
+
removeSelectedElement(this.board, this.element);
|
|
6091
|
+
this.getContainerG().remove();
|
|
6092
|
+
this.listRender?.destroy();
|
|
6093
|
+
}
|
|
6094
|
+
}
|
|
6095
|
+
|
|
6090
6096
|
/**
|
|
6091
6097
|
* 1.create board instance
|
|
6092
6098
|
* 2.build fake node weak map
|
|
@@ -6345,5 +6351,5 @@ const isDebug = (key) => {
|
|
|
6345
6351
|
* Generated bundle index. Do not edit.
|
|
6346
6352
|
*/
|
|
6347
6353
|
|
|
6348
|
-
export { A, ACTIVE_MOVING_CLASS_NAME, ACTIVE_STROKE_WIDTH, ALT, APOSTROPHE, ATTACHED_ELEMENT_CLASS_NAME, AT_SIGN, B, BACKSLASH, BACKSPACE, BOARD_TO_AFTER_CHANGE, 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_MOVING_POINT_IN_BOARD, BOARD_TO_ON_CHANGE, BOARD_TO_ROUGH_SVG, BOARD_TO_SELECTED_ELEMENT, BOARD_TO_TEMPORARY_ELEMENTS, BOARD_TO_TOUCH_REF, BOARD_TO_VIEWPORT_ORIGINATION, BoardTransforms, C, CAPS_LOCK, CLOSE_SQUARE_BRACKET, COMMA, CONTEXT_MENU, CONTROL, ColorfulThemeColor, CoreTransforms, CursorClass, D, DASH, DELETE, DOWN_ARROW, DarkThemeColor, DebugGenerator, DefaultThemeColor, Direction, E, EIGHT,
|
|
6354
|
+
export { A, ACTIVE_MOVING_CLASS_NAME, ACTIVE_STROKE_WIDTH, ALT, APOSTROPHE, ATTACHED_ELEMENT_CLASS_NAME, AT_SIGN, B, BACKSLASH, BACKSPACE, BOARD_TO_AFTER_CHANGE, 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_MOVING_POINT_IN_BOARD, BOARD_TO_ON_CHANGE, BOARD_TO_ROUGH_SVG, BOARD_TO_SELECTED_ELEMENT, BOARD_TO_TEMPORARY_ELEMENTS, BOARD_TO_TOUCH_REF, BOARD_TO_VIEWPORT_ORIGINATION, BoardTransforms, C, CAPS_LOCK, CLOSE_SQUARE_BRACKET, COMMA, CONTEXT_MENU, CONTROL, ColorfulThemeColor, CoreTransforms, CursorClass, D, DASH, DELETE, DOWN_ARROW, DarkThemeColor, DebugGenerator, DefaultThemeColor, Direction, E, EIGHT, ELEMENT_TO_REF, END, ENTER, EQUALS, ESCAPE, ElementFlavour, F, F1, F10, F11, F12, F2, F3, F4, F5, F6, F7, F8, F9, FF_EQUALS, FF_MINUS, FF_MUTE, FF_SEMICOLON, FF_VOLUME_DOWN, FF_VOLUME_UP, FIRST_MEDIA, FIVE, FLUSHING, FOUR, G, H, HIT_DISTANCE_BUFFER, HOME, HOST_CLASS_NAME, I, INSERT, IS_APPLE, IS_BOARD_ALIVE, IS_BOARD_CACHE, IS_CHROME, IS_CHROME_LEGACY, IS_DRAGGING, IS_EDGE_LEGACY, IS_FIREFOX, IS_IOS, IS_MAC, IS_SAFARI, IS_TEXT_EDITABLE, J, K, L, LAST_MEDIA, LEFT_ARROW, M, MAC_ENTER, MAC_META, MAC_WK_CMD_LEFT, MAC_WK_CMD_RIGHT, MAX_RADIUS, MERGING, META, MUTE, N, NINE, NODE_TO_CONTAINER_G, NODE_TO_G, NODE_TO_INDEX, NODE_TO_PARENT, NS, NUMPAD_DIVIDE, NUMPAD_EIGHT, NUMPAD_FIVE, NUMPAD_FOUR, NUMPAD_MINUS, NUMPAD_MULTIPLY, NUMPAD_NINE, NUMPAD_ONE, NUMPAD_PERIOD, NUMPAD_PLUS, NUMPAD_SEVEN, NUMPAD_SIX, NUMPAD_THREE, NUMPAD_TWO, NUMPAD_ZERO, NUM_CENTER, NUM_LOCK, O, ONE, OPEN_SQUARE_BRACKET, P, PAGE_DOWN, PAGE_UP, PATH_REFS, PAUSE, PERIOD, PLUS_SIGN, POINTER_BUTTON, PRESS_AND_MOVE_BUFFER, PRINT_SCREEN, Path, PlaitBoard, PlaitBoardComponent, PlaitContextService, PlaitElement, PlaitGroupElement, PlaitHistoryBoard, PlaitIslandBaseComponent, PlaitIslandPopoverBaseComponent, PlaitNode, PlaitOperation, PlaitPluginKey, PlaitPointerType, Point, Q, QUESTION_MARK, R, RESIZE_CURSORS, RESIZE_HANDLE_CLASS_NAME, RIGHT_ARROW, ROTATE_HANDLE_CLASS_NAME, RectangleClient, ResizeCursorClass, RetroThemeColor, RgbaToHEX, S, SAVING, SCROLL_BAR_WIDTH, SCROLL_LOCK, SELECTION_BORDER_COLOR, SELECTION_FILL_COLOR, SELECTION_RECTANGLE_CLASS_NAME, SEMICOLON, SEVEN, SHIFT, SINGLE_QUOTE, SIX, SLASH, SNAPPING_STROKE_WIDTH, SNAP_TOLERANCE, SPACE, Selection, SoftThemeColor, StarryThemeColor, T, TAB, THREE, TILDE, TWO, ThemeColorMode, ThemeColors, Transforms, U, UP_ARROW, V, VOLUME_DOWN, VOLUME_UP, Viewport, W, WritableClipboardOperationType, WritableClipboardType, X, Y, Z, ZERO, addClipboardContext, addSelectedElement, approximately, arrowPoints, buildPlaitHtml, cacheMovingElements, cacheSelectedElements, cacheSelectedElementsWithGroup, cacheSelectedElementsWithGroupOnShift, calcNewViewBox, canAddGroup, canRemoveGroup, canSetZIndex, catmullRomFitting, clampZoomLevel, clearNodeWeakMap, clearSelectedElement, clearSelectionMoving, clearViewportOrigination, createClipboardContext, createDebugGenerator, createFakeEvent, createForeignObject, createG, createGroup, createGroupRectangleG, createKeyboardEvent, createMask, createModModifierKeys, createMouseEvent, createPath, createPointerEvent, createRect, createSVG, createTestingBoard, createText, createTouchEvent, debounce, degreesToRadians, deleteFragment, deleteTemporaryElements, depthFirstRecursion, distanceBetweenPointAndPoint, distanceBetweenPointAndRectangle, distanceBetweenPointAndSegment, distanceBetweenPointAndSegments, downloadImage, drawArrow, drawBezierPath, drawCircle, drawDashedLines, drawEntireActiveRectangleG, drawLine, drawLinearPath, drawPendingNodesG, drawPointSnapLines, drawRectangle, drawRoundRectangle, drawSolidLines, duplicateElements, fakeNodeWeakMap, filterSelectedGroups, findElements, findIndex, findLastIndex, getAllElementsInGroup, getAllMoveOptions, getAngleBetweenPoints, getAngleByElement, getBarPoint, getBoardRectangle, getBoundingRectangleByElements, getClipboardData, getClipboardFromHtml, getCrossingPointsBetweenEllipseAndSegment, getDataTransferClipboard, getDataTransferClipboardText, getEditingGroup, getElementById, getElementHostBBox, getElementsInGroup, getElementsInGroupByElement, getElementsIndices, getEllipseTangentSlope, getGroupByElement, getHighestGroup, getHighestIndexOfElement, getHighestSelectedElements, getHighestSelectedGroup, getHighestSelectedGroups, getHitElementByPoint, getHitElementsBySelection, getHitSelectedElements, getIsRecursionFunc, getMinPointDelta, getMovingElements, getNearestDelta, getNearestPointBetweenPointAndEllipse, getNearestPointBetweenPointAndSegment, getNearestPointBetweenPointAndSegments, getNearestPointRectangle, getOffsetAfterRotate, getOneMoveOptions, getProbablySupportsClipboardRead, getProbablySupportsClipboardWrite, getProbablySupportsClipboardWriteText, getRealScrollBarWidth, getRectangleByAngle, getRectangleByElements, getRectangleByGroup, getRotatedBoundingRectangle, getSelectedElements, getSelectedGroups, getSelectedIsolatedElements, getSelectedIsolatedElementsCanAddToGroup, getSelectedTargetElements, getSelectionAngle, getSnapRectangles, getTemporaryElements, getTemporaryRef, getTripleAxis, getValidElements, getVectorFromPointAndSlope, getViewBox, getViewBoxCenterPoint, getViewportContainerRect, getViewportOrigination, handleTouchTarget, hasBeforeContextChange, hasInputOrTextareaTarget, hasOnBoardChange, hasOnContextChanged, hasSameAngle, hasSelectedElementsInSameGroup, hasValidAngle, hotkeys, idCreator, initializeViewBox, initializeViewportContainer, initializeViewportOffset, inverse, isAxisChangedByAngle, isContextmenu, isDOMElement, isDOMNode, isDebug, isDragging, isFromScrolling, isFromViewportChange, isHandleSelection, isHitElement, isHitSelectedRectangle, isInPlaitBoard, isIndicesContinuous, isLineHitLine, isMainPointer, isMovingElements, isNullOrUndefined, isPointInEllipse, isPointInPolygon, isPointInRoundRectangle, isPolylineHitRectangle, isPreventTouchMove, isSecondaryPointer, isSelectedAllElementsInGroup, isSelectedElement, isSelectedElementOrGroup, isSelectionMoving, isSetSelectionOperation, isSetViewportOperation, isSnapPoint, moveElementsToNewPath, moveElementsToNewPathAfterAddGroup, nonGroupInHighestSelectedElements, normalizeAngle, normalizePoint, preventTouchMove, radiansToDegrees, removeMovingElements, removeSelectedElement, rotate, rotateAntiPointsByElement, rotateElements, rotatePoints, rotatePointsByElement, rotatedDataPoints, scrollToRectangle, setAngleForG, setClipboardData, setDataTransferClipboard, setDataTransferClipboardText, setDragging, setFragment, setIsFromScrolling, setIsFromViewportChange, setPathStrokeLinecap, setSVGViewBox, setSelectedElementsWithGroup, setSelectionMoving, setStrokeLinecap, shouldClear, shouldMerge, shouldSave, sortElements, stripHtml, temporaryDisableSelection, throttleRAF, toDomPrecision, toFixed, toHostPoint, toHostPointFromViewBoxPoint, toImage, toScreenPointFromHostPoint, toViewBoxPoint, toViewBoxPoints, uniqueById, updateForeignObject, updateForeignObjectWidth, updatePoints, updateViewportByScrolling, updateViewportContainerScroll, updateViewportOffset, updateViewportOrigination, withArrowMoving, withMoving, withOptions, withSelection };
|
|
6349
6355
|
//# sourceMappingURL=plait-core.mjs.map
|