@plait/core 0.0.14 → 0.0.16

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