@plait/core 0.52.0 → 0.53.1
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/cursor.d.ts +1 -0
- package/esm2022/board/board.component.mjs +3 -3
- package/esm2022/constants/cursor.mjs +2 -1
- package/esm2022/interfaces/board.mjs +1 -1
- package/esm2022/interfaces/path.mjs +2 -2
- package/esm2022/plugins/create-board.mjs +3 -2
- package/esm2022/plugins/with-moving.mjs +36 -17
- package/esm2022/plugins/with-related-fragment.mjs +20 -0
- package/esm2022/plugins/with-selection.mjs +32 -98
- package/esm2022/public-api.mjs +2 -1
- package/esm2022/transforms/group.mjs +47 -0
- package/esm2022/transforms/index.mjs +2 -1
- package/esm2022/utils/angle.mjs +75 -0
- package/esm2022/utils/debug.mjs +76 -0
- package/esm2022/utils/element.mjs +17 -5
- package/esm2022/utils/group.mjs +79 -84
- package/esm2022/utils/helper.mjs +10 -1
- package/esm2022/utils/index.mjs +2 -1
- package/esm2022/utils/math.mjs +11 -1
- package/esm2022/utils/selection.mjs +89 -3
- package/esm2022/utils/touch.mjs +15 -4
- package/fesm2022/plait-core.mjs +1332 -1073
- package/fesm2022/plait-core.mjs.map +1 -1
- package/interfaces/board.d.ts +1 -0
- package/package.json +1 -1
- package/plugins/with-moving.d.ts +1 -1
- package/plugins/with-related-fragment.d.ts +2 -0
- package/public-api.d.ts +1 -0
- package/transforms/group.d.ts +7 -0
- package/transforms/index.d.ts +1 -0
- package/utils/angle.d.ts +13 -0
- package/utils/debug.d.ts +13 -0
- package/utils/group.d.ts +15 -15
- package/utils/helper.d.ts +2 -0
- package/utils/index.d.ts +1 -0
- package/utils/math.d.ts +8 -0
- package/utils/selection.d.ts +6 -3
- package/utils/touch.d.ts +1 -1
- package/esm2022/plugins/with-group.mjs +0 -27
- package/plugins/with-group.d.ts +0 -2
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
|
|
@@ -493,6 +493,7 @@ var CursorClass;
|
|
|
493
493
|
(function (CursorClass) {
|
|
494
494
|
CursorClass["crosshair"] = "crosshair";
|
|
495
495
|
})(CursorClass || (CursorClass = {}));
|
|
496
|
+
const RESIZE_CURSORS = [ResizeCursorClass.ns, ResizeCursorClass.nesw, ResizeCursorClass.ew, ResizeCursorClass.nwse];
|
|
496
497
|
|
|
497
498
|
const ATTACHED_ELEMENT_CLASS_NAME = 'plait-board-attached';
|
|
498
499
|
const ACTIVE_STROKE_WIDTH = 1;
|
|
@@ -952,6 +953,16 @@ function toDomPrecision(v) {
|
|
|
952
953
|
function toFixed(v) {
|
|
953
954
|
return +v.toFixed(2);
|
|
954
955
|
}
|
|
956
|
+
/**
|
|
957
|
+
* Whether two numbers numbers a and b are approximately equal.
|
|
958
|
+
*
|
|
959
|
+
* @param a - The first point.
|
|
960
|
+
* @param b - The second point.
|
|
961
|
+
* @public
|
|
962
|
+
*/
|
|
963
|
+
function approximately(a, b, precision = 0.000001) {
|
|
964
|
+
return Math.abs(a - b) <= precision;
|
|
965
|
+
}
|
|
955
966
|
|
|
956
967
|
function isInPlaitBoard(board, x, y) {
|
|
957
968
|
const plaitBoardElement = PlaitBoard.getBoardContainer(board);
|
|
@@ -1030,6 +1041,15 @@ const RgbaToHEX = (Rgb, opacity) => {
|
|
|
1030
1041
|
function isContextmenu(event) {
|
|
1031
1042
|
return event.button === 2;
|
|
1032
1043
|
}
|
|
1044
|
+
function uniqueById(elements) {
|
|
1045
|
+
const uniqueMap = new Map();
|
|
1046
|
+
elements.forEach(item => {
|
|
1047
|
+
if (!uniqueMap.has(item.id)) {
|
|
1048
|
+
uniqueMap.set(item.id, item);
|
|
1049
|
+
}
|
|
1050
|
+
});
|
|
1051
|
+
return Array.from(uniqueMap.values());
|
|
1052
|
+
}
|
|
1033
1053
|
|
|
1034
1054
|
/**
|
|
1035
1055
|
* Check whether to merge an operation into the previous operation.
|
|
@@ -2151,8 +2171,16 @@ const isPreventTouchMove = (board) => {
|
|
|
2151
2171
|
return !!BOARD_TO_TOUCH_REF.get(board);
|
|
2152
2172
|
};
|
|
2153
2173
|
const preventTouchMove = (board, event, state) => {
|
|
2154
|
-
|
|
2155
|
-
|
|
2174
|
+
const hostElement = PlaitBoard.getElementHost(board);
|
|
2175
|
+
const activeHostElement = PlaitBoard.getElementActiveHost(board);
|
|
2176
|
+
if (state) {
|
|
2177
|
+
if ((event.target instanceof HTMLElement || event.target instanceof SVGElement) &&
|
|
2178
|
+
(hostElement.contains(event.target) || activeHostElement.contains(event.target))) {
|
|
2179
|
+
BOARD_TO_TOUCH_REF.set(board, { state, target: event.target instanceof SVGElement ? event.target : undefined });
|
|
2180
|
+
}
|
|
2181
|
+
else {
|
|
2182
|
+
BOARD_TO_TOUCH_REF.set(board, { state, target: undefined });
|
|
2183
|
+
}
|
|
2156
2184
|
}
|
|
2157
2185
|
else {
|
|
2158
2186
|
const ref = BOARD_TO_TOUCH_REF.get(board);
|
|
@@ -2170,7 +2198,10 @@ const preventTouchMove = (board, event, state) => {
|
|
|
2170
2198
|
*/
|
|
2171
2199
|
const handleTouchTarget = (board) => {
|
|
2172
2200
|
const touchRef = BOARD_TO_TOUCH_REF.get(board);
|
|
2173
|
-
if (touchRef &&
|
|
2201
|
+
if (touchRef &&
|
|
2202
|
+
touchRef.target &&
|
|
2203
|
+
!PlaitBoard.getElementHost(board).contains(touchRef.target) &&
|
|
2204
|
+
!PlaitBoard.getElementActiveHost(board).contains(touchRef.target)) {
|
|
2174
2205
|
touchRef.target.style.opacity = '0';
|
|
2175
2206
|
const host = createG();
|
|
2176
2207
|
host.appendChild(touchRef.target);
|
|
@@ -2180,1057 +2211,1262 @@ const handleTouchTarget = (board) => {
|
|
|
2180
2211
|
}
|
|
2181
2212
|
};
|
|
2182
2213
|
|
|
2183
|
-
const
|
|
2184
|
-
|
|
2185
|
-
|
|
2214
|
+
const rotatePoints = (points, centerPoint, angle) => {
|
|
2215
|
+
if (!angle) {
|
|
2216
|
+
angle = 0;
|
|
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
|
+
});
|
|
2186
2225
|
}
|
|
2187
2226
|
};
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
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;
|
|
2192
2284
|
}
|
|
2193
2285
|
};
|
|
2194
2286
|
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2287
|
+
function isSelectionMoving(board) {
|
|
2288
|
+
return !!BOARD_TO_IS_SELECTION_MOVING.get(board);
|
|
2289
|
+
}
|
|
2290
|
+
function setSelectionMoving(board) {
|
|
2291
|
+
PlaitBoard.getBoardContainer(board).classList.add('selection-moving');
|
|
2292
|
+
BOARD_TO_IS_SELECTION_MOVING.set(board, true);
|
|
2293
|
+
setDragging(board, true);
|
|
2294
|
+
}
|
|
2295
|
+
function clearSelectionMoving(board) {
|
|
2296
|
+
PlaitBoard.getBoardContainer(board).classList.remove('selection-moving');
|
|
2297
|
+
BOARD_TO_IS_SELECTION_MOVING.delete(board);
|
|
2298
|
+
setDragging(board, false);
|
|
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
2336
|
}
|
|
2226
|
-
|
|
2227
|
-
|
|
2337
|
+
return selectionRectangleG;
|
|
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
|
+
}
|
|
2228
2371
|
}
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2372
|
+
}
|
|
2373
|
+
}
|
|
2374
|
+
function cacheSelectedElementsWithGroupOnShift(board, elements, isSelectGroupElement, elementsInHighestGroup) {
|
|
2375
|
+
const selectedElements = getSelectedElements(board);
|
|
2376
|
+
let newElements = [...selectedElements];
|
|
2377
|
+
const hitElement = elements[0];
|
|
2378
|
+
let pendingElements = [];
|
|
2379
|
+
if (!isSelectGroupElement) {
|
|
2380
|
+
pendingElements = elementsInHighestGroup;
|
|
2381
|
+
}
|
|
2382
|
+
else {
|
|
2383
|
+
const isHitSelectedElement = selectedElements.some(item => item.id === hitElement.id);
|
|
2384
|
+
const selectedElementsInGroup = elementsInHighestGroup.filter(item => selectedElements.includes(item));
|
|
2385
|
+
if (isHitSelectedElement) {
|
|
2386
|
+
pendingElements = selectedElementsInGroup.filter(item => item.id !== hitElement.id);
|
|
2234
2387
|
}
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
next(path) {
|
|
2238
|
-
if (path.length === 0) {
|
|
2239
|
-
throw new Error(`Cannot get the next path of a root path [${path}], because it has no next index.`);
|
|
2388
|
+
else {
|
|
2389
|
+
pendingElements.push(...selectedElementsInGroup, ...elements);
|
|
2240
2390
|
}
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
return path[path.length - 1] > 0;
|
|
2246
|
-
},
|
|
2247
|
-
previous(path) {
|
|
2248
|
-
if (path.length === 0) {
|
|
2249
|
-
throw new Error(`Cannot get the next path of a root path [${path}], because it has no previous index.`);
|
|
2391
|
+
}
|
|
2392
|
+
elementsInHighestGroup.forEach(element => {
|
|
2393
|
+
if (newElements.includes(element)) {
|
|
2394
|
+
newElements.splice(newElements.indexOf(element), 1);
|
|
2250
2395
|
}
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
*
|
|
2264
|
-
* Note: Two paths of unequal length can still receive a `0` result if one is
|
|
2265
|
-
* directly above or below the other. If you want exact matching, use
|
|
2266
|
-
* [[Path.equals]] instead.
|
|
2267
|
-
*/
|
|
2268
|
-
compare(path, another) {
|
|
2269
|
-
const min = Math.min(path.length, another.length);
|
|
2270
|
-
for (let i = 0; i < min; i++) {
|
|
2271
|
-
if (path[i] < another[i])
|
|
2272
|
-
return -1;
|
|
2273
|
-
if (path[i] > another[i])
|
|
2274
|
-
return 1;
|
|
2396
|
+
});
|
|
2397
|
+
if (pendingElements.length) {
|
|
2398
|
+
newElements.push(...pendingElements);
|
|
2399
|
+
}
|
|
2400
|
+
cacheSelectedElements(board, uniqueById(newElements));
|
|
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);
|
|
2275
2408
|
}
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
equals(path, another) {
|
|
2282
|
-
return path.length === another.length && path.every((n, i) => n === another[i]);
|
|
2283
|
-
},
|
|
2284
|
-
/**
|
|
2285
|
-
* Check if a path ends before one of the indexes in another.
|
|
2286
|
-
*/
|
|
2287
|
-
endsBefore(path, another) {
|
|
2288
|
-
const i = path.length - 1;
|
|
2289
|
-
const as = path.slice(0, i);
|
|
2290
|
-
const bs = another.slice(0, i);
|
|
2291
|
-
const av = path[i];
|
|
2292
|
-
const bv = another[i];
|
|
2293
|
-
return Path.equals(as, bs) && av < bv;
|
|
2294
|
-
},
|
|
2295
|
-
/**
|
|
2296
|
-
* Check if a path is a sibling of another.
|
|
2297
|
-
*/
|
|
2298
|
-
isSibling(path, another) {
|
|
2299
|
-
if (path.length !== another.length) {
|
|
2300
|
-
return false;
|
|
2409
|
+
}
|
|
2410
|
+
else {
|
|
2411
|
+
const elementsInGroup = getAllElementsInGroup(board, hitElementGroups[hitElementGroups.length - 1], true);
|
|
2412
|
+
if (!isSelectGroupElement) {
|
|
2413
|
+
newElements = elementsInGroup;
|
|
2301
2414
|
}
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
if (
|
|
2312
|
-
|
|
2415
|
+
}
|
|
2416
|
+
cacheSelectedElements(board, uniqueById(newElements));
|
|
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));
|
|
2313
2429
|
}
|
|
2314
|
-
|
|
2315
|
-
|
|
2430
|
+
else {
|
|
2431
|
+
result.push(item);
|
|
2316
2432
|
}
|
|
2317
|
-
switch (operation.type) {
|
|
2318
|
-
case 'insert_node': {
|
|
2319
|
-
const { path: op } = operation;
|
|
2320
|
-
if (Path.equals(op, p) || Path.endsBefore(op, p) || Path.isAncestor(op, p)) {
|
|
2321
|
-
p[op.length - 1] += 1;
|
|
2322
|
-
}
|
|
2323
|
-
break;
|
|
2324
|
-
}
|
|
2325
|
-
case 'remove_node': {
|
|
2326
|
-
const { path: op } = operation;
|
|
2327
|
-
if (Path.equals(op, p) || Path.isAncestor(op, p)) {
|
|
2328
|
-
return null;
|
|
2329
|
-
}
|
|
2330
|
-
else if (Path.endsBefore(op, p)) {
|
|
2331
|
-
p[op.length - 1] -= 1;
|
|
2332
|
-
}
|
|
2333
|
-
break;
|
|
2334
|
-
}
|
|
2335
|
-
case 'move_node': {
|
|
2336
|
-
const { path: op, newPath: onp } = operation;
|
|
2337
|
-
// If the old and new path are the same, it's a no-op.
|
|
2338
|
-
if (Path.equals(op, onp)) {
|
|
2339
|
-
return;
|
|
2340
|
-
}
|
|
2341
|
-
if (Path.isAncestor(op, p) || Path.equals(op, p)) {
|
|
2342
|
-
const copy = onp.slice();
|
|
2343
|
-
// op.length <= onp.length is different for slate
|
|
2344
|
-
// resolve drag from [0, 0] to [0, 3] issue
|
|
2345
|
-
if (Path.endsBefore(op, onp) && op.length <= onp.length) {
|
|
2346
|
-
copy[op.length - 1] -= 1;
|
|
2347
|
-
}
|
|
2348
|
-
return copy.concat(p.slice(op.length));
|
|
2349
|
-
}
|
|
2350
|
-
else if (Path.isSibling(op, onp) && (Path.isAncestor(onp, p) || Path.equals(onp, p))) {
|
|
2351
|
-
if (Path.endsBefore(op, p)) {
|
|
2352
|
-
p[op.length - 1] -= 1;
|
|
2353
|
-
}
|
|
2354
|
-
else {
|
|
2355
|
-
p[op.length - 1] += 1;
|
|
2356
|
-
}
|
|
2357
|
-
}
|
|
2358
|
-
else if (Path.endsBefore(onp, p) || Path.equals(onp, p) || Path.isAncestor(onp, p)) {
|
|
2359
|
-
if (Path.endsBefore(op, p)) {
|
|
2360
|
-
p[op.length - 1] -= 1;
|
|
2361
|
-
}
|
|
2362
|
-
p[onp.length - 1] += 1;
|
|
2363
|
-
}
|
|
2364
|
-
else if (Path.endsBefore(op, p)) {
|
|
2365
|
-
if (Path.equals(onp, p)) {
|
|
2366
|
-
p[onp.length - 1] += 1;
|
|
2367
|
-
}
|
|
2368
|
-
p[op.length - 1] -= 1;
|
|
2369
|
-
}
|
|
2370
|
-
break;
|
|
2371
|
-
}
|
|
2372
|
-
}
|
|
2373
|
-
return p;
|
|
2374
2433
|
});
|
|
2375
2434
|
}
|
|
2435
|
+
else {
|
|
2436
|
+
result = includeGroup ? elements : elements.filter(item => !PlaitGroupElement.isGroup(item));
|
|
2437
|
+
}
|
|
2438
|
+
return result;
|
|
2376
2439
|
};
|
|
2377
|
-
|
|
2378
|
-
const
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
}
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
throw new Error(`Cannot find a descendant at path [${path}]`);
|
|
2402
|
-
}
|
|
2403
|
-
node = node.children[p];
|
|
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);
|
|
2404
2464
|
}
|
|
2405
|
-
return
|
|
2406
|
-
}
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
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);
|
|
2412
2504
|
}
|
|
2413
|
-
|
|
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];
|
|
2414
2523
|
}
|
|
2524
|
+
return null;
|
|
2415
2525
|
};
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
const
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
throw new Error(`Cannot apply an "insert_node" operation at path [${path}] because the destination is past the end of the node.`);
|
|
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);
|
|
2425
2534
|
}
|
|
2426
|
-
parent.children.splice(index, 0, node);
|
|
2427
|
-
break;
|
|
2428
2535
|
}
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
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);
|
|
2438
2547
|
}
|
|
2439
|
-
|
|
2440
|
-
const
|
|
2441
|
-
if (
|
|
2442
|
-
|
|
2548
|
+
else {
|
|
2549
|
+
const group = getHighestSelectedGroup(board, item, elements);
|
|
2550
|
+
if (!group) {
|
|
2551
|
+
result.push(item);
|
|
2443
2552
|
}
|
|
2444
|
-
const node = PlaitNode.get(board, path);
|
|
2445
|
-
const parent = PlaitNode.parent(board, path);
|
|
2446
|
-
const index = path[path.length - 1];
|
|
2447
|
-
// This is tricky, but since the `path` and `newPath` both refer to
|
|
2448
|
-
// the same snapshot in time, there's a mismatch. After either
|
|
2449
|
-
// removing the original position, the second step's path can be out
|
|
2450
|
-
// of date. So instead of using the `op.newPath` directly, we
|
|
2451
|
-
// transform `op.path` to ascertain what the `newPath` would be after
|
|
2452
|
-
// the operation was applied.
|
|
2453
|
-
parent.children?.splice(index, 1);
|
|
2454
|
-
const truePath = Path.transform(path, op);
|
|
2455
|
-
const newParent = PlaitNode.get(board, Path.parent(truePath));
|
|
2456
|
-
const newIndex = truePath[truePath.length - 1];
|
|
2457
|
-
newParent.children?.splice(newIndex, 0, node);
|
|
2458
|
-
break;
|
|
2459
2553
|
}
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
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
|
+
}));
|
|
2482
2578
|
}
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
}
|
|
2493
|
-
viewport = { ...newProperties };
|
|
2494
|
-
}
|
|
2495
|
-
for (const key in newProperties) {
|
|
2496
|
-
const value = newProperties[key];
|
|
2497
|
-
if (value == null) {
|
|
2498
|
-
delete viewport[key];
|
|
2499
|
-
}
|
|
2500
|
-
else {
|
|
2501
|
-
viewport[key] = value;
|
|
2502
|
-
}
|
|
2503
|
-
}
|
|
2504
|
-
}
|
|
2505
|
-
break;
|
|
2579
|
+
});
|
|
2580
|
+
return groupRectangleG;
|
|
2581
|
+
};
|
|
2582
|
+
const createGroup = (groupId) => {
|
|
2583
|
+
return groupId
|
|
2584
|
+
? {
|
|
2585
|
+
id: idCreator(),
|
|
2586
|
+
type: 'group',
|
|
2587
|
+
groupId
|
|
2506
2588
|
}
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
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;
|
|
2521
2619
|
}
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
theme = newProperties;
|
|
2525
|
-
break;
|
|
2620
|
+
else {
|
|
2621
|
+
return false;
|
|
2526
2622
|
}
|
|
2623
|
+
},
|
|
2624
|
+
getComponent(value) {
|
|
2625
|
+
return ELEMENT_TO_COMPONENT.get(value);
|
|
2527
2626
|
}
|
|
2528
|
-
return { selection, viewport, theme };
|
|
2529
2627
|
};
|
|
2530
|
-
|
|
2628
|
+
|
|
2629
|
+
const Path = {
|
|
2531
2630
|
/**
|
|
2532
|
-
*
|
|
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.
|
|
2533
2635
|
*/
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
let
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
try {
|
|
2540
|
-
const state = applyToDraft(board, selection, viewport, theme, op);
|
|
2541
|
-
viewport = state.viewport;
|
|
2542
|
-
selection = state.selection;
|
|
2543
|
-
theme = state.theme;
|
|
2636
|
+
ancestors(path, options = {}) {
|
|
2637
|
+
const { reverse = false } = options;
|
|
2638
|
+
let paths = Path.levels(path, options);
|
|
2639
|
+
if (reverse) {
|
|
2640
|
+
paths = paths.slice(1);
|
|
2544
2641
|
}
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
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.`);
|
|
2684
|
+
}
|
|
2685
|
+
const last = path[path.length - 1];
|
|
2686
|
+
return path.slice(0, -1).concat(last - 1);
|
|
2687
|
+
},
|
|
2688
|
+
/**
|
|
2689
|
+
* Check if a path is an ancestor of another.
|
|
2690
|
+
*/
|
|
2691
|
+
isAncestor(path, another) {
|
|
2692
|
+
return path.length < another.length && Path.compare(path, another) === 0;
|
|
2693
|
+
},
|
|
2694
|
+
/**
|
|
2695
|
+
* Compare a path to another, returning an integer indicating whether the path
|
|
2696
|
+
* was before, at, or after the other.
|
|
2697
|
+
*
|
|
2698
|
+
* Note: Two paths of unequal length can still receive a `0` result if one is
|
|
2699
|
+
* directly above or below the other. If you want exact matching, use
|
|
2700
|
+
* [[Path.equals]] instead.
|
|
2701
|
+
*/
|
|
2702
|
+
compare(path, another) {
|
|
2703
|
+
const min = Math.min(path.length, another.length);
|
|
2704
|
+
for (let i = 0; i < min; i++) {
|
|
2705
|
+
if (path[i] < another[i])
|
|
2706
|
+
return -1;
|
|
2707
|
+
if (path[i] > another[i])
|
|
2708
|
+
return 1;
|
|
2709
|
+
}
|
|
2710
|
+
return 0;
|
|
2711
|
+
},
|
|
2712
|
+
/**
|
|
2713
|
+
* Check if a path is exactly equal to another.
|
|
2714
|
+
*/
|
|
2715
|
+
equals(path, another) {
|
|
2716
|
+
return path.length === another.length && path.every((n, i) => n === another[i]);
|
|
2717
|
+
},
|
|
2718
|
+
/**
|
|
2719
|
+
* Check if a path ends before one of the indexes in another.
|
|
2720
|
+
*/
|
|
2721
|
+
endsBefore(path, another) {
|
|
2722
|
+
const i = path.length - 1;
|
|
2723
|
+
const as = path.slice(0, i);
|
|
2724
|
+
const bs = another.slice(0, i);
|
|
2725
|
+
const av = path[i];
|
|
2726
|
+
const bv = another[i];
|
|
2727
|
+
return Path.equals(as, bs) && av < bv;
|
|
2728
|
+
},
|
|
2729
|
+
/**
|
|
2730
|
+
* Check if a path is a sibling of another.
|
|
2731
|
+
*/
|
|
2732
|
+
isSibling(path, another) {
|
|
2733
|
+
if (path.length !== another.length) {
|
|
2734
|
+
return false;
|
|
2735
|
+
}
|
|
2736
|
+
const as = path.slice(0, -1);
|
|
2737
|
+
const bs = another.slice(0, -1);
|
|
2738
|
+
const al = path[path.length - 1];
|
|
2739
|
+
const bl = another[another.length - 1];
|
|
2740
|
+
return al !== bl && Path.equals(as, bs);
|
|
2741
|
+
},
|
|
2742
|
+
transform(path, operation) {
|
|
2743
|
+
return produce(path, p => {
|
|
2744
|
+
// PERF: Exit early if the operation is guaranteed not to have an effect.
|
|
2745
|
+
if (!path || path?.length === 0) {
|
|
2746
|
+
return;
|
|
2549
2747
|
}
|
|
2550
|
-
|
|
2551
|
-
|
|
2748
|
+
if (p === null) {
|
|
2749
|
+
return null;
|
|
2552
2750
|
}
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
}
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2751
|
+
switch (operation.type) {
|
|
2752
|
+
case 'insert_node': {
|
|
2753
|
+
const { path: op } = operation;
|
|
2754
|
+
if (Path.equals(op, p) || Path.endsBefore(op, p) || Path.isAncestor(op, p)) {
|
|
2755
|
+
p[op.length - 1] += 1;
|
|
2756
|
+
}
|
|
2757
|
+
break;
|
|
2758
|
+
}
|
|
2759
|
+
case 'remove_node': {
|
|
2760
|
+
const { path: op } = operation;
|
|
2761
|
+
if (Path.equals(op, p) || Path.isAncestor(op, p)) {
|
|
2762
|
+
return null;
|
|
2763
|
+
}
|
|
2764
|
+
else if (Path.endsBefore(op, p)) {
|
|
2765
|
+
p[op.length - 1] -= 1;
|
|
2766
|
+
}
|
|
2767
|
+
break;
|
|
2768
|
+
}
|
|
2769
|
+
case 'move_node': {
|
|
2770
|
+
const { path: op, newPath: onp } = operation;
|
|
2771
|
+
// If the old and new path are the same, it's a no-op.
|
|
2772
|
+
if (Path.equals(op, onp)) {
|
|
2773
|
+
return;
|
|
2774
|
+
}
|
|
2775
|
+
if (Path.isAncestor(op, p) || Path.equals(op, p)) {
|
|
2776
|
+
const copy = onp.slice();
|
|
2777
|
+
// op.length <= onp.length is different for slate
|
|
2778
|
+
// resolve drag from [0, 0] to [0, 3] issue
|
|
2779
|
+
if (Path.endsBefore(op, onp) && op.length <= onp.length) {
|
|
2780
|
+
copy[op.length - 1] -= 1;
|
|
2781
|
+
}
|
|
2782
|
+
return copy.concat(p.slice(op.length));
|
|
2783
|
+
}
|
|
2784
|
+
else if (Path.isSibling(op, onp) && (Path.isAncestor(onp, p) || Path.equals(onp, p))) {
|
|
2785
|
+
if (Path.endsBefore(op, p)) {
|
|
2786
|
+
p[op.length - 1] -= 1;
|
|
2787
|
+
}
|
|
2788
|
+
else {
|
|
2789
|
+
p[op.length - 1] += 1;
|
|
2790
|
+
}
|
|
2791
|
+
}
|
|
2792
|
+
else if (Path.endsBefore(onp, p) || Path.equals(onp, p) || Path.isAncestor(onp, p)) {
|
|
2793
|
+
if (Path.endsBefore(op, p)) {
|
|
2794
|
+
p[op.length - 1] -= 1;
|
|
2795
|
+
}
|
|
2796
|
+
p[onp.length - 1] += 1;
|
|
2797
|
+
}
|
|
2798
|
+
else if (Path.endsBefore(op, p)) {
|
|
2799
|
+
if (Path.equals(onp, p)) {
|
|
2800
|
+
p[onp.length - 1] += 1;
|
|
2801
|
+
}
|
|
2802
|
+
p[op.length - 1] -= 1;
|
|
2803
|
+
}
|
|
2804
|
+
break;
|
|
2805
|
+
}
|
|
2571
2806
|
}
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
}
|
|
2575
|
-
}
|
|
2576
|
-
const operation = { type: 'set_node', properties, newProperties, path };
|
|
2577
|
-
board.apply(operation);
|
|
2578
|
-
}
|
|
2579
|
-
function removeNode(board, path) {
|
|
2580
|
-
const node = PlaitNode.get(board, path);
|
|
2581
|
-
const operation = { type: 'remove_node', path, node };
|
|
2582
|
-
board.apply(operation);
|
|
2583
|
-
}
|
|
2584
|
-
function moveNode(board, path, newPath) {
|
|
2585
|
-
const operation = { type: 'move_node', path, newPath };
|
|
2586
|
-
board.apply(operation);
|
|
2587
|
-
}
|
|
2588
|
-
const NodeTransforms = {
|
|
2589
|
-
insertNode,
|
|
2590
|
-
setNode,
|
|
2591
|
-
removeNode,
|
|
2592
|
-
moveNode
|
|
2593
|
-
};
|
|
2594
|
-
|
|
2595
|
-
function setSelection(board, selection) {
|
|
2596
|
-
const operation = { type: 'set_selection', properties: board.selection, newProperties: selection };
|
|
2597
|
-
board.apply(operation);
|
|
2598
|
-
}
|
|
2599
|
-
const SelectionTransforms = {
|
|
2600
|
-
setSelection,
|
|
2601
|
-
addSelectionWithTemporaryElements
|
|
2602
|
-
};
|
|
2603
|
-
function addSelectionWithTemporaryElements(board, elements) {
|
|
2604
|
-
const timeoutId = setTimeout(() => {
|
|
2605
|
-
setSelection(board, { anchor: [0, 0], focus: [0, 0] });
|
|
2606
|
-
}, 0);
|
|
2607
|
-
let ref = getTemporaryRef(board);
|
|
2608
|
-
if (ref) {
|
|
2609
|
-
clearTimeout(ref.timeoutId);
|
|
2610
|
-
const currentElements = ref.elements;
|
|
2611
|
-
ref.elements.push(...elements.filter(element => !currentElements.includes(element)));
|
|
2612
|
-
ref.timeoutId = timeoutId;
|
|
2613
|
-
}
|
|
2614
|
-
else {
|
|
2615
|
-
BOARD_TO_TEMPORARY_ELEMENTS.set(board, { timeoutId, elements });
|
|
2807
|
+
return p;
|
|
2808
|
+
});
|
|
2616
2809
|
}
|
|
2617
|
-
}
|
|
2618
|
-
|
|
2619
|
-
const removeElements = (board, elements) => {
|
|
2620
|
-
elements
|
|
2621
|
-
.map(element => {
|
|
2622
|
-
const path = PlaitBoard.findPath(board, element);
|
|
2623
|
-
const ref = board.pathRef(path);
|
|
2624
|
-
return () => {
|
|
2625
|
-
removeNode(board, ref.current);
|
|
2626
|
-
ref.unref();
|
|
2627
|
-
removeSelectedElement(board, element, true);
|
|
2628
|
-
};
|
|
2629
|
-
})
|
|
2630
|
-
.forEach(action => {
|
|
2631
|
-
action();
|
|
2632
|
-
});
|
|
2633
|
-
};
|
|
2634
|
-
const CoreTransforms = {
|
|
2635
|
-
removeElements
|
|
2636
2810
|
};
|
|
2637
2811
|
|
|
2638
|
-
const
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
}
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
}
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
}
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
function getTemporaryRef(board) {
|
|
2675
|
-
return BOARD_TO_TEMPORARY_ELEMENTS.get(board);
|
|
2676
|
-
}
|
|
2677
|
-
function deleteTemporaryElements(board) {
|
|
2678
|
-
BOARD_TO_TEMPORARY_ELEMENTS.delete(board);
|
|
2679
|
-
}
|
|
2680
|
-
function createSelectionRectangleG(board) {
|
|
2681
|
-
const elements = getSelectedElements(board);
|
|
2682
|
-
const rectangle = getRectangleByElements(board, elements, false);
|
|
2683
|
-
if (rectangle.width > 0 && rectangle.height > 0 && elements.length > 1) {
|
|
2684
|
-
const selectionRectangleG = drawRectangle(board, RectangleClient.inflate(rectangle, ACTIVE_STROKE_WIDTH), {
|
|
2685
|
-
stroke: SELECTION_BORDER_COLOR,
|
|
2686
|
-
strokeWidth: ACTIVE_STROKE_WIDTH,
|
|
2687
|
-
fillStyle: 'solid'
|
|
2688
|
-
});
|
|
2689
|
-
selectionRectangleG.classList.add(SELECTION_RECTANGLE_CLASS_NAME);
|
|
2690
|
-
PlaitBoard.getElementActiveHost(board).append(selectionRectangleG);
|
|
2691
|
-
return selectionRectangleG;
|
|
2812
|
+
const PlaitNode = {
|
|
2813
|
+
parent: (board, path) => {
|
|
2814
|
+
const parentPath = Path.parent(path);
|
|
2815
|
+
const p = PlaitNode.get(board, parentPath);
|
|
2816
|
+
return p;
|
|
2817
|
+
},
|
|
2818
|
+
/**
|
|
2819
|
+
* Return a generator of all the ancestor nodes above a specific path.
|
|
2820
|
+
*
|
|
2821
|
+
* By default the order is top-down, from highest to lowest ancestor in
|
|
2822
|
+
* the tree, but you can pass the `reverse: true` option to go bottom-up.
|
|
2823
|
+
*/
|
|
2824
|
+
*parents(root, path, options = {}) {
|
|
2825
|
+
for (const p of Path.ancestors(path, options)) {
|
|
2826
|
+
const n = PlaitNode.get(root, p);
|
|
2827
|
+
yield n;
|
|
2828
|
+
}
|
|
2829
|
+
},
|
|
2830
|
+
get(root, path) {
|
|
2831
|
+
let node = root;
|
|
2832
|
+
for (let i = 0; i < path.length; i++) {
|
|
2833
|
+
const p = path[i];
|
|
2834
|
+
if (!node || !node.children || !node.children[p]) {
|
|
2835
|
+
throw new Error(`Cannot find a descendant at path [${path}]`);
|
|
2836
|
+
}
|
|
2837
|
+
node = node.children[p];
|
|
2838
|
+
}
|
|
2839
|
+
return node;
|
|
2840
|
+
},
|
|
2841
|
+
last(board, path) {
|
|
2842
|
+
let n = PlaitNode.get(board, path);
|
|
2843
|
+
while (n && n.children && n.children.length > 0) {
|
|
2844
|
+
const i = n.children.length - 1;
|
|
2845
|
+
n = n.children[i];
|
|
2846
|
+
}
|
|
2847
|
+
return n;
|
|
2692
2848
|
}
|
|
2693
|
-
|
|
2694
|
-
}
|
|
2849
|
+
};
|
|
2695
2850
|
|
|
2696
|
-
const
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2851
|
+
const isSetViewportOperation = (value) => {
|
|
2852
|
+
return value.type === 'set_viewport';
|
|
2853
|
+
};
|
|
2854
|
+
const inverse = (op) => {
|
|
2855
|
+
switch (op.type) {
|
|
2856
|
+
case 'insert_node': {
|
|
2857
|
+
return { ...op, type: 'remove_node' };
|
|
2858
|
+
}
|
|
2859
|
+
case 'remove_node': {
|
|
2860
|
+
return { ...op, type: 'insert_node' };
|
|
2861
|
+
}
|
|
2862
|
+
case 'move_node': {
|
|
2863
|
+
const { newPath, path } = op;
|
|
2864
|
+
// PERF: in this case the move operation is a no-op anyways.
|
|
2865
|
+
if (Path.equals(newPath, path)) {
|
|
2866
|
+
return op;
|
|
2867
|
+
}
|
|
2868
|
+
// when operation path is [0,0] -> [0,2], should exec Path.transform to get [0,1] -> [0,0]
|
|
2869
|
+
// shoud not return [0,2] -> [0,0] #WIK-8981
|
|
2870
|
+
// if (Path.isSibling(path, newPath)) {
|
|
2871
|
+
// return { ...op, path: newPath, newPath: path };
|
|
2872
|
+
// }
|
|
2873
|
+
// If the move does not happen within a single parent it is possible
|
|
2874
|
+
// for the move to impact the true path to the location where the node
|
|
2875
|
+
// was removed from and where it was inserted. We have to adjust for this
|
|
2876
|
+
// and find the original path. We can accomplish this (only in non-sibling)
|
|
2877
|
+
// moves by looking at the impact of the move operation on the node
|
|
2878
|
+
// after the original move path.
|
|
2879
|
+
const inversePath = Path.transform(path, op);
|
|
2880
|
+
const inverseNewPath = Path.transform(Path.next(path), op);
|
|
2881
|
+
return { ...op, path: inversePath, newPath: inverseNewPath };
|
|
2882
|
+
}
|
|
2883
|
+
case 'set_node': {
|
|
2884
|
+
const { properties, newProperties } = op;
|
|
2885
|
+
return { ...op, properties: newProperties, newProperties: properties };
|
|
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
|
+
};
|
|
2895
|
+
}
|
|
2896
|
+
else if (newProperties == null) {
|
|
2897
|
+
return {
|
|
2898
|
+
...op,
|
|
2899
|
+
properties: null,
|
|
2900
|
+
newProperties: properties
|
|
2901
|
+
};
|
|
2706
2902
|
}
|
|
2707
2903
|
else {
|
|
2708
|
-
|
|
2904
|
+
return { ...op, properties: newProperties, newProperties: properties };
|
|
2709
2905
|
}
|
|
2710
|
-
}
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2906
|
+
}
|
|
2907
|
+
case 'set_viewport': {
|
|
2908
|
+
const { properties, newProperties } = op;
|
|
2909
|
+
if (properties == null) {
|
|
2910
|
+
return {
|
|
2911
|
+
...op,
|
|
2912
|
+
properties: newProperties,
|
|
2913
|
+
newProperties: newProperties
|
|
2914
|
+
};
|
|
2915
|
+
}
|
|
2916
|
+
else if (newProperties == null) {
|
|
2917
|
+
return {
|
|
2918
|
+
...op,
|
|
2919
|
+
properties: properties,
|
|
2920
|
+
newProperties: properties
|
|
2921
|
+
};
|
|
2922
|
+
}
|
|
2923
|
+
else {
|
|
2924
|
+
return { ...op, properties: newProperties, newProperties: properties };
|
|
2925
|
+
}
|
|
2926
|
+
}
|
|
2927
|
+
case 'set_theme': {
|
|
2928
|
+
const { properties, newProperties } = op;
|
|
2929
|
+
return { ...op, properties: newProperties, newProperties: properties };
|
|
2930
|
+
}
|
|
2714
2931
|
}
|
|
2715
|
-
return result;
|
|
2716
2932
|
};
|
|
2717
|
-
const
|
|
2718
|
-
|
|
2719
|
-
|
|
2933
|
+
const PlaitOperation = {
|
|
2934
|
+
isSetViewportOperation,
|
|
2935
|
+
inverse
|
|
2720
2936
|
};
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
return
|
|
2725
|
-
}
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2937
|
+
|
|
2938
|
+
const Point = {
|
|
2939
|
+
isEquals(point, otherPoint) {
|
|
2940
|
+
return point && otherPoint && point[0] === otherPoint[0] && point[1] === otherPoint[1];
|
|
2941
|
+
},
|
|
2942
|
+
isHorizontal(point, otherPoint, tolerance = 0) {
|
|
2943
|
+
return point && otherPoint && Point.isOverHorizontal([point, otherPoint], tolerance);
|
|
2944
|
+
},
|
|
2945
|
+
isOverHorizontal(points, tolerance = 0) {
|
|
2946
|
+
return points.every(point => Math.abs(point[1] - points[0][1]) <= tolerance);
|
|
2947
|
+
},
|
|
2948
|
+
isVertical(point, otherPoint, tolerance = 0) {
|
|
2949
|
+
return point && otherPoint && Point.isOverVertical([point, otherPoint], tolerance);
|
|
2950
|
+
},
|
|
2951
|
+
isOverVertical(points, tolerance = 0) {
|
|
2952
|
+
return points.every(point => Math.abs(point[0] - points[0][0]) <= tolerance);
|
|
2953
|
+
},
|
|
2954
|
+
isAlign(points, tolerance = 0) {
|
|
2955
|
+
return Point.isOverHorizontal(points, tolerance) || Point.isOverVertical(points, tolerance);
|
|
2956
|
+
},
|
|
2957
|
+
getOffsetX(point1, point2) {
|
|
2958
|
+
return point2[0] - point1[0];
|
|
2959
|
+
},
|
|
2960
|
+
getOffsetY(point1, point2) {
|
|
2961
|
+
return point2[1] - point1[1];
|
|
2736
2962
|
}
|
|
2737
2963
|
};
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
return
|
|
2964
|
+
|
|
2965
|
+
const Viewport = {
|
|
2966
|
+
isViewport: (value) => {
|
|
2967
|
+
return !isNullOrUndefined(value.zoom) && !isNullOrUndefined(value.viewBackgroundColor);
|
|
2742
2968
|
}
|
|
2743
|
-
return null;
|
|
2744
2969
|
};
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2970
|
+
|
|
2971
|
+
const SAVING = new WeakMap();
|
|
2972
|
+
const MERGING = new WeakMap();
|
|
2973
|
+
|
|
2974
|
+
var ThemeColorMode;
|
|
2975
|
+
(function (ThemeColorMode) {
|
|
2976
|
+
ThemeColorMode["default"] = "default";
|
|
2977
|
+
ThemeColorMode["colorful"] = "colorful";
|
|
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'
|
|
2753
2987
|
};
|
|
2754
|
-
const
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
}
|
|
2759
|
-
return selectedElements.includes(element);
|
|
2988
|
+
const ColorfulThemeColor = {
|
|
2989
|
+
mode: ThemeColorMode.colorful,
|
|
2990
|
+
boardBackground: '#ffffff',
|
|
2991
|
+
textColor: '#333333'
|
|
2760
2992
|
};
|
|
2761
|
-
const
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2993
|
+
const SoftThemeColor = {
|
|
2994
|
+
mode: ThemeColorMode.soft,
|
|
2995
|
+
boardBackground: '#f5f5f5',
|
|
2996
|
+
textColor: '#333333'
|
|
2765
2997
|
};
|
|
2766
|
-
const
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
selectedGroups.push(item);
|
|
2771
|
-
}
|
|
2772
|
-
});
|
|
2773
|
-
return selectedGroups;
|
|
2998
|
+
const RetroThemeColor = {
|
|
2999
|
+
mode: ThemeColorMode.retro,
|
|
3000
|
+
boardBackground: '#f9f8ed',
|
|
3001
|
+
textColor: '#333333'
|
|
2774
3002
|
};
|
|
2775
|
-
const
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
return selectedGroups[selectedGroups.length - 1];
|
|
2780
|
-
}
|
|
2781
|
-
return null;
|
|
3003
|
+
const DarkThemeColor = {
|
|
3004
|
+
mode: ThemeColorMode.dark,
|
|
3005
|
+
boardBackground: '#141414',
|
|
3006
|
+
textColor: '#FFFFFF'
|
|
2782
3007
|
};
|
|
2783
|
-
const
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
if (item.groupId) {
|
|
2788
|
-
const group = getHighestSelectedGroup(board, item);
|
|
2789
|
-
if (group && !result.includes(group)) {
|
|
2790
|
-
result.push(group);
|
|
2791
|
-
}
|
|
2792
|
-
}
|
|
2793
|
-
});
|
|
2794
|
-
return result;
|
|
3008
|
+
const StarryThemeColor = {
|
|
3009
|
+
mode: ThemeColorMode.starry,
|
|
3010
|
+
boardBackground: '#0d2537',
|
|
3011
|
+
textColor: '#FFFFFF'
|
|
2795
3012
|
};
|
|
2796
|
-
const
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
3013
|
+
const ThemeColors = [
|
|
3014
|
+
DefaultThemeColor,
|
|
3015
|
+
ColorfulThemeColor,
|
|
3016
|
+
SoftThemeColor,
|
|
3017
|
+
RetroThemeColor,
|
|
3018
|
+
DarkThemeColor,
|
|
3019
|
+
StarryThemeColor
|
|
3020
|
+
];
|
|
3021
|
+
|
|
3022
|
+
var Direction;
|
|
3023
|
+
(function (Direction) {
|
|
3024
|
+
Direction["left"] = "left";
|
|
3025
|
+
Direction["top"] = "top";
|
|
3026
|
+
Direction["right"] = "right";
|
|
3027
|
+
Direction["bottom"] = "bottom";
|
|
3028
|
+
})(Direction || (Direction = {}));
|
|
3029
|
+
|
|
3030
|
+
const PlaitGroupElement = {
|
|
3031
|
+
isGroup: (value) => {
|
|
3032
|
+
return value.type === 'group';
|
|
3033
|
+
}
|
|
3034
|
+
};
|
|
3035
|
+
|
|
3036
|
+
function getRectangleByElements(board, elements, recursion) {
|
|
3037
|
+
const rectanglesCornerPoints = [];
|
|
3038
|
+
const callback = (node) => {
|
|
3039
|
+
const nodeRectangle = board.getRectangle(node);
|
|
3040
|
+
if (nodeRectangle) {
|
|
3041
|
+
const cornerPoints = RectangleClient.getCornerPoints(nodeRectangle);
|
|
3042
|
+
const rotatedCornerPoints = rotatePoints(cornerPoints, RectangleClient.getCenterPoint(nodeRectangle), node.angle || 0);
|
|
3043
|
+
rectanglesCornerPoints.push(rotatedCornerPoints);
|
|
2802
3044
|
}
|
|
2803
3045
|
else {
|
|
2804
|
-
|
|
2805
|
-
if (!group) {
|
|
2806
|
-
result.push(item);
|
|
2807
|
-
}
|
|
3046
|
+
console.error(`can not get rectangle of element:`, node);
|
|
2808
3047
|
}
|
|
2809
|
-
}
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
const selectedElements = getSelectedElements(board);
|
|
2817
|
-
const groupRectangleG = createG();
|
|
2818
|
-
const isMoving = isSelectionMoving(board);
|
|
2819
|
-
elements.forEach(item => {
|
|
2820
|
-
const isRender = (!selectedElements.includes(item) && !isMoving) || isMoving;
|
|
2821
|
-
if (item.groupId && isRender) {
|
|
2822
|
-
const elements = getElementsInGroupByElement(board, item);
|
|
2823
|
-
const rectangle = getRectangleByElements(board, elements, false);
|
|
2824
|
-
groupRectangleG.append(drawRectangle(board, rectangle, {
|
|
2825
|
-
stroke: SELECTION_BORDER_COLOR,
|
|
2826
|
-
strokeWidth: ACTIVE_STROKE_WIDTH,
|
|
2827
|
-
strokeLineDash: [5]
|
|
2828
|
-
}));
|
|
3048
|
+
};
|
|
3049
|
+
elements.forEach(element => {
|
|
3050
|
+
if (recursion) {
|
|
3051
|
+
depthFirstRecursion(element, node => callback(node), node => board.isRecursion(node));
|
|
3052
|
+
}
|
|
3053
|
+
else {
|
|
3054
|
+
callback(element);
|
|
2829
3055
|
}
|
|
2830
3056
|
});
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
const
|
|
2834
|
-
|
|
2835
|
-
id: idCreator(),
|
|
2836
|
-
type: 'group'
|
|
2837
|
-
};
|
|
2838
|
-
};
|
|
2839
|
-
const nonGroupInHighestSelectedElements = (elements) => {
|
|
2840
|
-
return elements.every(item => !item.groupId);
|
|
2841
|
-
};
|
|
2842
|
-
const hasSelectedElementsInSameGroup = (elements) => {
|
|
2843
|
-
return elements.every(item => item.groupId && item.groupId === elements[0].groupId);
|
|
2844
|
-
};
|
|
2845
|
-
const canAddGroup = (highestSelectedElements) => {
|
|
2846
|
-
if (highestSelectedElements.length > 1) {
|
|
2847
|
-
return nonGroupInHighestSelectedElements(highestSelectedElements) || hasSelectedElementsInSameGroup(highestSelectedElements);
|
|
2848
|
-
}
|
|
2849
|
-
return false;
|
|
2850
|
-
};
|
|
2851
|
-
const addGroup = (board) => {
|
|
2852
|
-
const selectedGroups = getHighestSelectedGroups(board);
|
|
2853
|
-
const selectedIsolatedElements = getSelectedIsolatedElements(board);
|
|
2854
|
-
const highestSelectedElements = [...selectedGroups, ...selectedIsolatedElements];
|
|
2855
|
-
const group = createGroup();
|
|
2856
|
-
if (canAddGroup(highestSelectedElements)) {
|
|
2857
|
-
highestSelectedElements.forEach(item => {
|
|
2858
|
-
const path = PlaitBoard.findPath(board, item);
|
|
2859
|
-
Transforms.setNode(board, { groupId: group.id }, path);
|
|
2860
|
-
});
|
|
2861
|
-
if (hasSelectedElementsInSameGroup(highestSelectedElements)) {
|
|
2862
|
-
const newGroupId = selectedIsolatedElements[0].groupId;
|
|
2863
|
-
Transforms.insertNode(board, {
|
|
2864
|
-
...group,
|
|
2865
|
-
groupId: newGroupId
|
|
2866
|
-
}, [board.children.length]);
|
|
3057
|
+
if (rectanglesCornerPoints.length > 0) {
|
|
3058
|
+
if (hasSameAngle(elements)) {
|
|
3059
|
+
const angle = getSelectionAngle(elements);
|
|
3060
|
+
return getRotatedBoundingRectangle(rectanglesCornerPoints, angle);
|
|
2867
3061
|
}
|
|
2868
3062
|
else {
|
|
2869
|
-
|
|
3063
|
+
const flatCornerPoints = rectanglesCornerPoints.reduce((acc, val) => {
|
|
3064
|
+
return acc.concat(val);
|
|
3065
|
+
}, []);
|
|
3066
|
+
return RectangleClient.getRectangleByPoints(flatCornerPoints);
|
|
2870
3067
|
}
|
|
2871
3068
|
}
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
if (canRemoveGroup(board, selectedGroups)) {
|
|
2880
|
-
selectedGroups.map(group => {
|
|
2881
|
-
const elementsInGroup = findElements(board, {
|
|
2882
|
-
match: item => item.groupId === group.id,
|
|
2883
|
-
recursion: () => false
|
|
2884
|
-
});
|
|
2885
|
-
elementsInGroup.forEach(item => {
|
|
2886
|
-
const path = PlaitBoard.findPath(board, item);
|
|
2887
|
-
Transforms.setNode(board, { groupId: group.groupId || undefined }, path);
|
|
2888
|
-
});
|
|
2889
|
-
const groupPath = PlaitBoard.findPath(board, group);
|
|
2890
|
-
Transforms.removeNode(board, groupPath);
|
|
2891
|
-
});
|
|
3069
|
+
else {
|
|
3070
|
+
return {
|
|
3071
|
+
x: 0,
|
|
3072
|
+
y: 0,
|
|
3073
|
+
width: 0,
|
|
3074
|
+
height: 0
|
|
3075
|
+
};
|
|
2892
3076
|
}
|
|
2893
|
-
}
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
3077
|
+
}
|
|
3078
|
+
function getBoardRectangle(board) {
|
|
3079
|
+
return getRectangleByElements(board, board.children, true);
|
|
3080
|
+
}
|
|
3081
|
+
function getElementById(board, id, dataSource) {
|
|
3082
|
+
if (!dataSource) {
|
|
3083
|
+
dataSource = findElements(board, { match: element => true, recursion: element => true });
|
|
3084
|
+
}
|
|
3085
|
+
let element = dataSource.find(element => element.id === id);
|
|
3086
|
+
return element;
|
|
3087
|
+
}
|
|
3088
|
+
function findElements(board, options) {
|
|
3089
|
+
let elements = [];
|
|
3090
|
+
const isReverse = options.isReverse ?? true;
|
|
3091
|
+
depthFirstRecursion(board, node => {
|
|
3092
|
+
if (!PlaitBoard.isBoard(node) && options.match(node)) {
|
|
3093
|
+
elements.push(node);
|
|
3094
|
+
}
|
|
3095
|
+
}, (value) => {
|
|
3096
|
+
if (PlaitBoard.isBoard(value)) {
|
|
2899
3097
|
return true;
|
|
2900
3098
|
}
|
|
2901
3099
|
else {
|
|
2902
|
-
return
|
|
3100
|
+
return getIsRecursionFunc(board)(value) && options.recursion(value);
|
|
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;
|
|
2903
3111
|
}
|
|
3112
|
+
const isBoard = typeof value.onChange === 'function' && typeof value.apply === 'function';
|
|
3113
|
+
IS_BOARD_CACHE.set(value, isBoard);
|
|
3114
|
+
return isBoard;
|
|
2904
3115
|
},
|
|
2905
|
-
|
|
2906
|
-
|
|
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;
|
|
3192
|
+
}
|
|
3193
|
+
return false;
|
|
3194
|
+
},
|
|
3195
|
+
getThemeColors(board) {
|
|
3196
|
+
return (board.options.themeColors || ThemeColors);
|
|
2907
3197
|
}
|
|
2908
3198
|
};
|
|
2909
3199
|
|
|
2910
|
-
const
|
|
2911
|
-
return value.type === 'set_viewport';
|
|
2912
|
-
};
|
|
2913
|
-
const inverse = (op) => {
|
|
3200
|
+
const applyToDraft = (board, selection, viewport, theme, op) => {
|
|
2914
3201
|
switch (op.type) {
|
|
2915
3202
|
case 'insert_node': {
|
|
2916
|
-
|
|
3203
|
+
const { path, node } = op;
|
|
3204
|
+
const parent = PlaitNode.parent(board, path);
|
|
3205
|
+
const index = path[path.length - 1];
|
|
3206
|
+
if (!parent.children || index > parent.children.length) {
|
|
3207
|
+
throw new Error(`Cannot apply an "insert_node" operation at path [${path}] because the destination is past the end of the node.`);
|
|
3208
|
+
}
|
|
3209
|
+
parent.children.splice(index, 0, node);
|
|
3210
|
+
break;
|
|
2917
3211
|
}
|
|
2918
3212
|
case 'remove_node': {
|
|
2919
|
-
|
|
3213
|
+
const { path } = op;
|
|
3214
|
+
const parent = PlaitNode.parent(board, path);
|
|
3215
|
+
const index = path[path.length - 1];
|
|
3216
|
+
if (!parent.children || index > parent.children.length) {
|
|
3217
|
+
throw new Error(`Cannot apply an "insert_node" operation at path [${path}] because the destination is past the end of the node.`);
|
|
3218
|
+
}
|
|
3219
|
+
parent.children.splice(index, 1);
|
|
3220
|
+
break;
|
|
2920
3221
|
}
|
|
2921
3222
|
case 'move_node': {
|
|
2922
|
-
const {
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
return op;
|
|
3223
|
+
const { path, newPath } = op;
|
|
3224
|
+
if (Path.isAncestor(path, newPath)) {
|
|
3225
|
+
throw new Error(`Cannot move a path [${path}] to new path [${newPath}] because the destination is inside itself.`);
|
|
2926
3226
|
}
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
//
|
|
2931
|
-
//
|
|
2932
|
-
//
|
|
2933
|
-
//
|
|
2934
|
-
//
|
|
2935
|
-
//
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
const
|
|
2939
|
-
const
|
|
2940
|
-
|
|
3227
|
+
const node = PlaitNode.get(board, path);
|
|
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;
|
|
2941
3242
|
}
|
|
2942
3243
|
case 'set_node': {
|
|
2943
|
-
const { properties, newProperties } = op;
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
case 'set_selection': {
|
|
2947
|
-
const { properties, newProperties } = op;
|
|
2948
|
-
if (properties == null) {
|
|
2949
|
-
return {
|
|
2950
|
-
...op,
|
|
2951
|
-
properties: newProperties,
|
|
2952
|
-
newProperties: null
|
|
2953
|
-
};
|
|
3244
|
+
const { path, properties, newProperties } = op;
|
|
3245
|
+
if (path.length === 0) {
|
|
3246
|
+
throw new Error(`Cannot set properties on the root node!`);
|
|
2954
3247
|
}
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
}
|
|
3248
|
+
const node = PlaitNode.get(board, path);
|
|
3249
|
+
for (const key in newProperties) {
|
|
3250
|
+
const value = newProperties[key];
|
|
3251
|
+
if (value == null) {
|
|
3252
|
+
delete node[key];
|
|
3253
|
+
}
|
|
3254
|
+
else {
|
|
3255
|
+
node[key] = value;
|
|
3256
|
+
}
|
|
2961
3257
|
}
|
|
2962
|
-
|
|
2963
|
-
|
|
3258
|
+
// properties that were previously defined, but are now missing, must be deleted
|
|
3259
|
+
for (const key in properties) {
|
|
3260
|
+
if (!newProperties.hasOwnProperty(key)) {
|
|
3261
|
+
delete node[key];
|
|
3262
|
+
}
|
|
2964
3263
|
}
|
|
3264
|
+
break;
|
|
2965
3265
|
}
|
|
2966
3266
|
case 'set_viewport': {
|
|
2967
|
-
const {
|
|
2968
|
-
if (
|
|
2969
|
-
|
|
2970
|
-
...op,
|
|
2971
|
-
properties: newProperties,
|
|
2972
|
-
newProperties: newProperties
|
|
2973
|
-
};
|
|
3267
|
+
const { newProperties } = op;
|
|
3268
|
+
if (newProperties == null) {
|
|
3269
|
+
viewport = newProperties;
|
|
2974
3270
|
}
|
|
2975
|
-
else
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
3271
|
+
else {
|
|
3272
|
+
if (viewport == null) {
|
|
3273
|
+
if (!Viewport.isViewport(newProperties)) {
|
|
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
|
+
}
|
|
3287
|
+
}
|
|
3288
|
+
break;
|
|
3289
|
+
}
|
|
3290
|
+
case 'set_selection': {
|
|
3291
|
+
const { newProperties } = op;
|
|
3292
|
+
if (newProperties == null) {
|
|
3293
|
+
selection = newProperties;
|
|
2981
3294
|
}
|
|
2982
3295
|
else {
|
|
2983
|
-
|
|
3296
|
+
if (selection === null) {
|
|
3297
|
+
selection = op.newProperties;
|
|
3298
|
+
}
|
|
3299
|
+
else {
|
|
3300
|
+
selection = newProperties;
|
|
3301
|
+
}
|
|
2984
3302
|
}
|
|
3303
|
+
break;
|
|
2985
3304
|
}
|
|
2986
3305
|
case 'set_theme': {
|
|
2987
|
-
const {
|
|
2988
|
-
|
|
3306
|
+
const { newProperties } = op;
|
|
3307
|
+
theme = newProperties;
|
|
3308
|
+
break;
|
|
2989
3309
|
}
|
|
2990
3310
|
}
|
|
3311
|
+
return { selection, viewport, theme };
|
|
2991
3312
|
};
|
|
2992
|
-
const
|
|
2993
|
-
|
|
2994
|
-
|
|
3313
|
+
const GeneralTransforms = {
|
|
3314
|
+
/**
|
|
3315
|
+
* Transform the board by an operation.
|
|
3316
|
+
*/
|
|
3317
|
+
transform(board, op) {
|
|
3318
|
+
board.children = createDraft(board.children);
|
|
3319
|
+
let viewport = board.viewport && createDraft(board.viewport);
|
|
3320
|
+
let selection = board.selection && createDraft(board.selection);
|
|
3321
|
+
let theme = board.theme && createDraft(board.theme);
|
|
3322
|
+
try {
|
|
3323
|
+
const state = applyToDraft(board, selection, viewport, theme, op);
|
|
3324
|
+
viewport = state.viewport;
|
|
3325
|
+
selection = state.selection;
|
|
3326
|
+
theme = state.theme;
|
|
3327
|
+
}
|
|
3328
|
+
finally {
|
|
3329
|
+
board.children = finishDraft(board.children);
|
|
3330
|
+
if (selection) {
|
|
3331
|
+
board.selection = isDraft(selection) ? finishDraft(selection) : selection;
|
|
3332
|
+
}
|
|
3333
|
+
else {
|
|
3334
|
+
board.selection = null;
|
|
3335
|
+
}
|
|
3336
|
+
board.viewport = isDraft(viewport) ? finishDraft(viewport) : viewport;
|
|
3337
|
+
board.theme = isDraft(theme) ? finishDraft(theme) : theme;
|
|
3338
|
+
}
|
|
3339
|
+
}
|
|
2995
3340
|
};
|
|
2996
3341
|
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
}
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
isAlign(points, tolerance = 0) {
|
|
3014
|
-
return Point.isOverHorizontal(points, tolerance) || Point.isOverVertical(points, tolerance);
|
|
3015
|
-
},
|
|
3016
|
-
getOffsetX(point1, point2) {
|
|
3017
|
-
return point2[0] - point1[0];
|
|
3018
|
-
},
|
|
3019
|
-
getOffsetY(point1, point2) {
|
|
3020
|
-
return point2[1] - point1[1];
|
|
3342
|
+
function insertNode(board, node, path) {
|
|
3343
|
+
const operation = { type: 'insert_node', node, path };
|
|
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];
|
|
3357
|
+
}
|
|
3021
3358
|
}
|
|
3359
|
+
const operation = { type: 'set_node', properties, newProperties, path };
|
|
3360
|
+
board.apply(operation);
|
|
3361
|
+
}
|
|
3362
|
+
function removeNode(board, path) {
|
|
3363
|
+
const node = PlaitNode.get(board, path);
|
|
3364
|
+
const operation = { type: 'remove_node', path, node };
|
|
3365
|
+
board.apply(operation);
|
|
3366
|
+
}
|
|
3367
|
+
function moveNode(board, path, newPath) {
|
|
3368
|
+
const operation = { type: 'move_node', path, newPath };
|
|
3369
|
+
board.apply(operation);
|
|
3370
|
+
}
|
|
3371
|
+
const NodeTransforms = {
|
|
3372
|
+
insertNode,
|
|
3373
|
+
setNode,
|
|
3374
|
+
removeNode,
|
|
3375
|
+
moveNode
|
|
3022
3376
|
};
|
|
3023
3377
|
|
|
3024
|
-
|
|
3025
|
-
const
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
ThemeColorMode["soft"] = "soft";
|
|
3032
|
-
ThemeColorMode["retro"] = "retro";
|
|
3033
|
-
ThemeColorMode["dark"] = "dark";
|
|
3034
|
-
ThemeColorMode["starry"] = "starry";
|
|
3035
|
-
})(ThemeColorMode || (ThemeColorMode = {}));
|
|
3036
|
-
const DefaultThemeColor = {
|
|
3037
|
-
mode: ThemeColorMode.default,
|
|
3038
|
-
boardBackground: '#ffffff',
|
|
3039
|
-
textColor: '#333333'
|
|
3040
|
-
};
|
|
3041
|
-
const ColorfulThemeColor = {
|
|
3042
|
-
mode: ThemeColorMode.colorful,
|
|
3043
|
-
boardBackground: '#ffffff',
|
|
3044
|
-
textColor: '#333333'
|
|
3045
|
-
};
|
|
3046
|
-
const SoftThemeColor = {
|
|
3047
|
-
mode: ThemeColorMode.soft,
|
|
3048
|
-
boardBackground: '#f5f5f5',
|
|
3049
|
-
textColor: '#333333'
|
|
3050
|
-
};
|
|
3051
|
-
const RetroThemeColor = {
|
|
3052
|
-
mode: ThemeColorMode.retro,
|
|
3053
|
-
boardBackground: '#f9f8ed',
|
|
3054
|
-
textColor: '#333333'
|
|
3378
|
+
function setSelection(board, selection) {
|
|
3379
|
+
const operation = { type: 'set_selection', properties: board.selection, newProperties: selection };
|
|
3380
|
+
board.apply(operation);
|
|
3381
|
+
}
|
|
3382
|
+
const SelectionTransforms = {
|
|
3383
|
+
setSelection,
|
|
3384
|
+
addSelectionWithTemporaryElements
|
|
3055
3385
|
};
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
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 });
|
|
3399
|
+
}
|
|
3400
|
+
}
|
|
3401
|
+
|
|
3402
|
+
const removeElements = (board, elements) => {
|
|
3403
|
+
elements
|
|
3404
|
+
.map(element => {
|
|
3405
|
+
const path = PlaitBoard.findPath(board, element);
|
|
3406
|
+
const ref = board.pathRef(path);
|
|
3407
|
+
return () => {
|
|
3408
|
+
removeNode(board, ref.current);
|
|
3409
|
+
ref.unref();
|
|
3410
|
+
removeSelectedElement(board, element, true);
|
|
3411
|
+
};
|
|
3412
|
+
})
|
|
3413
|
+
.forEach(action => {
|
|
3414
|
+
action();
|
|
3415
|
+
});
|
|
3060
3416
|
};
|
|
3061
|
-
const
|
|
3062
|
-
|
|
3063
|
-
boardBackground: '#0d2537',
|
|
3064
|
-
textColor: '#FFFFFF'
|
|
3417
|
+
const CoreTransforms = {
|
|
3418
|
+
removeElements
|
|
3065
3419
|
};
|
|
3066
|
-
const ThemeColors = [
|
|
3067
|
-
DefaultThemeColor,
|
|
3068
|
-
ColorfulThemeColor,
|
|
3069
|
-
SoftThemeColor,
|
|
3070
|
-
RetroThemeColor,
|
|
3071
|
-
DarkThemeColor,
|
|
3072
|
-
StarryThemeColor
|
|
3073
|
-
];
|
|
3074
|
-
|
|
3075
|
-
var Direction;
|
|
3076
|
-
(function (Direction) {
|
|
3077
|
-
Direction["left"] = "left";
|
|
3078
|
-
Direction["top"] = "top";
|
|
3079
|
-
Direction["right"] = "right";
|
|
3080
|
-
Direction["bottom"] = "bottom";
|
|
3081
|
-
})(Direction || (Direction = {}));
|
|
3082
3420
|
|
|
3083
|
-
|
|
3084
|
-
const
|
|
3085
|
-
const
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
}
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
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]);
|
|
3097
3437
|
}
|
|
3098
3438
|
else {
|
|
3099
|
-
|
|
3439
|
+
NodeTransforms.insertNode(board, group, [board.children.length]);
|
|
3100
3440
|
}
|
|
3101
|
-
});
|
|
3102
|
-
if (rectangles.length > 0) {
|
|
3103
|
-
return RectangleClient.getBoundingRectangle(rectangles);
|
|
3104
|
-
}
|
|
3105
|
-
else {
|
|
3106
|
-
return {
|
|
3107
|
-
x: 0,
|
|
3108
|
-
y: 0,
|
|
3109
|
-
width: 0,
|
|
3110
|
-
height: 0
|
|
3111
|
-
};
|
|
3112
3441
|
}
|
|
3113
|
-
}
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
|
|
3442
|
+
};
|
|
3443
|
+
const removeGroup = (board, elements) => {
|
|
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
|
+
});
|
|
3120
3458
|
}
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
const isReverse = options.isReverse ?? true;
|
|
3127
|
-
depthFirstRecursion(board, node => {
|
|
3128
|
-
if (!PlaitBoard.isBoard(node) && options.match(node)) {
|
|
3129
|
-
elements.push(node);
|
|
3130
|
-
}
|
|
3131
|
-
}, (value) => {
|
|
3132
|
-
if (PlaitBoard.isBoard(value)) {
|
|
3133
|
-
return true;
|
|
3134
|
-
}
|
|
3135
|
-
else {
|
|
3136
|
-
return getIsRecursionFunc(board)(value) && options.recursion(value);
|
|
3137
|
-
}
|
|
3138
|
-
}, isReverse);
|
|
3139
|
-
return elements;
|
|
3140
|
-
}
|
|
3459
|
+
};
|
|
3460
|
+
const GroupTransforms = {
|
|
3461
|
+
addGroup,
|
|
3462
|
+
removeGroup
|
|
3463
|
+
};
|
|
3141
3464
|
|
|
3142
|
-
const
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
}
|
|
3148
|
-
const isBoard = typeof value.onChange === 'function' && typeof value.apply === 'function';
|
|
3149
|
-
IS_BOARD_CACHE.set(value, isBoard);
|
|
3150
|
-
return isBoard;
|
|
3151
|
-
},
|
|
3152
|
-
findPath(board, node) {
|
|
3153
|
-
const path = [];
|
|
3154
|
-
let child = node;
|
|
3155
|
-
while (true) {
|
|
3156
|
-
const parent = NODE_TO_PARENT.get(child);
|
|
3157
|
-
if (parent == null) {
|
|
3158
|
-
if (PlaitBoard.isBoard(child)) {
|
|
3159
|
-
return path;
|
|
3160
|
-
}
|
|
3161
|
-
else {
|
|
3162
|
-
break;
|
|
3163
|
-
}
|
|
3164
|
-
}
|
|
3165
|
-
const i = NODE_TO_INDEX.get(child);
|
|
3166
|
-
if (i == null) {
|
|
3167
|
-
break;
|
|
3168
|
-
}
|
|
3169
|
-
path.unshift(i);
|
|
3170
|
-
child = parent;
|
|
3171
|
-
}
|
|
3172
|
-
throw new Error(`Unable to find the path for Plait node: ${JSON.stringify(node)}`);
|
|
3173
|
-
},
|
|
3174
|
-
getHost(board) {
|
|
3175
|
-
return BOARD_TO_HOST.get(board);
|
|
3176
|
-
},
|
|
3177
|
-
getElementHost(board) {
|
|
3178
|
-
return BOARD_TO_ELEMENT_HOST.get(board)?.host;
|
|
3179
|
-
},
|
|
3180
|
-
getElementUpperHost(board) {
|
|
3181
|
-
return BOARD_TO_ELEMENT_HOST.get(board)?.upperHost;
|
|
3182
|
-
},
|
|
3183
|
-
getElementActiveHost(board) {
|
|
3184
|
-
return BOARD_TO_ELEMENT_HOST.get(board)?.activeHost;
|
|
3185
|
-
},
|
|
3186
|
-
getRoughSVG(board) {
|
|
3187
|
-
return BOARD_TO_ROUGH_SVG.get(board);
|
|
3188
|
-
},
|
|
3189
|
-
getComponent(board) {
|
|
3190
|
-
return BOARD_TO_COMPONENT.get(board);
|
|
3191
|
-
},
|
|
3192
|
-
getBoardContainer(board) {
|
|
3193
|
-
return BOARD_TO_ELEMENT_HOST.get(board)?.container;
|
|
3194
|
-
},
|
|
3195
|
-
getRectangle(board) {
|
|
3196
|
-
return getRectangleByElements(board, board.children, true);
|
|
3197
|
-
},
|
|
3198
|
-
getViewportContainer(board) {
|
|
3199
|
-
return BOARD_TO_ELEMENT_HOST.get(board)?.viewportContainer;
|
|
3200
|
-
},
|
|
3201
|
-
isFocus(board) {
|
|
3202
|
-
return !!board.selection;
|
|
3203
|
-
},
|
|
3204
|
-
isReadonly(board) {
|
|
3205
|
-
return board.options.readonly;
|
|
3206
|
-
},
|
|
3207
|
-
hasBeenTextEditing(board) {
|
|
3208
|
-
return !!IS_TEXT_EDITABLE.get(board);
|
|
3209
|
-
},
|
|
3210
|
-
getPointer(board) {
|
|
3211
|
-
return board.pointer;
|
|
3212
|
-
},
|
|
3213
|
-
isPointer(board, pointer) {
|
|
3214
|
-
return board.pointer === pointer;
|
|
3215
|
-
},
|
|
3216
|
-
isInPointer(board, pointers) {
|
|
3217
|
-
const point = board.pointer;
|
|
3218
|
-
return pointers.includes(point);
|
|
3219
|
-
},
|
|
3220
|
-
getMovingPointInBoard(board) {
|
|
3221
|
-
return BOARD_TO_MOVING_POINT_IN_BOARD.get(board);
|
|
3222
|
-
},
|
|
3223
|
-
isMovingPointInBoard(board) {
|
|
3224
|
-
const point = BOARD_TO_MOVING_POINT.get(board);
|
|
3225
|
-
const rect = PlaitBoard.getBoardContainer(board).getBoundingClientRect();
|
|
3226
|
-
if (point && distanceBetweenPointAndRectangle(point[0], point[1], rect) === 0) {
|
|
3227
|
-
return true;
|
|
3228
|
-
}
|
|
3229
|
-
return false;
|
|
3230
|
-
},
|
|
3231
|
-
getThemeColors(board) {
|
|
3232
|
-
return (board.options.themeColors || ThemeColors);
|
|
3233
|
-
}
|
|
3465
|
+
const Transforms = {
|
|
3466
|
+
...GeneralTransforms,
|
|
3467
|
+
...ViewportTransforms$1,
|
|
3468
|
+
...SelectionTransforms,
|
|
3469
|
+
...NodeTransforms
|
|
3234
3470
|
};
|
|
3235
3471
|
|
|
3236
3472
|
const PathRef = {
|
|
@@ -3351,7 +3587,8 @@ function createBoard(children, options) {
|
|
|
3351
3587
|
pointerLeave: pointer => { },
|
|
3352
3588
|
globalPointerMove: pointer => { },
|
|
3353
3589
|
globalPointerUp: pointer => { },
|
|
3354
|
-
isImageBindingAllowed: (element) => false
|
|
3590
|
+
isImageBindingAllowed: (element) => false,
|
|
3591
|
+
canAddToGroup: (element) => true
|
|
3355
3592
|
};
|
|
3356
3593
|
return board;
|
|
3357
3594
|
}
|
|
@@ -3628,112 +3865,46 @@ function withSelection(board) {
|
|
|
3628
3865
|
selectionRectangleG?.remove();
|
|
3629
3866
|
}
|
|
3630
3867
|
const temporaryElements = getTemporaryElements(board);
|
|
3631
|
-
|
|
3632
|
-
|
|
3633
|
-
elements = [elements[0]];
|
|
3868
|
+
if (temporaryElements) {
|
|
3869
|
+
cacheSelectedElements(board, [...temporaryElements]);
|
|
3634
3870
|
}
|
|
3635
|
-
|
|
3636
|
-
|
|
3637
|
-
|
|
3638
|
-
|
|
3639
|
-
|
|
3640
|
-
|
|
3641
|
-
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
const selectedElementsInGroup = elementsInHighestGroup.filter(item => newSelectedElements.includes(item));
|
|
3653
|
-
// When partially selected elements belong to a group,
|
|
3654
|
-
// only select those elements along with the hit elements.
|
|
3655
|
-
if (selectedElementsInGroup.length) {
|
|
3656
|
-
pendingElements.push(...selectedElementsInGroup);
|
|
3871
|
+
else {
|
|
3872
|
+
let elements = getHitElementsBySelection(board);
|
|
3873
|
+
if (!options.isMultiple && elements.length > 1) {
|
|
3874
|
+
elements = [elements[0]];
|
|
3875
|
+
}
|
|
3876
|
+
const isHitElementWithGroup = elements.some(item => item.groupId);
|
|
3877
|
+
const selectedElements = getSelectedElements(board);
|
|
3878
|
+
if (isHitElementWithGroup) {
|
|
3879
|
+
setSelectedElementsWithGroup(board, elements, isShift);
|
|
3880
|
+
}
|
|
3881
|
+
else {
|
|
3882
|
+
if (isShift) {
|
|
3883
|
+
const newElements = [...selectedElements];
|
|
3884
|
+
if (board.selection && Selection.isCollapsed(board.selection)) {
|
|
3885
|
+
elements.forEach(element => {
|
|
3886
|
+
if (newElements.includes(element)) {
|
|
3887
|
+
newElements.splice(newElements.indexOf(element), 1);
|
|
3657
3888
|
}
|
|
3658
3889
|
else {
|
|
3659
|
-
|
|
3890
|
+
newElements.push(element);
|
|
3660
3891
|
}
|
|
3661
|
-
}
|
|
3662
|
-
|
|
3663
|
-
pendingElements = [];
|
|
3664
|
-
}
|
|
3892
|
+
});
|
|
3893
|
+
cacheSelectedElements(board, newElements);
|
|
3665
3894
|
}
|
|
3666
|
-
|
|
3667
|
-
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
}
|
|
3674
|
-
}
|
|
3675
|
-
else {
|
|
3676
|
-
elements.forEach(element => {
|
|
3677
|
-
if (newSelectedElements.includes(element)) {
|
|
3678
|
-
newSelectedElements.splice(newSelectedElements.indexOf(element), 1);
|
|
3679
|
-
}
|
|
3680
|
-
else {
|
|
3681
|
-
newSelectedElements.push(element);
|
|
3682
|
-
}
|
|
3683
|
-
});
|
|
3684
|
-
}
|
|
3685
|
-
cacheSelectedElements(board, newSelectedElements);
|
|
3686
|
-
}
|
|
3687
|
-
else {
|
|
3688
|
-
let newElements = [...elements];
|
|
3689
|
-
if (isHitElementWithGroup) {
|
|
3690
|
-
elements.forEach(item => {
|
|
3691
|
-
if (!item.groupId) {
|
|
3692
|
-
newElements.push(item);
|
|
3693
|
-
}
|
|
3694
|
-
else {
|
|
3695
|
-
newElements.push(...getElementsInGroupByElement(board, item));
|
|
3696
|
-
}
|
|
3697
|
-
});
|
|
3698
|
-
}
|
|
3699
|
-
newElements.forEach(element => {
|
|
3700
|
-
if (!newSelectedElements.includes(element)) {
|
|
3701
|
-
newSelectedElements.push(element);
|
|
3895
|
+
else {
|
|
3896
|
+
elements.forEach(element => {
|
|
3897
|
+
if (!newElements.includes(element)) {
|
|
3898
|
+
newElements.push(element);
|
|
3899
|
+
}
|
|
3900
|
+
});
|
|
3901
|
+
cacheSelectedElements(board, [...newElements]);
|
|
3702
3902
|
}
|
|
3703
|
-
});
|
|
3704
|
-
cacheSelectedElements(board, newSelectedElements);
|
|
3705
|
-
}
|
|
3706
|
-
}
|
|
3707
|
-
else {
|
|
3708
|
-
let newSelectedElements = [...elements];
|
|
3709
|
-
if (isHitElementWithGroup) {
|
|
3710
|
-
const isCollapsed = Selection.isCollapsed(board.selection);
|
|
3711
|
-
if (!isCollapsed) {
|
|
3712
|
-
newSelectedElements = [];
|
|
3713
|
-
elements.forEach(item => {
|
|
3714
|
-
if (!item.groupId) {
|
|
3715
|
-
newSelectedElements.push(item);
|
|
3716
|
-
}
|
|
3717
|
-
else {
|
|
3718
|
-
newSelectedElements.push(...getElementsInGroupByElement(board, item));
|
|
3719
|
-
}
|
|
3720
|
-
});
|
|
3721
3903
|
}
|
|
3722
3904
|
else {
|
|
3723
|
-
|
|
3724
|
-
const groups = getGroupByElement(board, hitElement, true);
|
|
3725
|
-
const selectedGroups = getSelectedGroups(board, groups);
|
|
3726
|
-
if (selectedGroups.length > 0) {
|
|
3727
|
-
if (selectedGroups.length > 1) {
|
|
3728
|
-
newSelectedElements = getElementsInGroup(board, selectedGroups[selectedGroups.length - 2], true);
|
|
3729
|
-
}
|
|
3730
|
-
}
|
|
3731
|
-
else {
|
|
3732
|
-
newSelectedElements = getElementsInGroup(board, groups[groups.length - 1], true);
|
|
3733
|
-
}
|
|
3905
|
+
cacheSelectedElements(board, [...elements]);
|
|
3734
3906
|
}
|
|
3735
3907
|
}
|
|
3736
|
-
cacheSelectedElements(board, newSelectedElements);
|
|
3737
3908
|
}
|
|
3738
3909
|
const newElements = getSelectedElements(board);
|
|
3739
3910
|
previousSelectedElements = newElements;
|
|
@@ -4185,6 +4356,9 @@ function withMoving(board) {
|
|
|
4185
4356
|
let activeElements = [];
|
|
4186
4357
|
let alignG = null;
|
|
4187
4358
|
let activeElementsRectangle = null;
|
|
4359
|
+
let selectedTargetElements = null;
|
|
4360
|
+
let hitTargetElement = undefined;
|
|
4361
|
+
let isHitSelectedTarget = undefined;
|
|
4188
4362
|
board.pointerDown = (event) => {
|
|
4189
4363
|
if (PlaitBoard.isReadonly(board) ||
|
|
4190
4364
|
!PlaitBoard.isPointer(board, PlaitPointerType.selection) ||
|
|
@@ -4194,24 +4368,31 @@ function withMoving(board) {
|
|
|
4194
4368
|
return;
|
|
4195
4369
|
}
|
|
4196
4370
|
const point = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
|
|
4197
|
-
|
|
4198
|
-
|
|
4199
|
-
|
|
4200
|
-
if (
|
|
4371
|
+
hitTargetElement = getHitElementByPoint(board, point, el => board.isMovable(el));
|
|
4372
|
+
selectedTargetElements = getSelectedTargetElements(board);
|
|
4373
|
+
isHitSelectedTarget = hitTargetElement && selectedTargetElements.includes(hitTargetElement);
|
|
4374
|
+
if (hitTargetElement && isHitSelectedTarget) {
|
|
4201
4375
|
startPoint = point;
|
|
4202
|
-
activeElements =
|
|
4376
|
+
activeElements = selectedTargetElements;
|
|
4377
|
+
activeElementsRectangle = getRectangleByElements(board, activeElements, true);
|
|
4203
4378
|
preventTouchMove(board, event, true);
|
|
4379
|
+
}
|
|
4380
|
+
else if (hitTargetElement) {
|
|
4381
|
+
startPoint = point;
|
|
4382
|
+
activeElements = getElementsInGroupByElement(board, hitTargetElement);
|
|
4204
4383
|
activeElementsRectangle = getRectangleByElements(board, activeElements, true);
|
|
4384
|
+
preventTouchMove(board, event, true);
|
|
4205
4385
|
}
|
|
4206
4386
|
else {
|
|
4207
|
-
|
|
4208
|
-
|
|
4387
|
+
// 只有判定用户未击中元素之后才可以验证用户是否击中了已选元素所在的空白区域
|
|
4388
|
+
// Only after it is determined that the user has not hit the element can it be verified whether the user hit the blank area where the selected element is located.
|
|
4389
|
+
const targetRectangle = selectedTargetElements.length > 0 && getRectangleByElements(board, selectedTargetElements, false);
|
|
4390
|
+
const isHitInTargetRectangle = targetRectangle && RectangleClient.isPointInRectangle(targetRectangle, point);
|
|
4391
|
+
if (isHitInTargetRectangle) {
|
|
4209
4392
|
startPoint = point;
|
|
4210
|
-
activeElements =
|
|
4211
|
-
|
|
4212
|
-
|
|
4213
|
-
}
|
|
4214
|
-
activeElementsRectangle = getRectangleByElements(board, activeElements, true);
|
|
4393
|
+
activeElements = selectedTargetElements;
|
|
4394
|
+
activeElementsRectangle = targetRectangle;
|
|
4395
|
+
preventTouchMove(board, event, true);
|
|
4215
4396
|
}
|
|
4216
4397
|
}
|
|
4217
4398
|
pointerDown(event);
|
|
@@ -4227,6 +4408,12 @@ function withMoving(board) {
|
|
|
4227
4408
|
offsetY = endPoint[1] - startPoint[1];
|
|
4228
4409
|
const distance = distanceBetweenPointAndPoint(...endPoint, ...startPoint);
|
|
4229
4410
|
if (distance > PRESS_AND_MOVE_BUFFER || getMovingElements(board).length > 0) {
|
|
4411
|
+
if (hitTargetElement && !isHitSelectedTarget && selectedTargetElements && selectedTargetElements.length > 0) {
|
|
4412
|
+
addSelectionWithTemporaryElements(board, []);
|
|
4413
|
+
hitTargetElement = undefined;
|
|
4414
|
+
selectedTargetElements = null;
|
|
4415
|
+
isHitSelectedTarget = undefined;
|
|
4416
|
+
}
|
|
4230
4417
|
throttleRAF(board, 'with-moving', () => {
|
|
4231
4418
|
if (!activeElementsRectangle) {
|
|
4232
4419
|
return;
|
|
@@ -4267,6 +4454,9 @@ function withMoving(board) {
|
|
|
4267
4454
|
};
|
|
4268
4455
|
board.globalPointerUp = event => {
|
|
4269
4456
|
isPreventDefault = false;
|
|
4457
|
+
hitTargetElement = undefined;
|
|
4458
|
+
selectedTargetElements = null;
|
|
4459
|
+
isHitSelectedTarget = undefined;
|
|
4270
4460
|
if (startPoint) {
|
|
4271
4461
|
cancelMove(board);
|
|
4272
4462
|
}
|
|
@@ -4315,7 +4505,7 @@ function withArrowMoving(board) {
|
|
|
4315
4505
|
break;
|
|
4316
4506
|
}
|
|
4317
4507
|
}
|
|
4318
|
-
const targetElements =
|
|
4508
|
+
const targetElements = getSelectedTargetElements(board);
|
|
4319
4509
|
throttleRAF(board, 'with-arrow-moving', () => {
|
|
4320
4510
|
updatePoints(board, targetElements, offset[0], offset[1]);
|
|
4321
4511
|
});
|
|
@@ -4328,7 +4518,7 @@ function withArrowMoving(board) {
|
|
|
4328
4518
|
};
|
|
4329
4519
|
return board;
|
|
4330
4520
|
}
|
|
4331
|
-
function
|
|
4521
|
+
function getSelectedTargetElements(board) {
|
|
4332
4522
|
const selectedElements = getSelectedElements(board);
|
|
4333
4523
|
const movableElements = board.children.filter(item => board.isMovable(item));
|
|
4334
4524
|
const targetElements = selectedElements.filter(element => {
|
|
@@ -4339,7 +4529,7 @@ function getTargetElements(board) {
|
|
|
4339
4529
|
return targetElements;
|
|
4340
4530
|
}
|
|
4341
4531
|
function updatePoints(board, targetElements, offsetX, offsetY) {
|
|
4342
|
-
const validElements = targetElements.filter(element => board.children.findIndex(item => item.id === element.id) > -1);
|
|
4532
|
+
const validElements = targetElements.filter(element => !PlaitGroupElement.isGroup(element) && board.children.findIndex(item => item.id === element.id) > -1);
|
|
4343
4533
|
const currentElements = validElements.map(element => {
|
|
4344
4534
|
const points = element.points || [];
|
|
4345
4535
|
const newPoints = points.map(p => [p[0] + offsetX, p[1] + offsetY]);
|
|
@@ -4671,27 +4861,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.2.4", ngImpor
|
|
|
4671
4861
|
type: Input
|
|
4672
4862
|
}] } });
|
|
4673
4863
|
|
|
4674
|
-
function
|
|
4675
|
-
const {
|
|
4676
|
-
|
|
4677
|
-
|
|
4678
|
-
|
|
4679
|
-
|
|
4680
|
-
let selection = { anchor: point, focus: point };
|
|
4681
|
-
if (board.selection && !Selection.isCollapsed(board.selection)) {
|
|
4682
|
-
selection = board.selection;
|
|
4864
|
+
function withRelatedFragment(board) {
|
|
4865
|
+
const { setFragment } = board;
|
|
4866
|
+
board.setFragment = (data, clipboardContext, rectangle, type) => {
|
|
4867
|
+
const relatedFragment = board.getRelatedFragment([]);
|
|
4868
|
+
if (!clipboardContext) {
|
|
4869
|
+
clipboardContext = createClipboardContext(WritableClipboardType.elements, relatedFragment, '');
|
|
4683
4870
|
}
|
|
4684
|
-
|
|
4685
|
-
|
|
4686
|
-
|
|
4687
|
-
|
|
4871
|
+
else {
|
|
4872
|
+
clipboardContext = addClipboardContext(clipboardContext, {
|
|
4873
|
+
text: '',
|
|
4874
|
+
type: WritableClipboardType.elements,
|
|
4875
|
+
data: relatedFragment
|
|
4876
|
+
});
|
|
4688
4877
|
}
|
|
4689
|
-
|
|
4690
|
-
};
|
|
4691
|
-
board.globalPointerUp = (event) => {
|
|
4692
|
-
groupRectangleG?.remove();
|
|
4693
|
-
groupRectangleG = null;
|
|
4694
|
-
globalPointerUp(event);
|
|
4878
|
+
setFragment(data, clipboardContext, rectangle, type);
|
|
4695
4879
|
};
|
|
4696
4880
|
return board;
|
|
4697
4881
|
}
|
|
@@ -4821,7 +5005,7 @@ class PlaitBoardComponent {
|
|
|
4821
5005
|
initializeViewportOffset(this.board);
|
|
4822
5006
|
}
|
|
4823
5007
|
initializePlugins() {
|
|
4824
|
-
let board = withHotkey(withHandPointer(withHistory(withSelection(
|
|
5008
|
+
let board = withRelatedFragment(withHotkey(withHandPointer(withHistory(withSelection(withMoving(withBoard(withViewport(withOptions(createBoard(this.plaitValue, this.plaitOptions))))))))));
|
|
4825
5009
|
this.plaitPlugins.forEach(plugin => {
|
|
4826
5010
|
board = plugin(board);
|
|
4827
5011
|
});
|
|
@@ -5263,6 +5447,81 @@ function createModModifierKeys() {
|
|
|
5263
5447
|
return modifiers;
|
|
5264
5448
|
}
|
|
5265
5449
|
|
|
5450
|
+
const TEMPORARY_G = new Map();
|
|
5451
|
+
const getTemporaryGArray = (debugKey) => {
|
|
5452
|
+
return TEMPORARY_G.get(debugKey) || [];
|
|
5453
|
+
};
|
|
5454
|
+
const setTemporaryGArray = (debugKey, gArray) => {
|
|
5455
|
+
TEMPORARY_G.set(debugKey, gArray);
|
|
5456
|
+
};
|
|
5457
|
+
class DebugGenerator {
|
|
5458
|
+
constructor(debugKey) {
|
|
5459
|
+
this.debugKey = debugKey;
|
|
5460
|
+
}
|
|
5461
|
+
isDebug() {
|
|
5462
|
+
return isDebug(this.debugKey);
|
|
5463
|
+
}
|
|
5464
|
+
clear() {
|
|
5465
|
+
if (!this.isDebug()) {
|
|
5466
|
+
return;
|
|
5467
|
+
}
|
|
5468
|
+
const gArray = getTemporaryGArray(this.debugKey);
|
|
5469
|
+
setTemporaryGArray(this.debugKey, []);
|
|
5470
|
+
gArray.forEach(g => g.remove());
|
|
5471
|
+
}
|
|
5472
|
+
drawPolygon(board, points, options) {
|
|
5473
|
+
if (!isDebug(this.debugKey)) {
|
|
5474
|
+
return;
|
|
5475
|
+
}
|
|
5476
|
+
const polygonG = PlaitBoard.getRoughSVG(board).polygon(points, options || { stroke: 'red' });
|
|
5477
|
+
PlaitBoard.getElementActiveHost(board).append(polygonG);
|
|
5478
|
+
const gArray = getTemporaryGArray(this.debugKey);
|
|
5479
|
+
gArray.push(polygonG);
|
|
5480
|
+
setTemporaryGArray(this.debugKey, gArray);
|
|
5481
|
+
return polygonG;
|
|
5482
|
+
}
|
|
5483
|
+
drawRectangle(board, data, options) {
|
|
5484
|
+
if (!isDebug(this.debugKey)) {
|
|
5485
|
+
return;
|
|
5486
|
+
}
|
|
5487
|
+
let rectangle;
|
|
5488
|
+
if (data instanceof Array) {
|
|
5489
|
+
rectangle = RectangleClient.getRectangleByPoints(data);
|
|
5490
|
+
}
|
|
5491
|
+
else {
|
|
5492
|
+
rectangle = data;
|
|
5493
|
+
}
|
|
5494
|
+
const rectangleG = PlaitBoard.getRoughSVG(board).rectangle(rectangle.x, rectangle.y, rectangle.width, rectangle.height, options || { stroke: 'red' });
|
|
5495
|
+
PlaitBoard.getElementActiveHost(board).append(rectangleG);
|
|
5496
|
+
const gArray = getTemporaryGArray(this.debugKey);
|
|
5497
|
+
gArray.push(rectangleG);
|
|
5498
|
+
setTemporaryGArray(this.debugKey, gArray);
|
|
5499
|
+
return rectangleG;
|
|
5500
|
+
}
|
|
5501
|
+
drawCircles(board, points, diameter = 0, isCumulativeDiameter = false, options) {
|
|
5502
|
+
if (!isDebug(this.debugKey)) {
|
|
5503
|
+
return;
|
|
5504
|
+
}
|
|
5505
|
+
const result = [];
|
|
5506
|
+
points.forEach((p, i) => {
|
|
5507
|
+
const circle = PlaitBoard.getRoughSVG(board).circle(p[0], p[1], isCumulativeDiameter ? diameter * (i + 1) : diameter, Object.assign({}, { stroke: 'red', fill: 'red', fillStyle: 'solid' }, options || {}));
|
|
5508
|
+
PlaitBoard.getElementActiveHost(board).append(circle);
|
|
5509
|
+
const gArray = getTemporaryGArray(this.debugKey);
|
|
5510
|
+
gArray.push(circle);
|
|
5511
|
+
result.push(circle);
|
|
5512
|
+
setTemporaryGArray(this.debugKey, gArray);
|
|
5513
|
+
});
|
|
5514
|
+
return result;
|
|
5515
|
+
}
|
|
5516
|
+
}
|
|
5517
|
+
const createDebugGenerator = (debugKey) => {
|
|
5518
|
+
return new DebugGenerator(debugKey);
|
|
5519
|
+
};
|
|
5520
|
+
const isDebug = (key) => {
|
|
5521
|
+
const defaultKey = 'debug:plait';
|
|
5522
|
+
return localStorage.getItem(key || defaultKey) === 'true';
|
|
5523
|
+
};
|
|
5524
|
+
|
|
5266
5525
|
/*
|
|
5267
5526
|
* Public API Surface of plait
|
|
5268
5527
|
*/
|
|
@@ -5271,5 +5530,5 @@ function createModModifierKeys() {
|
|
|
5271
5530
|
* Generated bundle index. Do not edit.
|
|
5272
5531
|
*/
|
|
5273
5532
|
|
|
5274
|
-
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, DefaultThemeColor, Direction, E, EIGHT, ELEMENT_TO_COMPONENT, END, ENTER, EQUALS, ESCAPE, F, F1, F10, F11, F12, F2, F3, F4, F5, F6, F7, F8, F9, FF_EQUALS, FF_MINUS, FF_MUTE, FF_SEMICOLON, FF_VOLUME_DOWN, FF_VOLUME_UP, FIRST_MEDIA, FIVE, FLUSHING, FOUR, G, H, 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, 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,
|
|
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, createSelectionRectangleG, createTestingBoard, createText, createTouchEvent, debounce, deleteTemporaryElements, depthFirstRecursion, distanceBetweenPointAndPoint, distanceBetweenPointAndRectangle, distanceBetweenPointAndSegment, distanceBetweenPointAndSegments, downloadImage, drawArrow, drawBezierPath, drawCircle, 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, 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, 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, removeMovingElements, removeSelectedElement, rotate, rotateAntiPointsByElement, 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 };
|
|
5275
5534
|
//# sourceMappingURL=plait-core.mjs.map
|