@plait/core 0.56.2 → 0.57.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { IterableDiffers, inject, ViewContainerRef, ChangeDetectorRef, Directive, Input, Injectable, EventEmitter, ElementRef, Component, ChangeDetectionStrategy, Output, HostBinding, ViewChild, ContentChildren } from '@angular/core';
2
+ import { Directive, Input, Injectable, IterableDiffers, EventEmitter, inject, ElementRef, Component, ChangeDetectionStrategy, Output, HostBinding, ViewChild, ContentChildren, ViewContainerRef, ChangeDetectorRef } from '@angular/core';
3
3
  import rough from 'roughjs/bin/rough';
4
4
  import { timer, Subject, fromEvent } from 'rxjs';
5
5
  import { takeUntil, filter, tap } from 'rxjs/operators';
@@ -42,51 +42,6 @@ var PlaitPointerType;
42
42
  * Extendable Custom Types Interface
43
43
  */
44
44
 
45
- function depthFirstRecursion(node, callback, recursion, isReverse) {
46
- if (!recursion || recursion(node)) {
47
- let children = [];
48
- if (node.children) {
49
- children = [...node.children];
50
- }
51
- children = isReverse ? children.reverse() : children;
52
- children.forEach(child => {
53
- depthFirstRecursion(child, callback, recursion);
54
- });
55
- }
56
- callback(node);
57
- }
58
- const getIsRecursionFunc = (board) => {
59
- return (element) => {
60
- if (PlaitBoard.isBoard(element) || board.isRecursion(element)) {
61
- return true;
62
- }
63
- else {
64
- return false;
65
- }
66
- };
67
- };
68
-
69
- const SELECTION_BORDER_COLOR = '#6698FF';
70
- const SELECTION_FILL_COLOR = '#6698FF25'; // opacity 0.25
71
- const Selection = {
72
- isCollapsed(selection) {
73
- if (selection.anchor[0] == selection.focus[0] && selection.anchor[1] === selection.focus[1]) {
74
- return true;
75
- }
76
- else {
77
- return false;
78
- }
79
- }
80
- };
81
-
82
- const sortElements = (board, elements, ascendingOrder = true) => {
83
- return [...elements].sort((a, b) => {
84
- const pathA = PlaitBoard.findPath(board, a);
85
- const pathB = PlaitBoard.findPath(board, b);
86
- return ascendingOrder ? pathA[0] - pathB[0] : pathB[0] - pathA[0];
87
- });
88
- };
89
-
90
45
  const RectangleClient = {
91
46
  isHit: (origin, target) => {
92
47
  return RectangleClient.isHitX(origin, target) && RectangleClient.isHitY(origin, target);
@@ -242,717 +197,7 @@ const RectangleClient = {
242
197
  height: maxY - minY
243
198
  };
244
199
  }
245
- };
246
-
247
- var PlaitPluginKey;
248
- (function (PlaitPluginKey) {
249
- PlaitPluginKey["withSelection"] = "withSelection";
250
- })(PlaitPluginKey || (PlaitPluginKey = {}));
251
-
252
- const getHitElementsBySelection = (board, selection, match = () => true) => {
253
- const newSelection = selection || board.selection;
254
- const rectangleHitElements = [];
255
- if (!newSelection) {
256
- return [];
257
- }
258
- const isCollapsed = Selection.isCollapsed(newSelection);
259
- if (isCollapsed) {
260
- const hitElement = getHitElementByPoint(board, newSelection.anchor, match);
261
- if (hitElement) {
262
- return [hitElement];
263
- }
264
- else {
265
- return [];
266
- }
267
- }
268
- depthFirstRecursion(board, node => {
269
- if (!PlaitBoard.isBoard(node) && match(node) && board.isRectangleHit(node, newSelection)) {
270
- rectangleHitElements.push(node);
271
- }
272
- }, getIsRecursionFunc(board), true);
273
- return rectangleHitElements;
274
- };
275
- const getHitElementByPoint = (board, point, match = () => true) => {
276
- let hitElement = undefined;
277
- let hitInsideElement = undefined;
278
- depthFirstRecursion(board, node => {
279
- if (hitElement) {
280
- return;
281
- }
282
- if (PlaitBoard.isBoard(node) || !match(node) || !PlaitElement.hasMounted(node)) {
283
- return;
284
- }
285
- if (board.isHit(node, point)) {
286
- hitElement = node;
287
- return;
288
- }
289
- /**
290
- * 需要增加场景测试
291
- * hitInsideElement 存的是第一个符合 isInsidePoint 的元素
292
- * 当有元素符合 isHit 时结束遍历,并返回 hitElement
293
- * 当所有元素都不符合 isHit ,则返回第一个符合 isInsidePoint 的元素
294
- * 这样保证最上面的元素优先被探测到;
295
- */
296
- if (!hitInsideElement && board.isInsidePoint(node, point)) {
297
- hitInsideElement = node;
298
- }
299
- }, getIsRecursionFunc(board), true);
300
- return hitElement || hitInsideElement;
301
- };
302
- const getHitSelectedElements = (board, point) => {
303
- const selectedElements = getSelectedElements(board);
304
- const targetRectangle = selectedElements.length > 0 && getRectangleByElements(board, selectedElements, false);
305
- const isInTargetRectangle = targetRectangle && RectangleClient.isPointInRectangle(targetRectangle, point);
306
- if (isInTargetRectangle) {
307
- return selectedElements;
308
- }
309
- else {
310
- return [];
311
- }
312
- };
313
- const cacheSelectedElements = (board, selectedElements) => {
314
- const sortedElements = sortElements(board, selectedElements);
315
- BOARD_TO_SELECTED_ELEMENT.set(board, sortedElements);
316
- };
317
- const getSelectedElements = (board) => {
318
- return BOARD_TO_SELECTED_ELEMENT.get(board) || [];
319
- };
320
- const addSelectedElement = (board, element) => {
321
- let elements = [];
322
- if (Array.isArray(element)) {
323
- elements.push(...element);
324
- }
325
- else {
326
- elements.push(element);
327
- }
328
- const selectedElements = getSelectedElements(board);
329
- cacheSelectedElements(board, [...selectedElements, ...elements]);
330
- };
331
- const removeSelectedElement = (board, element, isRemoveChildren = false) => {
332
- const selectedElements = getSelectedElements(board);
333
- if (selectedElements.includes(element)) {
334
- const targetElements = [];
335
- if (board.isRecursion(element) && isRemoveChildren) {
336
- depthFirstRecursion(element, node => {
337
- targetElements.push(node);
338
- }, node => board.isRecursion(node));
339
- }
340
- else {
341
- targetElements.push(element);
342
- }
343
- const newSelectedElements = selectedElements.filter(value => !targetElements.includes(value));
344
- cacheSelectedElements(board, newSelectedElements);
345
- }
346
- };
347
- const clearSelectedElement = (board) => {
348
- cacheSelectedElements(board, []);
349
- };
350
- const isSelectedElement = (board, element) => {
351
- const selectedElements = getSelectedElements(board);
352
- return !!selectedElements.find(value => value === element);
353
- };
354
- const temporaryDisableSelection = (board) => {
355
- const currentOptions = board.getPluginOptions(PlaitPluginKey.withSelection);
356
- board.setPluginOptions(PlaitPluginKey.withSelection, {
357
- isDisabledSelect: true
358
- });
359
- setTimeout(() => {
360
- board.setPluginOptions(PlaitPluginKey.withSelection, { ...currentOptions });
361
- }, 0);
362
- };
363
-
364
- /**
365
- * @license
366
- * Copyright Google LLC All Rights Reserved.
367
- *
368
- * Use of this source code is governed by an MIT-style license that can be
369
- * found in the LICENSE file at https://angular.io/license
370
- */
371
- const MAC_ENTER = 3;
372
- const BACKSPACE = 8;
373
- const TAB = 9;
374
- const NUM_CENTER = 12;
375
- const ENTER = 13;
376
- const SHIFT = 16;
377
- const CONTROL = 17;
378
- const ALT = 18;
379
- const PAUSE = 19;
380
- const CAPS_LOCK = 20;
381
- const ESCAPE = 27;
382
- const SPACE = 32;
383
- const PAGE_UP = 33;
384
- const PAGE_DOWN = 34;
385
- const END = 35;
386
- const HOME = 36;
387
- const LEFT_ARROW = 37;
388
- const UP_ARROW = 38;
389
- const RIGHT_ARROW = 39;
390
- const DOWN_ARROW = 40;
391
- const PLUS_SIGN = 43;
392
- const PRINT_SCREEN = 44;
393
- const INSERT = 45;
394
- const DELETE = 46;
395
- const ZERO = 48;
396
- const ONE = 49;
397
- const TWO = 50;
398
- const THREE = 51;
399
- const FOUR = 52;
400
- const FIVE = 53;
401
- const SIX = 54;
402
- const SEVEN = 55;
403
- const EIGHT = 56;
404
- const NINE = 57;
405
- const FF_SEMICOLON = 59; // Firefox (Gecko) fires this for semicolon instead of 186
406
- const FF_EQUALS = 61; // Firefox (Gecko) fires this for equals instead of 187
407
- const QUESTION_MARK = 63;
408
- const AT_SIGN = 64;
409
- const A = 65;
410
- const B = 66;
411
- const C = 67;
412
- const D = 68;
413
- const E = 69;
414
- const F = 70;
415
- const G = 71;
416
- const H = 72;
417
- const I = 73;
418
- const J = 74;
419
- const K = 75;
420
- const L = 76;
421
- const M = 77;
422
- const N = 78;
423
- const O = 79;
424
- const P = 80;
425
- const Q = 81;
426
- const R = 82;
427
- const S = 83;
428
- const T = 84;
429
- const U = 85;
430
- const V = 86;
431
- const W = 87;
432
- const X = 88;
433
- const Y = 89;
434
- const Z = 90;
435
- const META = 91; // WIN_KEY_LEFT
436
- const MAC_WK_CMD_LEFT = 91;
437
- const MAC_WK_CMD_RIGHT = 93;
438
- const CONTEXT_MENU = 93;
439
- const NUMPAD_ZERO = 96;
440
- const NUMPAD_ONE = 97;
441
- const NUMPAD_TWO = 98;
442
- const NUMPAD_THREE = 99;
443
- const NUMPAD_FOUR = 100;
444
- const NUMPAD_FIVE = 101;
445
- const NUMPAD_SIX = 102;
446
- const NUMPAD_SEVEN = 103;
447
- const NUMPAD_EIGHT = 104;
448
- const NUMPAD_NINE = 105;
449
- const NUMPAD_MULTIPLY = 106;
450
- const NUMPAD_PLUS = 107;
451
- const NUMPAD_MINUS = 109;
452
- const NUMPAD_PERIOD = 110;
453
- const NUMPAD_DIVIDE = 111;
454
- const F1 = 112;
455
- const F2 = 113;
456
- const F3 = 114;
457
- const F4 = 115;
458
- const F5 = 116;
459
- const F6 = 117;
460
- const F7 = 118;
461
- const F8 = 119;
462
- const F9 = 120;
463
- const F10 = 121;
464
- const F11 = 122;
465
- const F12 = 123;
466
- const NUM_LOCK = 144;
467
- const SCROLL_LOCK = 145;
468
- const FIRST_MEDIA = 166;
469
- const FF_MINUS = 173;
470
- const MUTE = 173; // Firefox (Gecko) fires 181 for MUTE
471
- const VOLUME_DOWN = 174; // Firefox (Gecko) fires 182 for VOLUME_DOWN
472
- const VOLUME_UP = 175; // Firefox (Gecko) fires 183 for VOLUME_UP
473
- const FF_MUTE = 181;
474
- const FF_VOLUME_DOWN = 182;
475
- const LAST_MEDIA = 183;
476
- const FF_VOLUME_UP = 183;
477
- const SEMICOLON = 186; // Firefox (Gecko) fires 59 for SEMICOLON
478
- const EQUALS = 187; // Firefox (Gecko) fires 61 for EQUALS
479
- const COMMA = 188;
480
- const DASH = 189; // Firefox (Gecko) fires 173 for DASH/MINUS
481
- const PERIOD = 190;
482
- const SLASH = 191;
483
- const APOSTROPHE = 192;
484
- const TILDE = 192;
485
- const OPEN_SQUARE_BRACKET = 219;
486
- const BACKSLASH = 220;
487
- const CLOSE_SQUARE_BRACKET = 221;
488
- const SINGLE_QUOTE = 222;
489
- const MAC_META = 224;
490
-
491
- var ResizeCursorClass;
492
- (function (ResizeCursorClass) {
493
- ResizeCursorClass["ew"] = "ew-resize";
494
- ResizeCursorClass["ns"] = "ns-resize";
495
- ResizeCursorClass["nesw"] = "nesw-resize";
496
- ResizeCursorClass["nwse"] = "nwse-resize";
497
- })(ResizeCursorClass || (ResizeCursorClass = {}));
498
- var CursorClass;
499
- (function (CursorClass) {
500
- CursorClass["crosshair"] = "crosshair";
501
- })(CursorClass || (CursorClass = {}));
502
- const RESIZE_CURSORS = [ResizeCursorClass.ns, ResizeCursorClass.nesw, ResizeCursorClass.ew, ResizeCursorClass.nwse];
503
-
504
- const ATTACHED_ELEMENT_CLASS_NAME = 'plait-board-attached';
505
- const ACTIVE_STROKE_WIDTH = 1;
506
- const SNAPPING_STROKE_WIDTH = 2;
507
- const SELECTION_RECTANGLE_CLASS_NAME = 'selection-rectangle';
508
-
509
- const HOST_CLASS_NAME = 'plait-board-container';
510
- const ACTIVE_MOVING_CLASS_NAME = 'active-with-moving';
511
- const ROTATE_HANDLE_CLASS_NAME = 'rotate-handle';
512
- const RESIZE_HANDLE_CLASS_NAME = 'resize-handle';
513
- const SCROLL_BAR_WIDTH = 20;
514
- const MAX_RADIUS = 16;
515
- const POINTER_BUTTON = {
516
- MAIN: 0,
517
- WHEEL: 1,
518
- SECONDARY: 2,
519
- TOUCH: -1
520
- };
521
- const PRESS_AND_MOVE_BUFFER = 3;
522
- const HIT_DISTANCE_BUFFER = 5;
523
-
524
- const NS = 'http://www.w3.org/2000/svg';
525
- function createG() {
526
- const newG = document.createElementNS(NS, 'g');
527
- return newG;
528
- }
529
- function createPath() {
530
- const newG = document.createElementNS(NS, 'path');
531
- return newG;
532
- }
533
- function createRect(rectangle, options) {
534
- const rect = document.createElementNS(NS, 'rect');
535
- rect.setAttribute('x', `${rectangle.x}`);
536
- rect.setAttribute('y', `${rectangle.y}`);
537
- rect.setAttribute('width', `${rectangle.width}`);
538
- rect.setAttribute('height', `${rectangle.height}`);
539
- for (let key in options) {
540
- const optionKey = key;
541
- rect.setAttribute(key, `${options[optionKey]}`);
542
- }
543
- return rect;
544
- }
545
- const setStrokeLinecap = (g, value) => {
546
- g.setAttribute('stroke-linecap', value);
547
- };
548
- const setPathStrokeLinecap = (g, value) => {
549
- g.querySelectorAll('path').forEach(path => {
550
- path.setAttribute('stroke-linecap', value);
551
- });
552
- };
553
- function createMask() {
554
- return document.createElementNS(NS, 'mask');
555
- }
556
- function createSVG() {
557
- const svg = document.createElementNS(NS, 'svg');
558
- return svg;
559
- }
560
- function createText(x, y, fill, textContent) {
561
- var text = document.createElementNS(NS, 'text');
562
- text.setAttribute('x', `${x}`);
563
- text.setAttribute('y', `${y}`);
564
- text.setAttribute('fill', fill);
565
- text.textContent = textContent;
566
- return text;
567
- }
568
- /**
569
- * Check if a DOM node is an element node.
570
- */
571
- const isDOMElement = (value) => {
572
- return isDOMNode(value) && value.nodeType === 1;
573
- };
574
- /**
575
- * Check if a value is a DOM node.
576
- */
577
- const isDOMNode = (value) => {
578
- return value instanceof window.Node;
579
- };
580
- const hasInputOrTextareaTarget = (target) => {
581
- if (isDOMElement(target)) {
582
- if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA') {
583
- return true;
584
- }
585
- }
586
- return false;
587
- };
588
- const isSecondaryPointer = (event) => {
589
- return event.button === POINTER_BUTTON.SECONDARY;
590
- };
591
- const isMainPointer = (event) => {
592
- return event.button === POINTER_BUTTON.MAIN;
593
- };
594
-
595
- function hasBeforeContextChange(value) {
596
- if (value.beforeContextChange) {
597
- return true;
598
- }
599
- return false;
600
- }
601
- function hasOnContextChanged(value) {
602
- if (value.onContextChanged) {
603
- return true;
604
- }
605
- return false;
606
- }
607
-
608
- class ListRender {
609
- constructor(board, viewContainerRef) {
610
- this.board = board;
611
- this.viewContainerRef = viewContainerRef;
612
- this.children = [];
613
- this.componentRefs = [];
614
- this.contexts = [];
615
- this.differ = null;
616
- this.initialized = false;
617
- }
618
- initialize(children, childrenContext) {
619
- this.initialized = true;
620
- this.children = children;
621
- children.forEach((descendant, index) => {
622
- NODE_TO_INDEX.set(descendant, index);
623
- NODE_TO_PARENT.set(descendant, childrenContext.parent);
624
- const context = getContext(this.board, descendant, index, childrenContext.parent);
625
- const componentType = getComponentType(this.board, context);
626
- const componentRef = createPluginComponent(componentType, context, this.viewContainerRef, childrenContext);
627
- this.componentRefs.push(componentRef);
628
- this.contexts.push(context);
629
- });
630
- const newDiffers = this.viewContainerRef.injector.get(IterableDiffers);
631
- this.differ = newDiffers.find(children).create(trackBy);
632
- this.differ.diff(children);
633
- }
634
- update(children, childrenContext) {
635
- if (!this.initialized) {
636
- this.initialize(children, childrenContext);
637
- return;
638
- }
639
- if (!this.differ) {
640
- throw new Error('Exception: Can not find differ ');
641
- }
642
- const { board, parent } = childrenContext;
643
- const diffResult = this.differ.diff(children);
644
- if (diffResult) {
645
- const newContexts = [];
646
- const newComponentRefs = [];
647
- let currentIndexForFirstElement = null;
648
- diffResult.forEachItem((record) => {
649
- NODE_TO_INDEX.set(record.item, record.currentIndex);
650
- NODE_TO_PARENT.set(record.item, childrenContext.parent);
651
- const previousContext = record.previousIndex === null ? undefined : this.contexts[record.previousIndex];
652
- const context = getContext(board, record.item, record.currentIndex, parent, previousContext);
653
- if (record.previousIndex === null) {
654
- const componentType = getComponentType(board, context);
655
- const componentRef = createPluginComponent(componentType, context, this.viewContainerRef, childrenContext);
656
- newContexts.push(context);
657
- newComponentRefs.push(componentRef);
658
- }
659
- else {
660
- const componentRef = this.componentRefs[record.previousIndex];
661
- componentRef.instance.context = context;
662
- newComponentRefs.push(componentRef);
663
- newContexts.push(context);
664
- }
665
- // item might has been changed, so need to compare the id
666
- if (record.item === this.children[0] || record.item.id === this.children[0]?.id) {
667
- currentIndexForFirstElement = record.currentIndex;
668
- }
669
- });
670
- diffResult.forEachOperation(record => {
671
- // removed
672
- if (record.currentIndex === null) {
673
- const componentRef = this.componentRefs[record.previousIndex];
674
- componentRef?.destroy();
675
- }
676
- // moved
677
- if (record.previousIndex !== null && record.currentIndex !== null) {
678
- mountOnItemMove(record.item, record.currentIndex, childrenContext, currentIndexForFirstElement);
679
- }
680
- });
681
- this.componentRefs = newComponentRefs;
682
- this.contexts = newContexts;
683
- this.children = children;
684
- }
685
- else {
686
- const newContexts = [];
687
- this.children.forEach((element, index) => {
688
- NODE_TO_INDEX.set(element, index);
689
- NODE_TO_PARENT.set(element, childrenContext.parent);
690
- const previousContext = this.contexts[index];
691
- const previousComponentRef = this.componentRefs[index];
692
- const context = getContext(board, element, index, parent, previousContext);
693
- previousComponentRef.instance.context = context;
694
- newContexts.push(context);
695
- });
696
- this.contexts = newContexts;
697
- }
698
- }
699
- destroy() {
700
- this.children.forEach((element, index) => {
701
- if (this.componentRefs[index]) {
702
- this.componentRefs[index].destroy();
703
- }
704
- });
705
- this.componentRefs = [];
706
- this.children = [];
707
- this.contexts = [];
708
- this.initialized = false;
709
- this.differ = null;
710
- }
711
- }
712
- const trackBy = (index, element) => {
713
- return element.id;
714
- };
715
- const createPluginComponent = (componentType, context, viewContainerRef, childrenContext) => {
716
- const componentRef = viewContainerRef.createComponent(componentType, { injector: viewContainerRef.injector });
717
- const instance = componentRef.instance;
718
- instance.context = context;
719
- componentRef.changeDetectorRef.detectChanges();
720
- const g = componentRef.instance.getContainerG();
721
- mountElementG(context.index, g, childrenContext);
722
- componentRef.instance.initializeListRender();
723
- return componentRef;
724
- };
725
- const getComponentType = (board, context) => {
726
- const result = board.drawElement(context);
727
- return result;
728
- };
729
- const getContext = (board, element, index, parent, previousContext) => {
730
- let isSelected = isSelectedElement(board, element);
731
- const previousElement = previousContext && previousContext.element;
732
- if (previousElement && previousElement !== element && isSelectedElement(board, previousElement)) {
733
- isSelected = true;
734
- removeSelectedElement(board, previousElement);
735
- addSelectedElement(board, element);
736
- }
737
- const context = {
738
- element: element,
739
- parent: parent,
740
- board: board,
741
- selected: isSelected,
742
- index
743
- };
744
- return context;
745
- };
746
- // the g depth of root element:[1]-[2]-[3]-[4]
747
- // the g depth of root element and children element(the [2] element has children):
748
- // [1]-
749
- // [2]([2-1-1][2-1-2][2-1][2-2][2-3-1][2-3-2][2-3][2])-
750
- // [3]-
751
- // [4]
752
- const mountElementG = (index, g, childrenContext,
753
- // for moving scene: the current index for first element before moving
754
- currentIndexForFirstElement = null) => {
755
- const { parent, parentG } = childrenContext;
756
- if (PlaitBoard.isBoard(parent)) {
757
- if (index > 0) {
758
- const previousElement = parent.children[index - 1];
759
- const previousContainerG = PlaitElement.getContainerG(previousElement, { suppressThrow: false });
760
- previousContainerG.insertAdjacentElement('afterend', g);
761
- }
762
- else {
763
- if (currentIndexForFirstElement !== null) {
764
- const firstElement = parent.children[currentIndexForFirstElement];
765
- const firstContainerG = firstElement && PlaitElement.getContainerG(firstElement, { suppressThrow: true });
766
- if (firstElement && firstContainerG) {
767
- parentG.insertBefore(g, firstContainerG);
768
- }
769
- else {
770
- throw new Error('fail to mount container on moving');
771
- }
772
- }
773
- else {
774
- parentG.append(g);
775
- }
776
- }
777
- }
778
- else {
779
- if (index > 0) {
780
- const previousElement = parent.children[index - 1];
781
- const previousElementG = PlaitElement.getElementG(previousElement);
782
- previousElementG.insertAdjacentElement('afterend', g);
783
- }
784
- else {
785
- if (currentIndexForFirstElement) {
786
- const nextElement = parent.children[currentIndexForFirstElement];
787
- const nextPath = nextElement && PlaitBoard.findPath(childrenContext.board, nextElement);
788
- const first = nextPath && PlaitNode.first(childrenContext.board, nextPath);
789
- const firstContainerG = first && PlaitElement.getContainerG(first, { suppressThrow: false });
790
- if (firstContainerG) {
791
- parentG.insertBefore(g, firstContainerG);
792
- }
793
- else {
794
- throw new Error('fail to mount container on moving');
795
- }
796
- }
797
- else {
798
- let parentElementG = PlaitElement.getElementG(parent);
799
- parentG.insertBefore(g, parentElementG);
800
- }
801
- }
802
- }
803
- };
804
- const mountOnItemMove = (element, index, childrenContext, currentIndexForFirstElement) => {
805
- const containerG = PlaitElement.getContainerG(element, { suppressThrow: false });
806
- mountElementG(index, containerG, childrenContext, currentIndexForFirstElement);
807
- if (element.children && !PlaitElement.isRootElement(element)) {
808
- element.children.forEach((child, index) => {
809
- mountOnItemMove(child, index, { ...childrenContext, parent: element }, null);
810
- });
811
- }
812
- };
813
-
814
- class PlaitPluginElementComponent {
815
- get hasChildren() {
816
- return !!this.element.children;
817
- }
818
- set context(value) {
819
- if (hasBeforeContextChange(this)) {
820
- this.beforeContextChange(value);
821
- }
822
- const previousContext = this._context;
823
- this._context = value;
824
- if (this.element) {
825
- ELEMENT_TO_COMPONENT.set(this.element, this);
826
- }
827
- if (this.initialized) {
828
- const elementG = this.getElementG();
829
- const containerG = this.getContainerG();
830
- NODE_TO_G.set(this.element, elementG);
831
- NODE_TO_CONTAINER_G.set(this.element, containerG);
832
- ELEMENT_TO_REF.set(this.element, this.ref);
833
- this.updateListRender();
834
- this.cdr.markForCheck();
835
- if (hasOnContextChanged(this)) {
836
- this.onContextChanged(value, previousContext);
837
- }
838
- }
839
- else {
840
- if (PlaitElement.isRootElement(this.element) && this.hasChildren) {
841
- this._g = createG();
842
- this._containerG = createG();
843
- this._containerG.append(this._g);
844
- }
845
- else {
846
- this._g = createG();
847
- this._containerG = this._g;
848
- }
849
- NODE_TO_G.set(this.element, this._g);
850
- NODE_TO_CONTAINER_G.set(this.element, this._containerG);
851
- ELEMENT_TO_REF.set(this.element, this.ref);
852
- }
853
- }
854
- get context() {
855
- return this._context;
856
- }
857
- get element() {
858
- return this.context && this.context.element;
859
- }
860
- get board() {
861
- return this.context && this.context.board;
862
- }
863
- get selected() {
864
- return this.context && this.context.selected;
865
- }
866
- getContainerG() {
867
- return this._containerG;
868
- }
869
- getElementG() {
870
- return this._g;
871
- }
872
- constructor(ref) {
873
- this.ref = ref;
874
- this.viewContainerRef = inject(ViewContainerRef);
875
- this.cdr = inject(ChangeDetectorRef);
876
- this.initialized = false;
877
- }
878
- ngOnInit() {
879
- if (this.element.type) {
880
- this.getContainerG().setAttribute(`plait-${this.element.type}`, 'true');
881
- }
882
- if (this.hasChildren) {
883
- if (PlaitElement.isRootElement(this.element)) {
884
- this._rootContainerG = this._containerG;
885
- }
886
- else {
887
- const path = PlaitBoard.findPath(this.board, this.element);
888
- const rootNode = PlaitNode.get(this.board, path.slice(0, 1));
889
- this._rootContainerG = PlaitElement.getContainerG(rootNode, { suppressThrow: false });
890
- }
891
- }
892
- this.getContainerG().setAttribute('plait-data-id', this.element.id);
893
- this.initialized = true;
894
- }
895
- initializeListRender() {
896
- if (this.hasChildren) {
897
- this.listRender = new ListRender(this.board, this.viewContainerRef);
898
- if (this.board.isExpanded(this.element)) {
899
- this.listRender.initialize(this.element.children, this.initializeChildrenContext());
900
- }
901
- }
902
- }
903
- getRef() {
904
- return this.ref;
905
- }
906
- updateListRender() {
907
- if (this.hasChildren) {
908
- if (!this.listRender) {
909
- throw new Error('incorrectly initialize list render');
910
- }
911
- if (this.board.isExpanded(this.element)) {
912
- this.listRender.update(this.element.children, this.initializeChildrenContext());
913
- }
914
- else {
915
- if (this.listRender.initialized) {
916
- this.listRender.destroy();
917
- }
918
- }
919
- }
920
- }
921
- initializeChildrenContext() {
922
- if (!this._rootContainerG) {
923
- throw new Error('can not resolve root container g');
924
- }
925
- return {
926
- board: this.board,
927
- parent: this.element,
928
- parentG: this._rootContainerG
929
- };
930
- }
931
- ngOnDestroy() {
932
- if (ELEMENT_TO_COMPONENT.get(this.element) === this) {
933
- ELEMENT_TO_COMPONENT.delete(this.element);
934
- }
935
- if (NODE_TO_G.get(this.element) === this._g) {
936
- NODE_TO_G.delete(this.element);
937
- }
938
- if (NODE_TO_CONTAINER_G.get(this.element) === this._containerG) {
939
- NODE_TO_CONTAINER_G.delete(this.element);
940
- }
941
- if (ELEMENT_TO_REF.get(this.element) === this.ref) {
942
- ELEMENT_TO_REF.set(this.element, this.ref);
943
- }
944
- removeSelectedElement(this.board, this.element);
945
- this.getContainerG().remove();
946
- }
947
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.2.4", ngImport: i0, type: PlaitPluginElementComponent, deps: "invalid", target: i0.ɵɵFactoryTarget.Directive }); }
948
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.2.4", type: PlaitPluginElementComponent, inputs: { context: "context" }, ngImport: i0 }); }
949
- }
950
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.2.4", ngImport: i0, type: PlaitPluginElementComponent, decorators: [{
951
- type: Directive
952
- }], ctorParameters: () => [{ type: undefined }], propDecorators: { context: [{
953
- type: Input
954
- }] } });
955
- const ELEMENT_TO_COMPONENT = new WeakMap();
200
+ };
956
201
 
