@plait/core 0.53.0 → 0.54.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/esm2022/board/board.component.mjs +6 -4
- package/esm2022/constants/selection.mjs +2 -1
- package/esm2022/interfaces/board.mjs +5 -1
- package/esm2022/interfaces/path.mjs +2 -2
- package/esm2022/interfaces/rectangle-client.mjs +4 -1
- package/esm2022/interfaces/selection.mjs +2 -2
- package/esm2022/plugins/create-board.mjs +7 -5
- package/esm2022/plugins/with-hotkey.mjs +3 -3
- package/esm2022/plugins/with-moving.mjs +7 -6
- package/esm2022/plugins/with-selection.mjs +7 -5
- package/esm2022/transforms/element.mjs +2 -2
- package/esm2022/utils/angle.mjs +42 -3
- package/esm2022/utils/common.mjs +3 -2
- package/esm2022/utils/debug.mjs +16 -1
- package/esm2022/utils/element.mjs +3 -3
- package/esm2022/utils/fragment.mjs +5 -0
- package/esm2022/utils/group.mjs +11 -5
- package/esm2022/utils/index.mjs +2 -1
- package/esm2022/utils/moving-snap.mjs +372 -0
- package/esm2022/utils/selection.mjs +2 -3
- package/esm2022/utils/weak-maps.mjs +2 -1
- package/fesm2022/plait-core.mjs +1092 -1015
- package/fesm2022/plait-core.mjs.map +1 -1
- package/interfaces/board.d.ts +4 -2
- package/interfaces/rectangle-client.d.ts +1 -0
- package/interfaces/selection.d.ts +1 -1
- package/package.json +1 -1
- package/utils/angle.d.ts +6 -1
- package/utils/debug.d.ts +1 -0
- package/utils/fragment.d.ts +2 -0
- package/utils/group.d.ts +2 -2
- package/utils/index.d.ts +1 -0
- package/utils/{reaction-manager.d.ts → moving-snap.d.ts} +3 -3
- package/utils/selection.d.ts +1 -1
- package/utils/weak-maps.d.ts +1 -0
- package/esm2022/utils/reaction-manager.mjs +0 -371
package/fesm2022/plait-core.mjs
CHANGED
|
@@ -4,7 +4,7 @@ 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
|
-
import produce,
|
|
7
|
+
import { produce, createDraft, finishDraft, isDraft } from 'immer';
|
|
8
8
|
import { NgFor } from '@angular/common';
|
|
9
9
|
|
|
10
10
|
// record richtext type status
|
|
@@ -18,6 +18,7 @@ const BOARD_TO_AFTER_CHANGE = new WeakMap();
|
|
|
18
18
|
const BOARD_TO_COMPONENT = new WeakMap();
|
|
19
19
|
const BOARD_TO_ROUGH_SVG = new WeakMap();
|
|
20
20
|
const BOARD_TO_HOST = new WeakMap();
|
|
21
|
+
const IS_BOARD_ALIVE = new WeakMap();
|
|
21
22
|
const BOARD_TO_ELEMENT_HOST = new WeakMap();
|
|
22
23
|
const BOARD_TO_SELECTED_ELEMENT = new WeakMap();
|
|
23
24
|
const BOARD_TO_MOVING_POINT_IN_BOARD = new WeakMap();
|
|
@@ -64,7 +65,7 @@ const getIsRecursionFunc = (board) => {
|
|
|
64
65
|
};
|
|
65
66
|
|
|
66
67
|
const SELECTION_BORDER_COLOR = '#6698FF';
|
|
67
|
-
const SELECTION_FILL_COLOR = '#
|
|
68
|
+
const SELECTION_FILL_COLOR = '#6698FF25'; // opacity 0.25
|
|
68
69
|
const Selection = {
|
|
69
70
|
isCollapsed(selection) {
|
|
70
71
|
if (selection.anchor[0] == selection.focus[0] && selection.anchor[1] === selection.focus[1]) {
|
|
@@ -185,6 +186,9 @@ const RectangleClient = {
|
|
|
185
186
|
getCenterPoint: (rectangle) => {
|
|
186
187
|
return [rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height / 2];
|
|
187
188
|
},
|
|
189
|
+
getCenterPointByPoints: (points) => {
|
|
190
|
+
return RectangleClient.getCenterPoint(RectangleClient.getRectangleByPoints(points));
|
|
191
|
+
},
|
|
188
192
|
getEdgeCenterPoints: (rectangle) => {
|
|
189
193
|
return [
|
|
190
194
|
[rectangle.x + rectangle.width / 2, rectangle.y],
|
|
@@ -497,6 +501,7 @@ const RESIZE_CURSORS = [ResizeCursorClass.ns, ResizeCursorClass.nesw, ResizeCurs
|
|
|
497
501
|
|
|
498
502
|
const ATTACHED_ELEMENT_CLASS_NAME = 'plait-board-attached';
|
|
499
503
|
const ACTIVE_STROKE_WIDTH = 1;
|
|
504
|
+
const SNAPPING_STROKE_WIDTH = 2;
|
|
500
505
|
const SELECTION_RECTANGLE_CLASS_NAME = 'selection-rectangle';
|
|
501
506
|
|
|
502
507
|
const HOST_CLASS_NAME = 'plait-board-container';
|
|
@@ -1703,7 +1708,7 @@ const throttleRAF = (board, key, fn) => {
|
|
|
1703
1708
|
const value = BOARD_TO_RAF.get(board) || {};
|
|
1704
1709
|
value[key] = null;
|
|
1705
1710
|
BOARD_TO_RAF.set(board, value);
|
|
1706
|
-
fn();
|
|
1711
|
+
PlaitBoard.isAlive(board) && fn();
|
|
1707
1712
|
});
|
|
1708
1713
|
const state = getRAFState(board);
|
|
1709
1714
|
state[key] = timerId;
|
|
@@ -2211,476 +2216,67 @@ const handleTouchTarget = (board) => {
|
|
|
2211
2216
|
}
|
|
2212
2217
|
};
|
|
2213
2218
|
|
|
2214
|
-
const
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
}
|
|
2218
|
-
if (Array.isArray(points) && typeof points[0] === 'number') {
|
|
2219
|
-
return rotate(points[0], points[1], centerPoint[0], centerPoint[1], angle);
|
|
2220
|
-
}
|
|
2221
|
-
else {
|
|
2222
|
-
return points.map(point => {
|
|
2223
|
-
return rotate(point[0], point[1], centerPoint[0], centerPoint[1], angle);
|
|
2224
|
-
});
|
|
2225
|
-
}
|
|
2226
|
-
};
|
|
2227
|
-
const getSelectionAngle = (elements) => {
|
|
2228
|
-
let angle = elements[0]?.angle || 0;
|
|
2229
|
-
elements.forEach(item => {
|
|
2230
|
-
if (item.angle !== angle && !approximately((item.angle % (Math.PI / 2)) - (angle % (Math.PI / 2)), 0)) {
|
|
2231
|
-
angle = 0;
|
|
2232
|
-
}
|
|
2233
|
-
});
|
|
2234
|
-
return angle;
|
|
2235
|
-
};
|
|
2236
|
-
const hasSameAngle = (elements) => {
|
|
2237
|
-
return !!getSelectionAngle(elements);
|
|
2238
|
-
};
|
|
2239
|
-
const getRotatedBoundingRectangle = (rectanglesCornerPoints, angle) => {
|
|
2240
|
-
let rectanglesFromOrigin = [];
|
|
2241
|
-
for (let i = 0; i < rectanglesCornerPoints.length; i++) {
|
|
2242
|
-
const cornerPoints = rectanglesCornerPoints[i];
|
|
2243
|
-
const invertCornerPointsFromOrigin = rotatePoints(cornerPoints, [0, 0], -angle);
|
|
2244
|
-
rectanglesFromOrigin.push(RectangleClient.getRectangleByPoints(invertCornerPointsFromOrigin));
|
|
2245
|
-
}
|
|
2246
|
-
const selectionRectangleFromOrigin = RectangleClient.getBoundingRectangle(rectanglesFromOrigin);
|
|
2247
|
-
const selectionCornerPoints = RectangleClient.getCornerPoints(selectionRectangleFromOrigin);
|
|
2248
|
-
const cornerPointsFromOrigin = rotatePoints(selectionCornerPoints, [0, 0], angle);
|
|
2249
|
-
const centerPoint = RectangleClient.getCenterPoint(RectangleClient.getRectangleByPoints(cornerPointsFromOrigin));
|
|
2250
|
-
return RectangleClient.getRectangleByPoints(rotatePoints(cornerPointsFromOrigin, centerPoint, -angle));
|
|
2251
|
-
};
|
|
2252
|
-
const getOffsetAfterRotate = (rectangle, rotateCenterPoint, angle) => {
|
|
2253
|
-
const targetCenterPoint = RectangleClient.getCenterPoint(rectangle);
|
|
2254
|
-
const [rotatedCenterPoint] = rotatePoints([targetCenterPoint], rotateCenterPoint, angle);
|
|
2255
|
-
const offsetX = rotatedCenterPoint[0] - targetCenterPoint[0];
|
|
2256
|
-
const offsetY = rotatedCenterPoint[1] - targetCenterPoint[1];
|
|
2257
|
-
return { offsetX, offsetY };
|
|
2258
|
-
};
|
|
2259
|
-
const rotatedDataPoints = (points, rotateCenterPoint, angle) => {
|
|
2260
|
-
const { offsetX, offsetY } = getOffsetAfterRotate(RectangleClient.getRectangleByPoints(points), rotateCenterPoint, angle);
|
|
2261
|
-
return points.map(p => [p[0] + offsetX, p[1] + offsetY]);
|
|
2262
|
-
};
|
|
2263
|
-
const hasValidAngle = (node) => {
|
|
2264
|
-
return node.angle && node.angle !== 0;
|
|
2265
|
-
};
|
|
2266
|
-
const rotatePointsByElement = (points, element) => {
|
|
2267
|
-
if (hasValidAngle(element)) {
|
|
2268
|
-
let rectangle = RectangleClient.getRectangleByPoints(element.points);
|
|
2269
|
-
const centerPoint = RectangleClient.getCenterPoint(rectangle);
|
|
2270
|
-
return rotatePoints(points, centerPoint, element.angle);
|
|
2271
|
-
}
|
|
2272
|
-
else {
|
|
2273
|
-
return null;
|
|
2274
|
-
}
|
|
2275
|
-
};
|
|
2276
|
-
const rotateAntiPointsByElement = (points, element) => {
|
|
2277
|
-
if (hasValidAngle(element)) {
|
|
2278
|
-
let rectangle = RectangleClient.getRectangleByPoints(element.points);
|
|
2279
|
-
const centerPoint = RectangleClient.getCenterPoint(rectangle);
|
|
2280
|
-
return rotatePoints(points, centerPoint, -element.angle);
|
|
2281
|
-
}
|
|
2282
|
-
else {
|
|
2283
|
-
return null;
|
|
2219
|
+
const Viewport = {
|
|
2220
|
+
isViewport: (value) => {
|
|
2221
|
+
return !isNullOrUndefined(value.zoom) && !isNullOrUndefined(value.viewBackgroundColor);
|
|
2284
2222
|
}
|
|
2285
2223
|
};
|
|
2286
2224
|
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
}
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
}
|
|
2300
|
-
function isHandleSelection(board) {
|
|
2301
|
-
const options = board.getPluginOptions(PlaitPluginKey.withSelection);
|
|
2302
|
-
return board.pointer !== PlaitPointerType.hand && !options.isDisabledSelect && !PlaitBoard.isReadonly(board);
|
|
2303
|
-
}
|
|
2304
|
-
function isSetSelectionOperation(board) {
|
|
2305
|
-
return !!board.operations.find(value => value.type === 'set_selection');
|
|
2306
|
-
}
|
|
2307
|
-
function getTemporaryElements(board) {
|
|
2308
|
-
const ref = BOARD_TO_TEMPORARY_ELEMENTS.get(board);
|
|
2309
|
-
if (ref) {
|
|
2310
|
-
return ref.elements;
|
|
2311
|
-
}
|
|
2312
|
-
else {
|
|
2313
|
-
return undefined;
|
|
2314
|
-
}
|
|
2315
|
-
}
|
|
2316
|
-
function getTemporaryRef(board) {
|
|
2317
|
-
return BOARD_TO_TEMPORARY_ELEMENTS.get(board);
|
|
2318
|
-
}
|
|
2319
|
-
function deleteTemporaryElements(board) {
|
|
2320
|
-
BOARD_TO_TEMPORARY_ELEMENTS.delete(board);
|
|
2321
|
-
}
|
|
2322
|
-
function createSelectionRectangleG(board) {
|
|
2323
|
-
const elements = getSelectedElements(board);
|
|
2324
|
-
const rectangle = getRectangleByElements(board, elements, false);
|
|
2325
|
-
if (rectangle.width > 0 && rectangle.height > 0 && elements.length > 1) {
|
|
2326
|
-
const selectionRectangleG = drawRectangle(board, RectangleClient.inflate(rectangle, ACTIVE_STROKE_WIDTH), {
|
|
2327
|
-
stroke: SELECTION_BORDER_COLOR,
|
|
2328
|
-
strokeWidth: ACTIVE_STROKE_WIDTH,
|
|
2329
|
-
fillStyle: 'solid'
|
|
2330
|
-
});
|
|
2331
|
-
selectionRectangleG.classList.add(SELECTION_RECTANGLE_CLASS_NAME);
|
|
2332
|
-
PlaitBoard.getElementActiveHost(board).append(selectionRectangleG);
|
|
2333
|
-
const angle = getSelectionAngle(elements);
|
|
2334
|
-
if (angle) {
|
|
2335
|
-
setAngleForG(selectionRectangleG, RectangleClient.getCenterPoint(rectangle), angle);
|
|
2225
|
+
const Path = {
|
|
2226
|
+
/**
|
|
2227
|
+
* Get a list of ancestor paths for a given path.
|
|
2228
|
+
*
|
|
2229
|
+
* The paths are sorted from shallowest to deepest ancestor. However, if the
|
|
2230
|
+
* `reverse: true` option is passed, they are reversed.
|
|
2231
|
+
*/
|
|
2232
|
+
ancestors(path, options = {}) {
|
|
2233
|
+
const { reverse = false } = options;
|
|
2234
|
+
let paths = Path.levels(path, options);
|
|
2235
|
+
if (reverse) {
|
|
2236
|
+
paths = paths.slice(1);
|
|
2336
2237
|
}
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
return null;
|
|
2340
|
-
}
|
|
2341
|
-
function setSelectedElementsWithGroup(board, elements, isShift) {
|
|
2342
|
-
if (!board.selection) {
|
|
2343
|
-
return;
|
|
2344
|
-
}
|
|
2345
|
-
const selectedElements = getSelectedElements(board);
|
|
2346
|
-
if (!Selection.isCollapsed(board.selection)) {
|
|
2347
|
-
let newElements = [...selectedElements];
|
|
2348
|
-
elements.forEach(item => {
|
|
2349
|
-
if (!item.groupId) {
|
|
2350
|
-
newElements.push(item);
|
|
2351
|
-
}
|
|
2352
|
-
else {
|
|
2353
|
-
newElements.push(...getElementsInGroupByElement(board, item));
|
|
2354
|
-
}
|
|
2355
|
-
});
|
|
2356
|
-
cacheSelectedElements(board, uniqueById(newElements));
|
|
2357
|
-
return;
|
|
2358
|
-
}
|
|
2359
|
-
if (Selection.isCollapsed(board.selection)) {
|
|
2360
|
-
const hitElement = elements[0];
|
|
2361
|
-
const hitElementGroups = getGroupByElement(board, hitElement, true);
|
|
2362
|
-
if (hitElementGroups.length) {
|
|
2363
|
-
const elementsInHighestGroup = getElementsInGroup(board, hitElementGroups[hitElementGroups.length - 1], true) || [];
|
|
2364
|
-
const isSelectGroupElement = selectedElements.some(element => elementsInHighestGroup.map(item => item.id).includes(element.id));
|
|
2365
|
-
if (isShift) {
|
|
2366
|
-
cacheSelectedElementsWithGroupOnShift(board, elements, isSelectGroupElement, elementsInHighestGroup);
|
|
2367
|
-
}
|
|
2368
|
-
else {
|
|
2369
|
-
cacheSelectedElementsWithGroup(board, elements, isSelectGroupElement, hitElementGroups);
|
|
2370
|
-
}
|
|
2238
|
+
else {
|
|
2239
|
+
paths = paths.slice(0, -1);
|
|
2371
2240
|
}
|
|
2372
|
-
|
|
2373
|
-
}
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
}
|
|
2382
|
-
|
|
2383
|
-
const
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
pendingElements = selectedElementsInGroup.filter(item => item.id !== hitElement.id);
|
|
2241
|
+
return paths;
|
|
2242
|
+
},
|
|
2243
|
+
/**
|
|
2244
|
+
* Get a list of paths at every level down to a path. Note: this is the same
|
|
2245
|
+
* as `Path.ancestors`, but including the path itself.
|
|
2246
|
+
*
|
|
2247
|
+
* The paths are sorted from shallowest to deepest. However, if the `reverse:
|
|
2248
|
+
* true` option is passed, they are reversed.
|
|
2249
|
+
*/
|
|
2250
|
+
levels(path, options = {}) {
|
|
2251
|
+
const { reverse = false } = options;
|
|
2252
|
+
const list = [];
|
|
2253
|
+
for (let i = 0; i <= path.length; i++) {
|
|
2254
|
+
list.push(path.slice(0, i));
|
|
2387
2255
|
}
|
|
2388
|
-
|
|
2389
|
-
|
|
2256
|
+
if (reverse) {
|
|
2257
|
+
list.reverse();
|
|
2390
2258
|
}
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2259
|
+
return list;
|
|
2260
|
+
},
|
|
2261
|
+
parent(path) {
|
|
2262
|
+
if (path.length === 0) {
|
|
2263
|
+
throw new Error(`Cannot get the parent path of the root path [${path}].`);
|
|
2395
2264
|
}
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
}
|
|
2402
|
-
function cacheSelectedElementsWithGroup(board, elements, isSelectGroupElement, hitElementGroups) {
|
|
2403
|
-
let newElements = [...elements];
|
|
2404
|
-
const selectedGroups = filterSelectedGroups(board, hitElementGroups);
|
|
2405
|
-
if (selectedGroups.length > 0) {
|
|
2406
|
-
if (selectedGroups.length > 1) {
|
|
2407
|
-
newElements = getAllElementsInGroup(board, selectedGroups[selectedGroups.length - 2], true);
|
|
2265
|
+
return path.slice(0, -1);
|
|
2266
|
+
},
|
|
2267
|
+
next(path) {
|
|
2268
|
+
if (path.length === 0) {
|
|
2269
|
+
throw new Error(`Cannot get the next path of a root path [${path}], because it has no next index.`);
|
|
2408
2270
|
}
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
}
|
|
2418
|
-
|
|
2419
|
-
const getElementsInGroup = (board, group, recursion, includeGroup) => {
|
|
2420
|
-
let result = [];
|
|
2421
|
-
const elements = board.children.filter(value => value.groupId === group.id);
|
|
2422
|
-
if (recursion) {
|
|
2423
|
-
elements.forEach(item => {
|
|
2424
|
-
if (PlaitGroupElement.isGroup(item)) {
|
|
2425
|
-
if (includeGroup) {
|
|
2426
|
-
result.push(item);
|
|
2427
|
-
}
|
|
2428
|
-
result.push(...getElementsInGroup(board, item, recursion, includeGroup));
|
|
2429
|
-
}
|
|
2430
|
-
else {
|
|
2431
|
-
result.push(item);
|
|
2432
|
-
}
|
|
2433
|
-
});
|
|
2434
|
-
}
|
|
2435
|
-
else {
|
|
2436
|
-
result = includeGroup ? elements : elements.filter(item => !PlaitGroupElement.isGroup(item));
|
|
2437
|
-
}
|
|
2438
|
-
return result;
|
|
2439
|
-
};
|
|
2440
|
-
const getAllElementsInGroup = (board, group, recursion, includeGroup) => {
|
|
2441
|
-
const elementsInGroup = getElementsInGroup(board, group, recursion, includeGroup);
|
|
2442
|
-
const result = [];
|
|
2443
|
-
elementsInGroup.forEach(element => {
|
|
2444
|
-
depthFirstRecursion(element, node => {
|
|
2445
|
-
result.push(node);
|
|
2446
|
-
}, () => true);
|
|
2447
|
-
});
|
|
2448
|
-
return result;
|
|
2449
|
-
};
|
|
2450
|
-
const getRectangleByGroup = (board, group, recursion) => {
|
|
2451
|
-
const elementsInGroup = getAllElementsInGroup(board, group, recursion);
|
|
2452
|
-
return getRectangleByElements(board, elementsInGroup, false);
|
|
2453
|
-
};
|
|
2454
|
-
const getGroupByElement = (board, element, recursion, source) => {
|
|
2455
|
-
const group = (source || board.children).find(item => item.id === element?.groupId);
|
|
2456
|
-
if (!group) {
|
|
2457
|
-
return recursion ? [] : null;
|
|
2458
|
-
}
|
|
2459
|
-
if (recursion) {
|
|
2460
|
-
const groups = [group];
|
|
2461
|
-
const grandGroups = getGroupByElement(board, group, recursion, source);
|
|
2462
|
-
if (grandGroups.length) {
|
|
2463
|
-
groups.push(...grandGroups);
|
|
2464
|
-
}
|
|
2465
|
-
return groups;
|
|
2466
|
-
}
|
|
2467
|
-
else {
|
|
2468
|
-
return group;
|
|
2469
|
-
}
|
|
2470
|
-
};
|
|
2471
|
-
const getHighestGroup = (board, element) => {
|
|
2472
|
-
const hitElementGroups = getGroupByElement(board, element, true);
|
|
2473
|
-
if (hitElementGroups.length) {
|
|
2474
|
-
return hitElementGroups[hitElementGroups.length - 1];
|
|
2475
|
-
}
|
|
2476
|
-
return null;
|
|
2477
|
-
};
|
|
2478
|
-
const getElementsInGroupByElement = (board, element) => {
|
|
2479
|
-
const highestGroup = getHighestGroup(board, element);
|
|
2480
|
-
if (highestGroup) {
|
|
2481
|
-
return getAllElementsInGroup(board, highestGroup, true);
|
|
2482
|
-
}
|
|
2483
|
-
else {
|
|
2484
|
-
return [element];
|
|
2485
|
-
}
|
|
2486
|
-
};
|
|
2487
|
-
const isSelectedElementOrGroup = (board, element, elements) => {
|
|
2488
|
-
const selectedElements = elements || getSelectedElements(board);
|
|
2489
|
-
if (PlaitGroupElement.isGroup(element)) {
|
|
2490
|
-
return isSelectedAllElementsInGroup(board, element, elements);
|
|
2491
|
-
}
|
|
2492
|
-
return selectedElements.map(item => item.id).includes(element.id);
|
|
2493
|
-
};
|
|
2494
|
-
const isSelectedAllElementsInGroup = (board, group, elements) => {
|
|
2495
|
-
const selectedElements = elements || getSelectedElements(board);
|
|
2496
|
-
const elementsInGroup = getElementsInGroup(board, group, true);
|
|
2497
|
-
return elementsInGroup.every(item => selectedElements.map(element => element.id).includes(item.id));
|
|
2498
|
-
};
|
|
2499
|
-
const filterSelectedGroups = (board, groups, elements) => {
|
|
2500
|
-
const selectedGroups = [];
|
|
2501
|
-
groups.forEach(item => {
|
|
2502
|
-
if (isSelectedElementOrGroup(board, item, elements)) {
|
|
2503
|
-
selectedGroups.push(item);
|
|
2504
|
-
}
|
|
2505
|
-
});
|
|
2506
|
-
return selectedGroups;
|
|
2507
|
-
};
|
|
2508
|
-
const getSelectedGroups = (board, elements) => {
|
|
2509
|
-
const highestSelectedGroups = getHighestSelectedGroups(board, elements);
|
|
2510
|
-
const groups = [];
|
|
2511
|
-
highestSelectedGroups.forEach(item => {
|
|
2512
|
-
groups.push(item);
|
|
2513
|
-
const elementsInGroup = getElementsInGroup(board, item, true, true);
|
|
2514
|
-
groups.push(...elementsInGroup.filter(item => PlaitGroupElement.isGroup(item)));
|
|
2515
|
-
});
|
|
2516
|
-
return groups;
|
|
2517
|
-
};
|
|
2518
|
-
const getHighestSelectedGroup = (board, element, elements) => {
|
|
2519
|
-
const hitElementGroups = getGroupByElement(board, element, true, elements);
|
|
2520
|
-
const selectedGroups = filterSelectedGroups(board, hitElementGroups, elements);
|
|
2521
|
-
if (selectedGroups.length) {
|
|
2522
|
-
return selectedGroups[selectedGroups.length - 1];
|
|
2523
|
-
}
|
|
2524
|
-
return null;
|
|
2525
|
-
};
|
|
2526
|
-
const getHighestSelectedGroups = (board, elements) => {
|
|
2527
|
-
let result = [];
|
|
2528
|
-
const selectedElements = elements || getSelectedElements(board);
|
|
2529
|
-
selectedElements.forEach(item => {
|
|
2530
|
-
if (item.groupId) {
|
|
2531
|
-
const group = getHighestSelectedGroup(board, item, elements);
|
|
2532
|
-
if (group && !result.includes(group)) {
|
|
2533
|
-
result.push(group);
|
|
2534
|
-
}
|
|
2535
|
-
}
|
|
2536
|
-
});
|
|
2537
|
-
return result;
|
|
2538
|
-
};
|
|
2539
|
-
const getSelectedIsolatedElements = (board, elements) => {
|
|
2540
|
-
let result = [];
|
|
2541
|
-
const selectedElements = elements || getSelectedElements(board);
|
|
2542
|
-
selectedElements
|
|
2543
|
-
.filter(item => !PlaitGroupElement.isGroup(item))
|
|
2544
|
-
.forEach(item => {
|
|
2545
|
-
if (!item.groupId) {
|
|
2546
|
-
result.push(item);
|
|
2547
|
-
}
|
|
2548
|
-
else {
|
|
2549
|
-
const group = getHighestSelectedGroup(board, item, elements);
|
|
2550
|
-
if (!group) {
|
|
2551
|
-
result.push(item);
|
|
2552
|
-
}
|
|
2553
|
-
}
|
|
2554
|
-
});
|
|
2555
|
-
return result;
|
|
2556
|
-
};
|
|
2557
|
-
const getSelectedIsolatedElementsCanAddToGroup = (board, elements) => {
|
|
2558
|
-
const selectedIsolatedElements = getSelectedIsolatedElements(board, elements);
|
|
2559
|
-
return selectedIsolatedElements.filter(item => board.canAddToGroup(item));
|
|
2560
|
-
};
|
|
2561
|
-
const getHighestSelectedElements = (board, elements) => {
|
|
2562
|
-
return [...getHighestSelectedGroups(board, elements), ...getSelectedIsolatedElements(board, elements)];
|
|
2563
|
-
};
|
|
2564
|
-
const createGroupRectangleG = (board, elements) => {
|
|
2565
|
-
const selectedElements = getSelectedElements(board);
|
|
2566
|
-
const groupRectangleG = createG();
|
|
2567
|
-
const isMoving = isSelectionMoving(board);
|
|
2568
|
-
elements.forEach(item => {
|
|
2569
|
-
const isRender = (!selectedElements.includes(item) && !isMoving) || isMoving;
|
|
2570
|
-
if (item.groupId && isRender) {
|
|
2571
|
-
const elements = getElementsInGroupByElement(board, item);
|
|
2572
|
-
const rectangle = getRectangleByElements(board, elements, false);
|
|
2573
|
-
groupRectangleG.append(drawRectangle(board, rectangle, {
|
|
2574
|
-
stroke: SELECTION_BORDER_COLOR,
|
|
2575
|
-
strokeWidth: ACTIVE_STROKE_WIDTH,
|
|
2576
|
-
strokeLineDash: [5]
|
|
2577
|
-
}));
|
|
2578
|
-
}
|
|
2579
|
-
});
|
|
2580
|
-
return groupRectangleG;
|
|
2581
|
-
};
|
|
2582
|
-
const createGroup = (groupId) => {
|
|
2583
|
-
return groupId
|
|
2584
|
-
? {
|
|
2585
|
-
id: idCreator(),
|
|
2586
|
-
type: 'group',
|
|
2587
|
-
groupId
|
|
2588
|
-
}
|
|
2589
|
-
: {
|
|
2590
|
-
id: idCreator(),
|
|
2591
|
-
type: 'group'
|
|
2592
|
-
};
|
|
2593
|
-
};
|
|
2594
|
-
const nonGroupInHighestSelectedElements = (elements) => {
|
|
2595
|
-
return elements.every(item => !item.groupId);
|
|
2596
|
-
};
|
|
2597
|
-
const hasSelectedElementsInSameGroup = (elements) => {
|
|
2598
|
-
return elements.every(item => item.groupId && item.groupId === elements[0].groupId);
|
|
2599
|
-
};
|
|
2600
|
-
const canAddGroup = (board, elements) => {
|
|
2601
|
-
const highestSelectedElements = getHighestSelectedElements(board, elements);
|
|
2602
|
-
const rootElements = highestSelectedElements.filter(item => board.canAddToGroup(item));
|
|
2603
|
-
if (rootElements.length > 1) {
|
|
2604
|
-
return nonGroupInHighestSelectedElements(rootElements) || hasSelectedElementsInSameGroup(rootElements);
|
|
2605
|
-
}
|
|
2606
|
-
return false;
|
|
2607
|
-
};
|
|
2608
|
-
const canRemoveGroup = (board, elements) => {
|
|
2609
|
-
const selectedGroups = getHighestSelectedGroups(board, elements);
|
|
2610
|
-
const selectedElements = elements || getSelectedElements(board);
|
|
2611
|
-
return selectedElements.length > 0 && selectedGroups.length > 0;
|
|
2612
|
-
};
|
|
2613
|
-
|
|
2614
|
-
const PlaitElement = {
|
|
2615
|
-
isRootElement(value) {
|
|
2616
|
-
const parent = NODE_TO_PARENT.get(value);
|
|
2617
|
-
if (parent && PlaitBoard.isBoard(parent)) {
|
|
2618
|
-
return true;
|
|
2619
|
-
}
|
|
2620
|
-
else {
|
|
2621
|
-
return false;
|
|
2622
|
-
}
|
|
2623
|
-
},
|
|
2624
|
-
getComponent(value) {
|
|
2625
|
-
return ELEMENT_TO_COMPONENT.get(value);
|
|
2626
|
-
}
|
|
2627
|
-
};
|
|
2628
|
-
|
|
2629
|
-
const Path = {
|
|
2630
|
-
/**
|
|
2631
|
-
* Get a list of ancestor paths for a given path.
|
|
2632
|
-
*
|
|
2633
|
-
* The paths are sorted from shallowest to deepest ancestor. However, if the
|
|
2634
|
-
* `reverse: true` option is passed, they are reversed.
|
|
2635
|
-
*/
|
|
2636
|
-
ancestors(path, options = {}) {
|
|
2637
|
-
const { reverse = false } = options;
|
|
2638
|
-
let paths = Path.levels(path, options);
|
|
2639
|
-
if (reverse) {
|
|
2640
|
-
paths = paths.slice(1);
|
|
2641
|
-
}
|
|
2642
|
-
else {
|
|
2643
|
-
paths = paths.slice(0, -1);
|
|
2644
|
-
}
|
|
2645
|
-
return paths;
|
|
2646
|
-
},
|
|
2647
|
-
/**
|
|
2648
|
-
* Get a list of paths at every level down to a path. Note: this is the same
|
|
2649
|
-
* as `Path.ancestors`, but including the path itself.
|
|
2650
|
-
*
|
|
2651
|
-
* The paths are sorted from shallowest to deepest. However, if the `reverse:
|
|
2652
|
-
* true` option is passed, they are reversed.
|
|
2653
|
-
*/
|
|
2654
|
-
levels(path, options = {}) {
|
|
2655
|
-
const { reverse = false } = options;
|
|
2656
|
-
const list = [];
|
|
2657
|
-
for (let i = 0; i <= path.length; i++) {
|
|
2658
|
-
list.push(path.slice(0, i));
|
|
2659
|
-
}
|
|
2660
|
-
if (reverse) {
|
|
2661
|
-
list.reverse();
|
|
2662
|
-
}
|
|
2663
|
-
return list;
|
|
2664
|
-
},
|
|
2665
|
-
parent(path) {
|
|
2666
|
-
if (path.length === 0) {
|
|
2667
|
-
throw new Error(`Cannot get the parent path of the root path [${path}].`);
|
|
2668
|
-
}
|
|
2669
|
-
return path.slice(0, -1);
|
|
2670
|
-
},
|
|
2671
|
-
next(path) {
|
|
2672
|
-
if (path.length === 0) {
|
|
2673
|
-
throw new Error(`Cannot get the next path of a root path [${path}], because it has no next index.`);
|
|
2674
|
-
}
|
|
2675
|
-
const last = path[path.length - 1];
|
|
2676
|
-
return path.slice(0, -1).concat(last + 1);
|
|
2677
|
-
},
|
|
2678
|
-
hasPrevious(path) {
|
|
2679
|
-
return path[path.length - 1] > 0;
|
|
2680
|
-
},
|
|
2681
|
-
previous(path) {
|
|
2682
|
-
if (path.length === 0) {
|
|
2683
|
-
throw new Error(`Cannot get the next path of a root path [${path}], because it has no previous index.`);
|
|
2271
|
+
const last = path[path.length - 1];
|
|
2272
|
+
return path.slice(0, -1).concat(last + 1);
|
|
2273
|
+
},
|
|
2274
|
+
hasPrevious(path) {
|
|
2275
|
+
return path[path.length - 1] > 0;
|
|
2276
|
+
},
|
|
2277
|
+
previous(path) {
|
|
2278
|
+
if (path.length === 0) {
|
|
2279
|
+
throw new Error(`Cannot get the next path of a root path [${path}], because it has no previous index.`);
|
|
2684
2280
|
}
|
|
2685
2281
|
const last = path[path.length - 1];
|
|
2686
2282
|
return path.slice(0, -1).concat(last - 1);
|
|
@@ -2848,625 +2444,1084 @@ const PlaitNode = {
|
|
|
2848
2444
|
}
|
|
2849
2445
|
};
|
|
2850
2446
|
|
|
2851
|
-
const
|
|
2852
|
-
return value.type === 'set_viewport';
|
|
2853
|
-
};
|
|
2854
|
-
const inverse = (op) => {
|
|
2447
|
+
const applyToDraft = (board, selection, viewport, theme, op) => {
|
|
2855
2448
|
switch (op.type) {
|
|
2856
2449
|
case 'insert_node': {
|
|
2857
|
-
|
|
2450
|
+
const { path, node } = op;
|
|
2451
|
+
const parent = PlaitNode.parent(board, path);
|
|
2452
|
+
const index = path[path.length - 1];
|
|
2453
|
+
if (!parent.children || index > parent.children.length) {
|
|
2454
|
+
throw new Error(`Cannot apply an "insert_node" operation at path [${path}] because the destination is past the end of the node.`);
|
|
2455
|
+
}
|
|
2456
|
+
parent.children.splice(index, 0, node);
|
|
2457
|
+
break;
|
|
2858
2458
|
}
|
|
2859
2459
|
case 'remove_node': {
|
|
2860
|
-
|
|
2460
|
+
const { path } = op;
|
|
2461
|
+
const parent = PlaitNode.parent(board, path);
|
|
2462
|
+
const index = path[path.length - 1];
|
|
2463
|
+
if (!parent.children || index > parent.children.length) {
|
|
2464
|
+
throw new Error(`Cannot apply an "insert_node" operation at path [${path}] because the destination is past the end of the node.`);
|
|
2465
|
+
}
|
|
2466
|
+
parent.children.splice(index, 1);
|
|
2467
|
+
break;
|
|
2861
2468
|
}
|
|
2862
2469
|
case 'move_node': {
|
|
2863
|
-
const {
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
return op;
|
|
2470
|
+
const { path, newPath } = op;
|
|
2471
|
+
if (Path.isAncestor(path, newPath)) {
|
|
2472
|
+
throw new Error(`Cannot move a path [${path}] to new path [${newPath}] because the destination is inside itself.`);
|
|
2867
2473
|
}
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
//
|
|
2872
|
-
//
|
|
2873
|
-
//
|
|
2874
|
-
//
|
|
2875
|
-
//
|
|
2876
|
-
//
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
const
|
|
2880
|
-
const
|
|
2881
|
-
|
|
2474
|
+
const node = PlaitNode.get(board, path);
|
|
2475
|
+
const parent = PlaitNode.parent(board, path);
|
|
2476
|
+
const index = path[path.length - 1];
|
|
2477
|
+
// This is tricky, but since the `path` and `newPath` both refer to
|
|
2478
|
+
// the same snapshot in time, there's a mismatch. After either
|
|
2479
|
+
// removing the original position, the second step's path can be out
|
|
2480
|
+
// of date. So instead of using the `op.newPath` directly, we
|
|
2481
|
+
// transform `op.path` to ascertain what the `newPath` would be after
|
|
2482
|
+
// the operation was applied.
|
|
2483
|
+
parent.children?.splice(index, 1);
|
|
2484
|
+
const truePath = Path.transform(path, op);
|
|
2485
|
+
const newParent = PlaitNode.get(board, Path.parent(truePath));
|
|
2486
|
+
const newIndex = truePath[truePath.length - 1];
|
|
2487
|
+
newParent.children?.splice(newIndex, 0, node);
|
|
2488
|
+
break;
|
|
2882
2489
|
}
|
|
2883
2490
|
case 'set_node': {
|
|
2884
|
-
const { properties, newProperties } = op;
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
case 'set_selection': {
|
|
2888
|
-
const { properties, newProperties } = op;
|
|
2889
|
-
if (properties == null) {
|
|
2890
|
-
return {
|
|
2891
|
-
...op,
|
|
2892
|
-
properties: newProperties,
|
|
2893
|
-
newProperties: null
|
|
2894
|
-
};
|
|
2491
|
+
const { path, properties, newProperties } = op;
|
|
2492
|
+
if (path.length === 0) {
|
|
2493
|
+
throw new Error(`Cannot set properties on the root node!`);
|
|
2895
2494
|
}
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
}
|
|
2495
|
+
const node = PlaitNode.get(board, path);
|
|
2496
|
+
for (const key in newProperties) {
|
|
2497
|
+
const value = newProperties[key];
|
|
2498
|
+
if (value == null) {
|
|
2499
|
+
delete node[key];
|
|
2500
|
+
}
|
|
2501
|
+
else {
|
|
2502
|
+
node[key] = value;
|
|
2503
|
+
}
|
|
2902
2504
|
}
|
|
2903
|
-
|
|
2904
|
-
|
|
2505
|
+
// properties that were previously defined, but are now missing, must be deleted
|
|
2506
|
+
for (const key in properties) {
|
|
2507
|
+
if (!newProperties.hasOwnProperty(key)) {
|
|
2508
|
+
delete node[key];
|
|
2509
|
+
}
|
|
2905
2510
|
}
|
|
2511
|
+
break;
|
|
2906
2512
|
}
|
|
2907
2513
|
case 'set_viewport': {
|
|
2908
|
-
const {
|
|
2909
|
-
if (
|
|
2910
|
-
|
|
2911
|
-
...op,
|
|
2912
|
-
properties: newProperties,
|
|
2913
|
-
newProperties: newProperties
|
|
2914
|
-
};
|
|
2514
|
+
const { newProperties } = op;
|
|
2515
|
+
if (newProperties == null) {
|
|
2516
|
+
viewport = newProperties;
|
|
2915
2517
|
}
|
|
2916
|
-
else
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2518
|
+
else {
|
|
2519
|
+
if (viewport == null) {
|
|
2520
|
+
if (!Viewport.isViewport(newProperties)) {
|
|
2521
|
+
throw new Error(`Cannot apply an incomplete "set_viewport" operation properties ${JSON.stringify(newProperties)} when there is no current viewport.`);
|
|
2522
|
+
}
|
|
2523
|
+
viewport = { ...newProperties };
|
|
2524
|
+
}
|
|
2525
|
+
for (const key in newProperties) {
|
|
2526
|
+
const value = newProperties[key];
|
|
2527
|
+
if (value == null) {
|
|
2528
|
+
delete viewport[key];
|
|
2529
|
+
}
|
|
2530
|
+
else {
|
|
2531
|
+
viewport[key] = value;
|
|
2532
|
+
}
|
|
2533
|
+
}
|
|
2534
|
+
}
|
|
2535
|
+
break;
|
|
2536
|
+
}
|
|
2537
|
+
case 'set_selection': {
|
|
2538
|
+
const { newProperties } = op;
|
|
2539
|
+
if (newProperties == null) {
|
|
2540
|
+
selection = newProperties;
|
|
2922
2541
|
}
|
|
2923
2542
|
else {
|
|
2924
|
-
|
|
2543
|
+
if (selection === null) {
|
|
2544
|
+
selection = op.newProperties;
|
|
2545
|
+
}
|
|
2546
|
+
else {
|
|
2547
|
+
selection = newProperties;
|
|
2548
|
+
}
|
|
2925
2549
|
}
|
|
2550
|
+
break;
|
|
2926
2551
|
}
|
|
2927
2552
|
case 'set_theme': {
|
|
2928
|
-
const {
|
|
2929
|
-
|
|
2553
|
+
const { newProperties } = op;
|
|
2554
|
+
theme = newProperties;
|
|
2555
|
+
break;
|
|
2930
2556
|
}
|
|
2931
2557
|
}
|
|
2558
|
+
return { selection, viewport, theme };
|
|
2932
2559
|
};
|
|
2933
|
-
const
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
},
|
|
2960
|
-
getOffsetY(point1, point2) {
|
|
2961
|
-
return point2[1] - point1[1];
|
|
2560
|
+
const GeneralTransforms = {
|
|
2561
|
+
/**
|
|
2562
|
+
* Transform the board by an operation.
|
|
2563
|
+
*/
|
|
2564
|
+
transform(board, op) {
|
|
2565
|
+
board.children = createDraft(board.children);
|
|
2566
|
+
let viewport = board.viewport && createDraft(board.viewport);
|
|
2567
|
+
let selection = board.selection && createDraft(board.selection);
|
|
2568
|
+
let theme = board.theme && createDraft(board.theme);
|
|
2569
|
+
try {
|
|
2570
|
+
const state = applyToDraft(board, selection, viewport, theme, op);
|
|
2571
|
+
viewport = state.viewport;
|
|
2572
|
+
selection = state.selection;
|
|
2573
|
+
theme = state.theme;
|
|
2574
|
+
}
|
|
2575
|
+
finally {
|
|
2576
|
+
board.children = finishDraft(board.children);
|
|
2577
|
+
if (selection) {
|
|
2578
|
+
board.selection = isDraft(selection) ? finishDraft(selection) : selection;
|
|
2579
|
+
}
|
|
2580
|
+
else {
|
|
2581
|
+
board.selection = null;
|
|
2582
|
+
}
|
|
2583
|
+
board.viewport = isDraft(viewport) ? finishDraft(viewport) : viewport;
|
|
2584
|
+
board.theme = isDraft(theme) ? finishDraft(theme) : theme;
|
|
2585
|
+
}
|
|
2962
2586
|
}
|
|
2963
2587
|
};
|
|
2964
2588
|
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2589
|
+
function insertNode(board, node, path) {
|
|
2590
|
+
const operation = { type: 'insert_node', node, path };
|
|
2591
|
+
board.apply(operation);
|
|
2592
|
+
}
|
|
2593
|
+
function setNode(board, props, path) {
|
|
2594
|
+
const properties = {};
|
|
2595
|
+
const newProperties = {};
|
|
2596
|
+
const node = PlaitNode.get(board, path);
|
|
2597
|
+
for (const k in props) {
|
|
2598
|
+
if (node[k] !== props[k]) {
|
|
2599
|
+
if (node.hasOwnProperty(k)) {
|
|
2600
|
+
properties[k] = node[k];
|
|
2601
|
+
}
|
|
2602
|
+
if (props[k] != null)
|
|
2603
|
+
newProperties[k] = props[k];
|
|
2604
|
+
}
|
|
2968
2605
|
}
|
|
2606
|
+
const operation = { type: 'set_node', properties, newProperties, path };
|
|
2607
|
+
board.apply(operation);
|
|
2608
|
+
}
|
|
2609
|
+
function removeNode(board, path) {
|
|
2610
|
+
const node = PlaitNode.get(board, path);
|
|
2611
|
+
const operation = { type: 'remove_node', path, node };
|
|
2612
|
+
board.apply(operation);
|
|
2613
|
+
}
|
|
2614
|
+
function moveNode(board, path, newPath) {
|
|
2615
|
+
const operation = { type: 'move_node', path, newPath };
|
|
2616
|
+
board.apply(operation);
|
|
2617
|
+
}
|
|
2618
|
+
const NodeTransforms = {
|
|
2619
|
+
insertNode,
|
|
2620
|
+
setNode,
|
|
2621
|
+
removeNode,
|
|
2622
|
+
moveNode
|
|
2969
2623
|
};
|
|
2970
2624
|
|
|
2971
|
-
|
|
2972
|
-
const
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
ThemeColorMode["soft"] = "soft";
|
|
2979
|
-
ThemeColorMode["retro"] = "retro";
|
|
2980
|
-
ThemeColorMode["dark"] = "dark";
|
|
2981
|
-
ThemeColorMode["starry"] = "starry";
|
|
2982
|
-
})(ThemeColorMode || (ThemeColorMode = {}));
|
|
2983
|
-
const DefaultThemeColor = {
|
|
2984
|
-
mode: ThemeColorMode.default,
|
|
2985
|
-
boardBackground: '#ffffff',
|
|
2986
|
-
textColor: '#333333'
|
|
2987
|
-
};
|
|
2988
|
-
const ColorfulThemeColor = {
|
|
2989
|
-
mode: ThemeColorMode.colorful,
|
|
2990
|
-
boardBackground: '#ffffff',
|
|
2991
|
-
textColor: '#333333'
|
|
2625
|
+
function setSelection(board, selection) {
|
|
2626
|
+
const operation = { type: 'set_selection', properties: board.selection, newProperties: selection };
|
|
2627
|
+
board.apply(operation);
|
|
2628
|
+
}
|
|
2629
|
+
const SelectionTransforms = {
|
|
2630
|
+
setSelection,
|
|
2631
|
+
addSelectionWithTemporaryElements
|
|
2992
2632
|
};
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2633
|
+
function addSelectionWithTemporaryElements(board, elements) {
|
|
2634
|
+
const timeoutId = setTimeout(() => {
|
|
2635
|
+
setSelection(board, { anchor: [0, 0], focus: [0, 0] });
|
|
2636
|
+
}, 0);
|
|
2637
|
+
let ref = getTemporaryRef(board);
|
|
2638
|
+
if (ref) {
|
|
2639
|
+
clearTimeout(ref.timeoutId);
|
|
2640
|
+
const currentElements = ref.elements;
|
|
2641
|
+
ref.elements.push(...elements.filter(element => !currentElements.includes(element)));
|
|
2642
|
+
ref.timeoutId = timeoutId;
|
|
2643
|
+
}
|
|
2644
|
+
else {
|
|
2645
|
+
BOARD_TO_TEMPORARY_ELEMENTS.set(board, { timeoutId, elements });
|
|
2646
|
+
}
|
|
2647
|
+
}
|
|
2648
|
+
|
|
2649
|
+
const removeElements = (board, elements) => {
|
|
2650
|
+
elements
|
|
2651
|
+
.map(element => {
|
|
2652
|
+
const path = PlaitBoard.findPath(board, element);
|
|
2653
|
+
const ref = board.pathRef(path);
|
|
2654
|
+
return () => {
|
|
2655
|
+
ref.current && removeNode(board, ref.current);
|
|
2656
|
+
ref.unref();
|
|
2657
|
+
removeSelectedElement(board, element, true);
|
|
2658
|
+
};
|
|
2659
|
+
})
|
|
2660
|
+
.forEach(action => {
|
|
2661
|
+
action();
|
|
2662
|
+
});
|
|
2997
2663
|
};
|
|
2998
|
-
const
|
|
2999
|
-
|
|
3000
|
-
boardBackground: '#f9f8ed',
|
|
3001
|
-
textColor: '#333333'
|
|
2664
|
+
const CoreTransforms = {
|
|
2665
|
+
removeElements
|
|
3002
2666
|
};
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
2667
|
+
|
|
2668
|
+
const addGroup = (board, elements) => {
|
|
2669
|
+
const selectedGroups = getHighestSelectedGroups(board, elements);
|
|
2670
|
+
const selectedIsolatedElements = getSelectedIsolatedElementsCanAddToGroup(board);
|
|
2671
|
+
const highestSelectedElements = [...selectedGroups, ...selectedIsolatedElements];
|
|
2672
|
+
const group = createGroup();
|
|
2673
|
+
if (canAddGroup(board)) {
|
|
2674
|
+
highestSelectedElements.forEach(item => {
|
|
2675
|
+
const path = PlaitBoard.findPath(board, item);
|
|
2676
|
+
NodeTransforms.setNode(board, { groupId: group.id }, path);
|
|
2677
|
+
});
|
|
2678
|
+
if (hasSelectedElementsInSameGroup(highestSelectedElements)) {
|
|
2679
|
+
const newGroupId = selectedIsolatedElements[0].groupId;
|
|
2680
|
+
NodeTransforms.insertNode(board, {
|
|
2681
|
+
...group,
|
|
2682
|
+
groupId: newGroupId
|
|
2683
|
+
}, [board.children.length]);
|
|
2684
|
+
}
|
|
2685
|
+
else {
|
|
2686
|
+
NodeTransforms.insertNode(board, group, [board.children.length]);
|
|
2687
|
+
}
|
|
2688
|
+
}
|
|
3007
2689
|
};
|
|
3008
|
-
const
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
2690
|
+
const removeGroup = (board, elements) => {
|
|
2691
|
+
const selectedGroups = getHighestSelectedGroups(board, elements);
|
|
2692
|
+
if (canRemoveGroup(board)) {
|
|
2693
|
+
selectedGroups.map(group => {
|
|
2694
|
+
const elementsInGroup = findElements(board, {
|
|
2695
|
+
match: item => item.groupId === group.id,
|
|
2696
|
+
recursion: () => false
|
|
2697
|
+
});
|
|
2698
|
+
elementsInGroup.forEach(item => {
|
|
2699
|
+
const path = PlaitBoard.findPath(board, item);
|
|
2700
|
+
NodeTransforms.setNode(board, { groupId: group.groupId || undefined }, path);
|
|
2701
|
+
});
|
|
2702
|
+
const groupPath = PlaitBoard.findPath(board, group);
|
|
2703
|
+
NodeTransforms.removeNode(board, groupPath);
|
|
2704
|
+
});
|
|
2705
|
+
}
|
|
2706
|
+
};
|
|
2707
|
+
const GroupTransforms = {
|
|
2708
|
+
addGroup,
|
|
2709
|
+
removeGroup
|
|
3012
2710
|
};
|
|
3013
|
-
const ThemeColors = [
|
|
3014
|
-
DefaultThemeColor,
|
|
3015
|
-
ColorfulThemeColor,
|
|
3016
|
-
SoftThemeColor,
|
|
3017
|
-
RetroThemeColor,
|
|
3018
|
-
DarkThemeColor,
|
|
3019
|
-
StarryThemeColor
|
|
3020
|
-
];
|
|
3021
2711
|
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
})(Direction || (Direction = {}));
|
|
2712
|
+
const Transforms = {
|
|
2713
|
+
...GeneralTransforms,
|
|
2714
|
+
...ViewportTransforms$1,
|
|
2715
|
+
...SelectionTransforms,
|
|
2716
|
+
...NodeTransforms
|
|
2717
|
+
};
|
|
3029
2718
|
|
|
3030
|
-
const
|
|
3031
|
-
|
|
3032
|
-
|
|
2719
|
+
const rotatePoints = (points, centerPoint, angle) => {
|
|
2720
|
+
if (!angle) {
|
|
2721
|
+
angle = 0;
|
|
2722
|
+
}
|
|
2723
|
+
if (Array.isArray(points) && typeof points[0] === 'number') {
|
|
2724
|
+
return rotate(points[0], points[1], centerPoint[0], centerPoint[1], angle);
|
|
2725
|
+
}
|
|
2726
|
+
else {
|
|
2727
|
+
return points.map(point => {
|
|
2728
|
+
return rotate(point[0], point[1], centerPoint[0], centerPoint[1], angle);
|
|
2729
|
+
});
|
|
2730
|
+
}
|
|
2731
|
+
};
|
|
2732
|
+
const getSelectionAngle = (elements) => {
|
|
2733
|
+
let angle = elements[0]?.angle || 0;
|
|
2734
|
+
elements.forEach(item => {
|
|
2735
|
+
if (item.angle !== angle && !approximately((item.angle % (Math.PI / 2)) - (angle % (Math.PI / 2)), 0)) {
|
|
2736
|
+
angle = 0;
|
|
2737
|
+
}
|
|
2738
|
+
});
|
|
2739
|
+
return angle;
|
|
2740
|
+
};
|
|
2741
|
+
const hasSameAngle = (elements) => {
|
|
2742
|
+
if (!elements.length) {
|
|
2743
|
+
return false;
|
|
2744
|
+
}
|
|
2745
|
+
const angle = elements[0].angle;
|
|
2746
|
+
if (angle === undefined) {
|
|
2747
|
+
return false;
|
|
3033
2748
|
}
|
|
2749
|
+
return !elements.some(item => item.angle !== angle);
|
|
3034
2750
|
};
|
|
2751
|
+
const getRotatedBoundingRectangle = (rectanglesCornerPoints, angle) => {
|
|
2752
|
+
let rectanglesFromOrigin = [];
|
|
2753
|
+
for (let i = 0; i < rectanglesCornerPoints.length; i++) {
|
|
2754
|
+
const cornerPoints = rectanglesCornerPoints[i];
|
|
2755
|
+
const invertCornerPointsFromOrigin = rotatePoints(cornerPoints, [0, 0], -angle);
|
|
2756
|
+
rectanglesFromOrigin.push(RectangleClient.getRectangleByPoints(invertCornerPointsFromOrigin));
|
|
2757
|
+
}
|
|
2758
|
+
const selectionRectangleFromOrigin = RectangleClient.getBoundingRectangle(rectanglesFromOrigin);
|
|
2759
|
+
const selectionCornerPoints = RectangleClient.getCornerPoints(selectionRectangleFromOrigin);
|
|
2760
|
+
const cornerPointsFromOrigin = rotatePoints(selectionCornerPoints, [0, 0], angle);
|
|
2761
|
+
const centerPoint = RectangleClient.getCenterPoint(RectangleClient.getRectangleByPoints(cornerPointsFromOrigin));
|
|
2762
|
+
return RectangleClient.getRectangleByPoints(rotatePoints(cornerPointsFromOrigin, centerPoint, -angle));
|
|
2763
|
+
};
|
|
2764
|
+
const getOffsetAfterRotate = (rectangle, rotateCenterPoint, angle) => {
|
|
2765
|
+
const targetCenterPoint = RectangleClient.getCenterPoint(rectangle);
|
|
2766
|
+
const [rotatedCenterPoint] = rotatePoints([targetCenterPoint], rotateCenterPoint, angle);
|
|
2767
|
+
const offsetX = rotatedCenterPoint[0] - targetCenterPoint[0];
|
|
2768
|
+
const offsetY = rotatedCenterPoint[1] - targetCenterPoint[1];
|
|
2769
|
+
return { offsetX, offsetY };
|
|
2770
|
+
};
|
|
2771
|
+
const rotatedDataPoints = (points, rotateCenterPoint, angle) => {
|
|
2772
|
+
const { offsetX, offsetY } = getOffsetAfterRotate(RectangleClient.getRectangleByPoints(points), rotateCenterPoint, angle);
|
|
2773
|
+
return points.map(p => [p[0] + offsetX, p[1] + offsetY]);
|
|
2774
|
+
};
|
|
2775
|
+
const hasValidAngle = (node) => {
|
|
2776
|
+
return node.angle && node.angle !== 0;
|
|
2777
|
+
};
|
|
2778
|
+
const rotatePointsByElement = (points, element) => {
|
|
2779
|
+
if (hasValidAngle(element)) {
|
|
2780
|
+
let rectangle = RectangleClient.getRectangleByPoints(element.points);
|
|
2781
|
+
const centerPoint = RectangleClient.getCenterPoint(rectangle);
|
|
2782
|
+
return rotatePoints(points, centerPoint, element.angle);
|
|
2783
|
+
}
|
|
2784
|
+
else {
|
|
2785
|
+
return null;
|
|
2786
|
+
}
|
|
2787
|
+
};
|
|
2788
|
+
const rotateAntiPointsByElement = (points, element) => {
|
|
2789
|
+
if (hasValidAngle(element)) {
|
|
2790
|
+
let rectangle = RectangleClient.getRectangleByPoints(element.points);
|
|
2791
|
+
const centerPoint = RectangleClient.getCenterPoint(rectangle);
|
|
2792
|
+
return rotatePoints(points, centerPoint, -element.angle);
|
|
2793
|
+
}
|
|
2794
|
+
else {
|
|
2795
|
+
return null;
|
|
2796
|
+
}
|
|
2797
|
+
};
|
|
2798
|
+
const getRectangleByAngle = (rectangle, angle) => {
|
|
2799
|
+
if (angle) {
|
|
2800
|
+
const cornerPoints = RectangleClient.getCornerPoints(rectangle);
|
|
2801
|
+
const centerPoint = RectangleClient.getCenterPoint(rectangle);
|
|
2802
|
+
return RectangleClient.getRectangleByPoints(rotatePoints(cornerPoints, centerPoint, angle));
|
|
2803
|
+
}
|
|
2804
|
+
else {
|
|
2805
|
+
return null;
|
|
2806
|
+
}
|
|
2807
|
+
};
|
|
2808
|
+
const isAxisChangedByAngle = (angle) => {
|
|
2809
|
+
const unitAngle = Math.abs(angle) % Math.PI;
|
|
2810
|
+
return unitAngle >= (1 / 4) * Math.PI && unitAngle <= (3 / 4) * Math.PI;
|
|
2811
|
+
};
|
|
2812
|
+
function degreesToRadians(d) {
|
|
2813
|
+
return (d / 180) * Math.PI;
|
|
2814
|
+
}
|
|
2815
|
+
function radiansToDegrees(r) {
|
|
2816
|
+
return (r / Math.PI) * 180;
|
|
2817
|
+
}
|
|
2818
|
+
function rotateElements(board, elements, angle) {
|
|
2819
|
+
const selectionRectangle = getRectangleByElements(board, elements, false);
|
|
2820
|
+
const selectionCenterPoint = RectangleClient.getCenterPoint(selectionRectangle);
|
|
2821
|
+
elements.forEach(item => {
|
|
2822
|
+
const originAngle = item.angle;
|
|
2823
|
+
const points = rotatedDataPoints(item.points, selectionCenterPoint, angle);
|
|
2824
|
+
const path = PlaitBoard.findPath(board, item);
|
|
2825
|
+
Transforms.setNode(board, { points, angle: originAngle + angle }, path);
|
|
2826
|
+
});
|
|
2827
|
+
}
|
|
3035
2828
|
|
|
3036
|
-
function
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
2829
|
+
function isSelectionMoving(board) {
|
|
2830
|
+
return !!BOARD_TO_IS_SELECTION_MOVING.get(board);
|
|
2831
|
+
}
|
|
2832
|
+
function setSelectionMoving(board) {
|
|
2833
|
+
PlaitBoard.getBoardContainer(board).classList.add('selection-moving');
|
|
2834
|
+
BOARD_TO_IS_SELECTION_MOVING.set(board, true);
|
|
2835
|
+
setDragging(board, true);
|
|
2836
|
+
}
|
|
2837
|
+
function clearSelectionMoving(board) {
|
|
2838
|
+
PlaitBoard.getBoardContainer(board).classList.remove('selection-moving');
|
|
2839
|
+
BOARD_TO_IS_SELECTION_MOVING.delete(board);
|
|
2840
|
+
setDragging(board, false);
|
|
2841
|
+
}
|
|
2842
|
+
function isHandleSelection(board) {
|
|
2843
|
+
const options = board.getPluginOptions(PlaitPluginKey.withSelection);
|
|
2844
|
+
return board.pointer !== PlaitPointerType.hand && !options.isDisabledSelect && !PlaitBoard.isReadonly(board);
|
|
2845
|
+
}
|
|
2846
|
+
function isSetSelectionOperation(board) {
|
|
2847
|
+
return !!board.operations.find(value => value.type === 'set_selection');
|
|
2848
|
+
}
|
|
2849
|
+
function getTemporaryElements(board) {
|
|
2850
|
+
const ref = BOARD_TO_TEMPORARY_ELEMENTS.get(board);
|
|
2851
|
+
if (ref) {
|
|
2852
|
+
return ref.elements;
|
|
2853
|
+
}
|
|
2854
|
+
else {
|
|
2855
|
+
return undefined;
|
|
2856
|
+
}
|
|
2857
|
+
}
|
|
2858
|
+
function getTemporaryRef(board) {
|
|
2859
|
+
return BOARD_TO_TEMPORARY_ELEMENTS.get(board);
|
|
2860
|
+
}
|
|
2861
|
+
function deleteTemporaryElements(board) {
|
|
2862
|
+
BOARD_TO_TEMPORARY_ELEMENTS.delete(board);
|
|
2863
|
+
}
|
|
2864
|
+
function drawEntireActiveRectangleG(board) {
|
|
2865
|
+
const elements = getSelectedElements(board);
|
|
2866
|
+
const rectangle = getRectangleByElements(board, elements, false);
|
|
2867
|
+
if (rectangle.width > 0 && rectangle.height > 0 && elements.length > 1) {
|
|
2868
|
+
const selectionRectangleG = drawRectangle(board, RectangleClient.inflate(rectangle, ACTIVE_STROKE_WIDTH), {
|
|
2869
|
+
stroke: SELECTION_BORDER_COLOR,
|
|
2870
|
+
strokeWidth: ACTIVE_STROKE_WIDTH,
|
|
2871
|
+
fillStyle: 'solid'
|
|
2872
|
+
});
|
|
2873
|
+
selectionRectangleG.classList.add(SELECTION_RECTANGLE_CLASS_NAME);
|
|
2874
|
+
const angle = getSelectionAngle(elements);
|
|
2875
|
+
if (angle) {
|
|
2876
|
+
setAngleForG(selectionRectangleG, RectangleClient.getCenterPoint(rectangle), angle);
|
|
2877
|
+
}
|
|
2878
|
+
return selectionRectangleG;
|
|
2879
|
+
}
|
|
2880
|
+
return null;
|
|
2881
|
+
}
|
|
2882
|
+
function setSelectedElementsWithGroup(board, elements, isShift) {
|
|
2883
|
+
if (!board.selection) {
|
|
2884
|
+
return;
|
|
2885
|
+
}
|
|
2886
|
+
const selectedElements = getSelectedElements(board);
|
|
2887
|
+
if (!Selection.isCollapsed(board.selection)) {
|
|
2888
|
+
let newElements = [...selectedElements];
|
|
2889
|
+
elements.forEach(item => {
|
|
2890
|
+
if (!item.groupId) {
|
|
2891
|
+
newElements.push(item);
|
|
2892
|
+
}
|
|
2893
|
+
else {
|
|
2894
|
+
newElements.push(...getElementsInGroupByElement(board, item));
|
|
2895
|
+
}
|
|
2896
|
+
});
|
|
2897
|
+
cacheSelectedElements(board, uniqueById(newElements));
|
|
2898
|
+
return;
|
|
2899
|
+
}
|
|
2900
|
+
if (Selection.isCollapsed(board.selection)) {
|
|
2901
|
+
const hitElement = elements[0];
|
|
2902
|
+
const hitElementGroups = getGroupByElement(board, hitElement, true);
|
|
2903
|
+
if (hitElementGroups.length) {
|
|
2904
|
+
const elementsInHighestGroup = getElementsInGroup(board, hitElementGroups[hitElementGroups.length - 1], true) || [];
|
|
2905
|
+
const isSelectGroupElement = selectedElements.some(element => elementsInHighestGroup.map(item => item.id).includes(element.id));
|
|
2906
|
+
if (isShift) {
|
|
2907
|
+
cacheSelectedElementsWithGroupOnShift(board, elements, isSelectGroupElement, elementsInHighestGroup);
|
|
2908
|
+
}
|
|
2909
|
+
else {
|
|
2910
|
+
cacheSelectedElementsWithGroup(board, elements, isSelectGroupElement, hitElementGroups);
|
|
2911
|
+
}
|
|
2912
|
+
}
|
|
2913
|
+
}
|
|
2914
|
+
}
|
|
2915
|
+
function cacheSelectedElementsWithGroupOnShift(board, elements, isSelectGroupElement, elementsInHighestGroup) {
|
|
2916
|
+
const selectedElements = getSelectedElements(board);
|
|
2917
|
+
let newElements = [...selectedElements];
|
|
2918
|
+
const hitElement = elements[0];
|
|
2919
|
+
let pendingElements = [];
|
|
2920
|
+
if (!isSelectGroupElement) {
|
|
2921
|
+
pendingElements = elementsInHighestGroup;
|
|
2922
|
+
}
|
|
2923
|
+
else {
|
|
2924
|
+
const isHitSelectedElement = selectedElements.some(item => item.id === hitElement.id);
|
|
2925
|
+
const selectedElementsInGroup = elementsInHighestGroup.filter(item => selectedElements.includes(item));
|
|
2926
|
+
if (isHitSelectedElement) {
|
|
2927
|
+
pendingElements = selectedElementsInGroup.filter(item => item.id !== hitElement.id);
|
|
3044
2928
|
}
|
|
3045
2929
|
else {
|
|
3046
|
-
|
|
2930
|
+
pendingElements.push(...selectedElementsInGroup, ...elements);
|
|
3047
2931
|
}
|
|
3048
|
-
}
|
|
3049
|
-
|
|
3050
|
-
if (
|
|
3051
|
-
|
|
2932
|
+
}
|
|
2933
|
+
elementsInHighestGroup.forEach(element => {
|
|
2934
|
+
if (newElements.includes(element)) {
|
|
2935
|
+
newElements.splice(newElements.indexOf(element), 1);
|
|
2936
|
+
}
|
|
2937
|
+
});
|
|
2938
|
+
if (pendingElements.length) {
|
|
2939
|
+
newElements.push(...pendingElements);
|
|
2940
|
+
}
|
|
2941
|
+
cacheSelectedElements(board, uniqueById(newElements));
|
|
2942
|
+
}
|
|
2943
|
+
function cacheSelectedElementsWithGroup(board, elements, isSelectGroupElement, hitElementGroups) {
|
|
2944
|
+
let newElements = [...elements];
|
|
2945
|
+
const selectedGroups = filterSelectedGroups(board, hitElementGroups);
|
|
2946
|
+
if (selectedGroups.length > 0) {
|
|
2947
|
+
if (selectedGroups.length > 1) {
|
|
2948
|
+
newElements = getAllElementsInGroup(board, selectedGroups[selectedGroups.length - 2], true);
|
|
2949
|
+
}
|
|
2950
|
+
}
|
|
2951
|
+
else {
|
|
2952
|
+
const elementsInGroup = getAllElementsInGroup(board, hitElementGroups[hitElementGroups.length - 1], true);
|
|
2953
|
+
if (!isSelectGroupElement) {
|
|
2954
|
+
newElements = elementsInGroup;
|
|
2955
|
+
}
|
|
2956
|
+
}
|
|
2957
|
+
cacheSelectedElements(board, uniqueById(newElements));
|
|
2958
|
+
}
|
|
2959
|
+
|
|
2960
|
+
const getElementsInGroup = (board, group, recursion, includeGroup) => {
|
|
2961
|
+
let result = [];
|
|
2962
|
+
const elements = board.children.filter(value => value.groupId === group.id);
|
|
2963
|
+
if (recursion) {
|
|
2964
|
+
elements.forEach(item => {
|
|
2965
|
+
if (PlaitGroupElement.isGroup(item)) {
|
|
2966
|
+
if (includeGroup) {
|
|
2967
|
+
result.push(item);
|
|
2968
|
+
}
|
|
2969
|
+
result.push(...getElementsInGroup(board, item, recursion, includeGroup));
|
|
2970
|
+
}
|
|
2971
|
+
else {
|
|
2972
|
+
result.push(item);
|
|
2973
|
+
}
|
|
2974
|
+
});
|
|
2975
|
+
}
|
|
2976
|
+
else {
|
|
2977
|
+
result = includeGroup ? elements : elements.filter(item => !PlaitGroupElement.isGroup(item));
|
|
2978
|
+
}
|
|
2979
|
+
return result;
|
|
2980
|
+
};
|
|
2981
|
+
const getAllElementsInGroup = (board, group, recursion, includeGroup) => {
|
|
2982
|
+
const elementsInGroup = getElementsInGroup(board, group, recursion, includeGroup);
|
|
2983
|
+
const result = [];
|
|
2984
|
+
elementsInGroup.forEach(element => {
|
|
2985
|
+
depthFirstRecursion(element, node => {
|
|
2986
|
+
result.push(node);
|
|
2987
|
+
}, () => true);
|
|
2988
|
+
});
|
|
2989
|
+
return result;
|
|
2990
|
+
};
|
|
2991
|
+
const getRectangleByGroup = (board, group, recursion) => {
|
|
2992
|
+
const elementsInGroup = getAllElementsInGroup(board, group, recursion);
|
|
2993
|
+
return getRectangleByElements(board, elementsInGroup, false);
|
|
2994
|
+
};
|
|
2995
|
+
const getGroupByElement = (board, element, recursion, source) => {
|
|
2996
|
+
const group = (source || board.children).find(item => item.id === element?.groupId);
|
|
2997
|
+
if (!group) {
|
|
2998
|
+
return recursion ? [] : null;
|
|
2999
|
+
}
|
|
3000
|
+
if (recursion) {
|
|
3001
|
+
const groups = [group];
|
|
3002
|
+
const grandGroups = getGroupByElement(board, group, recursion, source);
|
|
3003
|
+
if (grandGroups.length) {
|
|
3004
|
+
groups.push(...grandGroups);
|
|
3005
|
+
}
|
|
3006
|
+
return groups;
|
|
3007
|
+
}
|
|
3008
|
+
else {
|
|
3009
|
+
return group;
|
|
3010
|
+
}
|
|
3011
|
+
};
|
|
3012
|
+
const getHighestGroup = (board, element) => {
|
|
3013
|
+
const hitElementGroups = getGroupByElement(board, element, true);
|
|
3014
|
+
if (hitElementGroups.length) {
|
|
3015
|
+
return hitElementGroups[hitElementGroups.length - 1];
|
|
3016
|
+
}
|
|
3017
|
+
return null;
|
|
3018
|
+
};
|
|
3019
|
+
const getElementsInGroupByElement = (board, element) => {
|
|
3020
|
+
const highestGroup = getHighestGroup(board, element);
|
|
3021
|
+
if (highestGroup) {
|
|
3022
|
+
return getAllElementsInGroup(board, highestGroup, true);
|
|
3023
|
+
}
|
|
3024
|
+
else {
|
|
3025
|
+
return [element];
|
|
3026
|
+
}
|
|
3027
|
+
};
|
|
3028
|
+
const isSelectedElementOrGroup = (board, element, elements) => {
|
|
3029
|
+
const selectedElements = elements || getSelectedElements(board);
|
|
3030
|
+
if (PlaitGroupElement.isGroup(element)) {
|
|
3031
|
+
return isSelectedAllElementsInGroup(board, element, elements);
|
|
3032
|
+
}
|
|
3033
|
+
return selectedElements.map(item => item.id).includes(element.id);
|
|
3034
|
+
};
|
|
3035
|
+
const isSelectedAllElementsInGroup = (board, group, elements) => {
|
|
3036
|
+
const selectedElements = elements || getSelectedElements(board);
|
|
3037
|
+
const elementsInGroup = getElementsInGroup(board, group, true);
|
|
3038
|
+
return elementsInGroup.every(item => selectedElements.map(element => element.id).includes(item.id));
|
|
3039
|
+
};
|
|
3040
|
+
const filterSelectedGroups = (board, groups, elements) => {
|
|
3041
|
+
const selectedGroups = [];
|
|
3042
|
+
groups.forEach(item => {
|
|
3043
|
+
if (isSelectedElementOrGroup(board, item, elements)) {
|
|
3044
|
+
selectedGroups.push(item);
|
|
3045
|
+
}
|
|
3046
|
+
});
|
|
3047
|
+
return selectedGroups;
|
|
3048
|
+
};
|
|
3049
|
+
const getSelectedGroups = (board, elements) => {
|
|
3050
|
+
const highestSelectedGroups = getHighestSelectedGroups(board, elements);
|
|
3051
|
+
const groups = [];
|
|
3052
|
+
highestSelectedGroups.forEach(item => {
|
|
3053
|
+
groups.push(item);
|
|
3054
|
+
const elementsInGroup = getElementsInGroup(board, item, true, true);
|
|
3055
|
+
groups.push(...elementsInGroup.filter(item => PlaitGroupElement.isGroup(item)));
|
|
3056
|
+
});
|
|
3057
|
+
return groups;
|
|
3058
|
+
};
|
|
3059
|
+
const getHighestSelectedGroup = (board, element, elements) => {
|
|
3060
|
+
const hitElementGroups = getGroupByElement(board, element, true, elements);
|
|
3061
|
+
const selectedGroups = filterSelectedGroups(board, hitElementGroups, elements);
|
|
3062
|
+
if (selectedGroups.length) {
|
|
3063
|
+
return selectedGroups[selectedGroups.length - 1];
|
|
3064
|
+
}
|
|
3065
|
+
return null;
|
|
3066
|
+
};
|
|
3067
|
+
const getHighestSelectedGroups = (board, elements) => {
|
|
3068
|
+
let result = [];
|
|
3069
|
+
const selectedElements = elements || getSelectedElements(board);
|
|
3070
|
+
selectedElements.forEach(item => {
|
|
3071
|
+
if (item.groupId) {
|
|
3072
|
+
const group = getHighestSelectedGroup(board, item, elements);
|
|
3073
|
+
if (group && !result.includes(group)) {
|
|
3074
|
+
result.push(group);
|
|
3075
|
+
}
|
|
3076
|
+
}
|
|
3077
|
+
});
|
|
3078
|
+
return result;
|
|
3079
|
+
};
|
|
3080
|
+
const getSelectedIsolatedElements = (board, elements) => {
|
|
3081
|
+
let result = [];
|
|
3082
|
+
const selectedElements = elements || getSelectedElements(board);
|
|
3083
|
+
selectedElements
|
|
3084
|
+
.filter(item => !PlaitGroupElement.isGroup(item))
|
|
3085
|
+
.forEach(item => {
|
|
3086
|
+
if (!item.groupId) {
|
|
3087
|
+
result.push(item);
|
|
3052
3088
|
}
|
|
3053
3089
|
else {
|
|
3054
|
-
|
|
3090
|
+
const group = getHighestSelectedGroup(board, item, elements);
|
|
3091
|
+
if (!group) {
|
|
3092
|
+
result.push(item);
|
|
3093
|
+
}
|
|
3055
3094
|
}
|
|
3056
3095
|
});
|
|
3057
|
-
|
|
3058
|
-
|
|
3096
|
+
return result;
|
|
3097
|
+
};
|
|
3098
|
+
const getSelectedIsolatedElementsCanAddToGroup = (board, elements) => {
|
|
3099
|
+
const selectedIsolatedElements = getSelectedIsolatedElements(board, elements);
|
|
3100
|
+
return selectedIsolatedElements.filter(item => board.canAddToGroup(item));
|
|
3101
|
+
};
|
|
3102
|
+
const getHighestSelectedElements = (board, elements) => {
|
|
3103
|
+
return [...getHighestSelectedGroups(board, elements), ...getSelectedIsolatedElements(board, elements)];
|
|
3104
|
+
};
|
|
3105
|
+
const createGroupRectangleG = (board, elements) => {
|
|
3106
|
+
const selectedElements = getSelectedElements(board);
|
|
3107
|
+
const groupRectangleG = createG();
|
|
3108
|
+
const isMoving = isSelectionMoving(board);
|
|
3109
|
+
elements.forEach(item => {
|
|
3110
|
+
const isRender = (!selectedElements.includes(item) && !isMoving) || isMoving;
|
|
3111
|
+
if (item.groupId && isRender) {
|
|
3112
|
+
const elements = getElementsInGroupByElement(board, item);
|
|
3113
|
+
const rectangle = getRectangleByElements(board, elements, false);
|
|
3114
|
+
const rectangleG = drawRectangle(board, rectangle, {
|
|
3115
|
+
stroke: SELECTION_BORDER_COLOR,
|
|
3116
|
+
strokeWidth: ACTIVE_STROKE_WIDTH,
|
|
3117
|
+
strokeLineDash: [5]
|
|
3118
|
+
});
|
|
3059
3119
|
const angle = getSelectionAngle(elements);
|
|
3060
|
-
|
|
3120
|
+
if (angle) {
|
|
3121
|
+
setAngleForG(rectangleG, RectangleClient.getCenterPoint(rectangle), angle);
|
|
3122
|
+
}
|
|
3123
|
+
groupRectangleG.append(rectangleG);
|
|
3061
3124
|
}
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3125
|
+
});
|
|
3126
|
+
return groupRectangleG;
|
|
3127
|
+
};
|
|
3128
|
+
const createGroup = (groupId) => {
|
|
3129
|
+
return groupId
|
|
3130
|
+
? {
|
|
3131
|
+
id: idCreator(),
|
|
3132
|
+
type: 'group',
|
|
3133
|
+
groupId
|
|
3067
3134
|
}
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
x: 0,
|
|
3072
|
-
y: 0,
|
|
3073
|
-
width: 0,
|
|
3074
|
-
height: 0
|
|
3135
|
+
: {
|
|
3136
|
+
id: idCreator(),
|
|
3137
|
+
type: 'group'
|
|
3075
3138
|
};
|
|
3139
|
+
};
|
|
3140
|
+
const nonGroupInHighestSelectedElements = (elements) => {
|
|
3141
|
+
return elements.every(item => !item.groupId);
|
|
3142
|
+
};
|
|
3143
|
+
const hasSelectedElementsInSameGroup = (elements) => {
|
|
3144
|
+
return elements.every(item => item.groupId && item.groupId === elements[0].groupId);
|
|
3145
|
+
};
|
|
3146
|
+
const canAddGroup = (board, elements) => {
|
|
3147
|
+
const highestSelectedElements = getHighestSelectedElements(board, elements);
|
|
3148
|
+
const rootElements = highestSelectedElements.filter(item => board.canAddToGroup(item));
|
|
3149
|
+
if (rootElements.length > 1) {
|
|
3150
|
+
return nonGroupInHighestSelectedElements(rootElements) || hasSelectedElementsInSameGroup(rootElements);
|
|
3076
3151
|
}
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
}
|
|
3095
|
-
}, (value) => {
|
|
3096
|
-
if (PlaitBoard.isBoard(value)) {
|
|
3152
|
+
return false;
|
|
3153
|
+
};
|
|
3154
|
+
const canRemoveGroup = (board, elements) => {
|
|
3155
|
+
const selectedGroups = getHighestSelectedGroups(board, elements);
|
|
3156
|
+
const selectedElements = elements || getSelectedElements(board);
|
|
3157
|
+
return selectedElements.length > 0 && selectedGroups.length > 0;
|
|
3158
|
+
};
|
|
3159
|
+
|
|
3160
|
+
const deleteFragment = (board) => {
|
|
3161
|
+
const elements = board.getDeletedFragment([]);
|
|
3162
|
+
board.deleteFragment(elements);
|
|
3163
|
+
};
|
|
3164
|
+
|
|
3165
|
+
const PlaitElement = {
|
|
3166
|
+
isRootElement(value) {
|
|
3167
|
+
const parent = NODE_TO_PARENT.get(value);
|
|
3168
|
+
if (parent && PlaitBoard.isBoard(parent)) {
|
|
3097
3169
|
return true;
|
|
3098
3170
|
}
|
|
3099
3171
|
else {
|
|
3100
|
-
return
|
|
3101
|
-
}
|
|
3102
|
-
}, isReverse);
|
|
3103
|
-
return elements;
|
|
3104
|
-
}
|
|
3105
|
-
|
|
3106
|
-
const PlaitBoard = {
|
|
3107
|
-
isBoard(value) {
|
|
3108
|
-
const cachedIsBoard = IS_BOARD_CACHE.get(value);
|
|
3109
|
-
if (cachedIsBoard !== undefined) {
|
|
3110
|
-
return cachedIsBoard;
|
|
3111
|
-
}
|
|
3112
|
-
const isBoard = typeof value.onChange === 'function' && typeof value.apply === 'function';
|
|
3113
|
-
IS_BOARD_CACHE.set(value, isBoard);
|
|
3114
|
-
return isBoard;
|
|
3115
|
-
},
|
|
3116
|
-
findPath(board, node) {
|
|
3117
|
-
const path = [];
|
|
3118
|
-
let child = node;
|
|
3119
|
-
while (true) {
|
|
3120
|
-
const parent = NODE_TO_PARENT.get(child);
|
|
3121
|
-
if (parent == null) {
|
|
3122
|
-
if (PlaitBoard.isBoard(child)) {
|
|
3123
|
-
return path;
|
|
3124
|
-
}
|
|
3125
|
-
else {
|
|
3126
|
-
break;
|
|
3127
|
-
}
|
|
3128
|
-
}
|
|
3129
|
-
const i = NODE_TO_INDEX.get(child);
|
|
3130
|
-
if (i == null) {
|
|
3131
|
-
break;
|
|
3132
|
-
}
|
|
3133
|
-
path.unshift(i);
|
|
3134
|
-
child = parent;
|
|
3135
|
-
}
|
|
3136
|
-
throw new Error(`Unable to find the path for Plait node: ${JSON.stringify(node)}`);
|
|
3137
|
-
},
|
|
3138
|
-
getHost(board) {
|
|
3139
|
-
return BOARD_TO_HOST.get(board);
|
|
3140
|
-
},
|
|
3141
|
-
getElementHost(board) {
|
|
3142
|
-
return BOARD_TO_ELEMENT_HOST.get(board)?.host;
|
|
3143
|
-
},
|
|
3144
|
-
getElementUpperHost(board) {
|
|
3145
|
-
return BOARD_TO_ELEMENT_HOST.get(board)?.upperHost;
|
|
3146
|
-
},
|
|
3147
|
-
getElementActiveHost(board) {
|
|
3148
|
-
return BOARD_TO_ELEMENT_HOST.get(board)?.activeHost;
|
|
3149
|
-
},
|
|
3150
|
-
getRoughSVG(board) {
|
|
3151
|
-
return BOARD_TO_ROUGH_SVG.get(board);
|
|
3152
|
-
},
|
|
3153
|
-
getComponent(board) {
|
|
3154
|
-
return BOARD_TO_COMPONENT.get(board);
|
|
3155
|
-
},
|
|
3156
|
-
getBoardContainer(board) {
|
|
3157
|
-
return BOARD_TO_ELEMENT_HOST.get(board)?.container;
|
|
3158
|
-
},
|
|
3159
|
-
getRectangle(board) {
|
|
3160
|
-
return getRectangleByElements(board, board.children, true);
|
|
3161
|
-
},
|
|
3162
|
-
getViewportContainer(board) {
|
|
3163
|
-
return BOARD_TO_ELEMENT_HOST.get(board)?.viewportContainer;
|
|
3164
|
-
},
|
|
3165
|
-
isFocus(board) {
|
|
3166
|
-
return !!board.selection;
|
|
3167
|
-
},
|
|
3168
|
-
isReadonly(board) {
|
|
3169
|
-
return board.options.readonly;
|
|
3170
|
-
},
|
|
3171
|
-
hasBeenTextEditing(board) {
|
|
3172
|
-
return !!IS_TEXT_EDITABLE.get(board);
|
|
3173
|
-
},
|
|
3174
|
-
getPointer(board) {
|
|
3175
|
-
return board.pointer;
|
|
3176
|
-
},
|
|
3177
|
-
isPointer(board, pointer) {
|
|
3178
|
-
return board.pointer === pointer;
|
|
3179
|
-
},
|
|
3180
|
-
isInPointer(board, pointers) {
|
|
3181
|
-
const point = board.pointer;
|
|
3182
|
-
return pointers.includes(point);
|
|
3183
|
-
},
|
|
3184
|
-
getMovingPointInBoard(board) {
|
|
3185
|
-
return BOARD_TO_MOVING_POINT_IN_BOARD.get(board);
|
|
3186
|
-
},
|
|
3187
|
-
isMovingPointInBoard(board) {
|
|
3188
|
-
const point = BOARD_TO_MOVING_POINT.get(board);
|
|
3189
|
-
const rect = PlaitBoard.getBoardContainer(board).getBoundingClientRect();
|
|
3190
|
-
if (point && distanceBetweenPointAndRectangle(point[0], point[1], rect) === 0) {
|
|
3191
|
-
return true;
|
|
3172
|
+
return false;
|
|
3192
3173
|
}
|
|
3193
|
-
return false;
|
|
3194
3174
|
},
|
|
3195
|
-
|
|
3196
|
-
return (
|
|
3175
|
+
getComponent(value) {
|
|
3176
|
+
return ELEMENT_TO_COMPONENT.get(value);
|
|
3197
3177
|
}
|
|
3198
3178
|
};
|
|
3199
3179
|
|
|
3200
|
-
const
|
|
3180
|
+
const isSetViewportOperation = (value) => {
|
|
3181
|
+
return value.type === 'set_viewport';
|
|
3182
|
+
};
|
|
3183
|
+
const inverse = (op) => {
|
|
3201
3184
|
switch (op.type) {
|
|
3202
3185
|
case 'insert_node': {
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
if (
|
|
3217
|
-
|
|
3218
|
-
}
|
|
3219
|
-
parent
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
|
|
3224
|
-
|
|
3225
|
-
|
|
3226
|
-
|
|
3227
|
-
|
|
3228
|
-
const parent = PlaitNode.parent(board, path);
|
|
3229
|
-
const index = path[path.length - 1];
|
|
3230
|
-
// This is tricky, but since the `path` and `newPath` both refer to
|
|
3231
|
-
// the same snapshot in time, there's a mismatch. After either
|
|
3232
|
-
// removing the original position, the second step's path can be out
|
|
3233
|
-
// of date. So instead of using the `op.newPath` directly, we
|
|
3234
|
-
// transform `op.path` to ascertain what the `newPath` would be after
|
|
3235
|
-
// the operation was applied.
|
|
3236
|
-
parent.children?.splice(index, 1);
|
|
3237
|
-
const truePath = Path.transform(path, op);
|
|
3238
|
-
const newParent = PlaitNode.get(board, Path.parent(truePath));
|
|
3239
|
-
const newIndex = truePath[truePath.length - 1];
|
|
3240
|
-
newParent.children?.splice(newIndex, 0, node);
|
|
3241
|
-
break;
|
|
3186
|
+
return { ...op, type: 'remove_node' };
|
|
3187
|
+
}
|
|
3188
|
+
case 'remove_node': {
|
|
3189
|
+
return { ...op, type: 'insert_node' };
|
|
3190
|
+
}
|
|
3191
|
+
case 'move_node': {
|
|
3192
|
+
const { newPath, path } = op;
|
|
3193
|
+
// PERF: in this case the move operation is a no-op anyways.
|
|
3194
|
+
if (Path.equals(newPath, path)) {
|
|
3195
|
+
return op;
|
|
3196
|
+
}
|
|
3197
|
+
// when operation path is [0,0] -> [0,2], should exec Path.transform to get [0,1] -> [0,0]
|
|
3198
|
+
// shoud not return [0,2] -> [0,0] #WIK-8981
|
|
3199
|
+
// if (Path.isSibling(path, newPath)) {
|
|
3200
|
+
// return { ...op, path: newPath, newPath: path };
|
|
3201
|
+
// }
|
|
3202
|
+
// If the move does not happen within a single parent it is possible
|
|
3203
|
+
// for the move to impact the true path to the location where the node
|
|
3204
|
+
// was removed from and where it was inserted. We have to adjust for this
|
|
3205
|
+
// and find the original path. We can accomplish this (only in non-sibling)
|
|
3206
|
+
// moves by looking at the impact of the move operation on the node
|
|
3207
|
+
// after the original move path.
|
|
3208
|
+
const inversePath = Path.transform(path, op);
|
|
3209
|
+
const inverseNewPath = Path.transform(Path.next(path), op);
|
|
3210
|
+
return { ...op, path: inversePath, newPath: inverseNewPath };
|
|
3242
3211
|
}
|
|
3243
3212
|
case 'set_node': {
|
|
3244
|
-
const {
|
|
3245
|
-
|
|
3246
|
-
|
|
3213
|
+
const { properties, newProperties } = op;
|
|
3214
|
+
return { ...op, properties: newProperties, newProperties: properties };
|
|
3215
|
+
}
|
|
3216
|
+
case 'set_selection': {
|
|
3217
|
+
const { properties, newProperties } = op;
|
|
3218
|
+
if (properties == null) {
|
|
3219
|
+
return {
|
|
3220
|
+
...op,
|
|
3221
|
+
properties: newProperties,
|
|
3222
|
+
newProperties: null
|
|
3223
|
+
};
|
|
3247
3224
|
}
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
|
|
3251
|
-
|
|
3252
|
-
|
|
3253
|
-
}
|
|
3254
|
-
else {
|
|
3255
|
-
node[key] = value;
|
|
3256
|
-
}
|
|
3225
|
+
else if (newProperties == null) {
|
|
3226
|
+
return {
|
|
3227
|
+
...op,
|
|
3228
|
+
properties: null,
|
|
3229
|
+
newProperties: properties
|
|
3230
|
+
};
|
|
3257
3231
|
}
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
if (!newProperties.hasOwnProperty(key)) {
|
|
3261
|
-
delete node[key];
|
|
3262
|
-
}
|
|
3232
|
+
else {
|
|
3233
|
+
return { ...op, properties: newProperties, newProperties: properties };
|
|
3263
3234
|
}
|
|
3264
|
-
break;
|
|
3265
3235
|
}
|
|
3266
3236
|
case 'set_viewport': {
|
|
3267
|
-
const { newProperties } = op;
|
|
3268
|
-
if (
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
throw new Error(`Cannot apply an incomplete "set_viewport" operation properties ${JSON.stringify(newProperties)} when there is no current viewport.`);
|
|
3275
|
-
}
|
|
3276
|
-
viewport = { ...newProperties };
|
|
3277
|
-
}
|
|
3278
|
-
for (const key in newProperties) {
|
|
3279
|
-
const value = newProperties[key];
|
|
3280
|
-
if (value == null) {
|
|
3281
|
-
delete viewport[key];
|
|
3282
|
-
}
|
|
3283
|
-
else {
|
|
3284
|
-
viewport[key] = value;
|
|
3285
|
-
}
|
|
3286
|
-
}
|
|
3237
|
+
const { properties, newProperties } = op;
|
|
3238
|
+
if (properties == null) {
|
|
3239
|
+
return {
|
|
3240
|
+
...op,
|
|
3241
|
+
properties: newProperties,
|
|
3242
|
+
newProperties: newProperties
|
|
3243
|
+
};
|
|
3287
3244
|
}
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
|
|
3291
|
-
|
|
3292
|
-
|
|
3293
|
-
|
|
3245
|
+
else if (newProperties == null) {
|
|
3246
|
+
return {
|
|
3247
|
+
...op,
|
|
3248
|
+
properties: properties,
|
|
3249
|
+
newProperties: properties
|
|
3250
|
+
};
|
|
3294
3251
|
}
|
|
3295
3252
|
else {
|
|
3296
|
-
|
|
3297
|
-
selection = op.newProperties;
|
|
3298
|
-
}
|
|
3299
|
-
else {
|
|
3300
|
-
selection = newProperties;
|
|
3301
|
-
}
|
|
3253
|
+
return { ...op, properties: newProperties, newProperties: properties };
|
|
3302
3254
|
}
|
|
3303
|
-
break;
|
|
3304
3255
|
}
|
|
3305
3256
|
case 'set_theme': {
|
|
3306
|
-
const { newProperties } = op;
|
|
3307
|
-
|
|
3308
|
-
break;
|
|
3257
|
+
const { properties, newProperties } = op;
|
|
3258
|
+
return { ...op, properties: newProperties, newProperties: properties };
|
|
3309
3259
|
}
|
|
3310
3260
|
}
|
|
3311
|
-
return { selection, viewport, theme };
|
|
3312
3261
|
};
|
|
3313
|
-
const
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3262
|
+
const PlaitOperation = {
|
|
3263
|
+
isSetViewportOperation,
|
|
3264
|
+
inverse
|
|
3265
|
+
};
|
|
3266
|
+
|
|
3267
|
+
const Point = {
|
|
3268
|
+
isEquals(point, otherPoint) {
|
|
3269
|
+
return point && otherPoint && point[0] === otherPoint[0] && point[1] === otherPoint[1];
|
|
3270
|
+
},
|
|
3271
|
+
isHorizontal(point, otherPoint, tolerance = 0) {
|
|
3272
|
+
return point && otherPoint && Point.isOverHorizontal([point, otherPoint], tolerance);
|
|
3273
|
+
},
|
|
3274
|
+
isOverHorizontal(points, tolerance = 0) {
|
|
3275
|
+
return points.every(point => Math.abs(point[1] - points[0][1]) <= tolerance);
|
|
3276
|
+
},
|
|
3277
|
+
isVertical(point, otherPoint, tolerance = 0) {
|
|
3278
|
+
return point && otherPoint && Point.isOverVertical([point, otherPoint], tolerance);
|
|
3279
|
+
},
|
|
3280
|
+
isOverVertical(points, tolerance = 0) {
|
|
3281
|
+
return points.every(point => Math.abs(point[0] - points[0][0]) <= tolerance);
|
|
3282
|
+
},
|
|
3283
|
+
isAlign(points, tolerance = 0) {
|
|
3284
|
+
return Point.isOverHorizontal(points, tolerance) || Point.isOverVertical(points, tolerance);
|
|
3285
|
+
},
|
|
3286
|
+
getOffsetX(point1, point2) {
|
|
3287
|
+
return point2[0] - point1[0];
|
|
3288
|
+
},
|
|
3289
|
+
getOffsetY(point1, point2) {
|
|
3290
|
+
return point2[1] - point1[1];
|
|
3291
|
+
}
|
|
3292
|
+
};
|
|
3293
|
+
|
|
3294
|
+
const SAVING = new WeakMap();
|
|
3295
|
+
const MERGING = new WeakMap();
|
|
3296
|
+
|
|
3297
|
+
var ThemeColorMode;
|
|
3298
|
+
(function (ThemeColorMode) {
|
|
3299
|
+
ThemeColorMode["default"] = "default";
|
|
3300
|
+
ThemeColorMode["colorful"] = "colorful";
|
|
3301
|
+
ThemeColorMode["soft"] = "soft";
|
|
3302
|
+
ThemeColorMode["retro"] = "retro";
|
|
3303
|
+
ThemeColorMode["dark"] = "dark";
|
|
3304
|
+
ThemeColorMode["starry"] = "starry";
|
|
3305
|
+
})(ThemeColorMode || (ThemeColorMode = {}));
|
|
3306
|
+
const DefaultThemeColor = {
|
|
3307
|
+
mode: ThemeColorMode.default,
|
|
3308
|
+
boardBackground: '#ffffff',
|
|
3309
|
+
textColor: '#333333'
|
|
3310
|
+
};
|
|
3311
|
+
const ColorfulThemeColor = {
|
|
3312
|
+
mode: ThemeColorMode.colorful,
|
|
3313
|
+
boardBackground: '#ffffff',
|
|
3314
|
+
textColor: '#333333'
|
|
3315
|
+
};
|
|
3316
|
+
const SoftThemeColor = {
|
|
3317
|
+
mode: ThemeColorMode.soft,
|
|
3318
|
+
boardBackground: '#f5f5f5',
|
|
3319
|
+
textColor: '#333333'
|
|
3320
|
+
};
|
|
3321
|
+
const RetroThemeColor = {
|
|
3322
|
+
mode: ThemeColorMode.retro,
|
|
3323
|
+
boardBackground: '#f9f8ed',
|
|
3324
|
+
textColor: '#333333'
|
|
3325
|
+
};
|
|
3326
|
+
const DarkThemeColor = {
|
|
3327
|
+
mode: ThemeColorMode.dark,
|
|
3328
|
+
boardBackground: '#141414',
|
|
3329
|
+
textColor: '#FFFFFF'
|
|
3330
|
+
};
|
|
3331
|
+
const StarryThemeColor = {
|
|
3332
|
+
mode: ThemeColorMode.starry,
|
|
3333
|
+
boardBackground: '#0d2537',
|
|
3334
|
+
textColor: '#FFFFFF'
|
|
3335
|
+
};
|
|
3336
|
+
const ThemeColors = [
|
|
3337
|
+
DefaultThemeColor,
|
|
3338
|
+
ColorfulThemeColor,
|
|
3339
|
+
SoftThemeColor,
|
|
3340
|
+
RetroThemeColor,
|
|
3341
|
+
DarkThemeColor,
|
|
3342
|
+
StarryThemeColor
|
|
3343
|
+
];
|
|
3344
|
+
|
|
3345
|
+
var Direction;
|
|
3346
|
+
(function (Direction) {
|
|
3347
|
+
Direction["left"] = "left";
|
|
3348
|
+
Direction["top"] = "top";
|
|
3349
|
+
Direction["right"] = "right";
|
|
3350
|
+
Direction["bottom"] = "bottom";
|
|
3351
|
+
})(Direction || (Direction = {}));
|
|
3352
|
+
|
|
3353
|
+
const PlaitGroupElement = {
|
|
3354
|
+
isGroup: (value) => {
|
|
3355
|
+
return value.type === 'group';
|
|
3356
|
+
}
|
|
3357
|
+
};
|
|
3358
|
+
|
|
3359
|
+
function getRectangleByElements(board, elements, recursion) {
|
|
3360
|
+
const rectanglesCornerPoints = [];
|
|
3361
|
+
const callback = (node) => {
|
|
3362
|
+
const nodeRectangle = board.getRectangle(node);
|
|
3363
|
+
if (nodeRectangle) {
|
|
3364
|
+
const cornerPoints = RectangleClient.getCornerPoints(nodeRectangle);
|
|
3365
|
+
const rotatedCornerPoints = rotatePointsByElement(cornerPoints, node) || cornerPoints;
|
|
3366
|
+
rectanglesCornerPoints.push(rotatedCornerPoints);
|
|
3327
3367
|
}
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3368
|
+
else {
|
|
3369
|
+
console.error(`can not get rectangle of element:`, node);
|
|
3370
|
+
}
|
|
3371
|
+
};
|
|
3372
|
+
elements.forEach(element => {
|
|
3373
|
+
if (recursion) {
|
|
3374
|
+
depthFirstRecursion(element, node => callback(node), node => board.isRecursion(node));
|
|
3375
|
+
}
|
|
3376
|
+
else {
|
|
3377
|
+
callback(element);
|
|
3378
|
+
}
|
|
3379
|
+
});
|
|
3380
|
+
if (rectanglesCornerPoints.length > 0) {
|
|
3381
|
+
if (hasSameAngle(elements)) {
|
|
3382
|
+
const angle = getSelectionAngle(elements);
|
|
3383
|
+
return getRotatedBoundingRectangle(rectanglesCornerPoints, angle);
|
|
3338
3384
|
}
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
board.apply(operation);
|
|
3345
|
-
}
|
|
3346
|
-
function setNode(board, props, path) {
|
|
3347
|
-
const properties = {};
|
|
3348
|
-
const newProperties = {};
|
|
3349
|
-
const node = PlaitNode.get(board, path);
|
|
3350
|
-
for (const k in props) {
|
|
3351
|
-
if (node[k] !== props[k]) {
|
|
3352
|
-
if (node.hasOwnProperty(k)) {
|
|
3353
|
-
properties[k] = node[k];
|
|
3354
|
-
}
|
|
3355
|
-
if (props[k] != null)
|
|
3356
|
-
newProperties[k] = props[k];
|
|
3385
|
+
else {
|
|
3386
|
+
const flatCornerPoints = rectanglesCornerPoints.reduce((acc, val) => {
|
|
3387
|
+
return acc.concat(val);
|
|
3388
|
+
}, []);
|
|
3389
|
+
return RectangleClient.getRectangleByPoints(flatCornerPoints);
|
|
3357
3390
|
}
|
|
3358
3391
|
}
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
}
|
|
3367
|
-
function moveNode(board, path, newPath) {
|
|
3368
|
-
const operation = { type: 'move_node', path, newPath };
|
|
3369
|
-
board.apply(operation);
|
|
3392
|
+
else {
|
|
3393
|
+
return {
|
|
3394
|
+
x: 0,
|
|
3395
|
+
y: 0,
|
|
3396
|
+
width: 0,
|
|
3397
|
+
height: 0
|
|
3398
|
+
};
|
|
3399
|
+
}
|
|
3370
3400
|
}
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
setNode,
|
|
3374
|
-
removeNode,
|
|
3375
|
-
moveNode
|
|
3376
|
-
};
|
|
3377
|
-
|
|
3378
|
-
function setSelection(board, selection) {
|
|
3379
|
-
const operation = { type: 'set_selection', properties: board.selection, newProperties: selection };
|
|
3380
|
-
board.apply(operation);
|
|
3401
|
+
function getBoardRectangle(board) {
|
|
3402
|
+
return getRectangleByElements(board, board.children, true);
|
|
3381
3403
|
}
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
};
|
|
3386
|
-
function addSelectionWithTemporaryElements(board, elements) {
|
|
3387
|
-
const timeoutId = setTimeout(() => {
|
|
3388
|
-
setSelection(board, { anchor: [0, 0], focus: [0, 0] });
|
|
3389
|
-
}, 0);
|
|
3390
|
-
let ref = getTemporaryRef(board);
|
|
3391
|
-
if (ref) {
|
|
3392
|
-
clearTimeout(ref.timeoutId);
|
|
3393
|
-
const currentElements = ref.elements;
|
|
3394
|
-
ref.elements.push(...elements.filter(element => !currentElements.includes(element)));
|
|
3395
|
-
ref.timeoutId = timeoutId;
|
|
3396
|
-
}
|
|
3397
|
-
else {
|
|
3398
|
-
BOARD_TO_TEMPORARY_ELEMENTS.set(board, { timeoutId, elements });
|
|
3404
|
+
function getElementById(board, id, dataSource) {
|
|
3405
|
+
if (!dataSource) {
|
|
3406
|
+
dataSource = findElements(board, { match: element => true, recursion: element => true });
|
|
3399
3407
|
}
|
|
3408
|
+
let element = dataSource.find(element => element.id === id);
|
|
3409
|
+
return element;
|
|
3400
3410
|
}
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
};
|
|
3412
|
-
})
|
|
3413
|
-
.forEach(action => {
|
|
3414
|
-
action();
|
|
3415
|
-
});
|
|
3416
|
-
};
|
|
3417
|
-
const CoreTransforms = {
|
|
3418
|
-
removeElements
|
|
3419
|
-
};
|
|
3420
|
-
|
|
3421
|
-
const addGroup = (board, elements) => {
|
|
3422
|
-
const selectedGroups = getHighestSelectedGroups(board, elements);
|
|
3423
|
-
const selectedIsolatedElements = getSelectedIsolatedElementsCanAddToGroup(board);
|
|
3424
|
-
const highestSelectedElements = [...selectedGroups, ...selectedIsolatedElements];
|
|
3425
|
-
const group = createGroup();
|
|
3426
|
-
if (canAddGroup(board)) {
|
|
3427
|
-
highestSelectedElements.forEach(item => {
|
|
3428
|
-
const path = PlaitBoard.findPath(board, item);
|
|
3429
|
-
NodeTransforms.setNode(board, { groupId: group.id }, path);
|
|
3430
|
-
});
|
|
3431
|
-
if (hasSelectedElementsInSameGroup(highestSelectedElements)) {
|
|
3432
|
-
const newGroupId = selectedIsolatedElements[0].groupId;
|
|
3433
|
-
NodeTransforms.insertNode(board, {
|
|
3434
|
-
...group,
|
|
3435
|
-
groupId: newGroupId
|
|
3436
|
-
}, [board.children.length]);
|
|
3411
|
+
function findElements(board, options) {
|
|
3412
|
+
let elements = [];
|
|
3413
|
+
const isReverse = options.isReverse ?? true;
|
|
3414
|
+
depthFirstRecursion(board, node => {
|
|
3415
|
+
if (!PlaitBoard.isBoard(node) && options.match(node)) {
|
|
3416
|
+
elements.push(node);
|
|
3417
|
+
}
|
|
3418
|
+
}, (value) => {
|
|
3419
|
+
if (PlaitBoard.isBoard(value)) {
|
|
3420
|
+
return true;
|
|
3437
3421
|
}
|
|
3438
3422
|
else {
|
|
3439
|
-
|
|
3423
|
+
return getIsRecursionFunc(board)(value) && options.recursion(value);
|
|
3440
3424
|
}
|
|
3441
|
-
}
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
const selectedGroups = getHighestSelectedGroups(board, elements);
|
|
3445
|
-
if (canRemoveGroup(board)) {
|
|
3446
|
-
selectedGroups.map(group => {
|
|
3447
|
-
const elementsInGroup = findElements(board, {
|
|
3448
|
-
match: item => item.groupId === group.id,
|
|
3449
|
-
recursion: () => false
|
|
3450
|
-
});
|
|
3451
|
-
elementsInGroup.forEach(item => {
|
|
3452
|
-
const path = PlaitBoard.findPath(board, item);
|
|
3453
|
-
NodeTransforms.setNode(board, { groupId: group.groupId || undefined }, path);
|
|
3454
|
-
});
|
|
3455
|
-
const groupPath = PlaitBoard.findPath(board, group);
|
|
3456
|
-
NodeTransforms.removeNode(board, groupPath);
|
|
3457
|
-
});
|
|
3458
|
-
}
|
|
3459
|
-
};
|
|
3460
|
-
const GroupTransforms = {
|
|
3461
|
-
addGroup,
|
|
3462
|
-
removeGroup
|
|
3463
|
-
};
|
|
3425
|
+
}, isReverse);
|
|
3426
|
+
return elements;
|
|
3427
|
+
}
|
|
3464
3428
|
|
|
3465
|
-
const
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
|
|
3469
|
-
|
|
3429
|
+
const PlaitBoard = {
|
|
3430
|
+
isBoard(value) {
|
|
3431
|
+
const cachedIsBoard = IS_BOARD_CACHE.get(value);
|
|
3432
|
+
if (cachedIsBoard !== undefined) {
|
|
3433
|
+
return cachedIsBoard;
|
|
3434
|
+
}
|
|
3435
|
+
const isBoard = typeof value.onChange === 'function' && typeof value.apply === 'function';
|
|
3436
|
+
IS_BOARD_CACHE.set(value, isBoard);
|
|
3437
|
+
return isBoard;
|
|
3438
|
+
},
|
|
3439
|
+
isAlive(board) {
|
|
3440
|
+
const isAlive = IS_BOARD_CACHE.get(board);
|
|
3441
|
+
return !!isAlive;
|
|
3442
|
+
},
|
|
3443
|
+
findPath(board, node) {
|
|
3444
|
+
const path = [];
|
|
3445
|
+
let child = node;
|
|
3446
|
+
while (true) {
|
|
3447
|
+
const parent = NODE_TO_PARENT.get(child);
|
|
3448
|
+
if (parent == null) {
|
|
3449
|
+
if (PlaitBoard.isBoard(child)) {
|
|
3450
|
+
return path;
|
|
3451
|
+
}
|
|
3452
|
+
else {
|
|
3453
|
+
break;
|
|
3454
|
+
}
|
|
3455
|
+
}
|
|
3456
|
+
const i = NODE_TO_INDEX.get(child);
|
|
3457
|
+
if (i == null) {
|
|
3458
|
+
break;
|
|
3459
|
+
}
|
|
3460
|
+
path.unshift(i);
|
|
3461
|
+
child = parent;
|
|
3462
|
+
}
|
|
3463
|
+
throw new Error(`Unable to find the path for Plait node: ${JSON.stringify(node)}`);
|
|
3464
|
+
},
|
|
3465
|
+
getHost(board) {
|
|
3466
|
+
return BOARD_TO_HOST.get(board);
|
|
3467
|
+
},
|
|
3468
|
+
getElementHost(board) {
|
|
3469
|
+
return BOARD_TO_ELEMENT_HOST.get(board)?.host;
|
|
3470
|
+
},
|
|
3471
|
+
getElementUpperHost(board) {
|
|
3472
|
+
return BOARD_TO_ELEMENT_HOST.get(board)?.upperHost;
|
|
3473
|
+
},
|
|
3474
|
+
getElementActiveHost(board) {
|
|
3475
|
+
return BOARD_TO_ELEMENT_HOST.get(board)?.activeHost;
|
|
3476
|
+
},
|
|
3477
|
+
getRoughSVG(board) {
|
|
3478
|
+
return BOARD_TO_ROUGH_SVG.get(board);
|
|
3479
|
+
},
|
|
3480
|
+
getComponent(board) {
|
|
3481
|
+
return BOARD_TO_COMPONENT.get(board);
|
|
3482
|
+
},
|
|
3483
|
+
getBoardContainer(board) {
|
|
3484
|
+
return BOARD_TO_ELEMENT_HOST.get(board)?.container;
|
|
3485
|
+
},
|
|
3486
|
+
getRectangle(board) {
|
|
3487
|
+
return getRectangleByElements(board, board.children, true);
|
|
3488
|
+
},
|
|
3489
|
+
getViewportContainer(board) {
|
|
3490
|
+
return BOARD_TO_ELEMENT_HOST.get(board)?.viewportContainer;
|
|
3491
|
+
},
|
|
3492
|
+
isFocus(board) {
|
|
3493
|
+
return !!board.selection;
|
|
3494
|
+
},
|
|
3495
|
+
isReadonly(board) {
|
|
3496
|
+
return board.options.readonly;
|
|
3497
|
+
},
|
|
3498
|
+
hasBeenTextEditing(board) {
|
|
3499
|
+
return !!IS_TEXT_EDITABLE.get(board);
|
|
3500
|
+
},
|
|
3501
|
+
getPointer(board) {
|
|
3502
|
+
return board.pointer;
|
|
3503
|
+
},
|
|
3504
|
+
isPointer(board, pointer) {
|
|
3505
|
+
return board.pointer === pointer;
|
|
3506
|
+
},
|
|
3507
|
+
isInPointer(board, pointers) {
|
|
3508
|
+
const point = board.pointer;
|
|
3509
|
+
return pointers.includes(point);
|
|
3510
|
+
},
|
|
3511
|
+
getMovingPointInBoard(board) {
|
|
3512
|
+
return BOARD_TO_MOVING_POINT_IN_BOARD.get(board);
|
|
3513
|
+
},
|
|
3514
|
+
isMovingPointInBoard(board) {
|
|
3515
|
+
const point = BOARD_TO_MOVING_POINT.get(board);
|
|
3516
|
+
const rect = PlaitBoard.getBoardContainer(board).getBoundingClientRect();
|
|
3517
|
+
if (point && distanceBetweenPointAndRectangle(point[0], point[1], rect) === 0) {
|
|
3518
|
+
return true;
|
|
3519
|
+
}
|
|
3520
|
+
return false;
|
|
3521
|
+
},
|
|
3522
|
+
getThemeColors(board) {
|
|
3523
|
+
return (board.options.themeColors || ThemeColors);
|
|
3524
|
+
}
|
|
3470
3525
|
};
|
|
3471
3526
|
|
|
3472
3527
|
const PathRef = {
|
|
@@ -3547,6 +3602,9 @@ function createBoard(children, options) {
|
|
|
3547
3602
|
},
|
|
3548
3603
|
onChange: () => { },
|
|
3549
3604
|
afterChange: () => { },
|
|
3605
|
+
drawActiveRectangle: () => {
|
|
3606
|
+
return drawEntireActiveRectangleG(board);
|
|
3607
|
+
},
|
|
3550
3608
|
mousedown: (event) => { },
|
|
3551
3609
|
mousemove: (event) => { },
|
|
3552
3610
|
mouseleave: (event) => { },
|
|
@@ -3561,12 +3619,11 @@ function createBoard(children, options) {
|
|
|
3561
3619
|
setClipboardData(data, clipboardContext);
|
|
3562
3620
|
},
|
|
3563
3621
|
insertFragment: (data) => { },
|
|
3564
|
-
deleteFragment: (
|
|
3565
|
-
const elements = board.getDeletedFragment([]);
|
|
3622
|
+
deleteFragment: (elements) => {
|
|
3566
3623
|
CoreTransforms.removeElements(board, elements);
|
|
3567
3624
|
},
|
|
3568
3625
|
getDeletedFragment: (data) => data,
|
|
3569
|
-
getRelatedFragment: (data) => data,
|
|
3626
|
+
getRelatedFragment: (data, originData) => data,
|
|
3570
3627
|
drawElement: (context) => [],
|
|
3571
3628
|
redrawElement: (context, previousContext) => { },
|
|
3572
3629
|
destroyElement: (context) => { },
|
|
@@ -3751,7 +3808,7 @@ function withHandPointer(board) {
|
|
|
3751
3808
|
}
|
|
3752
3809
|
|
|
3753
3810
|
function withSelection(board) {
|
|
3754
|
-
const { pointerDown, pointerUp, pointerMove, globalPointerUp, onChange, afterChange } = board;
|
|
3811
|
+
const { pointerDown, pointerUp, pointerMove, globalPointerUp, onChange, afterChange, drawActiveRectangle } = board;
|
|
3755
3812
|
let start = null;
|
|
3756
3813
|
let end = null;
|
|
3757
3814
|
let selectionMovingG;
|
|
@@ -3912,7 +3969,8 @@ function withSelection(board) {
|
|
|
3912
3969
|
if (!isSelectionMoving(board)) {
|
|
3913
3970
|
selectionRectangleG?.remove();
|
|
3914
3971
|
if (newElements.length > 1) {
|
|
3915
|
-
selectionRectangleG =
|
|
3972
|
+
selectionRectangleG = board.drawActiveRectangle();
|
|
3973
|
+
PlaitBoard.getElementActiveHost(board).append(selectionRectangleG);
|
|
3916
3974
|
}
|
|
3917
3975
|
}
|
|
3918
3976
|
}
|
|
@@ -3931,7 +3989,8 @@ function withSelection(board) {
|
|
|
3931
3989
|
(currentSelectedElements.length !== previousSelectedElements.length ||
|
|
3932
3990
|
currentSelectedElements.some((c, index) => c !== previousSelectedElements[index]))) {
|
|
3933
3991
|
selectionRectangleG?.remove();
|
|
3934
|
-
selectionRectangleG =
|
|
3992
|
+
selectionRectangleG = board.drawActiveRectangle();
|
|
3993
|
+
PlaitBoard.getElementActiveHost(board).append(selectionRectangleG);
|
|
3935
3994
|
previousSelectedElements = currentSelectedElements;
|
|
3936
3995
|
}
|
|
3937
3996
|
}
|
|
@@ -3980,8 +4039,8 @@ function withViewport(board) {
|
|
|
3980
4039
|
return board;
|
|
3981
4040
|
}
|
|
3982
4041
|
|
|
3983
|
-
const
|
|
3984
|
-
class
|
|
4042
|
+
const SNAP_TOLERANCE = 2;
|
|
4043
|
+
class MovingSnapReaction {
|
|
3985
4044
|
constructor(board, activeElements, activeRectangle) {
|
|
3986
4045
|
this.board = board;
|
|
3987
4046
|
this.activeElements = activeElements;
|
|
@@ -3995,7 +4054,7 @@ class AlignReaction {
|
|
|
3995
4054
|
return;
|
|
3996
4055
|
}
|
|
3997
4056
|
const rectangle = this.board.getRectangle(node);
|
|
3998
|
-
rectangle && result.push(rectangle);
|
|
4057
|
+
rectangle && result.push(getRectangleByAngle(rectangle, node.angle) || rectangle);
|
|
3999
4058
|
}, node => {
|
|
4000
4059
|
if (node && (PlaitBoard.isBoard(node) || this.board.isRecursion(node))) {
|
|
4001
4060
|
return true;
|
|
@@ -4006,7 +4065,7 @@ class AlignReaction {
|
|
|
4006
4065
|
}, true);
|
|
4007
4066
|
return result;
|
|
4008
4067
|
}
|
|
4009
|
-
|
|
4068
|
+
handleSnapping() {
|
|
4010
4069
|
const alignRectangles = this.getAlignRectangle();
|
|
4011
4070
|
const g = createG();
|
|
4012
4071
|
let alignLines = [];
|
|
@@ -4018,7 +4077,7 @@ class AlignReaction {
|
|
|
4018
4077
|
for (let alignRectangle of alignRectangles) {
|
|
4019
4078
|
const closestDistances = this.calculateClosestDistances(this.activeRectangle, alignRectangle);
|
|
4020
4079
|
let canDrawHorizontal = false;
|
|
4021
|
-
if (!isCorrectX && closestDistances.absXDistance <
|
|
4080
|
+
if (!isCorrectX && closestDistances.absXDistance < SNAP_TOLERANCE) {
|
|
4022
4081
|
deltaX = closestDistances.xDistance;
|
|
4023
4082
|
this.activeRectangle.x -= deltaX;
|
|
4024
4083
|
isCorrectX = true;
|
|
@@ -4068,7 +4127,7 @@ class AlignReaction {
|
|
|
4068
4127
|
isCorrectX = true;
|
|
4069
4128
|
}
|
|
4070
4129
|
let canDrawVertical = false;
|
|
4071
|
-
if (!isCorrectY && closestDistances.absYDistance <
|
|
4130
|
+
if (!isCorrectY && closestDistances.absYDistance < SNAP_TOLERANCE) {
|
|
4072
4131
|
deltaY = closestDistances.yDistance;
|
|
4073
4132
|
this.activeRectangle.y -= deltaY;
|
|
4074
4133
|
isCorrectY = true;
|
|
@@ -4215,7 +4274,7 @@ class AlignReaction {
|
|
|
4215
4274
|
//middle
|
|
4216
4275
|
let _center = (before[axis] + before[side] + after[axis]) / 2;
|
|
4217
4276
|
dif = Math.abs(activeRectangleCenter - _center);
|
|
4218
|
-
if (dif <
|
|
4277
|
+
if (dif < SNAP_TOLERANCE) {
|
|
4219
4278
|
distributeDistance = (after[axis] - (before[axis] + before[side]) - this.activeRectangle[side]) / 2;
|
|
4220
4279
|
delta = activeRectangleCenter - _center;
|
|
4221
4280
|
beforeIndex = i;
|
|
@@ -4225,7 +4284,7 @@ class AlignReaction {
|
|
|
4225
4284
|
const distanceRight = after[axis] - (before[axis] + before[side]);
|
|
4226
4285
|
_center = after[axis] + after[side] + distanceRight + this.activeRectangle[side] / 2;
|
|
4227
4286
|
dif = Math.abs(activeRectangleCenter - _center);
|
|
4228
|
-
if (!distributeDistance && dif <
|
|
4287
|
+
if (!distributeDistance && dif < SNAP_TOLERANCE) {
|
|
4229
4288
|
distributeDistance = distanceRight;
|
|
4230
4289
|
beforeIndex = j;
|
|
4231
4290
|
delta = activeRectangleCenter - _center;
|
|
@@ -4234,7 +4293,7 @@ class AlignReaction {
|
|
|
4234
4293
|
const distanceBefore = after[axis] - (before[axis] + before[side]);
|
|
4235
4294
|
_center = before[axis] - distanceBefore - this.activeRectangle[side] / 2;
|
|
4236
4295
|
dif = Math.abs(activeRectangleCenter - _center);
|
|
4237
|
-
if (!distributeDistance && dif <
|
|
4296
|
+
if (!distributeDistance && dif < SNAP_TOLERANCE) {
|
|
4238
4297
|
distributeDistance = distanceBefore;
|
|
4239
4298
|
afterIndex = i;
|
|
4240
4299
|
delta = activeRectangleCenter - _center;
|
|
@@ -4379,7 +4438,8 @@ function withMoving(board) {
|
|
|
4379
4438
|
}
|
|
4380
4439
|
else if (hitTargetElement) {
|
|
4381
4440
|
startPoint = point;
|
|
4382
|
-
|
|
4441
|
+
const relatedElements = board.getRelatedFragment([], [hitTargetElement]);
|
|
4442
|
+
activeElements = [...getElementsInGroupByElement(board, hitTargetElement), ...relatedElements];
|
|
4383
4443
|
activeElementsRectangle = getRectangleByElements(board, activeElements, true);
|
|
4384
4444
|
preventTouchMove(board, event, true);
|
|
4385
4445
|
}
|
|
@@ -4423,8 +4483,8 @@ function withMoving(board) {
|
|
|
4423
4483
|
x: activeElementsRectangle.x + offsetX,
|
|
4424
4484
|
y: activeElementsRectangle.y + offsetY
|
|
4425
4485
|
};
|
|
4426
|
-
const
|
|
4427
|
-
const ref =
|
|
4486
|
+
const movingSnapReaction = new MovingSnapReaction(board, activeElements, getRectangleByAngle(newRectangle, getSelectionAngle(activeElements)) || newRectangle);
|
|
4487
|
+
const ref = movingSnapReaction.handleSnapping();
|
|
4428
4488
|
offsetX -= ref.deltaX;
|
|
4429
4489
|
offsetY -= ref.deltaY;
|
|
4430
4490
|
alignG = ref.g;
|
|
@@ -4653,7 +4713,7 @@ const withHotkey = (board) => {
|
|
|
4653
4713
|
selectedElements.length > 0 &&
|
|
4654
4714
|
(hotkeys.isDeleteBackward(event) || hotkeys.isDeleteForward(event))) {
|
|
4655
4715
|
event.preventDefault();
|
|
4656
|
-
|
|
4716
|
+
deleteFragment(board);
|
|
4657
4717
|
}
|
|
4658
4718
|
keyDown(event);
|
|
4659
4719
|
};
|
|
@@ -4953,6 +5013,7 @@ class PlaitBoardComponent {
|
|
|
4953
5013
|
BOARD_TO_COMPONENT.set(this.board, this);
|
|
4954
5014
|
BOARD_TO_ROUGH_SVG.set(this.board, roughSVG);
|
|
4955
5015
|
BOARD_TO_HOST.set(this.board, this.host);
|
|
5016
|
+
IS_BOARD_ALIVE.set(this.board, true);
|
|
4956
5017
|
BOARD_TO_ELEMENT_HOST.set(this.board, {
|
|
4957
5018
|
host: elementHost,
|
|
4958
5019
|
upperHost: elementUpperHost,
|
|
@@ -5126,7 +5187,7 @@ class PlaitBoardComponent {
|
|
|
5126
5187
|
event.preventDefault();
|
|
5127
5188
|
const rectangle = getRectangleByElements(this.board, selectedElements, false);
|
|
5128
5189
|
this.board.setFragment(event.clipboardData, null, rectangle, 'cut');
|
|
5129
|
-
this.board
|
|
5190
|
+
deleteFragment(this.board);
|
|
5130
5191
|
});
|
|
5131
5192
|
}
|
|
5132
5193
|
viewportScrollListener() {
|
|
@@ -5208,6 +5269,7 @@ class PlaitBoardComponent {
|
|
|
5208
5269
|
BOARD_TO_ROUGH_SVG.delete(this.board);
|
|
5209
5270
|
BOARD_TO_HOST.delete(this.board);
|
|
5210
5271
|
BOARD_TO_ELEMENT_HOST.delete(this.board);
|
|
5272
|
+
IS_BOARD_ALIVE.set(this.board, false);
|
|
5211
5273
|
BOARD_TO_ON_CHANGE.delete(this.board);
|
|
5212
5274
|
BOARD_TO_AFTER_CHANGE.set(this.board, () => { });
|
|
5213
5275
|
}
|
|
@@ -5474,12 +5536,25 @@ class DebugGenerator {
|
|
|
5474
5536
|
return;
|
|
5475
5537
|
}
|
|
5476
5538
|
const polygonG = PlaitBoard.getRoughSVG(board).polygon(points, options || { stroke: 'red' });
|
|
5539
|
+
polygonG.classList.add(this.debugKey);
|
|
5477
5540
|
PlaitBoard.getElementActiveHost(board).append(polygonG);
|
|
5478
5541
|
const gArray = getTemporaryGArray(this.debugKey);
|
|
5479
5542
|
gArray.push(polygonG);
|
|
5480
5543
|
setTemporaryGArray(this.debugKey, gArray);
|
|
5481
5544
|
return polygonG;
|
|
5482
5545
|
}
|
|
5546
|
+
drawLine(board, points, options) {
|
|
5547
|
+
if (!isDebug(this.debugKey)) {
|
|
5548
|
+
return;
|
|
5549
|
+
}
|
|
5550
|
+
const lineG = PlaitBoard.getRoughSVG(board).linearPath(points, options || { stroke: 'red' });
|
|
5551
|
+
lineG.classList.add(this.debugKey);
|
|
5552
|
+
PlaitBoard.getElementActiveHost(board).append(lineG);
|
|
5553
|
+
const gArray = getTemporaryGArray(this.debugKey);
|
|
5554
|
+
gArray.push(lineG);
|
|
5555
|
+
setTemporaryGArray(this.debugKey, gArray);
|
|
5556
|
+
return lineG;
|
|
5557
|
+
}
|
|
5483
5558
|
drawRectangle(board, data, options) {
|
|
5484
5559
|
if (!isDebug(this.debugKey)) {
|
|
5485
5560
|
return;
|
|
@@ -5492,6 +5567,7 @@ class DebugGenerator {
|
|
|
5492
5567
|
rectangle = data;
|
|
5493
5568
|
}
|
|
5494
5569
|
const rectangleG = PlaitBoard.getRoughSVG(board).rectangle(rectangle.x, rectangle.y, rectangle.width, rectangle.height, options || { stroke: 'red' });
|
|
5570
|
+
rectangleG.classList.add(this.debugKey);
|
|
5495
5571
|
PlaitBoard.getElementActiveHost(board).append(rectangleG);
|
|
5496
5572
|
const gArray = getTemporaryGArray(this.debugKey);
|
|
5497
5573
|
gArray.push(rectangleG);
|
|
@@ -5505,6 +5581,7 @@ class DebugGenerator {
|
|
|
5505
5581
|
const result = [];
|
|
5506
5582
|
points.forEach((p, i) => {
|
|
5507
5583
|
const circle = PlaitBoard.getRoughSVG(board).circle(p[0], p[1], isCumulativeDiameter ? diameter * (i + 1) : diameter, Object.assign({}, { stroke: 'red', fill: 'red', fillStyle: 'solid' }, options || {}));
|
|
5584
|
+
circle.classList.add(this.debugKey);
|
|
5508
5585
|
PlaitBoard.getElementActiveHost(board).append(circle);
|
|
5509
5586
|
const gArray = getTemporaryGArray(this.debugKey);
|
|
5510
5587
|
gArray.push(circle);
|
|
@@ -5530,5 +5607,5 @@ const isDebug = (key) => {
|
|
|
5530
5607
|
* Generated bundle index. Do not edit.
|
|
5531
5608
|
*/
|
|
5532
5609
|
|
|
5533
|
-
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_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, GroupTransforms, H, HIT_DISTANCE_BUFFER, HOME, HOST_CLASS_NAME, I, INSERT, IS_APPLE, 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_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, PlaitGroupElement, PlaitHistoryBoard, PlaitIslandBaseComponent, PlaitIslandPopoverBaseComponent, PlaitNode, PlaitOperation, PlaitPluginElementComponent, PlaitPluginKey, PlaitPointerType, Point, Q, QUESTION_MARK, R, RESIZE_CURSORS, RIGHT_ARROW, 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, SPACE, Selection, SoftThemeColor, StarryThemeColor, T, TAB, THREE, TILDE, TWO, ThemeColorMode, ThemeColors, Transforms, U, UP_ARROW, V, VOLUME_DOWN, VOLUME_UP, Viewport, W, WritableClipboardType, X, Y, Z, ZERO, addClipboardContext, addSelectedElement, approximately, arrowPoints, buildPlaitHtml, cacheMovingElements, cacheSelectedElements, cacheSelectedElementsWithGroup, cacheSelectedElementsWithGroupOnShift, calcNewViewBox, canAddGroup, canRemoveGroup, catmullRomFitting, clampZoomLevel, clearNodeWeakMap, clearSelectedElement, clearSelectionMoving, clearViewportOrigination, createClipboardContext, createDebugGenerator, createFakeEvent, createForeignObject, createG, createGroup, createGroupRectangleG, createKeyboardEvent, createMask, createModModifierKeys, createMouseEvent, createPath, createPointerEvent, createRect, createSVG,
|
|
5610
|
+
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_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, GroupTransforms, 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_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, PlaitGroupElement, PlaitHistoryBoard, PlaitIslandBaseComponent, PlaitIslandPopoverBaseComponent, PlaitNode, PlaitOperation, PlaitPluginElementComponent, PlaitPluginKey, PlaitPointerType, Point, Q, QUESTION_MARK, R, RESIZE_CURSORS, RIGHT_ARROW, 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, SPACE, Selection, SoftThemeColor, StarryThemeColor, T, TAB, THREE, TILDE, TWO, ThemeColorMode, ThemeColors, Transforms, U, UP_ARROW, V, VOLUME_DOWN, VOLUME_UP, Viewport, W, WritableClipboardType, X, Y, Z, ZERO, addClipboardContext, addSelectedElement, approximately, arrowPoints, buildPlaitHtml, cacheMovingElements, cacheSelectedElements, cacheSelectedElementsWithGroup, cacheSelectedElementsWithGroupOnShift, calcNewViewBox, canAddGroup, canRemoveGroup, 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, drawEntireActiveRectangleG, drawLine, drawLinearPath, drawRectangle, drawRoundRectangle, fakeNodeWeakMap, filterSelectedGroups, findElements, getAllElementsInGroup, getBoardRectangle, getClipboardData, getClipboardFromHtml, getDataTransferClipboard, getDataTransferClipboardText, getElementById, getElementHostBBox, getElementsInGroup, getElementsInGroupByElement, getEllipseTangentSlope, getGroupByElement, getHighestGroup, getHighestSelectedElements, getHighestSelectedGroup, getHighestSelectedGroups, getHitElementByPoint, getHitElementsBySelection, getHitSelectedElements, getIsRecursionFunc, getMovingElements, getNearestPointBetweenPointAndSegment, getNearestPointBetweenPointAndSegments, getOffsetAfterRotate, getProbablySupportsClipboardRead, getProbablySupportsClipboardWrite, getProbablySupportsClipboardWriteText, getRealScrollBarWidth, getRectangleByAngle, getRectangleByElements, getRectangleByGroup, getRotatedBoundingRectangle, getSelectedElements, getSelectedGroups, getSelectedIsolatedElements, getSelectedIsolatedElementsCanAddToGroup, getSelectedTargetElements, getSelectionAngle, getTemporaryElements, getTemporaryRef, 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, isInPlaitBoard, isLineHitLine, isMainPointer, isMovingElements, isNullOrUndefined, isPointInEllipse, isPointInPolygon, isPointInRoundRectangle, isPolylineHitRectangle, isPreventTouchMove, isSecondaryPointer, isSelectedAllElementsInGroup, isSelectedElement, isSelectedElementOrGroup, isSelectionMoving, isSetSelectionOperation, isSetViewportOperation, nonGroupInHighestSelectedElements, normalizePoint, preventTouchMove, radiansToDegrees, removeMovingElements, removeSelectedElement, rotate, rotateAntiPointsByElement, rotateElements, rotatePoints, rotatePointsByElement, rotatedDataPoints, scrollToRectangle, setAngleForG, setClipboardData, setDataTransferClipboard, setDataTransferClipboardText, setDragging, setIsFromScrolling, setIsFromViewportChange, setPathStrokeLinecap, setSVGViewBox, setSelectedElementsWithGroup, setSelectionMoving, setStrokeLinecap, shouldClear, shouldMerge, shouldSave, stripHtml, temporaryDisableSelection, throttleRAF, toDomPrecision, toFixed, toHostPoint, toHostPointFromViewBoxPoint, toImage, toScreenPointFromHostPoint, toViewBoxPoint, toViewBoxPoints, uniqueById, updateForeignObject, updateForeignObjectWidth, updatePoints, updateViewportByScrolling, updateViewportContainerScroll, updateViewportOffset, updateViewportOrigination, withArrowMoving, withMoving, withOptions, withSelection };
|
|
5534
5611
|
//# sourceMappingURL=plait-core.mjs.map
|