@plait/core 0.24.0-next.8 → 0.28.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/board/board.component.d.ts +1 -1
- package/constants/selection.d.ts +1 -0
- package/core/children/children.component.d.ts +3 -3
- package/core/element/element.component.d.ts +1 -1
- package/esm2022/board/board.component.mjs +9 -7
- package/esm2022/constants/resize.mjs +1 -1
- package/esm2022/constants/selection.mjs +2 -1
- package/esm2022/core/children/children.component.mjs +11 -9
- package/esm2022/core/element/context.mjs +1 -1
- package/esm2022/core/element/element.component.mjs +4 -3
- package/esm2022/interfaces/board.mjs +1 -1
- package/esm2022/interfaces/direction.mjs +8 -0
- package/esm2022/interfaces/index.mjs +2 -1
- package/esm2022/interfaces/plugin-key.mjs +1 -1
- package/esm2022/interfaces/point.mjs +1 -1
- package/esm2022/interfaces/rectangle-client.mjs +4 -1
- package/esm2022/interfaces/viewport.mjs +2 -2
- package/esm2022/plugins/create-board.mjs +10 -9
- package/esm2022/plugins/with-hotkey.mjs +5 -3
- package/esm2022/plugins/with-moving.mjs +17 -4
- package/esm2022/plugins/with-options.mjs +1 -1
- package/esm2022/plugins/with-selection.mjs +37 -25
- package/esm2022/public-api.mjs +1 -2
- package/esm2022/testing/core/fake-weak-map.mjs +2 -2
- package/esm2022/testing/core/index.mjs +1 -1
- package/esm2022/testing/fake-events/event-objects.mjs +1 -1
- package/esm2022/testing/fake-events/index.mjs +1 -1
- package/esm2022/testing/index.mjs +1 -1
- package/esm2022/testing/test-element.mjs +1 -1
- package/esm2022/transforms/element.mjs +4 -4
- package/esm2022/transforms/selection.mjs +16 -6
- package/esm2022/utils/board.mjs +1 -1
- package/esm2022/utils/draw/line.mjs +2 -1
- package/esm2022/utils/draw/rectangle.mjs +1 -1
- package/esm2022/utils/element.mjs +3 -3
- package/esm2022/utils/reaction-manager.mjs +370 -0
- package/esm2022/utils/to-image.mjs +106 -34
- package/esm2022/utils/touch.mjs +3 -3
- package/esm2022/utils/tree.mjs +2 -2
- package/esm2022/utils/weak-maps.mjs +1 -1
- package/fesm2022/plait-core.mjs +732 -256
- package/fesm2022/plait-core.mjs.map +1 -1
- package/interfaces/board.d.ts +2 -1
- package/interfaces/direction.d.ts +7 -0
- package/interfaces/index.d.ts +1 -0
- package/interfaces/rectangle-client.d.ts +6 -0
- package/package.json +3 -2
- package/plugins/with-selection.d.ts +5 -1
- package/public-api.d.ts +0 -1
- package/styles/styles.scss +1 -1
- package/testing/core/fake-weak-map.d.ts +2 -2
- package/transforms/element.d.ts +2 -2
- package/transforms/selection.d.ts +2 -2
- package/utils/reaction-manager.d.ts +41 -0
- package/utils/to-image.d.ts +11 -0
- package/utils/touch.d.ts +1 -1
- package/utils/tree.d.ts +2 -2
- package/utils/weak-maps.d.ts +4 -1
- package/esm2022/plait.module.mjs +0 -21
- package/plait.module.d.ts +0 -10
package/fesm2022/plait-core.mjs
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { Directive, Input, Injectable, Component, ChangeDetectionStrategy, EventEmitter, ElementRef, Output, HostBinding, ViewChild, ContentChildren
|
|
2
|
+
import { Directive, Input, Injectable, Component, ChangeDetectionStrategy, EventEmitter, ElementRef, 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';
|
|
6
6
|
import { isKeyHotkey, isHotkey } from 'is-hotkey';
|
|
7
7
|
import produce, { createDraft, finishDraft, isDraft } from 'immer';
|
|
8
|
-
import
|
|
9
|
-
import { CommonModule } from '@angular/common';
|
|
8
|
+
import { NgFor } from '@angular/common';
|
|
10
9
|
|
|
11
10
|
// record richtext type status
|
|
12
11
|
const IS_BOARD_CACHE = new WeakMap();
|
|
@@ -271,6 +270,7 @@ var ResizeCursorClass;
|
|
|
271
270
|
|
|
272
271
|
const ATTACHED_ELEMENT_CLASS_NAME = 'plait-board-attached';
|
|
273
272
|
const ACTIVE_STROKE_WIDTH = 1;
|
|
273
|
+
const SELECTION_RECTANGLE_CLASS_NAME = 'selection-rectangle';
|
|
274
274
|
|
|
275
275
|
const CLIP_BOARD_FORMAT_KEY = 'x-plait-fragment';
|
|
276
276
|
const HOST_CLASS_NAME = 'plait-board-container';
|
|
@@ -503,6 +503,9 @@ const RectangleClient = {
|
|
|
503
503
|
[rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height],
|
|
504
504
|
[rectangle.x, rectangle.y + rectangle.height / 2]
|
|
505
505
|
];
|
|
506
|
+
},
|
|
507
|
+
getConnectionPoint: (rectangle, point) => {
|
|
508
|
+
return [rectangle.x + rectangle.width * point[0], rectangle.y + rectangle.height * point[1]];
|
|
506
509
|
}
|
|
507
510
|
};
|
|
508
511
|
|
|
@@ -1014,6 +1017,7 @@ function drawLinearPath(points, options, closePath) {
|
|
|
1014
1017
|
path.setAttribute('stroke', `${options?.stroke}`);
|
|
1015
1018
|
path.setAttribute('stroke-width', `${options?.strokeWidth}`);
|
|
1016
1019
|
path.setAttribute('fill', `${options?.fill || 'none'}`);
|
|
1020
|
+
options?.strokeLineDash && path.setAttribute('stroke-dasharray', `${options.strokeLineDash}`);
|
|
1017
1021
|
g.appendChild(path);
|
|
1018
1022
|
return g;
|
|
1019
1023
|
}
|
|
@@ -1240,6 +1244,68 @@ const cacheMovingElements = (board, elements) => {
|
|
|
1240
1244
|
BOARD_TO_MOVING_ELEMENT.set(board, elements);
|
|
1241
1245
|
};
|
|
1242
1246
|
|
|
1247
|
+
const IMAGE_CONTAINER = 'plait-image-container';
|
|
1248
|
+
/**
|
|
1249
|
+
* Is element node
|
|
1250
|
+
* @param node
|
|
1251
|
+
* @returns
|
|
1252
|
+
*/
|
|
1253
|
+
function isElementNode(node) {
|
|
1254
|
+
return node.nodeType === Node.ELEMENT_NODE;
|
|
1255
|
+
}
|
|
1256
|
+
/**
|
|
1257
|
+
* load image resources
|
|
1258
|
+
* @param url image url
|
|
1259
|
+
* @returns image element
|
|
1260
|
+
*/
|
|
1261
|
+
function loadImage(src) {
|
|
1262
|
+
return new Promise((resolve, reject) => {
|
|
1263
|
+
const img = new Image();
|
|
1264
|
+
img.crossOrigin = 'anonymous';
|
|
1265
|
+
img.onload = () => resolve(img);
|
|
1266
|
+
img.onerror = () => reject(new Error('Failed to load image'));
|
|
1267
|
+
img.src = src;
|
|
1268
|
+
});
|
|
1269
|
+
}
|
|
1270
|
+
/**
|
|
1271
|
+
* create and return canvas and context
|
|
1272
|
+
* @param width canvas width
|
|
1273
|
+
* @param height canvas height
|
|
1274
|
+
* @param fillStyle fill style
|
|
1275
|
+
* @returns canvas and context
|
|
1276
|
+
*/
|
|
1277
|
+
function createCanvas(width, height, fillStyle = 'transparent') {
|
|
1278
|
+
const canvas = document.createElement('canvas');
|
|
1279
|
+
const ctx = canvas.getContext('2d');
|
|
1280
|
+
canvas.width = width;
|
|
1281
|
+
canvas.height = height;
|
|
1282
|
+
canvas.style.width = `${width}px`;
|
|
1283
|
+
canvas.style.height = `${height}px`;
|
|
1284
|
+
ctx.strokeStyle = '#ffffff';
|
|
1285
|
+
ctx.fillStyle = fillStyle;
|
|
1286
|
+
ctx.fillRect(0, 0, width, height);
|
|
1287
|
+
return {
|
|
1288
|
+
canvas,
|
|
1289
|
+
ctx
|
|
1290
|
+
};
|
|
1291
|
+
}
|
|
1292
|
+
/**
|
|
1293
|
+
* convert image to base64
|
|
1294
|
+
* @param url image url
|
|
1295
|
+
* @returns image base64
|
|
1296
|
+
*/
|
|
1297
|
+
function convertImageToBase64(url) {
|
|
1298
|
+
return loadImage(url).then(img => {
|
|
1299
|
+
const { canvas, ctx } = createCanvas(img.width, img.height);
|
|
1300
|
+
ctx?.drawImage(img, 0, 0);
|
|
1301
|
+
return canvas.toDataURL('image/png');
|
|
1302
|
+
});
|
|
1303
|
+
}
|
|
1304
|
+
/**
|
|
1305
|
+
* clone node style
|
|
1306
|
+
* @param nativeNode source node
|
|
1307
|
+
* @param clonedNode clone node
|
|
1308
|
+
*/
|
|
1243
1309
|
function cloneCSSStyle(nativeNode, clonedNode) {
|
|
1244
1310
|
const targetStyle = clonedNode.style;
|
|
1245
1311
|
if (!targetStyle) {
|
|
@@ -1257,25 +1323,13 @@ function cloneCSSStyle(nativeNode, clonedNode) {
|
|
|
1257
1323
|
});
|
|
1258
1324
|
}
|
|
1259
1325
|
}
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
ctx.strokeStyle = '#ffffff';
|
|
1268
|
-
ctx.fillStyle = fillStyle;
|
|
1269
|
-
ctx.fillRect(0, 0, width, height);
|
|
1270
|
-
return {
|
|
1271
|
-
canvas,
|
|
1272
|
-
ctx
|
|
1273
|
-
};
|
|
1274
|
-
}
|
|
1275
|
-
function isElementNode(node) {
|
|
1276
|
-
return node.nodeType === Node.ELEMENT_NODE;
|
|
1277
|
-
}
|
|
1278
|
-
function cloneSvg(board, options) {
|
|
1326
|
+
/**
|
|
1327
|
+
* clone svg element
|
|
1328
|
+
* @param board board
|
|
1329
|
+
* @param options parameter configuration
|
|
1330
|
+
* @returns clone svg element
|
|
1331
|
+
*/
|
|
1332
|
+
async function cloneSvg(board, options) {
|
|
1279
1333
|
const elementHostBox = getRectangleByElements(board, board.children, true);
|
|
1280
1334
|
const { width, height, x, y } = elementHostBox;
|
|
1281
1335
|
const { padding = 4, inlineStyleClassNames } = options;
|
|
@@ -1288,8 +1342,9 @@ function cloneSvg(board, options) {
|
|
|
1288
1342
|
cloneSvgElement.setAttribute('height', `${height}`);
|
|
1289
1343
|
cloneSvgElement.setAttribute('viewBox', [x - padding, y - padding, width + 2 * padding, height + 2 * padding].join(','));
|
|
1290
1344
|
if (inlineStyleClassNames) {
|
|
1291
|
-
const
|
|
1292
|
-
const
|
|
1345
|
+
const classNames = inlineStyleClassNames + `,.${IMAGE_CONTAINER}`;
|
|
1346
|
+
const sourceNodes = Array.from(sourceSvg.querySelectorAll(classNames));
|
|
1347
|
+
const cloneNodes = Array.from(cloneSvgElement.querySelectorAll(classNames));
|
|
1293
1348
|
sourceNodes.forEach((node, index) => {
|
|
1294
1349
|
const cloneNode = cloneNodes[index];
|
|
1295
1350
|
const childElements = Array.from(node.querySelectorAll('*')).filter(isElementNode);
|
|
@@ -1297,21 +1352,38 @@ function cloneSvg(board, options) {
|
|
|
1297
1352
|
sourceNodes.push(...childElements);
|
|
1298
1353
|
cloneNodes.push(...cloneChildElements);
|
|
1299
1354
|
});
|
|
1300
|
-
|
|
1355
|
+
// processing styles
|
|
1356
|
+
sourceNodes.map((node, index) => {
|
|
1301
1357
|
const cloneNode = cloneNodes[index];
|
|
1302
1358
|
cloneCSSStyle(node, cloneNode);
|
|
1303
1359
|
});
|
|
1304
1360
|
}
|
|
1361
|
+
// 使用 Promise.all 等待所有异步操作完成
|
|
1362
|
+
const sourceImageNodes = Array.from(sourceSvg.querySelectorAll(`.${IMAGE_CONTAINER}`));
|
|
1363
|
+
const cloneImageNodes = Array.from(cloneSvgElement.querySelectorAll(`.${IMAGE_CONTAINER}`));
|
|
1364
|
+
await Promise.all(sourceImageNodes.map((_, index) => {
|
|
1365
|
+
return new Promise(resolve => {
|
|
1366
|
+
const cloneNode = cloneImageNodes[index];
|
|
1367
|
+
// processing image
|
|
1368
|
+
const image = cloneNode.querySelector('img');
|
|
1369
|
+
const url = image?.getAttribute('src');
|
|
1370
|
+
if (!url) {
|
|
1371
|
+
return resolve(true);
|
|
1372
|
+
}
|
|
1373
|
+
convertImageToBase64(url).then(base64Image => {
|
|
1374
|
+
image?.setAttribute('src', base64Image);
|
|
1375
|
+
resolve(true);
|
|
1376
|
+
});
|
|
1377
|
+
});
|
|
1378
|
+
}));
|
|
1305
1379
|
return cloneSvgElement;
|
|
1306
1380
|
}
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
});
|
|
1314
|
-
}
|
|
1381
|
+
/**
|
|
1382
|
+
* current board transfer pictures
|
|
1383
|
+
* @param board board
|
|
1384
|
+
* @param options parameter configuration
|
|
1385
|
+
* @returns images in the specified format base64
|
|
1386
|
+
*/
|
|
1315
1387
|
async function toImage(board, options) {
|
|
1316
1388
|
if (!board) {
|
|
1317
1389
|
return undefined;
|
|
@@ -1321,21 +1393,25 @@ async function toImage(board, options) {
|
|
|
1321
1393
|
const { width, height } = elementHostBox;
|
|
1322
1394
|
const ratioWidth = width * ratio;
|
|
1323
1395
|
const ratioHeight = height * ratio;
|
|
1324
|
-
const cloneSvgElement = cloneSvg(board, options);
|
|
1396
|
+
const cloneSvgElement = await cloneSvg(board, options);
|
|
1325
1397
|
const { canvas, ctx } = createCanvas(ratioWidth, ratioHeight, fillStyle);
|
|
1326
1398
|
const svgStr = new XMLSerializer().serializeToString(cloneSvgElement);
|
|
1327
1399
|
const imgSrc = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgStr)}`;
|
|
1328
1400
|
try {
|
|
1329
1401
|
const img = await loadImage(imgSrc);
|
|
1330
1402
|
ctx.drawImage(img, 0, 0, ratioWidth, ratioHeight);
|
|
1331
|
-
|
|
1332
|
-
return url;
|
|
1403
|
+
return canvas.toDataURL('image/png');
|
|
1333
1404
|
}
|
|
1334
1405
|
catch (error) {
|
|
1335
1406
|
console.error('Error converting SVG to image:', error);
|
|
1336
1407
|
return undefined;
|
|
1337
1408
|
}
|
|
1338
1409
|
}
|
|
1410
|
+
/**
|
|
1411
|
+
* download the file with the specified name
|
|
1412
|
+
* @param url download url
|
|
1413
|
+
* @param name file name
|
|
1414
|
+
*/
|
|
1339
1415
|
function downloadImage(url, name) {
|
|
1340
1416
|
const a = document.createElement('a');
|
|
1341
1417
|
a.href = url;
|
|
@@ -1394,7 +1470,7 @@ const isPreventTouchMove = (board) => {
|
|
|
1394
1470
|
};
|
|
1395
1471
|
const preventTouchMove = (board, event, state) => {
|
|
1396
1472
|
if (state && (event.target instanceof HTMLElement || event.target instanceof SVGElement)) {
|
|
1397
|
-
BOARD_TO_TOUCH_REF.set(board, { state, target: event.target });
|
|
1473
|
+
BOARD_TO_TOUCH_REF.set(board, { state, target: event.target instanceof SVGElement ? event.target : undefined });
|
|
1398
1474
|
}
|
|
1399
1475
|
else {
|
|
1400
1476
|
const ref = BOARD_TO_TOUCH_REF.get(board);
|
|
@@ -1412,7 +1488,7 @@ const preventTouchMove = (board, event, state) => {
|
|
|
1412
1488
|
*/
|
|
1413
1489
|
const handleTouchTarget = (board) => {
|
|
1414
1490
|
const touchRef = BOARD_TO_TOUCH_REF.get(board);
|
|
1415
|
-
if (touchRef && !touchRef.target.contains(PlaitBoard.getElementActiveHost(board))) {
|
|
1491
|
+
if (touchRef && touchRef.target && !touchRef.target.contains(PlaitBoard.getElementActiveHost(board))) {
|
|
1416
1492
|
touchRef.target.style.opacity = '0';
|
|
1417
1493
|
const host = createG();
|
|
1418
1494
|
host.appendChild(touchRef.target);
|
|
@@ -1754,7 +1830,7 @@ const Point = {
|
|
|
1754
1830
|
const Viewport = {
|
|
1755
1831
|
isViewport: (value) => {
|
|
1756
1832
|
return !isNullOrUndefined(value.zoom) && !isNullOrUndefined(value.viewBackgroundColor);
|
|
1757
|
-
}
|
|
1833
|
+
}
|
|
1758
1834
|
};
|
|
1759
1835
|
|
|
1760
1836
|
const SAVING = new WeakMap();
|
|
@@ -1813,6 +1889,14 @@ const ThemeColors = [
|
|
|
1813
1889
|
StarryThemeColor
|
|
1814
1890
|
];
|
|
1815
1891
|
|
|
1892
|
+
var Direction;
|
|
1893
|
+
(function (Direction) {
|
|
1894
|
+
Direction["left"] = "left";
|
|
1895
|
+
Direction["top"] = "top";
|
|
1896
|
+
Direction["right"] = "right";
|
|
1897
|
+
Direction["bottom"] = "bottom";
|
|
1898
|
+
})(Direction || (Direction = {}));
|
|
1899
|
+
|
|
1816
1900
|
function getRectangleByElements(board, elements, recursion) {
|
|
1817
1901
|
const boundaryBox = {
|
|
1818
1902
|
left: Number.MAX_VALUE,
|
|
@@ -1860,9 +1944,9 @@ function getBoardRectangle(board) {
|
|
|
1860
1944
|
}
|
|
1861
1945
|
function getElementById(board, id, dataSource) {
|
|
1862
1946
|
if (!dataSource) {
|
|
1863
|
-
dataSource = findElements(board, { match:
|
|
1947
|
+
dataSource = findElements(board, { match: element => true, recursion: element => true });
|
|
1864
1948
|
}
|
|
1865
|
-
let element = dataSource.find(
|
|
1949
|
+
let element = dataSource.find(element => element.id === id);
|
|
1866
1950
|
return element;
|
|
1867
1951
|
}
|
|
1868
1952
|
function findElements(board, options) {
|
|
@@ -2154,19 +2238,209 @@ const NodeTransforms = {
|
|
|
2154
2238
|
moveNode
|
|
2155
2239
|
};
|
|
2156
2240
|
|
|
2241
|
+
function withSelection(board) {
|
|
2242
|
+
const { pointerDown, globalPointerMove, globalPointerUp, onChange } = board;
|
|
2243
|
+
let start = null;
|
|
2244
|
+
let end = null;
|
|
2245
|
+
let selectionMovingG;
|
|
2246
|
+
let selectionRectangleG;
|
|
2247
|
+
let previousSelectedElements;
|
|
2248
|
+
// prevent text from being selected when user pressed main pointer and is moving
|
|
2249
|
+
let needPreventNativeSelectionWhenMoving = false;
|
|
2250
|
+
board.pointerDown = (event) => {
|
|
2251
|
+
if (event.target instanceof Element && !event.target.closest('.plait-richtext-container')) {
|
|
2252
|
+
needPreventNativeSelectionWhenMoving = true;
|
|
2253
|
+
}
|
|
2254
|
+
if (!isMainPointer(event)) {
|
|
2255
|
+
pointerDown(event);
|
|
2256
|
+
return;
|
|
2257
|
+
}
|
|
2258
|
+
const options = board.getPluginOptions(PlaitPluginKey.withSelection);
|
|
2259
|
+
const point = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
|
|
2260
|
+
const range = { anchor: point, focus: point };
|
|
2261
|
+
const hitElements = getHitElements(board, { ranges: [range] });
|
|
2262
|
+
const selectedElements = getSelectedElements(board);
|
|
2263
|
+
if (hitElements.length === 1 && selectedElements.includes(hitElements[0]) && !options.isDisabledSelect) {
|
|
2264
|
+
pointerDown(event);
|
|
2265
|
+
return;
|
|
2266
|
+
}
|
|
2267
|
+
if (PlaitBoard.isPointer(board, PlaitPointerType.selection) &&
|
|
2268
|
+
hitElements.length === 0 &&
|
|
2269
|
+
options.isMultiple &&
|
|
2270
|
+
!options.isDisabledSelect) {
|
|
2271
|
+
selectionRectangleG?.remove();
|
|
2272
|
+
start = point;
|
|
2273
|
+
preventTouchMove(board, event, true);
|
|
2274
|
+
}
|
|
2275
|
+
Transforms.setSelection(board, { ranges: [range] });
|
|
2276
|
+
pointerDown(event);
|
|
2277
|
+
};
|
|
2278
|
+
board.globalPointerMove = (event) => {
|
|
2279
|
+
if (needPreventNativeSelectionWhenMoving) {
|
|
2280
|
+
// prevent text from being selected
|
|
2281
|
+
event.preventDefault();
|
|
2282
|
+
}
|
|
2283
|
+
if (start) {
|
|
2284
|
+
const movedTarget = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
|
|
2285
|
+
const rectangle = RectangleClient.toRectangleClient([start, movedTarget]);
|
|
2286
|
+
selectionMovingG?.remove();
|
|
2287
|
+
if (Math.hypot(rectangle.width, rectangle.height) > 5) {
|
|
2288
|
+
end = movedTarget;
|
|
2289
|
+
throttleRAF(() => {
|
|
2290
|
+
if (start && end) {
|
|
2291
|
+
Transforms.setSelection(board, { ranges: [{ anchor: start, focus: end }] });
|
|
2292
|
+
}
|
|
2293
|
+
});
|
|
2294
|
+
setSelectionMoving(board);
|
|
2295
|
+
selectionMovingG = drawRectangle(board, rectangle, {
|
|
2296
|
+
stroke: SELECTION_BORDER_COLOR,
|
|
2297
|
+
strokeWidth: 1,
|
|
2298
|
+
fill: SELECTION_FILL_COLOR,
|
|
2299
|
+
fillStyle: 'solid'
|
|
2300
|
+
});
|
|
2301
|
+
PlaitBoard.getHost(board).append(selectionMovingG);
|
|
2302
|
+
}
|
|
2303
|
+
}
|
|
2304
|
+
globalPointerMove(event);
|
|
2305
|
+
};
|
|
2306
|
+
board.globalPointerUp = (event) => {
|
|
2307
|
+
if (start && end) {
|
|
2308
|
+
selectionMovingG?.remove();
|
|
2309
|
+
clearSelectionMoving(board);
|
|
2310
|
+
Transforms.setSelection(board, { ranges: [{ anchor: start, focus: end }] });
|
|
2311
|
+
}
|
|
2312
|
+
if (PlaitBoard.isFocus(board)) {
|
|
2313
|
+
const isInBoard = event.target instanceof Node && PlaitBoard.getBoardContainer(board).contains(event.target);
|
|
2314
|
+
const isInDocument = event.target instanceof Node && document.contains(event.target);
|
|
2315
|
+
const isAttachedElement = event.target instanceof Element && event.target.closest(`.${ATTACHED_ELEMENT_CLASS_NAME}`);
|
|
2316
|
+
// Clear selection when mouse board outside area
|
|
2317
|
+
// The framework needs to determine whether the board is focused through selection
|
|
2318
|
+
if (!isInBoard && !start && !isAttachedElement && isInDocument) {
|
|
2319
|
+
Transforms.setSelection(board, null);
|
|
2320
|
+
}
|
|
2321
|
+
}
|
|
2322
|
+
start = null;
|
|
2323
|
+
end = null;
|
|
2324
|
+
needPreventNativeSelectionWhenMoving = false;
|
|
2325
|
+
preventTouchMove(board, event, false);
|
|
2326
|
+
globalPointerUp(event);
|
|
2327
|
+
};
|
|
2328
|
+
board.onChange = () => {
|
|
2329
|
+
const options = board.getPluginOptions(PlaitPluginKey.withSelection);
|
|
2330
|
+
if (options.isDisabledSelect) {
|
|
2331
|
+
clearSelectedElement(board);
|
|
2332
|
+
}
|
|
2333
|
+
// calc selected elements entry
|
|
2334
|
+
if (board.pointer !== PlaitPointerType.hand && !options.isDisabledSelect) {
|
|
2335
|
+
try {
|
|
2336
|
+
if (board.operations.find(value => value.type === 'set_selection')) {
|
|
2337
|
+
selectionRectangleG?.remove();
|
|
2338
|
+
const temporaryElements = getTemporaryElements(board);
|
|
2339
|
+
let elements = temporaryElements ? temporaryElements : getHitElements(board);
|
|
2340
|
+
if (!options.isMultiple && elements.length > 1) {
|
|
2341
|
+
elements = [elements[0]];
|
|
2342
|
+
}
|
|
2343
|
+
cacheSelectedElements(board, elements);
|
|
2344
|
+
previousSelectedElements = elements;
|
|
2345
|
+
deleteTemporaryElements(board);
|
|
2346
|
+
if (!isSelectionMoving(board) && elements.length > 1) {
|
|
2347
|
+
selectionRectangleG = createSelectionRectangleG(board);
|
|
2348
|
+
}
|
|
2349
|
+
}
|
|
2350
|
+
else {
|
|
2351
|
+
// wait node destroy and remove selected element state
|
|
2352
|
+
setTimeout(() => {
|
|
2353
|
+
const currentSelectedElements = getSelectedElements(board);
|
|
2354
|
+
if (currentSelectedElements.length && currentSelectedElements.length > 1) {
|
|
2355
|
+
if (currentSelectedElements.length !== previousSelectedElements.length ||
|
|
2356
|
+
currentSelectedElements.some((c, index) => c !== previousSelectedElements[index])) {
|
|
2357
|
+
selectionRectangleG?.remove();
|
|
2358
|
+
selectionRectangleG = createSelectionRectangleG(board);
|
|
2359
|
+
previousSelectedElements = currentSelectedElements;
|
|
2360
|
+
}
|
|
2361
|
+
}
|
|
2362
|
+
else {
|
|
2363
|
+
selectionRectangleG?.remove();
|
|
2364
|
+
}
|
|
2365
|
+
});
|
|
2366
|
+
}
|
|
2367
|
+
}
|
|
2368
|
+
catch (error) {
|
|
2369
|
+
console.error(error);
|
|
2370
|
+
}
|
|
2371
|
+
}
|
|
2372
|
+
onChange();
|
|
2373
|
+
};
|
|
2374
|
+
board.setPluginOptions(PlaitPluginKey.withSelection, {
|
|
2375
|
+
isMultiple: true,
|
|
2376
|
+
isDisabledSelect: false
|
|
2377
|
+
});
|
|
2378
|
+
return board;
|
|
2379
|
+
}
|
|
2380
|
+
function getTemporaryElements(board) {
|
|
2381
|
+
const ref = BOARD_TO_TEMPORARY_ELEMENTS.get(board);
|
|
2382
|
+
if (ref) {
|
|
2383
|
+
return ref.elements;
|
|
2384
|
+
}
|
|
2385
|
+
else {
|
|
2386
|
+
return undefined;
|
|
2387
|
+
}
|
|
2388
|
+
}
|
|
2389
|
+
function getTemporaryRef(board) {
|
|
2390
|
+
return BOARD_TO_TEMPORARY_ELEMENTS.get(board);
|
|
2391
|
+
}
|
|
2392
|
+
function deleteTemporaryElements(board) {
|
|
2393
|
+
BOARD_TO_TEMPORARY_ELEMENTS.delete(board);
|
|
2394
|
+
}
|
|
2395
|
+
function isSelectionMoving(board) {
|
|
2396
|
+
return !!BOARD_TO_IS_SELECTION_MOVING.get(board);
|
|
2397
|
+
}
|
|
2398
|
+
function setSelectionMoving(board) {
|
|
2399
|
+
PlaitBoard.getBoardContainer(board).classList.add('selection-moving');
|
|
2400
|
+
BOARD_TO_IS_SELECTION_MOVING.set(board, true);
|
|
2401
|
+
}
|
|
2402
|
+
function clearSelectionMoving(board) {
|
|
2403
|
+
PlaitBoard.getBoardContainer(board).classList.remove('selection-moving');
|
|
2404
|
+
BOARD_TO_IS_SELECTION_MOVING.delete(board);
|
|
2405
|
+
}
|
|
2406
|
+
function createSelectionRectangleG(board) {
|
|
2407
|
+
const elements = getSelectedElements(board);
|
|
2408
|
+
const rectangle = getRectangleByElements(board, elements, false);
|
|
2409
|
+
if (rectangle.width > 0 && rectangle.height > 0 && elements.length > 1) {
|
|
2410
|
+
const selectionRectangleG = drawRectangle(board, RectangleClient.inflate(rectangle, ACTIVE_STROKE_WIDTH), {
|
|
2411
|
+
stroke: SELECTION_BORDER_COLOR,
|
|
2412
|
+
strokeWidth: ACTIVE_STROKE_WIDTH,
|
|
2413
|
+
fillStyle: 'solid'
|
|
2414
|
+
});
|
|
2415
|
+
selectionRectangleG.classList.add(SELECTION_RECTANGLE_CLASS_NAME);
|
|
2416
|
+
PlaitBoard.getHost(board).append(selectionRectangleG);
|
|
2417
|
+
return selectionRectangleG;
|
|
2418
|
+
}
|
|
2419
|
+
return null;
|
|
2420
|
+
}
|
|
2421
|
+
|
|
2157
2422
|
function setSelection(board, selection) {
|
|
2158
2423
|
const operation = { type: 'set_selection', properties: board.selection, newProperties: selection };
|
|
2159
2424
|
board.apply(operation);
|
|
2160
2425
|
}
|
|
2161
2426
|
const SelectionTransforms = {
|
|
2162
2427
|
setSelection,
|
|
2163
|
-
|
|
2428
|
+
addSelectionWithTemporaryElements
|
|
2164
2429
|
};
|
|
2165
|
-
function
|
|
2166
|
-
setTimeout(() => {
|
|
2167
|
-
BOARD_TO_TEMPORARY_ELEMENTS.set(board, elements);
|
|
2430
|
+
function addSelectionWithTemporaryElements(board, elements) {
|
|
2431
|
+
const timeoutId = setTimeout(() => {
|
|
2168
2432
|
setSelection(board, { ranges: [] });
|
|
2169
|
-
});
|
|
2433
|
+
}, 0);
|
|
2434
|
+
let ref = getTemporaryRef(board);
|
|
2435
|
+
if (ref) {
|
|
2436
|
+
clearTimeout(ref.timeoutId);
|
|
2437
|
+
const currentElements = ref.elements;
|
|
2438
|
+
ref.elements.push(...elements.filter(element => !currentElements.includes(element)));
|
|
2439
|
+
ref.timeoutId = timeoutId;
|
|
2440
|
+
}
|
|
2441
|
+
else {
|
|
2442
|
+
BOARD_TO_TEMPORARY_ELEMENTS.set(board, { timeoutId, elements });
|
|
2443
|
+
}
|
|
2170
2444
|
}
|
|
2171
2445
|
|
|
2172
2446
|
function setViewport(board, viewport) {
|
|
@@ -2423,14 +2697,15 @@ function createBoard(children, options) {
|
|
|
2423
2697
|
isMovable: element => false,
|
|
2424
2698
|
getRectangle: element => null,
|
|
2425
2699
|
applyTheme: (element) => { },
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2700
|
+
isAlign: element => false,
|
|
2701
|
+
pointerDown: pointer => { },
|
|
2702
|
+
pointerMove: pointer => { },
|
|
2703
|
+
pointerUp: pointer => { },
|
|
2704
|
+
pointerCancel: pointer => { },
|
|
2705
|
+
pointerOut: pointer => { },
|
|
2706
|
+
pointerLeave: pointer => { },
|
|
2707
|
+
globalPointerMove: pointer => { },
|
|
2708
|
+
globalPointerUp: pointer => { }
|
|
2434
2709
|
};
|
|
2435
2710
|
return board;
|
|
2436
2711
|
}
|
|
@@ -2585,175 +2860,6 @@ function withHandPointer(board) {
|
|
|
2585
2860
|
return board;
|
|
2586
2861
|
}
|
|
2587
2862
|
|
|
2588
|
-
function withSelection(board) {
|
|
2589
|
-
const { pointerDown, globalPointerMove, globalPointerUp, onChange } = board;
|
|
2590
|
-
let start = null;
|
|
2591
|
-
let end = null;
|
|
2592
|
-
let selectionMovingG;
|
|
2593
|
-
let selectionOuterG;
|
|
2594
|
-
let previousSelectedElements;
|
|
2595
|
-
// prevent text from being selected when user pressed main pointer and is moving
|
|
2596
|
-
let needPreventNativeSelectionWhenMoving = false;
|
|
2597
|
-
board.pointerDown = (event) => {
|
|
2598
|
-
if (event.target instanceof Element && !event.target.closest('.plait-richtext-container')) {
|
|
2599
|
-
needPreventNativeSelectionWhenMoving = true;
|
|
2600
|
-
}
|
|
2601
|
-
if (!isMainPointer(event)) {
|
|
2602
|
-
pointerDown(event);
|
|
2603
|
-
return;
|
|
2604
|
-
}
|
|
2605
|
-
const options = board.getPluginOptions(PlaitPluginKey.withSelection);
|
|
2606
|
-
const point = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
|
|
2607
|
-
const range = { anchor: point, focus: point };
|
|
2608
|
-
const hitElements = getHitElements(board, { ranges: [range] });
|
|
2609
|
-
const selectedElements = getSelectedElements(board);
|
|
2610
|
-
if (hitElements.length === 1 && selectedElements.includes(hitElements[0]) && !options.isDisabledSelect) {
|
|
2611
|
-
pointerDown(event);
|
|
2612
|
-
return;
|
|
2613
|
-
}
|
|
2614
|
-
if (PlaitBoard.isPointer(board, PlaitPointerType.selection) &&
|
|
2615
|
-
hitElements.length === 0 &&
|
|
2616
|
-
options.isMultiple &&
|
|
2617
|
-
!options.isDisabledSelect) {
|
|
2618
|
-
start = point;
|
|
2619
|
-
preventTouchMove(board, event, true);
|
|
2620
|
-
}
|
|
2621
|
-
Transforms.setSelection(board, { ranges: [range] });
|
|
2622
|
-
pointerDown(event);
|
|
2623
|
-
};
|
|
2624
|
-
board.globalPointerMove = (event) => {
|
|
2625
|
-
if (needPreventNativeSelectionWhenMoving) {
|
|
2626
|
-
// prevent text from being selected
|
|
2627
|
-
event.preventDefault();
|
|
2628
|
-
}
|
|
2629
|
-
if (start) {
|
|
2630
|
-
const movedTarget = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
|
|
2631
|
-
const rectangle = RectangleClient.toRectangleClient([start, movedTarget]);
|
|
2632
|
-
selectionMovingG?.remove();
|
|
2633
|
-
if (Math.hypot(rectangle.width, rectangle.height) > 5) {
|
|
2634
|
-
end = movedTarget;
|
|
2635
|
-
throttleRAF(() => {
|
|
2636
|
-
if (start && end) {
|
|
2637
|
-
Transforms.setSelection(board, { ranges: [{ anchor: start, focus: end }] });
|
|
2638
|
-
}
|
|
2639
|
-
});
|
|
2640
|
-
setSelectionMoving(board);
|
|
2641
|
-
selectionMovingG = drawRectangle(board, rectangle, {
|
|
2642
|
-
stroke: SELECTION_BORDER_COLOR,
|
|
2643
|
-
strokeWidth: 1,
|
|
2644
|
-
fill: SELECTION_FILL_COLOR,
|
|
2645
|
-
fillStyle: 'solid'
|
|
2646
|
-
});
|
|
2647
|
-
PlaitBoard.getHost(board).append(selectionMovingG);
|
|
2648
|
-
}
|
|
2649
|
-
}
|
|
2650
|
-
globalPointerMove(event);
|
|
2651
|
-
};
|
|
2652
|
-
board.globalPointerUp = (event) => {
|
|
2653
|
-
if (start && end) {
|
|
2654
|
-
selectionMovingG?.remove();
|
|
2655
|
-
clearSelectionMoving(board);
|
|
2656
|
-
Transforms.setSelection(board, { ranges: [{ anchor: start, focus: end }] });
|
|
2657
|
-
}
|
|
2658
|
-
if (PlaitBoard.isFocus(board)) {
|
|
2659
|
-
const isInBoard = event.target instanceof Node && PlaitBoard.getBoardContainer(board).contains(event.target);
|
|
2660
|
-
const isInDocument = event.target instanceof Node && document.contains(event.target);
|
|
2661
|
-
const isAttachedElement = event.target instanceof Element && event.target.closest(`.${ATTACHED_ELEMENT_CLASS_NAME}`);
|
|
2662
|
-
// Clear selection when mouse board outside area
|
|
2663
|
-
// The framework needs to determine whether the board is focused through selection
|
|
2664
|
-
if (!isInBoard && !start && !isAttachedElement && isInDocument) {
|
|
2665
|
-
Transforms.setSelection(board, null);
|
|
2666
|
-
}
|
|
2667
|
-
}
|
|
2668
|
-
start = null;
|
|
2669
|
-
end = null;
|
|
2670
|
-
needPreventNativeSelectionWhenMoving = false;
|
|
2671
|
-
preventTouchMove(board, event, false);
|
|
2672
|
-
globalPointerUp(event);
|
|
2673
|
-
};
|
|
2674
|
-
board.onChange = () => {
|
|
2675
|
-
const options = board.getPluginOptions(PlaitPluginKey.withSelection);
|
|
2676
|
-
if (options.isDisabledSelect) {
|
|
2677
|
-
selectionOuterG?.remove();
|
|
2678
|
-
clearSelectedElement(board);
|
|
2679
|
-
}
|
|
2680
|
-
// calc selected elements entry
|
|
2681
|
-
if (board.pointer !== PlaitPointerType.hand && !options.isDisabledSelect) {
|
|
2682
|
-
try {
|
|
2683
|
-
if (board.operations.find(value => value.type === 'set_selection')) {
|
|
2684
|
-
selectionOuterG?.remove();
|
|
2685
|
-
const temporaryElements = getTemporaryElements(board);
|
|
2686
|
-
let elements = temporaryElements ? temporaryElements : getHitElements(board);
|
|
2687
|
-
if (!options.isMultiple && elements.length > 1) {
|
|
2688
|
-
elements = [elements[0]];
|
|
2689
|
-
}
|
|
2690
|
-
cacheSelectedElements(board, elements);
|
|
2691
|
-
previousSelectedElements = elements;
|
|
2692
|
-
const { width, height } = getRectangleByElements(board, elements, false);
|
|
2693
|
-
if (width > 0 && height > 0 && elements.length > 1) {
|
|
2694
|
-
selectionOuterG = createSelectionOuterG(board, elements);
|
|
2695
|
-
selectionOuterG.classList.add('selection-outer');
|
|
2696
|
-
PlaitBoard.getHost(board).append(selectionOuterG);
|
|
2697
|
-
}
|
|
2698
|
-
deleteTemporaryElements(board);
|
|
2699
|
-
}
|
|
2700
|
-
else {
|
|
2701
|
-
// wait node destroy and remove selected element state
|
|
2702
|
-
setTimeout(() => {
|
|
2703
|
-
const currentSelectedElements = getSelectedElements(board);
|
|
2704
|
-
if (currentSelectedElements.length && currentSelectedElements.length > 1) {
|
|
2705
|
-
const selectedElementChange = currentSelectedElements.some(item => !previousSelectedElements.includes(item));
|
|
2706
|
-
if (selectedElementChange) {
|
|
2707
|
-
selectionOuterG?.remove();
|
|
2708
|
-
selectionOuterG = createSelectionOuterG(board, currentSelectedElements);
|
|
2709
|
-
selectionOuterG.classList.add('selection-outer');
|
|
2710
|
-
PlaitBoard.getHost(board).append(selectionOuterG);
|
|
2711
|
-
}
|
|
2712
|
-
}
|
|
2713
|
-
else {
|
|
2714
|
-
selectionOuterG?.remove();
|
|
2715
|
-
}
|
|
2716
|
-
});
|
|
2717
|
-
}
|
|
2718
|
-
}
|
|
2719
|
-
catch (error) {
|
|
2720
|
-
console.error(error);
|
|
2721
|
-
}
|
|
2722
|
-
}
|
|
2723
|
-
onChange();
|
|
2724
|
-
};
|
|
2725
|
-
board.setPluginOptions(PlaitPluginKey.withSelection, {
|
|
2726
|
-
isMultiple: true,
|
|
2727
|
-
isDisabledSelect: false
|
|
2728
|
-
});
|
|
2729
|
-
return board;
|
|
2730
|
-
}
|
|
2731
|
-
function getTemporaryElements(board) {
|
|
2732
|
-
return BOARD_TO_TEMPORARY_ELEMENTS.get(board);
|
|
2733
|
-
}
|
|
2734
|
-
function deleteTemporaryElements(board) {
|
|
2735
|
-
BOARD_TO_TEMPORARY_ELEMENTS.delete(board);
|
|
2736
|
-
}
|
|
2737
|
-
function isSelectionMoving(board) {
|
|
2738
|
-
return !!BOARD_TO_IS_SELECTION_MOVING.get(board);
|
|
2739
|
-
}
|
|
2740
|
-
function setSelectionMoving(board) {
|
|
2741
|
-
PlaitBoard.getBoardContainer(board).classList.add('selection-moving');
|
|
2742
|
-
BOARD_TO_IS_SELECTION_MOVING.set(board, true);
|
|
2743
|
-
}
|
|
2744
|
-
function clearSelectionMoving(board) {
|
|
2745
|
-
PlaitBoard.getBoardContainer(board).classList.remove('selection-moving');
|
|
2746
|
-
BOARD_TO_IS_SELECTION_MOVING.delete(board);
|
|
2747
|
-
}
|
|
2748
|
-
function createSelectionOuterG(board, selectElements) {
|
|
2749
|
-
const rectangle = getRectangleByElements(board, selectElements, false);
|
|
2750
|
-
return drawRectangle(board, RectangleClient.inflate(rectangle, ACTIVE_STROKE_WIDTH), {
|
|
2751
|
-
stroke: SELECTION_BORDER_COLOR,
|
|
2752
|
-
strokeWidth: ACTIVE_STROKE_WIDTH,
|
|
2753
|
-
fillStyle: 'solid'
|
|
2754
|
-
});
|
|
2755
|
-
}
|
|
2756
|
-
|
|
2757
2863
|
function withViewport(board) {
|
|
2758
2864
|
const { onChange } = board;
|
|
2759
2865
|
const throttleUpdate = debounce(() => {
|
|
@@ -2782,6 +2888,372 @@ function withViewport(board) {
|
|
|
2782
2888
|
return board;
|
|
2783
2889
|
}
|
|
2784
2890
|
|
|
2891
|
+
const ALIGN_TOLERANCE = 2;
|
|
2892
|
+
class AlignReaction {
|
|
2893
|
+
constructor(board, activeElements, activeRectangle) {
|
|
2894
|
+
this.board = board;
|
|
2895
|
+
this.activeElements = activeElements;
|
|
2896
|
+
this.activeRectangle = activeRectangle;
|
|
2897
|
+
this.alignRectangles = this.getAlignRectangle();
|
|
2898
|
+
}
|
|
2899
|
+
getAlignRectangle() {
|
|
2900
|
+
const result = [];
|
|
2901
|
+
depthFirstRecursion(this.board, node => {
|
|
2902
|
+
if (PlaitBoard.isBoard(node) || this.activeElements.some(element => node.id === element.id) || !this.board.isAlign(node)) {
|
|
2903
|
+
return;
|
|
2904
|
+
}
|
|
2905
|
+
const rectangle = this.board.getRectangle(node);
|
|
2906
|
+
rectangle && result.push(rectangle);
|
|
2907
|
+
}, node => {
|
|
2908
|
+
if (node && (PlaitBoard.isBoard(node) || this.board.isRecursion(node))) {
|
|
2909
|
+
return true;
|
|
2910
|
+
}
|
|
2911
|
+
else {
|
|
2912
|
+
return false;
|
|
2913
|
+
}
|
|
2914
|
+
}, true);
|
|
2915
|
+
return result;
|
|
2916
|
+
}
|
|
2917
|
+
handleAlign() {
|
|
2918
|
+
const alignRectangles = this.getAlignRectangle();
|
|
2919
|
+
const g = createG();
|
|
2920
|
+
let alignLines = [];
|
|
2921
|
+
const offset = 12;
|
|
2922
|
+
let deltaX = 0;
|
|
2923
|
+
let deltaY = 0;
|
|
2924
|
+
let isCorrectX = false;
|
|
2925
|
+
let isCorrectY = false;
|
|
2926
|
+
for (let alignRectangle of alignRectangles) {
|
|
2927
|
+
const closestDistances = this.calculateClosestDistances(this.activeRectangle, alignRectangle);
|
|
2928
|
+
let canDrawHorizontal = false;
|
|
2929
|
+
if (!isCorrectX && closestDistances.absXDistance < ALIGN_TOLERANCE) {
|
|
2930
|
+
deltaX = closestDistances.xDistance;
|
|
2931
|
+
this.activeRectangle.x -= deltaX;
|
|
2932
|
+
isCorrectX = true;
|
|
2933
|
+
canDrawHorizontal = true;
|
|
2934
|
+
}
|
|
2935
|
+
if (closestDistances.absXDistance === 0) {
|
|
2936
|
+
canDrawHorizontal = true;
|
|
2937
|
+
}
|
|
2938
|
+
if (canDrawHorizontal) {
|
|
2939
|
+
const verticalY = [
|
|
2940
|
+
alignRectangle.y,
|
|
2941
|
+
alignRectangle.y + alignRectangle.height,
|
|
2942
|
+
this.activeRectangle.y,
|
|
2943
|
+
this.activeRectangle.y + this.activeRectangle.height
|
|
2944
|
+
];
|
|
2945
|
+
const lineTopY = Math.min(...verticalY) - offset;
|
|
2946
|
+
const lineBottomY = Math.max(...verticalY) + offset;
|
|
2947
|
+
const leftLine = [this.activeRectangle.x, lineTopY, this.activeRectangle.x, lineBottomY];
|
|
2948
|
+
const middleLine = [
|
|
2949
|
+
this.activeRectangle.x + this.activeRectangle.width / 2,
|
|
2950
|
+
lineTopY,
|
|
2951
|
+
this.activeRectangle.x + this.activeRectangle.width / 2,
|
|
2952
|
+
lineBottomY
|
|
2953
|
+
];
|
|
2954
|
+
const rightLine = [
|
|
2955
|
+
this.activeRectangle.x + this.activeRectangle.width,
|
|
2956
|
+
lineTopY,
|
|
2957
|
+
this.activeRectangle.x + this.activeRectangle.width,
|
|
2958
|
+
lineBottomY
|
|
2959
|
+
];
|
|
2960
|
+
const shouldDrawLeftLine = closestDistances.indexX === 0 ||
|
|
2961
|
+
closestDistances.indexX === 1 ||
|
|
2962
|
+
(closestDistances.indexX === 2 && this.activeRectangle.width === alignRectangle.width);
|
|
2963
|
+
if (shouldDrawLeftLine && !alignLines[0]) {
|
|
2964
|
+
alignLines[0] = leftLine;
|
|
2965
|
+
}
|
|
2966
|
+
const shouldDrawRightLine = closestDistances.indexX === 2 ||
|
|
2967
|
+
closestDistances.indexX === 3 ||
|
|
2968
|
+
(closestDistances.indexX === 0 && this.activeRectangle.width === alignRectangle.width);
|
|
2969
|
+
if (shouldDrawRightLine && !alignLines[2]) {
|
|
2970
|
+
alignLines[2] = rightLine;
|
|
2971
|
+
}
|
|
2972
|
+
const shouldDrawMiddleLine = closestDistances.indexX === 4 || (!shouldDrawLeftLine && !shouldDrawRightLine);
|
|
2973
|
+
if (shouldDrawMiddleLine && !alignLines[1]) {
|
|
2974
|
+
alignLines[1] = middleLine;
|
|
2975
|
+
}
|
|
2976
|
+
isCorrectX = true;
|
|
2977
|
+
}
|
|
2978
|
+
let canDrawVertical = false;
|
|
2979
|
+
if (!isCorrectY && closestDistances.absYDistance < ALIGN_TOLERANCE) {
|
|
2980
|
+
deltaY = closestDistances.yDistance;
|
|
2981
|
+
this.activeRectangle.y -= deltaY;
|
|
2982
|
+
isCorrectY = true;
|
|
2983
|
+
canDrawVertical = true;
|
|
2984
|
+
}
|
|
2985
|
+
if (closestDistances.absYDistance === 0) {
|
|
2986
|
+
canDrawVertical = true;
|
|
2987
|
+
}
|
|
2988
|
+
if (canDrawVertical) {
|
|
2989
|
+
const horizontalX = [
|
|
2990
|
+
alignRectangle.x,
|
|
2991
|
+
alignRectangle.x + alignRectangle.width,
|
|
2992
|
+
this.activeRectangle.x,
|
|
2993
|
+
this.activeRectangle.x + this.activeRectangle.width
|
|
2994
|
+
];
|
|
2995
|
+
const lineLeftX = Math.min(...horizontalX) - offset;
|
|
2996
|
+
const lineRightX = Math.max(...horizontalX) + offset;
|
|
2997
|
+
const topLine = [lineLeftX, this.activeRectangle.y, lineRightX, this.activeRectangle.y];
|
|
2998
|
+
const horizontalMiddleLine = [
|
|
2999
|
+
lineLeftX,
|
|
3000
|
+
this.activeRectangle.y + this.activeRectangle.height / 2,
|
|
3001
|
+
lineRightX,
|
|
3002
|
+
this.activeRectangle.y + this.activeRectangle.height / 2
|
|
3003
|
+
];
|
|
3004
|
+
const bottomLine = [
|
|
3005
|
+
lineLeftX,
|
|
3006
|
+
this.activeRectangle.y + this.activeRectangle.height,
|
|
3007
|
+
lineRightX,
|
|
3008
|
+
this.activeRectangle.y + this.activeRectangle.height
|
|
3009
|
+
];
|
|
3010
|
+
const shouldDrawTopLine = closestDistances.indexY === 0 ||
|
|
3011
|
+
closestDistances.indexY === 1 ||
|
|
3012
|
+
(closestDistances.indexY === 2 && this.activeRectangle.height === alignRectangle.height);
|
|
3013
|
+
if (shouldDrawTopLine && !alignLines[3]) {
|
|
3014
|
+
alignLines[3] = topLine;
|
|
3015
|
+
}
|
|
3016
|
+
const shouldDrawBottomLine = closestDistances.indexY === 2 ||
|
|
3017
|
+
closestDistances.indexY === 3 ||
|
|
3018
|
+
(closestDistances.indexY === 0 && this.activeRectangle.width === alignRectangle.width);
|
|
3019
|
+
if (shouldDrawBottomLine && !alignLines[5]) {
|
|
3020
|
+
alignLines[5] = bottomLine;
|
|
3021
|
+
}
|
|
3022
|
+
const shouldDrawMiddleLine = closestDistances.indexY === 4 || (!shouldDrawTopLine && !shouldDrawBottomLine);
|
|
3023
|
+
if (shouldDrawMiddleLine && !alignLines[4]) {
|
|
3024
|
+
alignLines[4] = horizontalMiddleLine;
|
|
3025
|
+
}
|
|
3026
|
+
}
|
|
3027
|
+
}
|
|
3028
|
+
const alignDeltaX = deltaX;
|
|
3029
|
+
const alignDeltaY = deltaY;
|
|
3030
|
+
this.activeRectangle.x += deltaX;
|
|
3031
|
+
const distributeHorizontalResult = this.alignDistribute(alignRectangles, true);
|
|
3032
|
+
const distributeVerticalResult = this.alignDistribute(alignRectangles, false);
|
|
3033
|
+
const distributeLines = [...distributeHorizontalResult.distributeLines, ...distributeVerticalResult.distributeLines];
|
|
3034
|
+
if (distributeHorizontalResult.delta) {
|
|
3035
|
+
deltaX = distributeHorizontalResult.delta;
|
|
3036
|
+
if (alignDeltaX !== deltaX) {
|
|
3037
|
+
alignLines[0] = [];
|
|
3038
|
+
alignLines[1] = [];
|
|
3039
|
+
alignLines[2] = [];
|
|
3040
|
+
}
|
|
3041
|
+
}
|
|
3042
|
+
if (distributeVerticalResult.delta) {
|
|
3043
|
+
deltaY = distributeVerticalResult.delta;
|
|
3044
|
+
if (alignDeltaY !== deltaY) {
|
|
3045
|
+
alignLines[3] = [];
|
|
3046
|
+
alignLines[4] = [];
|
|
3047
|
+
alignLines[5] = [];
|
|
3048
|
+
}
|
|
3049
|
+
}
|
|
3050
|
+
if (alignLines.length) {
|
|
3051
|
+
this.drawAlignLines(alignLines, g);
|
|
3052
|
+
}
|
|
3053
|
+
if (distributeLines.length) {
|
|
3054
|
+
this.drawDistributeLines(distributeLines, g);
|
|
3055
|
+
}
|
|
3056
|
+
return { deltaX, deltaY, g };
|
|
3057
|
+
}
|
|
3058
|
+
calculateClosestDistances(activeRectangle, alignRectangle) {
|
|
3059
|
+
const activeRectangleCenter = [activeRectangle.x + activeRectangle.width / 2, activeRectangle.y + activeRectangle.height / 2];
|
|
3060
|
+
const alignRectangleCenter = [alignRectangle.x + alignRectangle.width / 2, alignRectangle.y + alignRectangle.height / 2];
|
|
3061
|
+
const centerXDistance = activeRectangleCenter[0] - alignRectangleCenter[0];
|
|
3062
|
+
const centerYDistance = activeRectangleCenter[1] - alignRectangleCenter[1];
|
|
3063
|
+
const leftToLeft = activeRectangle.x - alignRectangle.x;
|
|
3064
|
+
const leftToRight = activeRectangle.x - (alignRectangle.x + alignRectangle.width);
|
|
3065
|
+
const rightToRight = activeRectangle.x + activeRectangle.width - (alignRectangle.x + alignRectangle.width);
|
|
3066
|
+
const rightToLeft = activeRectangle.x + activeRectangle.width - alignRectangle.x;
|
|
3067
|
+
const topToTop = activeRectangle.y - alignRectangle.y;
|
|
3068
|
+
const topToBottom = activeRectangle.y - (alignRectangle.y + alignRectangle.height);
|
|
3069
|
+
const bottomToTop = activeRectangle.y + activeRectangle.height - alignRectangle.y;
|
|
3070
|
+
const bottomToBottom = activeRectangle.y + activeRectangle.height - (alignRectangle.y + alignRectangle.height);
|
|
3071
|
+
const xDistances = [leftToLeft, leftToRight, rightToRight, rightToLeft, centerXDistance];
|
|
3072
|
+
const yDistances = [topToTop, topToBottom, bottomToBottom, bottomToTop, centerYDistance];
|
|
3073
|
+
const xDistancesAbs = xDistances.map(distance => Math.abs(distance));
|
|
3074
|
+
const yDistancesAbs = yDistances.map(distance => Math.abs(distance));
|
|
3075
|
+
const indexX = xDistancesAbs.indexOf(Math.min(...xDistancesAbs));
|
|
3076
|
+
const indexY = yDistancesAbs.indexOf(Math.min(...yDistancesAbs));
|
|
3077
|
+
return {
|
|
3078
|
+
absXDistance: xDistancesAbs[indexX],
|
|
3079
|
+
xDistance: xDistances[indexX],
|
|
3080
|
+
absYDistance: yDistancesAbs[indexY],
|
|
3081
|
+
yDistance: yDistances[indexY],
|
|
3082
|
+
indexX,
|
|
3083
|
+
indexY
|
|
3084
|
+
};
|
|
3085
|
+
}
|
|
3086
|
+
alignDistribute(alignRectangles, isHorizontal) {
|
|
3087
|
+
let distributeLines = [];
|
|
3088
|
+
let delta = 0;
|
|
3089
|
+
let rectangles = [];
|
|
3090
|
+
const axis = isHorizontal ? 'x' : 'y';
|
|
3091
|
+
const side = isHorizontal ? 'width' : 'height';
|
|
3092
|
+
const activeRectangleCenter = this.activeRectangle[axis] + this.activeRectangle[side] / 2;
|
|
3093
|
+
alignRectangles.forEach(rec => {
|
|
3094
|
+
const isCross = isHorizontal ? isHorizontalCross(rec, this.activeRectangle) : isVerticalCross(rec, this.activeRectangle);
|
|
3095
|
+
if (isCross && !RectangleClient.isHit(rec, this.activeRectangle)) {
|
|
3096
|
+
rectangles.push(rec);
|
|
3097
|
+
}
|
|
3098
|
+
});
|
|
3099
|
+
rectangles = [...rectangles, this.activeRectangle].sort((a, b) => a[axis] - b[axis]);
|
|
3100
|
+
const refArray = [];
|
|
3101
|
+
let distributeDistance = 0;
|
|
3102
|
+
let beforeIndex = undefined;
|
|
3103
|
+
let afterIndex = undefined;
|
|
3104
|
+
for (let i = 0; i < rectangles.length; i++) {
|
|
3105
|
+
for (let j = i + 1; j < rectangles.length; j++) {
|
|
3106
|
+
const before = rectangles[i];
|
|
3107
|
+
const after = rectangles[j];
|
|
3108
|
+
const distance = after[axis] - (before[axis] + before[side]);
|
|
3109
|
+
let dif = Infinity;
|
|
3110
|
+
if (refArray[i]?.after) {
|
|
3111
|
+
refArray[i].after.push({ distance, index: j });
|
|
3112
|
+
}
|
|
3113
|
+
else {
|
|
3114
|
+
refArray[i] = { ...refArray[i], after: [{ distance, index: j }] };
|
|
3115
|
+
}
|
|
3116
|
+
if (refArray[j]?.before) {
|
|
3117
|
+
refArray[j].before.push({ distance, index: i });
|
|
3118
|
+
}
|
|
3119
|
+
else {
|
|
3120
|
+
refArray[j] = { ...refArray[j], before: [{ distance, index: i }] };
|
|
3121
|
+
}
|
|
3122
|
+
//middle
|
|
3123
|
+
let _center = (before[axis] + before[side] + after[axis]) / 2;
|
|
3124
|
+
dif = Math.abs(activeRectangleCenter - _center);
|
|
3125
|
+
if (dif < ALIGN_TOLERANCE) {
|
|
3126
|
+
distributeDistance = (after[axis] - (before[axis] + before[side]) - this.activeRectangle[side]) / 2;
|
|
3127
|
+
delta = activeRectangleCenter - _center;
|
|
3128
|
+
beforeIndex = i;
|
|
3129
|
+
afterIndex = j;
|
|
3130
|
+
}
|
|
3131
|
+
//after
|
|
3132
|
+
const distanceRight = after[axis] - (before[axis] + before[side]);
|
|
3133
|
+
_center = after[axis] + after[side] + distanceRight + this.activeRectangle[side] / 2;
|
|
3134
|
+
dif = Math.abs(activeRectangleCenter - _center);
|
|
3135
|
+
if (!distributeDistance && dif < ALIGN_TOLERANCE) {
|
|
3136
|
+
distributeDistance = distanceRight;
|
|
3137
|
+
beforeIndex = j;
|
|
3138
|
+
delta = activeRectangleCenter - _center;
|
|
3139
|
+
}
|
|
3140
|
+
//before
|
|
3141
|
+
const distanceBefore = after[axis] - (before[axis] + before[side]);
|
|
3142
|
+
_center = before[axis] - distanceBefore - this.activeRectangle[side] / 2;
|
|
3143
|
+
dif = Math.abs(activeRectangleCenter - _center);
|
|
3144
|
+
if (!distributeDistance && dif < ALIGN_TOLERANCE) {
|
|
3145
|
+
distributeDistance = distanceBefore;
|
|
3146
|
+
afterIndex = i;
|
|
3147
|
+
delta = activeRectangleCenter - _center;
|
|
3148
|
+
}
|
|
3149
|
+
}
|
|
3150
|
+
}
|
|
3151
|
+
const activeIndex = rectangles.indexOf(this.activeRectangle);
|
|
3152
|
+
let beforeIndexes = [];
|
|
3153
|
+
let afterIndexes = [];
|
|
3154
|
+
if (beforeIndex !== undefined) {
|
|
3155
|
+
beforeIndexes.push(beforeIndex);
|
|
3156
|
+
findRectangle(distributeDistance, refArray[beforeIndex], 'before', beforeIndexes);
|
|
3157
|
+
}
|
|
3158
|
+
if (afterIndex !== undefined) {
|
|
3159
|
+
afterIndexes.push(afterIndex);
|
|
3160
|
+
findRectangle(distributeDistance, refArray[afterIndex], 'after', afterIndexes);
|
|
3161
|
+
}
|
|
3162
|
+
if (beforeIndexes.length || afterIndexes.length) {
|
|
3163
|
+
const indexArr = [...beforeIndexes.reverse(), activeIndex, ...afterIndexes];
|
|
3164
|
+
this.activeRectangle[axis] -= delta;
|
|
3165
|
+
for (let i = 1; i < indexArr.length; i++) {
|
|
3166
|
+
distributeLines.push(getLinePoints(rectangles[indexArr[i - 1]], rectangles[indexArr[i]]));
|
|
3167
|
+
}
|
|
3168
|
+
}
|
|
3169
|
+
function findRectangle(distance, ref, direction, rectangleIndexes) {
|
|
3170
|
+
const arr = ref[direction];
|
|
3171
|
+
const index = refArray.indexOf(ref);
|
|
3172
|
+
if ((index === 0 && direction === 'before') || (index === refArray.length - 1 && direction === 'after'))
|
|
3173
|
+
return;
|
|
3174
|
+
for (let i = 0; i < arr.length; i++) {
|
|
3175
|
+
if (Math.abs(arr[i].distance - distance) < 0.1) {
|
|
3176
|
+
rectangleIndexes.push(arr[i].index);
|
|
3177
|
+
findRectangle(distance, refArray[arr[i].index], direction, rectangleIndexes);
|
|
3178
|
+
return;
|
|
3179
|
+
}
|
|
3180
|
+
}
|
|
3181
|
+
}
|
|
3182
|
+
function getLinePoints(beforeRectangle, afterRectangle) {
|
|
3183
|
+
const oppositeAxis = axis === 'x' ? 'y' : 'x';
|
|
3184
|
+
const oppositeSide = side === 'width' ? 'height' : 'width';
|
|
3185
|
+
const align = [
|
|
3186
|
+
beforeRectangle[oppositeAxis],
|
|
3187
|
+
beforeRectangle[oppositeAxis] + beforeRectangle[oppositeSide],
|
|
3188
|
+
afterRectangle[oppositeAxis],
|
|
3189
|
+
afterRectangle[oppositeAxis] + afterRectangle[oppositeSide]
|
|
3190
|
+
];
|
|
3191
|
+
const sortArr = align.sort((a, b) => a - b);
|
|
3192
|
+
const average = (sortArr[1] + sortArr[2]) / 2;
|
|
3193
|
+
const offset = 3;
|
|
3194
|
+
return isHorizontal
|
|
3195
|
+
? [
|
|
3196
|
+
[beforeRectangle.x + beforeRectangle.width + offset, average],
|
|
3197
|
+
[afterRectangle.x - offset, average]
|
|
3198
|
+
]
|
|
3199
|
+
: [
|
|
3200
|
+
[average, beforeRectangle.y + beforeRectangle.height + offset],
|
|
3201
|
+
[average, afterRectangle.y - offset]
|
|
3202
|
+
];
|
|
3203
|
+
}
|
|
3204
|
+
return { delta, distributeLines };
|
|
3205
|
+
}
|
|
3206
|
+
drawAlignLines(lines, g) {
|
|
3207
|
+
lines.forEach(points => {
|
|
3208
|
+
if (!points.length)
|
|
3209
|
+
return;
|
|
3210
|
+
const xAlign = PlaitBoard.getRoughSVG(this.board).line(points[0], points[1], points[2], points[3], {
|
|
3211
|
+
stroke: SELECTION_BORDER_COLOR,
|
|
3212
|
+
strokeWidth: 1,
|
|
3213
|
+
strokeLineDash: [4, 4]
|
|
3214
|
+
});
|
|
3215
|
+
g.appendChild(xAlign);
|
|
3216
|
+
});
|
|
3217
|
+
}
|
|
3218
|
+
drawDistributeLines(lines, g) {
|
|
3219
|
+
lines.forEach(line => {
|
|
3220
|
+
if (!line.length)
|
|
3221
|
+
return;
|
|
3222
|
+
let isHorizontal = line[0][1] === line[1][1];
|
|
3223
|
+
const yAlign = PlaitBoard.getRoughSVG(this.board).line(line[0][0], line[0][1], line[1][0], line[1][1], {
|
|
3224
|
+
stroke: SELECTION_BORDER_COLOR,
|
|
3225
|
+
strokeWidth: 1
|
|
3226
|
+
});
|
|
3227
|
+
g.appendChild(yAlign);
|
|
3228
|
+
line.forEach(point => {
|
|
3229
|
+
const barPoint = getBarPoint(point, isHorizontal);
|
|
3230
|
+
const bar = PlaitBoard.getRoughSVG(this.board).line(barPoint[0][0], barPoint[0][1], barPoint[1][0], barPoint[1][1], {
|
|
3231
|
+
stroke: SELECTION_BORDER_COLOR,
|
|
3232
|
+
strokeWidth: 1
|
|
3233
|
+
});
|
|
3234
|
+
g.appendChild(bar);
|
|
3235
|
+
});
|
|
3236
|
+
});
|
|
3237
|
+
}
|
|
3238
|
+
}
|
|
3239
|
+
function isHorizontalCross(rectangle, other) {
|
|
3240
|
+
return !(rectangle.y + rectangle.height < other.y || rectangle.y > other.y + other.height);
|
|
3241
|
+
}
|
|
3242
|
+
function isVerticalCross(rectangle, other) {
|
|
3243
|
+
return !(rectangle.x + rectangle.width < other.x || rectangle.x > other.x + other.width);
|
|
3244
|
+
}
|
|
3245
|
+
function getBarPoint(point, isHorizontal) {
|
|
3246
|
+
return isHorizontal
|
|
3247
|
+
? [
|
|
3248
|
+
[point[0], point[1] - 4],
|
|
3249
|
+
[point[0], point[1] + 4]
|
|
3250
|
+
]
|
|
3251
|
+
: [
|
|
3252
|
+
[point[0] - 4, point[1]],
|
|
3253
|
+
[point[0] + 4, point[1]]
|
|
3254
|
+
];
|
|
3255
|
+
}
|
|
3256
|
+
|
|
2785
3257
|
function withMoving(board) {
|
|
2786
3258
|
const { pointerDown, pointerMove, globalPointerUp, globalPointerMove } = board;
|
|
2787
3259
|
let offsetX = 0;
|
|
@@ -2789,6 +3261,7 @@ function withMoving(board) {
|
|
|
2789
3261
|
let isPreventDefault = false;
|
|
2790
3262
|
let startPoint;
|
|
2791
3263
|
let activeElements = [];
|
|
3264
|
+
let alignG = null;
|
|
2792
3265
|
board.pointerDown = (event) => {
|
|
2793
3266
|
const host = BOARD_TO_HOST.get(board);
|
|
2794
3267
|
const point = transformPoint(board, toPoint(event.x, event.y, host));
|
|
@@ -2815,13 +3288,23 @@ function withMoving(board) {
|
|
|
2815
3288
|
if (!isPreventDefault) {
|
|
2816
3289
|
isPreventDefault = true;
|
|
2817
3290
|
}
|
|
3291
|
+
alignG?.remove();
|
|
2818
3292
|
const host = BOARD_TO_HOST.get(board);
|
|
2819
3293
|
const endPoint = transformPoint(board, toPoint(event.x, event.y, host));
|
|
2820
3294
|
offsetX = endPoint[0] - startPoint[0];
|
|
2821
3295
|
offsetY = endPoint[1] - startPoint[1];
|
|
2822
|
-
const
|
|
2823
|
-
if (Math.abs(offsetX) >
|
|
3296
|
+
const tolerance = 5;
|
|
3297
|
+
if (Math.abs(offsetX) > tolerance || Math.abs(offsetY) > tolerance || getMovingElements(board).length > 0) {
|
|
2824
3298
|
throttleRAF(() => {
|
|
3299
|
+
const activeElementsRectangle = getRectangleByElements(board, activeElements, true);
|
|
3300
|
+
activeElementsRectangle.x += offsetX;
|
|
3301
|
+
activeElementsRectangle.y += offsetY;
|
|
3302
|
+
const reactionManager = new AlignReaction(board, activeElements, activeElementsRectangle);
|
|
3303
|
+
const ref = reactionManager.handleAlign();
|
|
3304
|
+
offsetX -= ref.deltaX;
|
|
3305
|
+
offsetY -= ref.deltaY;
|
|
3306
|
+
alignG = ref.g;
|
|
3307
|
+
PlaitBoard.getElementActiveHost(board).append(alignG);
|
|
2825
3308
|
handleTouchTarget(board);
|
|
2826
3309
|
const currentElements = activeElements.map(activeElement => {
|
|
2827
3310
|
const points = activeElement.points || [];
|
|
@@ -2863,6 +3346,7 @@ function withMoving(board) {
|
|
|
2863
3346
|
globalPointerUp(event);
|
|
2864
3347
|
};
|
|
2865
3348
|
function cancelMove(board) {
|
|
3349
|
+
alignG?.remove();
|
|
2866
3350
|
startPoint = null;
|
|
2867
3351
|
offsetX = 0;
|
|
2868
3352
|
offsetY = 0;
|
|
@@ -2976,11 +3460,13 @@ const withHotkey = (board) => {
|
|
|
2976
3460
|
return false;
|
|
2977
3461
|
}
|
|
2978
3462
|
}, true);
|
|
2979
|
-
Transforms.
|
|
3463
|
+
Transforms.addSelectionWithTemporaryElements(board, elements);
|
|
2980
3464
|
return;
|
|
2981
3465
|
}
|
|
2982
3466
|
const selectedElements = getSelectedElements(board);
|
|
2983
|
-
if (!PlaitBoard.isReadonly(board) &&
|
|
3467
|
+
if (!PlaitBoard.isReadonly(board) &&
|
|
3468
|
+
selectedElements.length > 0 &&
|
|
3469
|
+
(hotkeys.isDeleteBackward(event) || hotkeys.isDeleteForward(event))) {
|
|
2984
3470
|
event.preventDefault();
|
|
2985
3471
|
board.deleteFragment(null);
|
|
2986
3472
|
}
|
|
@@ -3108,14 +3594,15 @@ class PlaitElementComponent {
|
|
|
3108
3594
|
this.board.destroyElement(this.getContext());
|
|
3109
3595
|
}
|
|
3110
3596
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.3", ngImport: i0, type: PlaitElementComponent, deps: [{ token: i0.Renderer2 }, { token: i0.ViewContainerRef }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3111
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.3", type: PlaitElementComponent, selector: "plait-element", inputs: { index: "index", element: "element", parent: "parent", board: "board", effect: "effect", parentG: "parentG" }, usesOnChanges: true, ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
3597
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.3", type: PlaitElementComponent, isStandalone: true, selector: "plait-element", inputs: { index: "index", element: "element", parent: "parent", board: "board", effect: "effect", parentG: "parentG" }, usesOnChanges: true, ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
3112
3598
|
}
|
|
3113
3599
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.3", ngImport: i0, type: PlaitElementComponent, decorators: [{
|
|
3114
3600
|
type: Component,
|
|
3115
3601
|
args: [{
|
|
3116
3602
|
selector: 'plait-element',
|
|
3117
3603
|
template: '',
|
|
3118
|
-
changeDetection: ChangeDetectionStrategy.OnPush
|
|
3604
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
3605
|
+
standalone: true
|
|
3119
3606
|
}]
|
|
3120
3607
|
}], ctorParameters: function () { return [{ type: i0.Renderer2 }, { type: i0.ViewContainerRef }]; }, propDecorators: { index: [{
|
|
3121
3608
|
type: Input
|
|
@@ -3131,7 +3618,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.3", ngImpor
|
|
|
3131
3618
|
type: Input
|
|
3132
3619
|
}] } });
|
|
3133
3620
|
|
|
3134
|
-
class
|
|
3621
|
+
class PlaitChildrenElementComponent {
|
|
3135
3622
|
constructor() {
|
|
3136
3623
|
this.trackBy = (index, element) => {
|
|
3137
3624
|
return element.id;
|
|
@@ -3145,8 +3632,8 @@ class PlaitChildrenElement {
|
|
|
3145
3632
|
this.parentG = PlaitBoard.getElementHost(this.board);
|
|
3146
3633
|
}
|
|
3147
3634
|
}
|
|
3148
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.3", ngImport: i0, type:
|
|
3149
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.3", type:
|
|
3635
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.3", ngImport: i0, type: PlaitChildrenElementComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3636
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.3", type: PlaitChildrenElementComponent, isStandalone: true, selector: "plait-children", inputs: { board: "board", parent: "parent", effect: "effect", parentG: "parentG" }, ngImport: i0, template: `
|
|
3150
3637
|
<plait-element
|
|
3151
3638
|
*ngFor="let item of parent.children; let index = index; trackBy: trackBy"
|
|
3152
3639
|
[index]="index"
|
|
@@ -3156,9 +3643,9 @@ class PlaitChildrenElement {
|
|
|
3156
3643
|
[effect]="effect"
|
|
3157
3644
|
[parentG]="parentG"
|
|
3158
3645
|
></plait-element>
|
|
3159
|
-
`, isInline: true, dependencies: [{ kind: "directive", type:
|
|
3646
|
+
`, isInline: true, dependencies: [{ kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: PlaitElementComponent, selector: "plait-element", inputs: ["index", "element", "parent", "board", "effect", "parentG"] }] }); }
|
|
3160
3647
|
}
|
|
3161
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.3", ngImport: i0, type:
|
|
3648
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.3", ngImport: i0, type: PlaitChildrenElementComponent, decorators: [{
|
|
3162
3649
|
type: Component,
|
|
3163
3650
|
args: [{
|
|
3164
3651
|
selector: 'plait-children',
|
|
@@ -3172,7 +3659,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.3", ngImpor
|
|
|
3172
3659
|
[effect]="effect"
|
|
3173
3660
|
[parentG]="parentG"
|
|
3174
3661
|
></plait-element>
|
|
3175
|
-
|
|
3662
|
+
`,
|
|
3663
|
+
standalone: true,
|
|
3664
|
+
imports: [NgFor, PlaitElementComponent]
|
|
3176
3665
|
}]
|
|
3177
3666
|
}], ctorParameters: function () { return []; }, propDecorators: { board: [{
|
|
3178
3667
|
type: Input
|
|
@@ -3404,7 +3893,7 @@ class PlaitBoardComponent {
|
|
|
3404
3893
|
const selectedElements = getSelectedElements(this.board);
|
|
3405
3894
|
event.preventDefault();
|
|
3406
3895
|
const rectangle = getRectangleByElements(this.board, selectedElements, false);
|
|
3407
|
-
this.board.setFragment(event.clipboardData, rectangle);
|
|
3896
|
+
this.board.setFragment(event.clipboardData, rectangle, 'copy');
|
|
3408
3897
|
});
|
|
3409
3898
|
fromEvent(document, 'paste')
|
|
3410
3899
|
.pipe(takeUntil(this.destroy$), filter(() => this.isFocused && !PlaitBoard.isReadonly(this.board) && !PlaitBoard.hasBeenTextEditing(this.board)))
|
|
@@ -3421,7 +3910,7 @@ class PlaitBoardComponent {
|
|
|
3421
3910
|
const selectedElements = getSelectedElements(this.board);
|
|
3422
3911
|
event.preventDefault();
|
|
3423
3912
|
const rectangle = getRectangleByElements(this.board, selectedElements, false);
|
|
3424
|
-
this.board.setFragment(event.clipboardData, rectangle);
|
|
3913
|
+
this.board.setFragment(event.clipboardData, rectangle, 'cut');
|
|
3425
3914
|
this.board.deleteFragment(event.clipboardData);
|
|
3426
3915
|
});
|
|
3427
3916
|
}
|
|
@@ -3496,7 +3985,7 @@ class PlaitBoardComponent {
|
|
|
3496
3985
|
});
|
|
3497
3986
|
}
|
|
3498
3987
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.3", ngImport: i0, type: PlaitBoardComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i0.ViewContainerRef }, { token: i0.ElementRef }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3499
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.3", type: PlaitBoardComponent, 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: `
|
|
3988
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.3", 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: `
|
|
3500
3989
|
<div class="viewport-container" #viewportContainer>
|
|
3501
3990
|
<svg #svg width="100%" height="100%" style="position: relative;" class="board-host-svg">
|
|
3502
3991
|
<g class="element-host"></g>
|
|
@@ -3506,7 +3995,7 @@ class PlaitBoardComponent {
|
|
|
3506
3995
|
<plait-children [board]="board" [effect]="effect"></plait-children>
|
|
3507
3996
|
</div>
|
|
3508
3997
|
<ng-content></ng-content>
|
|
3509
|
-
`, isInline: true, dependencies: [{ kind: "component", type:
|
|
3998
|
+
`, isInline: true, dependencies: [{ kind: "component", type: PlaitChildrenElementComponent, selector: "plait-children", inputs: ["board", "parent", "effect", "parentG"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
3510
3999
|
}
|
|
3511
4000
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.3", ngImport: i0, type: PlaitBoardComponent, decorators: [{
|
|
3512
4001
|
type: Component,
|
|
@@ -3524,7 +4013,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.3", ngImpor
|
|
|
3524
4013
|
<ng-content></ng-content>
|
|
3525
4014
|
`,
|
|
3526
4015
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
3527
|
-
providers: [PlaitContextService]
|
|
4016
|
+
providers: [PlaitContextService],
|
|
4017
|
+
standalone: true,
|
|
4018
|
+
imports: [PlaitChildrenElementComponent]
|
|
3528
4019
|
}]
|
|
3529
4020
|
}], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }, { type: i0.ViewContainerRef }, { type: i0.ElementRef }, { type: i0.NgZone }]; }, propDecorators: { plaitValue: [{
|
|
3530
4021
|
type: Input
|
|
@@ -3563,21 +4054,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.3", ngImpor
|
|
|
3563
4054
|
args: [PlaitIslandBaseComponent, { descendants: true }]
|
|
3564
4055
|
}] } });
|
|
3565
4056
|
|
|
3566
|
-
const COMPONENTS = [PlaitBoardComponent, PlaitChildrenElement, PlaitElementComponent];
|
|
3567
|
-
class PlaitModule {
|
|
3568
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.3", ngImport: i0, type: PlaitModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
3569
|
-
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "16.2.3", ngImport: i0, type: PlaitModule, declarations: [PlaitBoardComponent, PlaitChildrenElement, PlaitElementComponent], imports: [CommonModule], exports: [PlaitBoardComponent, PlaitChildrenElement, PlaitElementComponent] }); }
|
|
3570
|
-
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.2.3", ngImport: i0, type: PlaitModule, imports: [CommonModule] }); }
|
|
3571
|
-
}
|
|
3572
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.3", ngImport: i0, type: PlaitModule, decorators: [{
|
|
3573
|
-
type: NgModule,
|
|
3574
|
-
args: [{
|
|
3575
|
-
declarations: [...COMPONENTS],
|
|
3576
|
-
imports: [CommonModule],
|
|
3577
|
-
exports: [...COMPONENTS]
|
|
3578
|
-
}]
|
|
3579
|
-
}] });
|
|
3580
|
-
|
|
3581
4057
|
/**
|
|
3582
4058
|
* 1.create board instance
|
|
3583
4059
|
* 2.build fake node weak map
|
|
@@ -3746,5 +4222,5 @@ function createModModifierKeys() {
|
|
|
3746
4222
|
* Generated bundle index. Do not edit.
|
|
3747
4223
|
*/
|
|
3748
4224
|
|
|
3749
|
-
export { A, ACTIVE_STROKE_WIDTH, ALT, APOSTROPHE, ATTACHED_ELEMENT_CLASS_NAME, AT_SIGN, B, BACKSLASH, BACKSPACE, 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, CLIP_BOARD_FORMAT_KEY, CLOSE_SQUARE_BRACKET, COMMA, CONTEXT_MENU, CONTROL, ColorfulThemeColor, CoreTransforms, D, DASH, DELETE, DOWN_ARROW, DarkThemeColor, DefaultThemeColor, E, EIGHT, ELEMENT_TO_COMPONENT, END, ENTER, EQUALS, ESCAPE, 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, HOME, HOST_CLASS_NAME, I, INSERT, IS_APPLE, IS_BOARD_CACHE, IS_CHROME, IS_CHROME_LEGACY, 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_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,
|
|
4225
|
+
export { A, ACTIVE_STROKE_WIDTH, ALT, APOSTROPHE, ATTACHED_ELEMENT_CLASS_NAME, AT_SIGN, B, BACKSLASH, BACKSPACE, 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, CLIP_BOARD_FORMAT_KEY, CLOSE_SQUARE_BRACKET, COMMA, CONTEXT_MENU, CONTROL, ColorfulThemeColor, CoreTransforms, D, DASH, DELETE, DOWN_ARROW, DarkThemeColor, DefaultThemeColor, Direction, E, EIGHT, ELEMENT_TO_COMPONENT, END, ENTER, EQUALS, ESCAPE, 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, HOME, HOST_CLASS_NAME, I, INSERT, IS_APPLE, IS_BOARD_CACHE, IS_CHROME, IS_CHROME_LEGACY, 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_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, PlaitChildrenElementComponent, PlaitContextService, PlaitElement, PlaitElementComponent, PlaitHistoryBoard, PlaitIslandBaseComponent, PlaitIslandPopoverBaseComponent, PlaitNode, PlaitOperation, PlaitPluginElementComponent, PlaitPluginKey, PlaitPointerType, Point, Q, QUESTION_MARK, R, RIGHT_ARROW, RectangleClient, ResizeCursorClass, RetroThemeColor, S, SAVING, SCROLL_BAR_WIDTH, SCROLL_LOCK, SELECTION_BORDER_COLOR, SELECTION_FILL_COLOR, SELECTION_RECTANGLE_CLASS_NAME, SEMICOLON, SEVEN, SHIFT, SINGLE_QUOTE, SIX, SLASH, SPACE, Selection, SoftThemeColor, StarryThemeColor, T, TAB, THREE, TILDE, TWO, ThemeColorMode, ThemeColors, Transforms, U, UP_ARROW, V, VOLUME_DOWN, VOLUME_UP, Viewport, W, X, Y, Z, ZERO, addMovingElements, addSelectedElement, arrowPoints, cacheMovingElements, cacheSelectedElements, clampZoomLevel, clearNodeWeakMap, clearSelectedElement, clearSelectionMoving, clearViewportOrigination, createFakeEvent, createForeignObject, createG, createKeyboardEvent, createMask, createModModifierKeys, createMouseEvent, createPath, createPointerEvent, createRect, createSVG, createSelectionRectangleG, createTestingBoard, createText, createTouchEvent, debounce, deleteTemporaryElements, depthFirstRecursion, distanceBetweenPointAndPoint, distanceBetweenPointAndRectangle, distanceBetweenPointAndSegment, distanceBetweenPointAndSegments, downloadImage, drawArrow, drawBezierPath, drawCircle, drawLine, drawLinearPath, drawRectangle, drawRoundRectangle, fakeNodeWeakMap, findElements, getBoardRectangle, getClipboardByKey, getClipboardDataByMedia, getDataFromClipboard, getElementById, getElementHostBBox, getHitElementOfRoot, getHitElements, getIsRecursionFunc, getMovingElements, getNearestPointBetweenPointAndSegment, getNearestPointBetweenPointAndSegments, getRealScrollBarWidth, getRectangleByElements, getSelectedElements, getTemporaryElements, getTemporaryRef, getTextFromClipboard, getViewBox, getViewBoxCenterPoint, getViewportContainerRect, getViewportOrigination, handleTouchTarget, hasBeforeContextChange, hasInputOrTextareaTarget, hasOnBoardChange, hasOnContextChanged, hotkeys, idCreator, initializeViewBox, initializeViewportContainer, initializeViewportOffset, inverse, isDOMElement, isDOMNode, isFromScrolling, isFromViewportChange, isHitElements, isInPlaitBoard, isLineHitLine, isMainPointer, isNullOrUndefined, isPointInEllipse, isPointInPolygon, isPointInRoundRectangle, isPolylineHitRectangle, isPreventTouchMove, isSecondaryPointer, isSelectedElement, isSelectionMoving, isSetViewportOperation, normalizePoint, preventTouchMove, removeMovingElements, removeSelectedElement, rotate, scrollToRectangle, setClipboardData, setClipboardDataByMedia, setClipboardDataByText, setIsFromScrolling, setIsFromViewportChange, setPathStrokeLinecap, setSVGViewBox, setSelectionMoving, setStrokeLinecap, shouldClear, shouldMerge, shouldSave, throttleRAF, toImage, toPoint, transformPoint, transformPoints, updateForeignObject, updateForeignObjectWidth, updateViewportContainerScroll, updateViewportOffset, updateViewportOrigination, withMoving, withOptions, withSelection };
|
|
3750
4226
|
//# sourceMappingURL=plait-core.mjs.map
|