@plait/core 0.0.14 → 0.0.18

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.
@@ -4,9 +4,9 @@ import produce, { createDraft, finishDraft, isDraft } from 'immer';
4
4
  import { Subject, fromEvent } from 'rxjs';
5
5
  import { takeUntil, filter } from 'rxjs/operators';
6
6
  import rough from 'roughjs/bin/rough';
7
+ import { isKeyHotkey, isHotkey } from 'is-hotkey';
7
8
  import * as i2 from '@angular/common';
8
9
  import { BrowserModule } from '@angular/platform-browser';
9
- import { isKeyHotkey } from 'is-hotkey';
10
10
 
11
11
  // record richtext type status
12
12
  const FLUSHING = new WeakMap();
@@ -341,7 +341,8 @@ function setNode(board, props, path) {
341
341
  board.apply(operation);
342
342
  }
343
343
  function removeNode(board, path) {
344
- const operation = { type: 'remove_node', path };
344
+ const node = PlaitNode.get(board, path);
345
+ const operation = { type: 'remove_node', path, node };
345
346
  board.apply(operation);
346
347
  }
347
348
  function moveNode(board, path, newPath) {
@@ -390,10 +391,16 @@ function createBoard(host, children, options) {
390
391
  },
391
392
  children,
392
393
  operations: [],
394
+ history: {
395
+ redos: [],
396
+ undos: []
397
+ },
393
398
  selection: null,
394
399
  cursor: BaseCursorStatus.select,
395
400
  readonly: options.readonly,
396
401
  allowClearBoard: options.allowClearBoard,
402
+ undo: () => { },
403
+ redo: () => { },
397
404
  apply: (operation) => {
398
405
  board.operations.push(operation);
399
406
  Transforms.transform(board, operation);
@@ -534,8 +541,372 @@ function withSelection(board) {
534
541
  const isSetViewportOperation = (value) => {
535
542
  return value.type === 'set_viewport';
536
543
  };
544
+ const inverse = (op) => {
545
+ switch (op.type) {
546
+ case 'insert_node': {
547
+ return Object.assign(Object.assign({}, op), { type: 'remove_node' });
548
+ }
549
+ case 'remove_node': {
550
+ return Object.assign(Object.assign({}, op), { type: 'insert_node' });
551
+ }
552
+ case 'move_node': {
553
+ const { newPath, path } = op;
554
+ // PERF: in this case the move operation is a no-op anyways.
555
+ if (Path.equals(newPath, path)) {
556
+ return op;
557
+ }
558
+ // If the move happens completely within a single parent the path and
559
+ // newPath are stable with respect to each other.
560
+ if (Path.isSibling(path, newPath)) {
561
+ return Object.assign(Object.assign({}, op), { path: newPath, newPath: path });
562
+ }
563
+ // If the move does not happen within a single parent it is possible
564
+ // for the move to impact the true path to the location where the node
565
+ // was removed from and where it was inserted. We have to adjust for this
566
+ // and find the original path. We can accomplish this (only in non-sibling)
567
+ // moves by looking at the impact of the move operation on the node
568
+ // after the original move path.
569
+ const inversePath = Path.transform(path, op);
570
+ const inverseNewPath = Path.transform(Path.next(path), op);
571
+ return Object.assign(Object.assign({}, op), { path: inversePath, newPath: inverseNewPath });
572
+ }
573
+ case 'set_node': {
574
+ const { properties, newProperties } = op;
575
+ return Object.assign(Object.assign({}, op), { properties: newProperties, newProperties: properties });
576
+ }
577
+ case 'set_selection': {
578
+ const { properties, newProperties } = op;
579
+ if (properties == null) {
580
+ return Object.assign(Object.assign({}, op), { properties: newProperties, newProperties: null });
581
+ }
582
+ else if (newProperties == null) {
583
+ return Object.assign(Object.assign({}, op), { properties: null, newProperties: properties });
584
+ }
585
+ else {
586
+ return Object.assign(Object.assign({}, op), { properties: newProperties, newProperties: properties });
587
+ }
588
+ }
589
+ case 'set_viewport': {
590
+ const { properties, newProperties } = op;
591
+ if (properties == null) {
592
+ return Object.assign(Object.assign({}, op), { properties: newProperties, newProperties: newProperties });
593
+ }
594
+ else if (newProperties == null) {
595
+ return Object.assign(Object.assign({}, op), { properties: properties, newProperties: properties });
596
+ }
597
+ else {
598
+ return Object.assign(Object.assign({}, op), { properties: newProperties, newProperties: properties });
599
+ }
600
+ }
601
+ }
602
+ };
537
603
  const PlaitOperation = {
538
- isSetViewportOperation
604
+ isSetViewportOperation,
605
+ inverse
606
+ };
607
+
608
+ const IS_IOS = typeof navigator !== 'undefined' &&
609
+ typeof window !== 'undefined' &&
610
+ /iPad|iPhone|iPod/.test(navigator.userAgent) &&
611
+ !window.MSStream;
612
+ const IS_APPLE = typeof navigator !== 'undefined' && /Mac OS X/.test(navigator.userAgent);
613
+ const IS_FIREFOX = typeof navigator !== 'undefined' && /^(?!.*Seamonkey)(?=.*Firefox).*/i.test(navigator.userAgent);
614
+ const IS_SAFARI = typeof navigator !== 'undefined' && /Version\/[\d\.]+.*Safari/.test(navigator.userAgent);
615
+ // "modern" Edge was released at 79.x
616
+ const IS_EDGE_LEGACY = typeof navigator !== 'undefined' && /Edge?\/(?:[0-6][0-9]|[0-7][0-8])/i.test(navigator.userAgent);
617
+ const IS_CHROME = typeof navigator !== 'undefined' && /Chrome/i.test(navigator.userAgent);
618
+ // Native beforeInput events don't work well with react on Chrome 75 and older, Chrome 76+ can use beforeInput
619
+ const IS_CHROME_LEGACY = typeof navigator !== 'undefined' && /Chrome?\/(?:[0-7][0-5]|[0-6][0-9])/i.test(navigator.userAgent);
620
+
621
+ /**
622
+ * Hotkey mappings for each platform.
623
+ */
624
+ const HOTKEYS = {
625
+ bold: 'mod+b',
626
+ compose: ['down', 'left', 'right', 'up', 'backspace', 'enter'],
627
+ moveBackward: 'left',
628
+ moveForward: 'right',
629
+ moveUp: 'up',
630
+ moveDown: 'down',
631
+ moveWordBackward: 'ctrl+left',
632
+ moveWordForward: 'ctrl+right',
633
+ deleteBackward: 'shift?+backspace',
634
+ deleteForward: 'shift?+delete',
635
+ extendBackward: 'shift+left',
636
+ extendForward: 'shift+right',
637
+ italic: 'mod+i',
638
+ splitBlock: 'shift?+enter',
639
+ undo: 'mod+z'
640
+ };
641
+ const APPLE_HOTKEYS = {
642
+ moveLineBackward: 'opt+up',
643
+ moveLineForward: 'opt+down',
644
+ moveWordBackward: 'opt+left',
645
+ moveWordForward: 'opt+right',
646
+ deleteBackward: ['ctrl+backspace', 'ctrl+h'],
647
+ deleteForward: ['ctrl+delete', 'ctrl+d'],
648
+ deleteLineBackward: 'cmd+shift?+backspace',
649
+ deleteLineForward: ['cmd+shift?+delete', 'ctrl+k'],
650
+ deleteWordBackward: 'opt+shift?+backspace',
651
+ deleteWordForward: 'opt+shift?+delete',
652
+ extendLineBackward: 'opt+shift+up',
653
+ extendLineForward: 'opt+shift+down',
654
+ redo: 'cmd+shift+z',
655
+ transposeCharacter: 'ctrl+t'
656
+ };
657
+ const WINDOWS_HOTKEYS = {
658
+ deleteWordBackward: 'ctrl+shift?+backspace',
659
+ deleteWordForward: 'ctrl+shift?+delete',
660
+ redo: ['ctrl+y', 'ctrl+shift+z']
661
+ };
662
+ /**
663
+ * Create a platform-aware hotkey checker.
664
+ */
665
+ const create = (key) => {
666
+ const generic = HOTKEYS[key];
667
+ const apple = APPLE_HOTKEYS[key];
668
+ const windows = WINDOWS_HOTKEYS[key];
669
+ const isGeneric = generic && isKeyHotkey(generic);
670
+ const isApple = apple && isKeyHotkey(apple);
671
+ const isWindows = windows && isKeyHotkey(windows);
672
+ return (event) => {
673
+ if (isGeneric && isGeneric(event)) {
674
+ return true;
675
+ }
676
+ if (IS_APPLE && isApple && isApple(event)) {
677
+ return true;
678
+ }
679
+ if (!IS_APPLE && isWindows && isWindows(event)) {
680
+ return true;
681
+ }
682
+ return false;
683
+ };
684
+ };
685
+ /**
686
+ * Hotkeys.
687
+ */
688
+ const hotkeys = {
689
+ isBold: create('bold'),
690
+ isCompose: create('compose'),
691
+ isMoveBackward: create('moveBackward'),
692
+ isMoveForward: create('moveForward'),
693
+ isMoveUp: create('moveUp'),
694
+ isMoveDown: create('moveDown'),
695
+ isDeleteBackward: create('deleteBackward'),
696
+ isDeleteForward: create('deleteForward'),
697
+ isDeleteLineBackward: create('deleteLineBackward'),
698
+ isDeleteLineForward: create('deleteLineForward'),
699
+ isDeleteWordBackward: create('deleteWordBackward'),
700
+ isDeleteWordForward: create('deleteWordForward'),
701
+ isExtendBackward: create('extendBackward'),
702
+ isExtendForward: create('extendForward'),
703
+ isExtendLineBackward: create('extendLineBackward'),
704
+ isExtendLineForward: create('extendLineForward'),
705
+ isItalic: create('italic'),
706
+ isMoveLineBackward: create('moveLineBackward'),
707
+ isMoveLineForward: create('moveLineForward'),
708
+ isMoveWordBackward: create('moveWordBackward'),
709
+ isMoveWordForward: create('moveWordForward'),
710
+ isRedo: create('redo'),
711
+ isSplitBlock: create('splitBlock'),
712
+ isTransposeCharacter: create('transposeCharacter'),
713
+ isUndo: create('undo')
714
+ };
715
+
716
+ function idCreator(length = 5) {
717
+ // remove numeral
718
+ const $chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz'; /****默认去掉了容易混淆的字符oOLl,9gq,Vv,Uu,I1****/
719
+ const maxPosition = $chars.length;
720
+ let key = '';
721
+ for (let i = 0; i < length; i++) {
722
+ key += $chars.charAt(Math.floor(Math.random() * maxPosition));
723
+ }
724
+ return key;
725
+ }
726
+
727
+ // https://stackoverflow.com/a/6853926/232122
728
+ function distanceBetweenPointAndSegment(x, y, x1, y1, x2, y2) {
729
+ const A = x - x1;
730
+ const B = y - y1;
731
+ const C = x2 - x1;
732
+ const D = y2 - y1;
733
+ const dot = A * C + B * D;
734
+ const lenSquare = C * C + D * D;
735
+ let param = -1;
736
+ if (lenSquare !== 0) {
737
+ // in case of 0 length line
738
+ param = dot / lenSquare;
739
+ }
740
+ let xx, yy;
741
+ if (param < 0) {
742
+ xx = x1;
743
+ yy = y1;
744
+ }
745
+ else if (param > 1) {
746
+ xx = x2;
747
+ yy = y2;
748
+ }
749
+ else {
750
+ xx = x1 + param * C;
751
+ yy = y1 + param * D;
752
+ }
753
+ const dx = x - xx;
754
+ const dy = y - yy;
755
+ return Math.hypot(dx, dy);
756
+ }
757
+ function rotate(x1, y1, x2, y2, angle) {
758
+ // 𝑎′𝑥=(𝑎𝑥−𝑐𝑥)cos𝜃−(𝑎𝑦−𝑐𝑦)sin𝜃+𝑐𝑥
759
+ // 𝑎′𝑦=(𝑎𝑥−𝑐𝑥)sin𝜃+(𝑎𝑦−𝑐𝑦)cos𝜃+𝑐𝑦.
760
+ // https://math.stackexchange.com/questions/2204520/how-do-i-rotate-a-line-segment-in-a-specific-point-on-the-line
761
+ return [(x1 - x2) * Math.cos(angle) - (y1 - y2) * Math.sin(angle) + x2, (x1 - x2) * Math.sin(angle) + (y1 - y2) * Math.cos(angle) + y2];
762
+ }
763
+
764
+ /**
765
+ * Check whether to merge an operation into the previous operation.
766
+ */
767
+ const shouldMerge = (op, prev) => {
768
+ if (op.type === 'set_viewport') {
769
+ return true;
770
+ }
771
+ return false;
772
+ };
773
+ /**
774
+ * Check whether an operation needs to be saved to the history.
775
+ */
776
+ const shouldSave = (op, prev) => {
777
+ if (op.type === 'set_selection') {
778
+ return false;
779
+ }
780
+ return true;
781
+ };
782
+ /**
783
+ * Check whether an operation should clear the redos stack.
784
+ */
785
+ const shouldClear = (op) => {
786
+ if (op.type === 'set_selection') {
787
+ return false;
788
+ }
789
+ return true;
790
+ };
791
+
792
+ function withHistroy(board) {
793
+ const { apply, keydown } = board;
794
+ board.history = { undos: [], redos: [] };
795
+ board.redo = () => {
796
+ const { history } = board;
797
+ const { redos } = history;
798
+ if (redos.length > 0) {
799
+ const batch = redos[redos.length - 1];
800
+ PlaitHistoryBoard.withoutSaving(board, () => {
801
+ for (const op of batch) {
802
+ board.apply(op);
803
+ }
804
+ });
805
+ history.redos.pop();
806
+ history.undos.push(batch);
807
+ }
808
+ };
809
+ board.undo = () => {
810
+ const { history } = board;
811
+ const { undos } = history;
812
+ if (undos.length > 0) {
813
+ const batch = undos[undos.length - 1];
814
+ PlaitHistoryBoard.withoutSaving(board, () => {
815
+ const inverseOps = batch.map(PlaitOperation.inverse).reverse();
816
+ for (const op of inverseOps) {
817
+ board.apply(op);
818
+ }
819
+ });
820
+ history.redos.push(batch);
821
+ history.undos.pop();
822
+ }
823
+ };
824
+ board.apply = (op) => {
825
+ const { operations, history } = board;
826
+ const { undos } = history;
827
+ const lastBatch = undos[undos.length - 1];
828
+ const lastOp = lastBatch && lastBatch[lastBatch.length - 1];
829
+ let save = PlaitHistoryBoard.isSaving(board);
830
+ let merge = PlaitHistoryBoard.isMerging(board);
831
+ if (save == null) {
832
+ save = shouldSave(op, lastOp);
833
+ }
834
+ if (save) {
835
+ if (merge == null) {
836
+ if (lastBatch == null) {
837
+ merge = false;
838
+ }
839
+ else if (operations.length !== 0) {
840
+ merge = true;
841
+ }
842
+ else {
843
+ merge = shouldMerge(op, lastOp);
844
+ }
845
+ }
846
+ if (lastBatch && merge) {
847
+ lastBatch.push(op);
848
+ }
849
+ else {
850
+ const batch = [op];
851
+ undos.push(batch);
852
+ }
853
+ while (undos.length > 100) {
854
+ undos.shift();
855
+ }
856
+ if (shouldClear(op)) {
857
+ history.redos = [];
858
+ }
859
+ }
860
+ apply(op);
861
+ };
862
+ board.keydown = (event) => {
863
+ if (isHotkey('mod+z', event)) {
864
+ board.undo();
865
+ return;
866
+ }
867
+ if (isHotkey('mod+shift+z', event)) {
868
+ board.redo();
869
+ return;
870
+ }
871
+ keydown(event);
872
+ };
873
+ return board;
874
+ }
875
+ const SAVING = new WeakMap();
876
+ const MERGING = new WeakMap();
877
+ const PlaitHistoryBoard = {
878
+ /**
879
+ * Get the saving flag's current value.
880
+ */
881
+ isSaving(board) {
882
+ return SAVING.get(board);
883
+ },
884
+ /**
885
+ * Get the merge flag's current value.
886
+ */
887
+ isMerging(board) {
888
+ return MERGING.get(board);
889
+ },
890
+ /**
891
+ * Apply a series of changes inside a synchronous `fn`, without merging any of
892
+ * the new operations into previous save point in the history.
893
+ */
894
+ withoutMerging(editor, fn) {
895
+ const prev = PlaitHistoryBoard.isMerging(editor);
896
+ MERGING.set(editor, false);
897
+ fn();
898
+ MERGING.set(editor, prev);
899
+ },
900
+ /**
901
+ * Apply a series of changes inside a synchronous `fn`, without saving any of
902
+ * their operations into the history.
903
+ */
904
+ withoutSaving(editor, fn) {
905
+ const prev = PlaitHistoryBoard.isSaving(editor);
906
+ SAVING.set(editor, false);
907
+ fn();
908
+ SAVING.set(editor, prev);
909
+ }
539
910
  };
540
911
 
541
912
  class PlaitElementComponent {
@@ -655,7 +1026,7 @@ class PlaitBoardComponent {
655
1026
  }
656
1027
  initializePlugins() {
657
1028
  const options = { readonly: this.plaitReadonly, allowClearBoard: this.plaitAllowClearBoard };
658
- let board = withSelection(withBoard(createBoard(this.host, this.plaitValue, options)));
1029
+ let board = withHistroy(withSelection(withBoard(createBoard(this.host, this.plaitValue, options))));
659
1030
  this.plaitPlugins.forEach(plugin => {
660
1031
  board = plugin(board);
661
1032
  });
@@ -711,12 +1082,15 @@ class PlaitBoardComponent {
711
1082
  (_a = this.board) === null || _a === void 0 ? void 0 : _a.keyup(event);
712
1083
  });
713
1084
  window.onresize = () => {
714
- var _a;
715
- const viewBoxModel = getViewBox(this.board);
716
- const viewBoxValues = (_a = this.host.getAttribute('viewBox')) === null || _a === void 0 ? void 0 : _a.split(',');
717
- this.renderer2.setAttribute(this.host, 'viewBox', `${viewBoxValues[0].trim()}, ${viewBoxValues[1].trim()}, ${viewBoxModel.width}, ${viewBoxModel.height}`);
1085
+ this.refreshViewport();
718
1086
  };
719
1087
  }
1088
+ refreshViewport() {
1089
+ var _a;
1090
+ const viewBoxModel = getViewBox(this.board);
1091
+ const viewBoxValues = (_a = this.host.getAttribute('viewBox')) === null || _a === void 0 ? void 0 : _a.split(',');
1092
+ this.renderer2.setAttribute(this.host, 'viewBox', `${viewBoxValues[0].trim()}, ${viewBoxValues[1].trim()}, ${viewBoxModel.width}, ${viewBoxModel.height}`);
1093
+ }
720
1094
  updateViewport() {
721
1095
  this.zoom = Math.floor(this.board.viewport.zoom * 100);
722
1096
  const viewBox = getViewBox(this.board);
@@ -824,162 +1198,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImpo
824
1198
  }]
825
1199
  }] });