957
202
  // https://stackoverflow.com/a/6853926/232122
958
203
  function distanceBetweenPointAndSegment(x, y, x1, y1, x2, y2) {
@@ -1246,79 +491,310 @@ function getVectorFromPointAndSlope(x, y, slope) {
1246
491
  if (y < 0) {
1247
492
  vector = [-vector[0], -vector[1]];
1248
493
  }
1249
- return vector;
494
+ return vector;
495
+ }
496
+ /**
497
+ * The DOM likes values to be fixed to 3 decimal places
498
+ */
499
+ function toDomPrecision(v) {
500
+ return +v.toFixed(4);
501
+ }
502
+ function toFixed(v) {
503
+ return +v.toFixed(2);
504
+ }
505
+ /**
506
+ * Whether two numbers numbers a and b are approximately equal.
507
+ *
508
+ * @param a - The first point.
509
+ * @param b - The second point.
510
+ * @public
511
+ */
512
+ function approximately(a, b, precision = 0.000001) {
513
+ return Math.abs(a - b) <= precision;
514
+ }
515
+ // https://medium.com/@steveruiz/find-the-points-where-a-line-segment-intercepts-an-angled-ellipse-in-javascript-typescript-e451524beece
516
+ function getCrossingPointsBetweenEllipseAndSegment(startPoint, endPoint, cx, cy, rx, ry, segment_only = true) {
517
+ // If the ellipse or line segment are empty, return no tValues.
518
+ if (rx === 0 || ry === 0 || (startPoint[0] === endPoint[0] && startPoint[1] === endPoint[1])) {
519
+ return [];
520
+ }
521
+ rx = rx < 0 ? rx : -rx;
522
+ ry = ry < 0 ? ry : -ry;
523
+ startPoint[0] -= cx;
524
+ startPoint[1] -= cy;
525
+ endPoint[0] -= cx;
526
+ endPoint[1] -= cy;
527
+ // Calculate the quadratic parameters.
528
+ var A = ((endPoint[0] - startPoint[0]) * (endPoint[0] - startPoint[0])) / rx / rx +
529
+ ((endPoint[1] - startPoint[1]) * (endPoint[1] - startPoint[1])) / ry / ry;
530
+ var B = (2 * startPoint[0] * (endPoint[0] - startPoint[0])) / rx / rx + (2 * startPoint[1] * (endPoint[1] - startPoint[1])) / ry / ry;
531
+ var C = (startPoint[0] * startPoint[0]) / rx / rx + (startPoint[1] * startPoint[1]) / ry / ry - 1;
532
+ // Make a list of t values (normalized points on the line where intersections occur).
533
+ var tValues = [];
534
+ // Calculate the discriminant.
535
+ var discriminant = B * B - 4 * A * C;
536
+ if (discriminant === 0) {
537
+ // One real solution.
538
+ tValues.push(-B / 2 / A);
539
+ }
540
+ else if (discriminant > 0) {
541
+ // Two real solutions.
542
+ tValues.push((-B + Math.sqrt(discriminant)) / 2 / A);
543
+ tValues.push((-B - Math.sqrt(discriminant)) / 2 / A);
544
+ }
545
+ return (tValues
546
+ // Filter to only points that are on the segment.
547
+ .filter(t => !segment_only || (t >= 0 && t <= 1))
548
+ // Solve for points.
549
+ .map(t => [startPoint[0] + (endPoint[0] - startPoint[0]) * t + cx, startPoint[1] + (endPoint[1] - startPoint[1]) * t + cy]));
550
+ }
551
+
552
+ function isInPlaitBoard(board, x, y) {
553
+ const plaitBoardElement = PlaitBoard.getBoardContainer(board);
554
+ const plaitBoardRect = plaitBoardElement.getBoundingClientRect();
555
+ const distances = distanceBetweenPointAndRectangle(x, y, plaitBoardRect);
556
+ return distances === 0;
557
+ }
558
+ function getRealScrollBarWidth(board) {
559
+ const { hideScrollbar } = board.options;
560
+ let scrollBarWidth = 0;
561
+ if (!hideScrollbar) {
562
+ const viewportContainer = PlaitBoard.getViewportContainer(board);
563
+ scrollBarWidth = viewportContainer.offsetWidth - viewportContainer.clientWidth;
564
+ }
565
+ return scrollBarWidth;
566
+ }
567
+
568
+ /**
569
+ * @license
570
+ * Copyright Google LLC All Rights Reserved.
571
+ *
572
+ * Use of this source code is governed by an MIT-style license that can be
573
+ * found in the LICENSE file at https://angular.io/license
574
+ */
575
+ const MAC_ENTER = 3;
576
+ const BACKSPACE = 8;
577
+ const TAB = 9;
578
+ const NUM_CENTER = 12;
579
+ const ENTER = 13;
580
+ const SHIFT = 16;
581
+ const CONTROL = 17;
582
+ const ALT = 18;
583
+ const PAUSE = 19;
584
+ const CAPS_LOCK = 20;
585
+ const ESCAPE = 27;
586
+ const SPACE = 32;
587
+ const PAGE_UP = 33;
588
+ const PAGE_DOWN = 34;
589
+ const END = 35;
590
+ const HOME = 36;
591
+ const LEFT_ARROW = 37;
592
+ const UP_ARROW = 38;
593
+ const RIGHT_ARROW = 39;
594
+ const DOWN_ARROW = 40;
595
+ const PLUS_SIGN = 43;
596
+ const PRINT_SCREEN = 44;
597
+ const INSERT = 45;
598
+ const DELETE = 46;
599
+ const ZERO = 48;
600
+ const ONE = 49;
601
+ const TWO = 50;
602
+ const THREE = 51;
603
+ const FOUR = 52;
604
+ const FIVE = 53;
605
+ const SIX = 54;
606
+ const SEVEN = 55;
607
+ const EIGHT = 56;
608
+ const NINE = 57;
609
+ const FF_SEMICOLON = 59; // Firefox (Gecko) fires this for semicolon instead of 186
610
+ const FF_EQUALS = 61; // Firefox (Gecko) fires this for equals instead of 187
611
+ const QUESTION_MARK = 63;
612
+ const AT_SIGN = 64;
613
+ const A = 65;
614
+ const B = 66;
615
+ const C = 67;
616
+ const D = 68;
617
+ const E = 69;
618
+ const F = 70;
619
+ const G = 71;
620
+ const H = 72;
621
+ const I = 73;
622
+ const J = 74;
623
+ const K = 75;
624
+ const L = 76;
625
+ const M = 77;
626
+ const N = 78;
627
+ const O = 79;
628
+ const P = 80;
629
+ const Q = 81;
630
+ const R = 82;
631
+ const S = 83;
632
+ const T = 84;
633
+ const U = 85;
634
+ const V = 86;
635
+ const W = 87;
636
+ const X = 88;
637
+ const Y = 89;
638
+ const Z = 90;
639
+ const META = 91; // WIN_KEY_LEFT
640
+ const MAC_WK_CMD_LEFT = 91;
641
+ const MAC_WK_CMD_RIGHT = 93;
642
+ const CONTEXT_MENU = 93;
643
+ const NUMPAD_ZERO = 96;
644
+ const NUMPAD_ONE = 97;
645
+ const NUMPAD_TWO = 98;
646
+ const NUMPAD_THREE = 99;
647
+ const NUMPAD_FOUR = 100;
648
+ const NUMPAD_FIVE = 101;
649
+ const NUMPAD_SIX = 102;
650
+ const NUMPAD_SEVEN = 103;
651
+ const NUMPAD_EIGHT = 104;
652
+ const NUMPAD_NINE = 105;
653
+ const NUMPAD_MULTIPLY = 106;
654
+ const NUMPAD_PLUS = 107;
655
+ const NUMPAD_MINUS = 109;
656
+ const NUMPAD_PERIOD = 110;
657
+ const NUMPAD_DIVIDE = 111;
658
+ const F1 = 112;
659
+ const F2 = 113;
660
+ const F3 = 114;
661
+ const F4 = 115;
662
+ const F5 = 116;
663
+ const F6 = 117;
664
+ const F7 = 118;
665
+ const F8 = 119;
666
+ const F9 = 120;
667
+ const F10 = 121;
668
+ const F11 = 122;
669
+ const F12 = 123;
670
+ const NUM_LOCK = 144;
671
+ const SCROLL_LOCK = 145;
672
+ const FIRST_MEDIA = 166;
673
+ const FF_MINUS = 173;
674
+ const MUTE = 173; // Firefox (Gecko) fires 181 for MUTE
675
+ const VOLUME_DOWN = 174; // Firefox (Gecko) fires 182 for VOLUME_DOWN
676
+ const VOLUME_UP = 175; // Firefox (Gecko) fires 183 for VOLUME_UP
677
+ const FF_MUTE = 181;
678
+ const FF_VOLUME_DOWN = 182;
679
+ const LAST_MEDIA = 183;
680
+ const FF_VOLUME_UP = 183;
681
+ const SEMICOLON = 186; // Firefox (Gecko) fires 59 for SEMICOLON
682
+ const EQUALS = 187; // Firefox (Gecko) fires 61 for EQUALS
683
+ const COMMA = 188;
684
+ const DASH = 189; // Firefox (Gecko) fires 173 for DASH/MINUS
685
+ const PERIOD = 190;
686
+ const SLASH = 191;
687
+ const APOSTROPHE = 192;
688
+ const TILDE = 192;
689
+ const OPEN_SQUARE_BRACKET = 219;
690
+ const BACKSLASH = 220;
691
+ const CLOSE_SQUARE_BRACKET = 221;
692
+ const SINGLE_QUOTE = 222;
693
+ const MAC_META = 224;
694
+
695
+ var ResizeCursorClass;
696
+ (function (ResizeCursorClass) {
697
+ ResizeCursorClass["ew"] = "ew-resize";
698
+ ResizeCursorClass["ns"] = "ns-resize";
699
+ ResizeCursorClass["nesw"] = "nesw-resize";
700
+ ResizeCursorClass["nwse"] = "nwse-resize";
701
+ })(ResizeCursorClass || (ResizeCursorClass = {}));
702
+ var CursorClass;
703
+ (function (CursorClass) {
704
+ CursorClass["crosshair"] = "crosshair";
705
+ })(CursorClass || (CursorClass = {}));
706
+ const RESIZE_CURSORS = [ResizeCursorClass.ns, ResizeCursorClass.nesw, ResizeCursorClass.ew, ResizeCursorClass.nwse];
707
+
708
+ const ATTACHED_ELEMENT_CLASS_NAME = 'plait-board-attached';
709
+ const ACTIVE_STROKE_WIDTH = 1;
710
+ const SNAPPING_STROKE_WIDTH = 2;
711
+ const SELECTION_RECTANGLE_CLASS_NAME = 'selection-rectangle';
712
+
713
+ const HOST_CLASS_NAME = 'plait-board-container';
714
+ const ACTIVE_MOVING_CLASS_NAME = 'active-with-moving';
715
+ const ROTATE_HANDLE_CLASS_NAME = 'rotate-handle';
716
+ const RESIZE_HANDLE_CLASS_NAME = 'resize-handle';
717
+ const SCROLL_BAR_WIDTH = 20;
718
+ const MAX_RADIUS = 16;
719
+ const POINTER_BUTTON = {
720
+ MAIN: 0,
721
+ WHEEL: 1,
722
+ SECONDARY: 2,
723
+ TOUCH: -1
724
+ };
725
+ const PRESS_AND_MOVE_BUFFER = 3;
726
+ const HIT_DISTANCE_BUFFER = 5;
727
+
728
+ const NS = 'http://www.w3.org/2000/svg';
729
+ function createG() {
730
+ const newG = document.createElementNS(NS, 'g');
731
+ return newG;
732
+ }
733
+ function createPath() {
734
+ const newG = document.createElementNS(NS, 'path');
735
+ return newG;
736
+ }
737
+ function createRect(rectangle, options) {
738
+ const rect = document.createElementNS(NS, 'rect');
739
+ rect.setAttribute('x', `${rectangle.x}`);
740
+ rect.setAttribute('y', `${rectangle.y}`);
741
+ rect.setAttribute('width', `${rectangle.width}`);
742
+ rect.setAttribute('height', `${rectangle.height}`);
743
+ for (let key in options) {
744
+ const optionKey = key;
745
+ rect.setAttribute(key, `${options[optionKey]}`);
746
+ }
747
+ return rect;
1250
748
  }
1251
- /**
1252
- * The DOM likes values to be fixed to 3 decimal places
1253
- */
1254
- function toDomPrecision(v) {
1255
- return +v.toFixed(4);
749
+ const setStrokeLinecap = (g, value) => {
750
+ g.setAttribute('stroke-linecap', value);
751
+ };
752
+ const setPathStrokeLinecap = (g, value) => {
753
+ g.querySelectorAll('path').forEach(path => {
754
+ path.setAttribute('stroke-linecap', value);
755
+ });
756
+ };
757
+ function createMask() {
758
+ return document.createElementNS(NS, 'mask');
1256
759
  }
1257
- function toFixed(v) {
1258
- return +v.toFixed(2);
760
+ function createSVG() {
761
+ const svg = document.createElementNS(NS, 'svg');
762
+ return svg;
763
+ }
764
+ function createText(x, y, fill, textContent) {
765
+ var text = document.createElementNS(NS, 'text');
766
+ text.setAttribute('x', `${x}`);
767
+ text.setAttribute('y', `${y}`);
768
+ text.setAttribute('fill', fill);
769
+ text.textContent = textContent;
770
+ return text;
1259
771
  }
1260
772
  /**
1261
- * Whether two numbers numbers a and b are approximately equal.
1262
- *
1263
- * @param a - The first point.
1264
- * @param b - The second point.
1265
- * @public
773
+ * Check if a DOM node is an element node.
1266
774
  */
1267
- function approximately(a, b, precision = 0.000001) {
1268
- return Math.abs(a - b) <= precision;
1269
- }
1270
- // https://medium.com/@steveruiz/find-the-points-where-a-line-segment-intercepts-an-angled-ellipse-in-javascript-typescript-e451524beece
1271
- function getCrossingPointsBetweenEllipseAndSegment(startPoint, endPoint, cx, cy, rx, ry, segment_only = true) {
1272
- // If the ellipse or line segment are empty, return no tValues.
1273
- if (rx === 0 || ry === 0 || (startPoint[0] === endPoint[0] && startPoint[1] === endPoint[1])) {
1274
- return [];
1275
- }
1276
- rx = rx < 0 ? rx : -rx;
1277
- ry = ry < 0 ? ry : -ry;
1278
- startPoint[0] -= cx;
1279
- startPoint[1] -= cy;
1280
- endPoint[0] -= cx;
1281
- endPoint[1] -= cy;
1282
- // Calculate the quadratic parameters.
1283
- var A = ((endPoint[0] - startPoint[0]) * (endPoint[0] - startPoint[0])) / rx / rx +
1284
- ((endPoint[1] - startPoint[1]) * (endPoint[1] - startPoint[1])) / ry / ry;
1285
- var B = (2 * startPoint[0] * (endPoint[0] - startPoint[0])) / rx / rx + (2 * startPoint[1] * (endPoint[1] - startPoint[1])) / ry / ry;
1286
- var C = (startPoint[0] * startPoint[0]) / rx / rx + (startPoint[1] * startPoint[1]) / ry / ry - 1;
1287
- // Make a list of t values (normalized points on the line where intersections occur).
1288
- var tValues = [];
1289
- // Calculate the discriminant.
1290
- var discriminant = B * B - 4 * A * C;
1291
- if (discriminant === 0) {
1292
- // One real solution.
1293
- tValues.push(-B / 2 / A);
1294
- }
1295
- else if (discriminant > 0) {
1296
- // Two real solutions.
1297
- tValues.push((-B + Math.sqrt(discriminant)) / 2 / A);
1298
- tValues.push((-B - Math.sqrt(discriminant)) / 2 / A);
1299
- }
1300
- return (tValues
1301
- // Filter to only points that are on the segment.
1302
- .filter(t => !segment_only || (t >= 0 && t <= 1))
1303
- // Solve for points.
1304
- .map(t => [startPoint[0] + (endPoint[0] - startPoint[0]) * t + cx, startPoint[1] + (endPoint[1] - startPoint[1]) * t + cy]));
1305
- }
1306
-
1307
- function isInPlaitBoard(board, x, y) {
1308
- const plaitBoardElement = PlaitBoard.getBoardContainer(board);
1309
- const plaitBoardRect = plaitBoardElement.getBoundingClientRect();
1310
- const distances = distanceBetweenPointAndRectangle(x, y, plaitBoardRect);
1311
- return distances === 0;
1312
- }
1313
- function getRealScrollBarWidth(board) {
1314
- const { hideScrollbar } = board.options;
1315
- let scrollBarWidth = 0;
1316
- if (!hideScrollbar) {
1317
- const viewportContainer = PlaitBoard.getViewportContainer(board);
1318
- scrollBarWidth = viewportContainer.offsetWidth - viewportContainer.clientWidth;
775
+ const isDOMElement = (value) => {
776
+ return isDOMNode(value) && value.nodeType === 1;
777
+ };
778
+ /**
779
+ * Check if a value is a DOM node.
780
+ */
781
+ const isDOMNode = (value) => {
782
+ return value instanceof window.Node;
783
+ };
784
+ const hasInputOrTextareaTarget = (target) => {
785
+ if (isDOMElement(target)) {
786
+ if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA') {
787
+ return true;
788
+ }
1319
789
  }
1320
- return scrollBarWidth;
1321
- }
790
+ return false;
791
+ };
792
+ const isSecondaryPointer = (event) => {
793
+ return event.button === POINTER_BUTTON.SECONDARY;
794
+ };
795
+ const isMainPointer = (event) => {
796
+ return event.button === POINTER_BUTTON.MAIN;
797
+ };
1322
798
 
1323
799
  function createForeignObject(x, y, width, height) {
1324
800
  var newForeignObject = document.createElementNS(NS, 'foreignObject');
@@ -1593,17 +1069,179 @@ const hotkeys = {
1593
1069
  isUndo: create('undo'),
1594
1070
  isShift: create('shift')
1595
1071
  };
1596
-
1597
- function idCreator(length = 5) {
1598
- // remove numeral
1599
- const $chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz'; /**** Easily confusing characters are removed by default oOLl,9gq,Vv,Uu,I1****/
1600
- const maxPosition = $chars.length;
1601
- let key = '';
1602
- for (let i = 0; i < length; i++) {
1603
- key += $chars.charAt(Math.floor(Math.random() * maxPosition));
1072
+
1073
+ function idCreator(length = 5) {
1074
+ // remove numeral
1075
+ const $chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz'; /**** Easily confusing characters are removed by default oOLl,9gq,Vv,Uu,I1****/
1076
+ const maxPosition = $chars.length;
1077
+ let key = '';
1078
+ for (let i = 0; i < length; i++) {
1079
+ key += $chars.charAt(Math.floor(Math.random() * maxPosition));
1080
+ }
1081
+ return key;
1082
+ }
1083
+
1084
+ function depthFirstRecursion(node, callback, recursion, isReverse) {
1085
+ if (!recursion || recursion(node)) {
1086
+ let children = [];
1087
+ if (node.children) {
1088
+ children = [...node.children];
1089
+ }
1090
+ children = isReverse ? children.reverse() : children;
1091
+ children.forEach(child => {
1092
+ depthFirstRecursion(child, callback, recursion);
1093
+ });
1094
+ }
1095
+ callback(node);
1096
+ }
1097
+ const getIsRecursionFunc = (board) => {
1098
+ return (element) => {
1099
+ if (PlaitBoard.isBoard(element) || board.isRecursion(element)) {
1100
+ return true;
1101
+ }
1102
+ else {
1103
+ return false;
1104
+ }
1105
+ };
1106
+ };
1107
+
1108
+ const SELECTION_BORDER_COLOR = '#6698FF';
1109
+ const SELECTION_FILL_COLOR = '#6698FF25'; // opacity 0.25
1110
+ const Selection = {
1111
+ isCollapsed(selection) {
1112
+ if (selection.anchor[0] == selection.focus[0] && selection.anchor[1] === selection.focus[1]) {
1113
+ return true;
1114
+ }
1115
+ else {
1116
+ return false;
1117
+ }
1118
+ }
1119
+ };
1120
+
1121
+ const sortElements = (board, elements, ascendingOrder = true) => {
1122
+ return [...elements].sort((a, b) => {
1123
+ const pathA = PlaitBoard.findPath(board, a);
1124
+ const pathB = PlaitBoard.findPath(board, b);
1125
+ return ascendingOrder ? pathA[0] - pathB[0] : pathB[0] - pathA[0];
1126
+ });
1127
+ };
1128
+
1129
+ var PlaitPluginKey;
1130
+ (function (PlaitPluginKey) {
1131
+ PlaitPluginKey["withSelection"] = "withSelection";
1132
+ })(PlaitPluginKey || (PlaitPluginKey = {}));
1133
+
1134
+ const getHitElementsBySelection = (board, selection, match = () => true) => {
1135
+ const newSelection = selection || board.selection;
1136
+ const rectangleHitElements = [];
1137
+ if (!newSelection) {
1138
+ return [];
1139
+ }
1140
+ const isCollapsed = Selection.isCollapsed(newSelection);
1141
+ if (isCollapsed) {
1142
+ const hitElement = getHitElementByPoint(board, newSelection.anchor, match);
1143
+ if (hitElement) {
1144
+ return [hitElement];
1145
+ }
1146
+ else {
1147
+ return [];
1148
+ }
1149
+ }
1150
+ depthFirstRecursion(board, node => {
1151
+ if (!PlaitBoard.isBoard(node) && match(node) && board.isRectangleHit(node, newSelection)) {
1152
+ rectangleHitElements.push(node);
1153
+ }
1154
+ }, getIsRecursionFunc(board), true);
1155
+ return rectangleHitElements;
1156
+ };
1157
+ const getHitElementByPoint = (board, point, match = () => true) => {
1158
+ let hitElement = undefined;
1159
+ let hitInsideElement = undefined;
1160
+ depthFirstRecursion(board, node => {
1161
+ if (hitElement) {
1162
+ return;
1163
+ }
1164
+ if (PlaitBoard.isBoard(node) || !match(node) || !PlaitElement.hasMounted(node)) {
1165
+ return;
1166
+ }
1167
+ if (board.isHit(node, point)) {
1168
+ hitElement = node;
1169
+ return;
1170
+ }
1171
+ /**
1172
+ * 需要增加场景测试
1173
+ * hitInsideElement 存的是第一个符合 isInsidePoint 的元素
1174
+ * 当有元素符合 isHit 时结束遍历,并返回 hitElement
1175
+ * 当所有元素都不符合 isHit ,则返回第一个符合 isInsidePoint 的元素
1176
+ * 这样保证最上面的元素优先被探测到;
1177
+ */
1178
+ if (!hitInsideElement && board.isInsidePoint(node, point)) {
1179
+ hitInsideElement = node;
1180
+ }
1181
+ }, getIsRecursionFunc(board), true);
1182
+ return hitElement || hitInsideElement;
1183
+ };
1184
+ const getHitSelectedElements = (board, point) => {
1185
+ const selectedElements = getSelectedElements(board);
1186
+ const targetRectangle = selectedElements.length > 0 && getRectangleByElements(board, selectedElements, false);
1187
+ const isInTargetRectangle = targetRectangle && RectangleClient.isPointInRectangle(targetRectangle, point);
1188
+ if (isInTargetRectangle) {
1189
+ return selectedElements;
1190
+ }
1191
+ else {
1192
+ return [];
1193
+ }
1194
+ };
1195
+ const cacheSelectedElements = (board, selectedElements) => {
1196
+ const sortedElements = sortElements(board, selectedElements);
1197
+ BOARD_TO_SELECTED_ELEMENT.set(board, sortedElements);
1198
+ };
1199
+ const getSelectedElements = (board) => {
1200
+ return BOARD_TO_SELECTED_ELEMENT.get(board) || [];
1201
+ };
1202
+ const addSelectedElement = (board, element) => {
1203
+ let elements = [];
1204
+ if (Array.isArray(element)) {
1205
+ elements.push(...element);
1206
+ }
1207
+ else {
1208
+ elements.push(element);
1209
+ }
1210
+ const selectedElements = getSelectedElements(board);
1211
+ cacheSelectedElements(board, [...selectedElements, ...elements]);
1212
+ };
1213
+ const removeSelectedElement = (board, element, isRemoveChildren = false) => {
1214
+ const selectedElements = getSelectedElements(board);
1215
+ if (selectedElements.includes(element)) {
1216
+ const targetElements = [];
1217
+ if (board.isRecursion(element) && isRemoveChildren) {
1218
+ depthFirstRecursion(element, node => {
1219
+ targetElements.push(node);
1220
+ }, node => board.isRecursion(node));
1221
+ }
1222
+ else {
1223
+ targetElements.push(element);
1224
+ }
1225
+ const newSelectedElements = selectedElements.filter(value => !targetElements.includes(value));
1226
+ cacheSelectedElements(board, newSelectedElements);
1604
1227
  }
1605
- return key;
1606
- }
1228
+ };
1229
+ const clearSelectedElement = (board) => {
1230
+ cacheSelectedElements(board, []);
1231
+ };
1232
+ const isSelectedElement = (board, element) => {
1233
+ const selectedElements = getSelectedElements(board);
1234
+ return !!selectedElements.find(value => value === element);
1235
+ };
1236
+ const temporaryDisableSelection = (board) => {
1237
+ const currentOptions = board.getPluginOptions(PlaitPluginKey.withSelection);
1238
+ board.setPluginOptions(PlaitPluginKey.withSelection, {
1239
+ isDisabledSelect: true
1240
+ });
1241
+ setTimeout(() => {
1242
+ board.setPluginOptions(PlaitPluginKey.withSelection, { ...currentOptions });
1243
+ }, 0);
1244
+ };
1607
1245
 
1608
1246
  /**
1609
1247
  * drawRoundRectangle
@@ -4077,9 +3715,6 @@ const PlaitElement = {
4077
3715
  return false;
4078
3716
  }
4079
3717
  },
4080
- getComponent(value) {
4081
- return ELEMENT_TO_COMPONENT.get(value);
4082
- },
4083
3718
  getElementRef(value) {
4084
3719
  return ELEMENT_TO_REF.get(value);
4085
3720
  },
@@ -4332,6 +3967,11 @@ function getRectangleByElements(board, elements, recursion) {
4332
3967
  };
4333
3968
  }
4334
3969
  }
3970
+ function getBoundingRectangleByElements(board, elements, recursion) {
3971
+ const rectangle = getRectangleByElements(board, elements, recursion);
3972
+ const angle = getSelectionAngle(elements);
3973
+ return getRectangleByAngle(rectangle, angle) || rectangle;
3974
+ }
4335
3975
  function getBoardRectangle(board) {
4336
3976
  return getRectangleByElements(board, board.children, true);
4337
3977
  }
@@ -4399,6 +4039,9 @@ const PlaitBoard = {
4399
4039
  getHost(board) {
4400
4040
  return BOARD_TO_HOST.get(board);
4401
4041
  },
4042
+ getElementLowerHost(board) {
4043
+ return BOARD_TO_ELEMENT_HOST.get(board)?.lowerHost;
4044
+ },
4402
4045
  getElementHost(board) {
4403
4046
  return BOARD_TO_ELEMENT_HOST.get(board)?.host;
4404
4047
  },
@@ -5606,70 +5249,277 @@ const withHotkey = (board) => {
5606
5249
  BoardTransforms.updateZoom(board, board.viewport.zoom - 0.1);
5607
5250
  return;
5608
5251
  }
5609
- if (isHotkey(['mod+0', 'mod+shift+0'], { byKey: true })(event)) {
5610
- event.preventDefault();
5611
- BoardTransforms.updateZoom(board, 1);
5612
- return;
5252
+ if (isHotkey(['mod+0', 'mod+shift+0'], { byKey: true })(event)) {
5253
+ event.preventDefault();
5254
+ BoardTransforms.updateZoom(board, 1);
5255
+ return;
5256
+ }
5257
+ }
5258
+ globalKeyDown(event);
5259
+ };
5260
+ return board;
5261
+ };
5262
+
5263
+ class PlaitContextService {
5264
+ constructor() {
5265
+ this._stable = new Subject();
5266
+ this.uploadingFiles = [];
5267
+ }
5268
+ getUploadingFile(url) {
5269
+ return this.uploadingFiles.find(file => file.url === url);
5270
+ }
5271
+ setUploadingFile(file) {
5272
+ return this.uploadingFiles.push(file);
5273
+ }
5274
+ removeUploadingFile(fileEntry) {
5275
+ this.uploadingFiles = this.uploadingFiles.filter(file => file.url !== fileEntry.url);
5276
+ }
5277
+ onStable() {
5278
+ return this._stable.asObservable();
5279
+ }
5280
+ nextStable() {
5281
+ this._stable.next('');
5282
+ }
5283
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.2.4", ngImport: i0, type: PlaitContextService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
5284
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.2.4", ngImport: i0, type: PlaitContextService }); }
5285
+ }
5286
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.2.4", ngImport: i0, type: PlaitContextService, decorators: [{
5287
+ type: Injectable
5288
+ }] });
5289
+
5290
+ function withRelatedFragment(board) {
5291
+ const { buildFragment } = board;
5292
+ board.buildFragment = (clipboardContext, rectangle, operationType, originData) => {
5293
+ let relatedFragment = board.getRelatedFragment(originData || []);
5294
+ if (relatedFragment) {
5295
+ if (originData?.length) {
5296
+ relatedFragment = relatedFragment.filter(item => !originData.map(element => element.id).includes(item.id));
5297
+ }
5298
+ if (relatedFragment.length) {
5299
+ if (!clipboardContext) {
5300
+ clipboardContext = createClipboardContext(WritableClipboardType.elements, relatedFragment, '');
5301
+ }
5302
+ else {
5303
+ clipboardContext = addClipboardContext(clipboardContext, {
5304
+ text: '',
5305
+ type: WritableClipboardType.elements,
5306
+ elements: relatedFragment
5307
+ });
5308
+ }
5309
+ }
5310
+ }
5311
+ return buildFragment(clipboardContext, rectangle, operationType, originData);
5312
+ };
5313
+ return board;
5314
+ }
5315
+
5316
+ class ListRender {
5317
+ constructor(board, viewContainerRef) {
5318
+ this.board = board;
5319
+ this.viewContainerRef = viewContainerRef;
5320
+ this.children = [];
5321
+ this.componentRefs = [];
5322
+ this.contexts = [];
5323
+ this.differ = null;
5324
+ this.initialized = false;
5325
+ }
5326
+ initialize(children, childrenContext) {
5327
+ this.initialized = true;
5328
+ this.children = children;
5329
+ children.forEach((descendant, index) => {
5330
+ NODE_TO_INDEX.set(descendant, index);
5331
+ NODE_TO_PARENT.set(descendant, childrenContext.parent);
5332
+ const context = getContext(this.board, descendant, index, childrenContext.parent);
5333
+ const componentType = getComponentType(this.board, context);
5334
+ const componentRef = createPluginComponent(componentType, context, this.viewContainerRef, childrenContext);
5335
+ this.componentRefs.push(componentRef);
5336
+ this.contexts.push(context);
5337
+ });
5338
+ const newDiffers = this.viewContainerRef.injector.get(IterableDiffers);
5339
+ this.differ = newDiffers.find(children).create(trackBy);
5340
+ this.differ.diff(children);
5341
+ }
5342
+ update(children, childrenContext) {
5343
+ if (!this.initialized) {
5344
+ this.initialize(children, childrenContext);
5345
+ return;
5346
+ }
5347
+ if (!this.differ) {
5348
+ throw new Error('Exception: Can not find differ ');
5349
+ }
5350
+ const { board, parent } = childrenContext;
5351
+ const diffResult = this.differ.diff(children);
5352
+ if (diffResult) {
5353
+ const newContexts = [];
5354
+ const newComponentRefs = [];
5355
+ let currentIndexForFirstElement = null;
5356
+ diffResult.forEachItem((record) => {
5357
+ NODE_TO_INDEX.set(record.item, record.currentIndex);
5358
+ NODE_TO_PARENT.set(record.item, childrenContext.parent);
5359
+ const previousContext = record.previousIndex === null ? undefined : this.contexts[record.previousIndex];
5360
+ const context = getContext(board, record.item, record.currentIndex, parent, previousContext);
5361
+ if (record.previousIndex === null) {
5362
+ const componentType = getComponentType(board, context);
5363
+ const componentRef = createPluginComponent(componentType, context, this.viewContainerRef, childrenContext);
5364
+ newContexts.push(context);
5365
+ newComponentRefs.push(componentRef);
5366
+ }
5367
+ else {
5368
+ const componentRef = this.componentRefs[record.previousIndex];
5369
+ componentRef.instance.context = context;
5370
+ newComponentRefs.push(componentRef);
5371
+ newContexts.push(context);
5372
+ }
5373
+ // item might has been changed, so need to compare the id
5374
+ if (record.item === this.children[0] || record.item.id === this.children[0]?.id) {
5375
+ currentIndexForFirstElement = record.currentIndex;
5376
+ }
5377
+ });
5378
+ diffResult.forEachOperation(record => {
5379
+ // removed
5380
+ if (record.currentIndex === null) {
5381
+ const componentRef = this.componentRefs[record.previousIndex];
5382
+ componentRef?.destroy();
5383
+ }
5384
+ // moved
5385
+ if (record.previousIndex !== null && record.currentIndex !== null) {
5386
+ mountOnItemMove(record.item, record.currentIndex, childrenContext, currentIndexForFirstElement);
5387
+ }
5388
+ });
5389
+ this.componentRefs = newComponentRefs;
5390
+ this.contexts = newContexts;
5391
+ this.children = children;
5392
+ }
5393
+ else {
5394
+ const newContexts = [];
5395
+ this.children.forEach((element, index) => {
5396
+ NODE_TO_INDEX.set(element, index);
5397
+ NODE_TO_PARENT.set(element, childrenContext.parent);
5398
+ const previousContext = this.contexts[index];
5399
+ const previousComponentRef = this.componentRefs[index];
5400
+ const context = getContext(board, element, index, parent, previousContext);
5401
+ previousComponentRef.instance.context = context;
5402
+ newContexts.push(context);
5403
+ });
5404
+ this.contexts = newContexts;
5405
+ }
5406
+ }
5407
+ destroy() {
5408
+ this.children.forEach((element, index) => {
5409
+ if (this.componentRefs[index]) {
5410
+ this.componentRefs[index].destroy();
5411
+ }
5412
+ });
5413
+ this.componentRefs = [];
5414
+ this.children = [];
5415
+ this.contexts = [];
5416
+ this.initialized = false;
5417
+ this.differ = null;
5418
+ }
5419
+ }
5420
+ const trackBy = (index, element) => {
5421
+ return element.id;
5422
+ };
5423
+ const createPluginComponent = (componentType, context, viewContainerRef, childrenContext) => {
5424
+ const componentRef = viewContainerRef.createComponent(componentType, { injector: viewContainerRef.injector });
5425
+ const instance = componentRef.instance;
5426
+ instance.context = context;
5427
+ componentRef.changeDetectorRef.detectChanges();
5428
+ const g = componentRef.instance.getContainerG();
5429
+ mountElementG(context.index, g, childrenContext);
5430
+ componentRef.instance.initializeListRender();
5431
+ return componentRef;
5432
+ };
5433
+ const getComponentType = (board, context) => {
5434
+ const result = board.drawElement(context);
5435
+ return result;
5436
+ };
5437
+ const getContext = (board, element, index, parent, previousContext) => {
5438
+ let isSelected = isSelectedElement(board, element);
5439
+ const previousElement = previousContext && previousContext.element;
5440
+ if (previousElement && previousElement !== element && isSelectedElement(board, previousElement)) {
5441
+ isSelected = true;
5442
+ removeSelectedElement(board, previousElement);
5443
+ addSelectedElement(board, element);
5444
+ }
5445
+ const context = {
5446
+ element: element,
5447
+ parent: parent,
5448
+ board: board,
5449
+ selected: isSelected,
5450
+ index
5451
+ };
5452
+ return context;
5453
+ };
5454
+ // the g depth of root element:[1]-[2]-[3]-[4]
5455
+ // the g depth of root element and children element(the [2] element has children):
5456
+ // [1]-
5457
+ // [2]([2-1-1][2-1-2][2-1][2-2][2-3-1][2-3-2][2-3][2])-
5458
+ // [3]-
5459
+ // [4]
5460
+ const mountElementG = (index, g, childrenContext,
5461
+ // for moving scene: the current index for first element before moving
5462
+ currentIndexForFirstElement = null) => {
5463
+ const { parent, parentG } = childrenContext;
5464
+ if (PlaitBoard.isBoard(parent)) {
5465
+ if (index > 0) {
5466
+ const previousElement = parent.children[index - 1];
5467
+ const previousContainerG = PlaitElement.getContainerG(previousElement, { suppressThrow: false });
5468
+ previousContainerG.insertAdjacentElement('afterend', g);
5469
+ }
5470
+ else {
5471
+ if (currentIndexForFirstElement !== null) {
5472
+ const firstElement = parent.children[currentIndexForFirstElement];
5473
+ const firstContainerG = firstElement && PlaitElement.getContainerG(firstElement, { suppressThrow: true });
5474
+ if (firstElement && firstContainerG) {
5475
+ parentG.insertBefore(g, firstContainerG);
5476
+ }
5477
+ else {
5478
+ throw new Error('fail to mount container on moving');
5479
+ }
5480
+ }
5481
+ else {
5482
+ parentG.append(g);
5613
5483
  }
5614
5484
  }
5615
- globalKeyDown(event);
5616
- };
5617
- return board;
5618
- };
5619
-
5620
- class PlaitContextService {
5621
- constructor() {
5622
- this._stable = new Subject();
5623
- this.uploadingFiles = [];
5624
- }
5625
- getUploadingFile(url) {
5626
- return this.uploadingFiles.find(file => file.url === url);
5627
- }
5628
- setUploadingFile(file) {
5629
- return this.uploadingFiles.push(file);
5630
- }
5631
- removeUploadingFile(fileEntry) {
5632
- this.uploadingFiles = this.uploadingFiles.filter(file => file.url !== fileEntry.url);
5633
- }
5634
- onStable() {
5635
- return this._stable.asObservable();
5636
- }
5637
- nextStable() {
5638
- this._stable.next('');
5639
5485
  }
5640
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.2.4", ngImport: i0, type: PlaitContextService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
5641
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.2.4", ngImport: i0, type: PlaitContextService }); }
5642
- }
5643
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.2.4", ngImport: i0, type: PlaitContextService, decorators: [{
5644
- type: Injectable
5645
- }] });
5646
-
5647
- function withRelatedFragment(board) {
5648
- const { buildFragment } = board;
5649
- board.buildFragment = (clipboardContext, rectangle, operationType, originData) => {
5650
- let relatedFragment = board.getRelatedFragment(originData || []);
5651
- if (relatedFragment) {
5652
- if (originData?.length) {
5653
- relatedFragment = relatedFragment.filter(item => !originData.map(element => element.id).includes(item.id));
5654
- }
5655
- if (relatedFragment.length) {
5656
- if (!clipboardContext) {
5657
- clipboardContext = createClipboardContext(WritableClipboardType.elements, relatedFragment, '');
5486
+ else {
5487
+ if (index > 0) {
5488
+ const previousElement = parent.children[index - 1];
5489
+ const previousElementG = PlaitElement.getElementG(previousElement);
5490
+ previousElementG.insertAdjacentElement('afterend', g);
5491
+ }
5492
+ else {
5493
+ if (currentIndexForFirstElement) {
5494
+ const nextElement = parent.children[currentIndexForFirstElement];
5495
+ const nextPath = nextElement && PlaitBoard.findPath(childrenContext.board, nextElement);
5496
+ const first = nextPath && PlaitNode.first(childrenContext.board, nextPath);
5497
+ const firstContainerG = first && PlaitElement.getContainerG(first, { suppressThrow: false });
5498
+ if (firstContainerG) {
5499
+ parentG.insertBefore(g, firstContainerG);
5658
5500
  }
5659
5501
  else {
5660
- clipboardContext = addClipboardContext(clipboardContext, {
5661
- text: '',
5662
- type: WritableClipboardType.elements,
5663
- elements: relatedFragment
5664
- });
5502
+ throw new Error('fail to mount container on moving');
5665
5503
  }
5666
5504
  }
5505
+ else {
5506
+ let parentElementG = PlaitElement.getElementG(parent);
5507
+ parentG.insertBefore(g, parentElementG);
5508
+ }
5667
5509
  }
5668
- return buildFragment(clipboardContext, rectangle, operationType, originData);
5669
- };
5670
- return board;
5671
- }
5510
+ }
5511
+ };
5512
+ const mountOnItemMove = (element, index, childrenContext, currentIndexForFirstElement) => {
5513
+ const containerG = PlaitElement.getContainerG(element, { suppressThrow: false });
5514
+ mountElementG(index, containerG, childrenContext, currentIndexForFirstElement);
5515
+ if (element.children && !PlaitElement.isRootElement(element)) {
5516
+ element.children.forEach((child, index) => {
5517
+ mountOnItemMove(child, index, { ...childrenContext, parent: element }, null);
5518
+ });
5519
+ }
5520
+ };
5672
5521
 
5522
+ const ElementLowerHostClass = 'element-lower-host';
5673
5523
  const ElementHostClass = 'element-host';
5674
5524
  const ElementUpperHostClass = 'element-upper-host';
5675
5525
  const ElementActiveHostClass = 'element-active-host';
@@ -5721,6 +5571,7 @@ class PlaitBoardComponent {
5721
5571
  };
5722
5572
  }
5723
5573
  ngOnInit() {
5574
+ const elementLowerHost = this.host.querySelector(`.${ElementLowerHostClass}`);
5724
5575
  const elementHost = this.host.querySelector(`.${ElementHostClass}`);
5725
5576
  const elementUpperHost = this.host.querySelector(`.${ElementUpperHostClass}`);
5726
5577
  const elementActiveHost = this.host.querySelector(`.${ElementActiveHostClass}`);
@@ -5745,6 +5596,7 @@ class PlaitBoardComponent {
5745
5596
  BOARD_TO_HOST.set(this.board, this.host);
5746
5597
  IS_BOARD_ALIVE.set(this.board, true);
5747
5598
  BOARD_TO_ELEMENT_HOST.set(this.board, {
5599
+ lowerHost: elementLowerHost,
5748
5600
  host: elementHost,
5749
5601
  upperHost: elementUpperHost,
5750
5602
  activeHost: elementActiveHost,
@@ -6024,6 +5876,7 @@ class PlaitBoardComponent {
6024
5876
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.2.4", type: PlaitBoardComponent, isStandalone: true, selector: "plait-board", inputs: { plaitValue: "plaitValue", plaitViewport: "plaitViewport", plaitPlugins: "plaitPlugins", plaitOptions: "plaitOptions", plaitTheme: "plaitTheme" }, outputs: { plaitChange: "plaitChange", plaitBoardInitialized: "plaitBoardInitialized" }, host: { properties: { "class": "this.hostClass", "class.readonly": "this.readonly", "class.focused": "this.isFocused", "class.disabled-scroll": "this.disabledScrollOnNonFocus" } }, providers: [PlaitContextService], queries: [{ propertyName: "islands", predicate: PlaitIslandBaseComponent, descendants: true }], viewQueries: [{ propertyName: "svg", first: true, predicate: ["svg"], descendants: true, static: true }, { propertyName: "viewportContainer", first: true, predicate: ["viewportContainer"], descendants: true, read: ElementRef, static: true }], usesOnChanges: true, ngImport: i0, template: `
6025
5877
  <div class="viewport-container" #viewportContainer>
6026
5878
  <svg #svg width="100%" height="100%" style="position: relative;" class="board-host-svg">
5879
+ <g class="element-lower-host"></g>
6027
5880
  <g class="element-host"></g>
6028
5881
  <g class="element-upper-host"></g>
6029
5882
  <g class="element-active-host"></g>
@@ -6039,6 +5892,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.2.4", ngImpor
6039
5892
  template: `
6040
5893
  <div class="viewport-container" #viewportContainer>
6041
5894
  <svg #svg width="100%" height="100%" style="position: relative;" class="board-host-svg">
5895
+ <g class="element-lower-host"></g>
6042
5896
  <g class="element-host"></g>
6043
5897
  <g class="element-upper-host"></g>
6044
5898
  <g class="element-active-host"></g>
@@ -6087,6 +5941,155 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.2.4", ngImpor
6087
5941
  args: [PlaitIslandBaseComponent, { descendants: true }]
6088
5942
  }] } });
6089
5943
 
5944
+ function hasBeforeContextChange(value) {
5945
+ if (value.beforeContextChange) {
5946
+ return true;
5947
+ }
5948
+ return false;
5949
+ }
5950
+ function hasOnContextChanged(value) {
5951
+ if (value.onContextChanged) {
5952
+ return true;
5953
+ }
5954
+ return false;
5955
+ }
5956
+
5957
+ class PlaitPluginElementComponent {
5958
+ get hasChildren() {
5959
+ return !!this.element.children;
5960
+ }
5961
+ set context(value) {
5962
+ if (hasBeforeContextChange(this)) {
5963
+ this.beforeContextChange(value);
5964
+ }
5965
+ const previousContext = this._context;
5966
+ this._context = value;
5967
+ if (this.initialized) {
5968
+ const elementG = this.getElementG();
5969
+ const containerG = this.getContainerG();
5970
+ NODE_TO_G.set(this.element, elementG);
5971
+ NODE_TO_CONTAINER_G.set(this.element, containerG);
5972
+ ELEMENT_TO_REF.set(this.element, this.ref);
5973
+ this.updateListRender();
5974
+ this.cdr.markForCheck();
5975
+ if (hasOnContextChanged(this)) {
5976
+ this.onContextChanged(value, previousContext);
5977
+ }
5978
+ }
5979
+ else {
5980
+ if (PlaitElement.isRootElement(this.element) && this.hasChildren) {
5981
+ this._g = createG();
5982
+ this._containerG = createG();
5983
+ this._containerG.append(this._g);
5984
+ }
5985
+ else {
5986
+ this._g = createG();
5987
+ this._containerG = this._g;
5988
+ }
5989
+ NODE_TO_G.set(this.element, this._g);
5990
+ NODE_TO_CONTAINER_G.set(this.element, this._containerG);
5991
+ ELEMENT_TO_REF.set(this.element, this.ref);
5992
+ }
5993
+ }
5994
+ get context() {
5995
+ return this._context;
5996
+ }
5997
+ get element() {
5998
+ return this.context && this.context.element;
5999
+ }
6000
+ get board() {
6001
+ return this.context && this.context.board;
6002
+ }
6003
+ get selected() {
6004
+ return this.context && this.context.selected;
6005
+ }
6006
+ getContainerG() {
6007
+ return this._containerG;
6008
+ }
6009
+ getElementG() {
6010
+ return this._g;
6011
+ }
6012
+ constructor(ref) {
6013
+ this.ref = ref;
6014
+ this.viewContainerRef = inject(ViewContainerRef);
6015
+ this.cdr = inject(ChangeDetectorRef);
6016
+ this.initialized = false;
6017
+ }
6018
+ ngOnInit() {
6019
+ if (this.element.type) {
6020
+ this.getContainerG().setAttribute(`plait-${this.element.type}`, 'true');
6021
+ }
6022
+ if (this.hasChildren) {
6023
+ if (PlaitElement.isRootElement(this.element)) {
6024
+ this._rootContainerG = this._containerG;
6025
+ }
6026
+ else {
6027
+ const path = PlaitBoard.findPath(this.board, this.element);
6028
+ const rootNode = PlaitNode.get(this.board, path.slice(0, 1));
6029
+ this._rootContainerG = PlaitElement.getContainerG(rootNode, { suppressThrow: false });
6030
+ }
6031
+ }
6032
+ this.getContainerG().setAttribute('plait-data-id', this.element.id);
6033
+ this.initialized = true;
6034
+ }
6035
+ initializeListRender() {
6036
+ if (this.hasChildren) {
6037
+ this.listRender = new ListRender(this.board, this.viewContainerRef);
6038
+ if (this.board.isExpanded(this.element)) {
6039
+ this.listRender.initialize(this.element.children, this.initializeChildrenContext());
6040
+ }
6041
+ }
6042
+ }
6043
+ getRef() {
6044
+ return this.ref;
6045
+ }
6046
+ updateListRender() {
6047
+ if (this.hasChildren) {
6048
+ if (!this.listRender) {
6049
+ throw new Error('incorrectly initialize list render');
6050
+ }
6051
+ if (this.board.isExpanded(this.element)) {
6052
+ this.listRender.update(this.element.children, this.initializeChildrenContext());
6053
+ }
6054
+ else {
6055
+ if (this.listRender.initialized) {
6056
+ this.listRender.destroy();
6057
+ }
6058
+ }
6059
+ }
6060
+ }
6061
+ initializeChildrenContext() {
6062
+ if (!this._rootContainerG) {
6063
+ throw new Error('can not resolve root container g');
6064
+ }
6065
+ return {
6066
+ board: this.board,
6067
+ parent: this.element,
6068
+ parentG: this._rootContainerG
6069
+ };
6070
+ }
6071
+ ngOnDestroy() {
6072
+ if (NODE_TO_G.get(this.element) === this._g) {
6073
+ NODE_TO_G.delete(this.element);
6074
+ }
6075
+ if (NODE_TO_CONTAINER_G.get(this.element) === this._containerG) {
6076
+ NODE_TO_CONTAINER_G.delete(this.element);
6077
+ }
6078
+ if (ELEMENT_TO_REF.get(this.element) === this.ref) {
6079
+ ELEMENT_TO_REF.set(this.element, this.ref);
6080
+ }
6081
+ removeSelectedElement(this.board, this.element);
6082
+ this.getContainerG().remove();
6083
+ }
6084
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.2.4", ngImport: i0, type: PlaitPluginElementComponent, deps: "invalid", target: i0.ɵɵFactoryTarget.Directive }); }
6085
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.2.4", type: PlaitPluginElementComponent, inputs: { context: "context" }, ngImport: i0 }); }
6086
+ }
6087
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.2.4", ngImport: i0, type: PlaitPluginElementComponent, decorators: [{
6088
+ type: Directive
6089
+ }], ctorParameters: () => [{ type: undefined }], propDecorators: { context: [{
6090
+ type: Input
6091
+ }] } });
6092
+
6090
6093
  /**
6091
6094
  * 1.create board instance
6092
6095
  * 2.build fake node weak map
@@ -6345,5 +6348,5 @@ const isDebug = (key) => {
6345
6348
  * Generated bundle index. Do not edit.
6346
6349
  */
6347
6350
 
6348
- export { A, ACTIVE_MOVING_CLASS_NAME, ACTIVE_STROKE_WIDTH, ALT, APOSTROPHE, ATTACHED_ELEMENT_CLASS_NAME, AT_SIGN, B, BACKSLASH, BACKSPACE, BOARD_TO_AFTER_CHANGE, BOARD_TO_COMPONENT, BOARD_TO_ELEMENT_HOST, BOARD_TO_HOST, BOARD_TO_IS_SELECTION_MOVING, BOARD_TO_MOVING_ELEMENT, BOARD_TO_MOVING_POINT, BOARD_TO_MOVING_POINT_IN_BOARD, BOARD_TO_ON_CHANGE, BOARD_TO_ROUGH_SVG, BOARD_TO_SELECTED_ELEMENT, BOARD_TO_TEMPORARY_ELEMENTS, BOARD_TO_TOUCH_REF, BOARD_TO_VIEWPORT_ORIGINATION, BoardTransforms, C, CAPS_LOCK, CLOSE_SQUARE_BRACKET, COMMA, CONTEXT_MENU, CONTROL, ColorfulThemeColor, CoreTransforms, CursorClass, D, DASH, DELETE, DOWN_ARROW, DarkThemeColor, DebugGenerator, DefaultThemeColor, Direction, E, EIGHT, ELEMENT_TO_COMPONENT, ELEMENT_TO_REF, 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_ALIVE, IS_BOARD_CACHE, IS_CHROME, IS_CHROME_LEGACY, IS_DRAGGING, IS_EDGE_LEGACY, IS_FIREFOX, IS_IOS, IS_MAC, IS_SAFARI, IS_TEXT_EDITABLE, J, K, L, LAST_MEDIA, LEFT_ARROW, M, MAC_ENTER, MAC_META, MAC_WK_CMD_LEFT, MAC_WK_CMD_RIGHT, MAX_RADIUS, MERGING, META, MUTE, N, NINE, NODE_TO_CONTAINER_G, NODE_TO_G, NODE_TO_INDEX, NODE_TO_PARENT, NS, NUMPAD_DIVIDE, NUMPAD_EIGHT, NUMPAD_FIVE, NUMPAD_FOUR, NUMPAD_MINUS, NUMPAD_MULTIPLY, NUMPAD_NINE, NUMPAD_ONE, NUMPAD_PERIOD, NUMPAD_PLUS, NUMPAD_SEVEN, NUMPAD_SIX, NUMPAD_THREE, NUMPAD_TWO, NUMPAD_ZERO, NUM_CENTER, NUM_LOCK, O, ONE, OPEN_SQUARE_BRACKET, P, PAGE_DOWN, PAGE_UP, PATH_REFS, PAUSE, PERIOD, PLUS_SIGN, POINTER_BUTTON, PRESS_AND_MOVE_BUFFER, PRINT_SCREEN, Path, PlaitBoard, PlaitBoardComponent, PlaitContextService, PlaitElement, PlaitGroupElement, PlaitHistoryBoard, PlaitIslandBaseComponent, PlaitIslandPopoverBaseComponent, PlaitNode, PlaitOperation, PlaitPluginElementComponent, PlaitPluginKey, PlaitPointerType, Point, Q, QUESTION_MARK, R, RESIZE_CURSORS, RESIZE_HANDLE_CLASS_NAME, RIGHT_ARROW, ROTATE_HANDLE_CLASS_NAME, RectangleClient, ResizeCursorClass, RetroThemeColor, RgbaToHEX, S, SAVING, SCROLL_BAR_WIDTH, SCROLL_LOCK, SELECTION_BORDER_COLOR, SELECTION_FILL_COLOR, SELECTION_RECTANGLE_CLASS_NAME, SEMICOLON, SEVEN, SHIFT, SINGLE_QUOTE, SIX, SLASH, SNAPPING_STROKE_WIDTH, SNAP_TOLERANCE, SPACE, Selection, SoftThemeColor, StarryThemeColor, T, TAB, THREE, TILDE, TWO, ThemeColorMode, ThemeColors, Transforms, U, UP_ARROW, V, VOLUME_DOWN, VOLUME_UP, Viewport, W, WritableClipboardOperationType, WritableClipboardType, X, Y, Z, ZERO, addClipboardContext, addSelectedElement, approximately, arrowPoints, buildPlaitHtml, cacheMovingElements, cacheSelectedElements, cacheSelectedElementsWithGroup, cacheSelectedElementsWithGroupOnShift, calcNewViewBox, canAddGroup, canRemoveGroup, canSetZIndex, catmullRomFitting, clampZoomLevel, clearNodeWeakMap, clearSelectedElement, clearSelectionMoving, clearViewportOrigination, createClipboardContext, createDebugGenerator, createFakeEvent, createForeignObject, createG, createGroup, createGroupRectangleG, createKeyboardEvent, createMask, createModModifierKeys, createMouseEvent, createPath, createPointerEvent, createRect, createSVG, createTestingBoard, createText, createTouchEvent, debounce, degreesToRadians, deleteFragment, deleteTemporaryElements, depthFirstRecursion, distanceBetweenPointAndPoint, distanceBetweenPointAndRectangle, distanceBetweenPointAndSegment, distanceBetweenPointAndSegments, downloadImage, drawArrow, drawBezierPath, drawCircle, drawDashedLines, drawEntireActiveRectangleG, drawLine, drawLinearPath, drawPendingNodesG, drawPointSnapLines, drawRectangle, drawRoundRectangle, drawSolidLines, duplicateElements, fakeNodeWeakMap, filterSelectedGroups, findElements, findIndex, findLastIndex, getAllElementsInGroup, getAllMoveOptions, getAngleBetweenPoints, getAngleByElement, getBarPoint, getBoardRectangle, getClipboardData, getClipboardFromHtml, getCrossingPointsBetweenEllipseAndSegment, getDataTransferClipboard, getDataTransferClipboardText, getEditingGroup, getElementById, getElementHostBBox, getElementsInGroup, getElementsInGroupByElement, getElementsIndices, getEllipseTangentSlope, getGroupByElement, getHighestGroup, getHighestIndexOfElement, getHighestSelectedElements, getHighestSelectedGroup, getHighestSelectedGroups, getHitElementByPoint, getHitElementsBySelection, getHitSelectedElements, getIsRecursionFunc, getMinPointDelta, getMovingElements, getNearestDelta, getNearestPointBetweenPointAndEllipse, getNearestPointBetweenPointAndSegment, getNearestPointBetweenPointAndSegments, getNearestPointRectangle, getOffsetAfterRotate, getOneMoveOptions, getProbablySupportsClipboardRead, getProbablySupportsClipboardWrite, getProbablySupportsClipboardWriteText, getRealScrollBarWidth, getRectangleByAngle, getRectangleByElements, getRectangleByGroup, getRotatedBoundingRectangle, getSelectedElements, getSelectedGroups, getSelectedIsolatedElements, getSelectedIsolatedElementsCanAddToGroup, getSelectedTargetElements, getSelectionAngle, getSnapRectangles, getTemporaryElements, getTemporaryRef, getTripleAxis, getValidElements, getVectorFromPointAndSlope, getViewBox, getViewBoxCenterPoint, getViewportContainerRect, getViewportOrigination, handleTouchTarget, hasBeforeContextChange, hasInputOrTextareaTarget, hasOnBoardChange, hasOnContextChanged, hasSameAngle, hasSelectedElementsInSameGroup, hasValidAngle, hotkeys, idCreator, initializeViewBox, initializeViewportContainer, initializeViewportOffset, inverse, isAxisChangedByAngle, isContextmenu, isDOMElement, isDOMNode, isDebug, isDragging, isFromScrolling, isFromViewportChange, isHandleSelection, isInPlaitBoard, isIndicesContinuous, isLineHitLine, isMainPointer, isMovingElements, isNullOrUndefined, isPointInEllipse, isPointInPolygon, isPointInRoundRectangle, isPolylineHitRectangle, isPreventTouchMove, isSecondaryPointer, isSelectedAllElementsInGroup, isSelectedElement, isSelectedElementOrGroup, isSelectionMoving, isSetSelectionOperation, isSetViewportOperation, isSnapPoint, moveElementsToNewPath, moveElementsToNewPathAfterAddGroup, nonGroupInHighestSelectedElements, normalizeAngle, normalizePoint, preventTouchMove, radiansToDegrees, removeMovingElements, removeSelectedElement, rotate, rotateAntiPointsByElement, rotateElements, rotatePoints, rotatePointsByElement, rotatedDataPoints, scrollToRectangle, setAngleForG, setClipboardData, setDataTransferClipboard, setDataTransferClipboardText, setDragging, setFragment, setIsFromScrolling, setIsFromViewportChange, setPathStrokeLinecap, setSVGViewBox, setSelectedElementsWithGroup, setSelectionMoving, setStrokeLinecap, shouldClear, shouldMerge, shouldSave, sortElements, stripHtml, temporaryDisableSelection, throttleRAF, toDomPrecision, toFixed, toHostPoint, toHostPointFromViewBoxPoint, toImage, toScreenPointFromHostPoint, toViewBoxPoint, toViewBoxPoints, uniqueById, updateForeignObject, updateForeignObjectWidth, updatePoints, updateViewportByScrolling, updateViewportContainerScroll, updateViewportOffset, updateViewportOrigination, withArrowMoving, withMoving, withOptions, withSelection };
6351
+ export { A, ACTIVE_MOVING_CLASS_NAME, ACTIVE_STROKE_WIDTH, ALT, APOSTROPHE, ATTACHED_ELEMENT_CLASS_NAME, AT_SIGN, B, BACKSLASH, BACKSPACE, BOARD_TO_AFTER_CHANGE, BOARD_TO_COMPONENT, BOARD_TO_ELEMENT_HOST, BOARD_TO_HOST, BOARD_TO_IS_SELECTION_MOVING, BOARD_TO_MOVING_ELEMENT, BOARD_TO_MOVING_POINT, BOARD_TO_MOVING_POINT_IN_BOARD, BOARD_TO_ON_CHANGE, BOARD_TO_ROUGH_SVG, BOARD_TO_SELECTED_ELEMENT, BOARD_TO_TEMPORARY_ELEMENTS, BOARD_TO_TOUCH_REF, BOARD_TO_VIEWPORT_ORIGINATION, BoardTransforms, C, CAPS_LOCK, CLOSE_SQUARE_BRACKET, COMMA, CONTEXT_MENU, CONTROL, ColorfulThemeColor, CoreTransforms, CursorClass, D, DASH, DELETE, DOWN_ARROW, DarkThemeColor, DebugGenerator, DefaultThemeColor, Direction, E, EIGHT, ELEMENT_TO_REF, END, ENTER, EQUALS, ESCAPE, F, F1, F10, F11, F12, F2, F3, F4, F5, F6, F7, F8, F9, FF_EQUALS, FF_MINUS, FF_MUTE, FF_SEMICOLON, FF_VOLUME_DOWN, FF_VOLUME_UP, FIRST_MEDIA, FIVE, FLUSHING, FOUR, G, H, HIT_DISTANCE_BUFFER, HOME, HOST_CLASS_NAME, I, INSERT, IS_APPLE, IS_BOARD_ALIVE, IS_BOARD_CACHE, IS_CHROME, IS_CHROME_LEGACY, IS_DRAGGING, IS_EDGE_LEGACY, IS_FIREFOX, IS_IOS, IS_MAC, IS_SAFARI, IS_TEXT_EDITABLE, J, K, L, LAST_MEDIA, LEFT_ARROW, M, MAC_ENTER, MAC_META, MAC_WK_CMD_LEFT, MAC_WK_CMD_RIGHT, MAX_RADIUS, MERGING, META, MUTE, N, NINE, NODE_TO_CONTAINER_G, NODE_TO_G, NODE_TO_INDEX, NODE_TO_PARENT, NS, NUMPAD_DIVIDE, NUMPAD_EIGHT, NUMPAD_FIVE, NUMPAD_FOUR, NUMPAD_MINUS, NUMPAD_MULTIPLY, NUMPAD_NINE, NUMPAD_ONE, NUMPAD_PERIOD, NUMPAD_PLUS, NUMPAD_SEVEN, NUMPAD_SIX, NUMPAD_THREE, NUMPAD_TWO, NUMPAD_ZERO, NUM_CENTER, NUM_LOCK, O, ONE, OPEN_SQUARE_BRACKET, P, PAGE_DOWN, PAGE_UP, PATH_REFS, PAUSE, PERIOD, PLUS_SIGN, POINTER_BUTTON, PRESS_AND_MOVE_BUFFER, PRINT_SCREEN, Path, PlaitBoard, PlaitBoardComponent, PlaitContextService, PlaitElement, PlaitGroupElement, PlaitHistoryBoard, PlaitIslandBaseComponent, PlaitIslandPopoverBaseComponent, PlaitNode, PlaitOperation, PlaitPluginElementComponent, PlaitPluginKey, PlaitPointerType, Point, Q, QUESTION_MARK, R, RESIZE_CURSORS, RESIZE_HANDLE_CLASS_NAME, RIGHT_ARROW, ROTATE_HANDLE_CLASS_NAME, RectangleClient, ResizeCursorClass, RetroThemeColor, RgbaToHEX, S, SAVING, SCROLL_BAR_WIDTH, SCROLL_LOCK, SELECTION_BORDER_COLOR, SELECTION_FILL_COLOR, SELECTION_RECTANGLE_CLASS_NAME, SEMICOLON, SEVEN, SHIFT, SINGLE_QUOTE, SIX, SLASH, SNAPPING_STROKE_WIDTH, SNAP_TOLERANCE, SPACE, Selection, SoftThemeColor, StarryThemeColor, T, TAB, THREE, TILDE, TWO, ThemeColorMode, ThemeColors, Transforms, U, UP_ARROW, V, VOLUME_DOWN, VOLUME_UP, Viewport, W, WritableClipboardOperationType, WritableClipboardType, X, Y, Z, ZERO, addClipboardContext, addSelectedElement, approximately, arrowPoints, buildPlaitHtml, cacheMovingElements, cacheSelectedElements, cacheSelectedElementsWithGroup, cacheSelectedElementsWithGroupOnShift, calcNewViewBox, canAddGroup, canRemoveGroup, canSetZIndex, catmullRomFitting, clampZoomLevel, clearNodeWeakMap, clearSelectedElement, clearSelectionMoving, clearViewportOrigination, createClipboardContext, createDebugGenerator, createFakeEvent, createForeignObject, createG, createGroup, createGroupRectangleG, createKeyboardEvent, createMask, createModModifierKeys, createMouseEvent, createPath, createPointerEvent, createRect, createSVG, createTestingBoard, createText, createTouchEvent, debounce, degreesToRadians, deleteFragment, deleteTemporaryElements, depthFirstRecursion, distanceBetweenPointAndPoint, distanceBetweenPointAndRectangle, distanceBetweenPointAndSegment, distanceBetweenPointAndSegments, downloadImage, drawArrow, drawBezierPath, drawCircle, drawDashedLines, drawEntireActiveRectangleG, drawLine, drawLinearPath, drawPendingNodesG, drawPointSnapLines, drawRectangle, drawRoundRectangle, drawSolidLines, duplicateElements, fakeNodeWeakMap, filterSelectedGroups, findElements, findIndex, findLastIndex, getAllElementsInGroup, getAllMoveOptions, getAngleBetweenPoints, getAngleByElement, getBarPoint, getBoardRectangle, getBoundingRectangleByElements, getClipboardData, getClipboardFromHtml, getCrossingPointsBetweenEllipseAndSegment, getDataTransferClipboard, getDataTransferClipboardText, getEditingGroup, getElementById, getElementHostBBox, getElementsInGroup, getElementsInGroupByElement, getElementsIndices, getEllipseTangentSlope, getGroupByElement, getHighestGroup, getHighestIndexOfElement, getHighestSelectedElements, getHighestSelectedGroup, getHighestSelectedGroups, getHitElementByPoint, getHitElementsBySelection, getHitSelectedElements, getIsRecursionFunc, getMinPointDelta, getMovingElements, getNearestDelta, getNearestPointBetweenPointAndEllipse, getNearestPointBetweenPointAndSegment, getNearestPointBetweenPointAndSegments, getNearestPointRectangle, getOffsetAfterRotate, getOneMoveOptions, getProbablySupportsClipboardRead, getProbablySupportsClipboardWrite, getProbablySupportsClipboardWriteText, getRealScrollBarWidth, getRectangleByAngle, getRectangleByElements, getRectangleByGroup, getRotatedBoundingRectangle, getSelectedElements, getSelectedGroups, getSelectedIsolatedElements, getSelectedIsolatedElementsCanAddToGroup, getSelectedTargetElements, getSelectionAngle, getSnapRectangles, getTemporaryElements, getTemporaryRef, getTripleAxis, getValidElements, getVectorFromPointAndSlope, getViewBox, getViewBoxCenterPoint, getViewportContainerRect, getViewportOrigination, handleTouchTarget, hasBeforeContextChange, hasInputOrTextareaTarget, hasOnBoardChange, hasOnContextChanged, hasSameAngle, hasSelectedElementsInSameGroup, hasValidAngle, hotkeys, idCreator, initializeViewBox, initializeViewportContainer, initializeViewportOffset, inverse, isAxisChangedByAngle, isContextmenu, isDOMElement, isDOMNode, isDebug, isDragging, isFromScrolling, isFromViewportChange, isHandleSelection, isInPlaitBoard, isIndicesContinuous, isLineHitLine, isMainPointer, isMovingElements, isNullOrUndefined, isPointInEllipse, isPointInPolygon, isPointInRoundRectangle, isPolylineHitRectangle, isPreventTouchMove, isSecondaryPointer, isSelectedAllElementsInGroup, isSelectedElement, isSelectedElementOrGroup, isSelectionMoving, isSetSelectionOperation, isSetViewportOperation, isSnapPoint, moveElementsToNewPath, moveElementsToNewPathAfterAddGroup, nonGroupInHighestSelectedElements, normalizeAngle, normalizePoint, preventTouchMove, radiansToDegrees, removeMovingElements, removeSelectedElement, rotate, rotateAntiPointsByElement, rotateElements, rotatePoints, rotatePointsByElement, rotatedDataPoints, scrollToRectangle, setAngleForG, setClipboardData, setDataTransferClipboard, setDataTransferClipboardText, setDragging, setFragment, setIsFromScrolling, setIsFromViewportChange, setPathStrokeLinecap, setSVGViewBox, setSelectedElementsWithGroup, setSelectionMoving, setStrokeLinecap, shouldClear, shouldMerge, shouldSave, sortElements, stripHtml, temporaryDisableSelection, throttleRAF, toDomPrecision, toFixed, toHostPoint, toHostPointFromViewBoxPoint, toImage, toScreenPointFromHostPoint, toViewBoxPoint, toViewBoxPoints, uniqueById, updateForeignObject, updateForeignObjectWidth, updatePoints, updateViewportByScrolling, updateViewportContainerScroll, updateViewportOffset, updateViewportOrigination, withArrowMoving, withMoving, withOptions, withSelection };
6349
6352
  //# sourceMappingURL=plait-core.mjs.map