826
1200
 
827
- const IS_IOS = typeof navigator !== 'undefined' &&
828
- typeof window !== 'undefined' &&
829
- /iPad|iPhone|iPod/.test(navigator.userAgent) &&
830
- !window.MSStream;
831
- const IS_APPLE = typeof navigator !== 'undefined' && /Mac OS X/.test(navigator.userAgent);
832
- const IS_FIREFOX = typeof navigator !== 'undefined' && /^(?!.*Seamonkey)(?=.*Firefox).*/i.test(navigator.userAgent);
833
- const IS_SAFARI = typeof navigator !== 'undefined' && /Version\/[\d\.]+.*Safari/.test(navigator.userAgent);
834
- // "modern" Edge was released at 79.x
835
- const IS_EDGE_LEGACY = typeof navigator !== 'undefined' && /Edge?\/(?:[0-6][0-9]|[0-7][0-8])/i.test(navigator.userAgent);
836
- const IS_CHROME = typeof navigator !== 'undefined' && /Chrome/i.test(navigator.userAgent);
837
- // Native beforeInput events don't work well with react on Chrome 75 and older, Chrome 76+ can use beforeInput
838
- const IS_CHROME_LEGACY = typeof navigator !== 'undefined' && /Chrome?\/(?:[0-7][0-5]|[0-6][0-9])/i.test(navigator.userAgent);
839
-
840
- /**
841
- * Hotkey mappings for each platform.
842
- */
843
- const HOTKEYS = {
844
- bold: 'mod+b',
845
- compose: ['down', 'left', 'right', 'up', 'backspace', 'enter'],
846
- moveBackward: 'left',
847
- moveForward: 'right',
848
- moveUp: 'up',
849
- moveDown: 'down',
850
- moveWordBackward: 'ctrl+left',
851
- moveWordForward: 'ctrl+right',
852
- deleteBackward: 'shift?+backspace',
853
- deleteForward: 'shift?+delete',
854
- extendBackward: 'shift+left',
855
- extendForward: 'shift+right',
856
- italic: 'mod+i',
857
- splitBlock: 'shift?+enter',
858
- undo: 'mod+z'
859
- };
860
- const APPLE_HOTKEYS = {
861
- moveLineBackward: 'opt+up',
862
- moveLineForward: 'opt+down',
863
- moveWordBackward: 'opt+left',
864
- moveWordForward: 'opt+right',
865
- deleteBackward: ['ctrl+backspace', 'ctrl+h'],
866
- deleteForward: ['ctrl+delete', 'ctrl+d'],
867
- deleteLineBackward: 'cmd+shift?+backspace',
868
- deleteLineForward: ['cmd+shift?+delete', 'ctrl+k'],
869
- deleteWordBackward: 'opt+shift?+backspace',
870
- deleteWordForward: 'opt+shift?+delete',
871
- extendLineBackward: 'opt+shift+up',
872
- extendLineForward: 'opt+shift+down',
873
- redo: 'cmd+shift+z',
874
- transposeCharacter: 'ctrl+t'
875
- };
876
- const WINDOWS_HOTKEYS = {
877
- deleteWordBackward: 'ctrl+shift?+backspace',
878
- deleteWordForward: 'ctrl+shift?+delete',
879
- redo: ['ctrl+y', 'ctrl+shift+z']
880
- };
881
- /**
882
- * Create a platform-aware hotkey checker.
883
- */
884
- const create = (key) => {
885
- const generic = HOTKEYS[key];
886
- const apple = APPLE_HOTKEYS[key];
887
- const windows = WINDOWS_HOTKEYS[key];
888
- const isGeneric = generic && isKeyHotkey(generic);
889
- const isApple = apple && isKeyHotkey(apple);
890
- const isWindows = windows && isKeyHotkey(windows);
891
- return (event) => {
892
- if (isGeneric && isGeneric(event)) {
893
- return true;
894
- }
895
- if (IS_APPLE && isApple && isApple(event)) {
896
- return true;
897
- }
898
- if (!IS_APPLE && isWindows && isWindows(event)) {
899
- return true;
900
- }
901
- return false;
902
- };
903
- };
904
- /**
905
- * Hotkeys.
906
- */
907
- const hotkeys = {
908
- isBold: create('bold'),
909
- isCompose: create('compose'),
910
- isMoveBackward: create('moveBackward'),
911
- isMoveForward: create('moveForward'),
912
- isMoveUp: create('moveUp'),
913
- isMoveDown: create('moveDown'),
914
- isDeleteBackward: create('deleteBackward'),
915
- isDeleteForward: create('deleteForward'),
916
- isDeleteLineBackward: create('deleteLineBackward'),
917
- isDeleteLineForward: create('deleteLineForward'),
918
- isDeleteWordBackward: create('deleteWordBackward'),
919
- isDeleteWordForward: create('deleteWordForward'),
920
- isExtendBackward: create('extendBackward'),
921
- isExtendForward: create('extendForward'),
922
- isExtendLineBackward: create('extendLineBackward'),
923
- isExtendLineForward: create('extendLineForward'),
924
- isItalic: create('italic'),
925
- isMoveLineBackward: create('moveLineBackward'),
926
- isMoveLineForward: create('moveLineForward'),
927
- isMoveWordBackward: create('moveWordBackward'),
928
- isMoveWordForward: create('moveWordForward'),
929
- isRedo: create('redo'),
930
- isSplitBlock: create('splitBlock'),
931
- isTransposeCharacter: create('transposeCharacter'),
932
- isUndo: create('undo')
933
- };
934
-
935
- function idCreator(length = 5) {
936
- // remove numeral
937
- const $chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz'; /****默认去掉了容易混淆的字符oOLl,9gq,Vv,Uu,I1****/
938
- const maxPosition = $chars.length;
939
- let key = '';
940
- for (let i = 0; i < length; i++) {
941
- key += $chars.charAt(Math.floor(Math.random() * maxPosition));
942
- }
943
- return key;
944
- }
945
-
946
- // https://stackoverflow.com/a/6853926/232122
947
- function distanceBetweenPointAndSegment(x, y, x1, y1, x2, y2) {
948
- const A = x - x1;
949
- const B = y - y1;
950
- const C = x2 - x1;
951
- const D = y2 - y1;
952
- const dot = A * C + B * D;
953
- const lenSquare = C * C + D * D;
954
- let param = -1;
955
- if (lenSquare !== 0) {
956
- // in case of 0 length line
957
- param = dot / lenSquare;
958
- }
959
- let xx, yy;
960
- if (param < 0) {
961
- xx = x1;
962
- yy = y1;
963
- }
964
- else if (param > 1) {
965
- xx = x2;
966
- yy = y2;
967
- }
968
- else {
969
- xx = x1 + param * C;
970
- yy = y1 + param * D;
971
- }
972
- const dx = x - xx;
973
- const dy = y - yy;
974
- return Math.hypot(dx, dy);
975
- }
976
- function rotate(x1, y1, x2, y2, angle) {
977
- // 𝑎′𝑥=(𝑎𝑥−𝑐𝑥)cos𝜃−(𝑎𝑦−𝑐𝑦)sin𝜃+𝑐𝑥
978
- // 𝑎′𝑦=(𝑎𝑥−𝑐𝑥)sin𝜃+(𝑎𝑦−𝑐𝑦)cos𝜃+𝑐𝑦.
979
- // https://math.stackexchange.com/questions/2204520/how-do-i-rotate-a-line-segment-in-a-specific-point-on-the-line
980
- return [(x1 - x2) * Math.cos(angle) - (y1 - y2) * Math.sin(angle) + x2, (x1 - x2) * Math.sin(angle) + (y1 - y2) * Math.cos(angle) + y2];
981
- }
982
-
983
1201
  /*
984
1202
  * Public API Surface of plait
985
1203
  */
@@ -988,5 +1206,5 @@ function rotate(x1, y1, x2, y2, angle) {
988
1206
  * Generated bundle index. Do not edit.
989
1207
  */
990
1208
 
991
- export { BOARD_TO_ON_CHANGE, BaseCursorStatus, FLUSHING, HOST_TO_ROUGH_SVG, IS_APPLE, IS_CHROME, IS_CHROME_LEGACY, IS_EDGE_LEGACY, IS_FIREFOX, IS_IOS, IS_SAFARI, IS_TEXT_EDITABLE, NS, Path, PlaitBoardComponent, PlaitElementComponent, PlaitModule, PlaitNode, PlaitOperation, Transforms, Viewport, createG, createSVG, createText, distanceBetweenPointAndSegment, getViewBox, hotkeys, idCreator, isNoSelectionElement, isNullOrUndefined, isSetViewportOperation, rotate, toPoint, toRectangleClient, transformPoint, transformPoints };
1209
+ export { BOARD_TO_ON_CHANGE, BaseCursorStatus, FLUSHING, HOST_TO_ROUGH_SVG, IS_APPLE, IS_CHROME, IS_CHROME_LEGACY, IS_EDGE_LEGACY, IS_FIREFOX, IS_IOS, IS_SAFARI, IS_TEXT_EDITABLE, NS, Path, PlaitBoardComponent, PlaitElementComponent, PlaitModule, PlaitNode, PlaitOperation, Transforms, Viewport, createG, createSVG, createText, distanceBetweenPointAndSegment, getViewBox, hotkeys, idCreator, inverse, isNoSelectionElement, isNullOrUndefined, isSetViewportOperation, rotate, shouldClear, shouldMerge, shouldSave, toPoint, toRectangleClient, transformPoint, transformPoints };
992
1210
  //# sourceMappingURL=plait-core.mjs.map