js-draw 1.20.3 → 1.21.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (243) hide show
  1. package/LICENSE +1 -1
  2. package/dist/Editor.css +134 -26
  3. package/dist/bundle.js +2 -2
  4. package/dist/bundledStyles.js +1 -1
  5. package/dist/cjs/Editor.d.ts +27 -6
  6. package/dist/cjs/Editor.js +30 -8
  7. package/dist/cjs/SVGLoader/SVGLoader.js +2 -2
  8. package/dist/cjs/Viewport.d.ts +2 -2
  9. package/dist/cjs/commands/Command.d.ts +5 -0
  10. package/dist/cjs/commands/Command.js +5 -0
  11. package/dist/cjs/commands/SerializableCommand.d.ts +7 -0
  12. package/dist/cjs/commands/SerializableCommand.js +9 -0
  13. package/dist/cjs/dialogs/makeAboutDialog.d.ts +1 -1
  14. package/dist/cjs/dialogs/makeAboutDialog.js +10 -25
  15. package/dist/cjs/dialogs/makeMessageDialog.d.ts +11 -0
  16. package/dist/cjs/dialogs/makeMessageDialog.js +56 -0
  17. package/dist/cjs/image/EditorImage.d.ts +15 -1
  18. package/dist/cjs/image/EditorImage.js +15 -5
  19. package/dist/cjs/inputEvents.d.ts +10 -2
  20. package/dist/cjs/inputEvents.js +1 -0
  21. package/dist/cjs/localizations/es.js +3 -0
  22. package/dist/cjs/rendering/Display.d.ts +1 -0
  23. package/dist/cjs/rendering/Display.js +1 -0
  24. package/dist/cjs/rendering/TextRenderingStyle.d.ts +7 -6
  25. package/dist/cjs/rendering/TextRenderingStyle.js +1 -0
  26. package/dist/cjs/rendering/renderers/CanvasRenderer.d.ts +12 -3
  27. package/dist/cjs/rendering/renderers/CanvasRenderer.js +15 -2
  28. package/dist/cjs/rendering/renderers/DummyRenderer.d.ts +1 -1
  29. package/dist/cjs/testing/firstElementAncestorOfNode.d.ts +1 -1
  30. package/dist/cjs/testing/firstElementAncestorOfNode.js +1 -1
  31. package/dist/cjs/testing/sendPenEvent.d.ts +2 -2
  32. package/dist/cjs/testing/sendTouchEvent.d.ts +2 -2
  33. package/dist/cjs/toolbar/AbstractToolbar.d.ts +6 -1
  34. package/dist/cjs/toolbar/AbstractToolbar.js +6 -1
  35. package/dist/cjs/toolbar/IconProvider.d.ts +1 -1
  36. package/dist/cjs/toolbar/IconProvider.js +6 -1
  37. package/dist/cjs/toolbar/widgets/BaseWidget.d.ts +8 -0
  38. package/dist/cjs/toolbar/widgets/BaseWidget.js +8 -0
  39. package/dist/cjs/toolbar/widgets/HandToolWidget.d.ts +1 -0
  40. package/dist/cjs/toolbar/widgets/HandToolWidget.js +1 -0
  41. package/dist/cjs/toolbar/widgets/PenToolWidget.d.ts +6 -0
  42. package/dist/cjs/toolbar/widgets/PenToolWidget.js +5 -0
  43. package/dist/cjs/types.d.ts +5 -0
  44. package/dist/cjs/types.js +1 -0
  45. package/dist/cjs/util/ClipboardHandler.d.ts +9 -1
  46. package/dist/cjs/util/ClipboardHandler.js +82 -24
  47. package/dist/cjs/version.js +1 -1
  48. package/dist/mjs/Editor.d.ts +27 -6
  49. package/dist/mjs/Editor.mjs +31 -9
  50. package/dist/mjs/SVGLoader/SVGLoader.mjs +2 -2
  51. package/dist/mjs/Viewport.d.ts +2 -2
  52. package/dist/mjs/commands/Command.d.ts +5 -0
  53. package/dist/mjs/commands/Command.mjs +5 -0
  54. package/dist/mjs/commands/SerializableCommand.d.ts +7 -0
  55. package/dist/mjs/commands/SerializableCommand.mjs +9 -0
  56. package/dist/mjs/dialogs/makeAboutDialog.d.ts +1 -1
  57. package/dist/mjs/dialogs/makeAboutDialog.mjs +7 -25
  58. package/dist/mjs/dialogs/makeMessageDialog.d.ts +11 -0
  59. package/dist/mjs/dialogs/makeMessageDialog.mjs +51 -0
  60. package/dist/mjs/image/EditorImage.d.ts +15 -1
  61. package/dist/mjs/image/EditorImage.mjs +15 -5
  62. package/dist/mjs/inputEvents.d.ts +10 -2
  63. package/dist/mjs/inputEvents.mjs +1 -0
  64. package/dist/mjs/localizations/es.mjs +3 -0
  65. package/dist/mjs/rendering/Display.d.ts +1 -0
  66. package/dist/mjs/rendering/Display.mjs +1 -0
  67. package/dist/mjs/rendering/TextRenderingStyle.d.ts +7 -6
  68. package/dist/mjs/rendering/TextRenderingStyle.mjs +1 -0
  69. package/dist/mjs/rendering/renderers/CanvasRenderer.d.ts +12 -3
  70. package/dist/mjs/rendering/renderers/CanvasRenderer.mjs +15 -2
  71. package/dist/mjs/rendering/renderers/DummyRenderer.d.ts +1 -1
  72. package/dist/mjs/testing/firstElementAncestorOfNode.d.ts +1 -1
  73. package/dist/mjs/testing/firstElementAncestorOfNode.mjs +1 -1
  74. package/dist/mjs/testing/sendPenEvent.d.ts +2 -2
  75. package/dist/mjs/testing/sendTouchEvent.d.ts +2 -2
  76. package/dist/mjs/toolbar/AbstractToolbar.d.ts +6 -1
  77. package/dist/mjs/toolbar/AbstractToolbar.mjs +6 -1
  78. package/dist/mjs/toolbar/IconProvider.d.ts +1 -1
  79. package/dist/mjs/toolbar/IconProvider.mjs +6 -1
  80. package/dist/mjs/toolbar/widgets/BaseWidget.d.ts +8 -0
  81. package/dist/mjs/toolbar/widgets/BaseWidget.mjs +8 -0
  82. package/dist/mjs/toolbar/widgets/HandToolWidget.d.ts +1 -0
  83. package/dist/mjs/toolbar/widgets/HandToolWidget.mjs +1 -0
  84. package/dist/mjs/toolbar/widgets/PenToolWidget.d.ts +6 -0
  85. package/dist/mjs/toolbar/widgets/PenToolWidget.mjs +5 -0
  86. package/dist/mjs/types.d.ts +5 -0
  87. package/dist/mjs/types.mjs +1 -0
  88. package/dist/mjs/util/ClipboardHandler.d.ts +9 -1
  89. package/dist/mjs/util/ClipboardHandler.mjs +82 -24
  90. package/dist/mjs/version.mjs +1 -1
  91. package/package.json +8 -9
  92. package/src/dialogs/dialogs.scss +9 -21
  93. package/src/dialogs/makeAboutDialog.scss +13 -33
  94. package/src/dialogs/makeMessageDialog.scss +46 -0
  95. package/dist/cjs/tools/BaseTool.d.ts +0 -60
  96. package/dist/cjs/tools/BaseTool.js +0 -174
  97. package/dist/cjs/tools/Eraser.d.ts +0 -56
  98. package/dist/cjs/tools/Eraser.js +0 -295
  99. package/dist/cjs/tools/Eraser.test.d.ts +0 -1
  100. package/dist/cjs/tools/FindTool.d.ts +0 -21
  101. package/dist/cjs/tools/FindTool.js +0 -137
  102. package/dist/cjs/tools/FindTool.test.d.ts +0 -1
  103. package/dist/cjs/tools/InputFilter/FunctionMapper.d.ts +0 -12
  104. package/dist/cjs/tools/InputFilter/FunctionMapper.js +0 -21
  105. package/dist/cjs/tools/InputFilter/InputMapper.d.ts +0 -23
  106. package/dist/cjs/tools/InputFilter/InputMapper.js +0 -38
  107. package/dist/cjs/tools/InputFilter/InputPipeline.d.ts +0 -15
  108. package/dist/cjs/tools/InputFilter/InputPipeline.js +0 -54
  109. package/dist/cjs/tools/InputFilter/InputPipeline.test.d.ts +0 -1
  110. package/dist/cjs/tools/InputFilter/InputStabilizer.d.ts +0 -29
  111. package/dist/cjs/tools/InputFilter/InputStabilizer.js +0 -181
  112. package/dist/cjs/tools/InputFilter/StrokeKeyboardControl.d.ts +0 -21
  113. package/dist/cjs/tools/InputFilter/StrokeKeyboardControl.js +0 -84
  114. package/dist/cjs/tools/PanZoom.d.ts +0 -119
  115. package/dist/cjs/tools/PanZoom.js +0 -508
  116. package/dist/cjs/tools/PanZoom.test.d.ts +0 -1
  117. package/dist/cjs/tools/PasteHandler.d.ts +0 -23
  118. package/dist/cjs/tools/PasteHandler.js +0 -109
  119. package/dist/cjs/tools/Pen.d.ts +0 -53
  120. package/dist/cjs/tools/Pen.js +0 -318
  121. package/dist/cjs/tools/Pen.test.d.ts +0 -1
  122. package/dist/cjs/tools/PipetteTool.d.ts +0 -28
  123. package/dist/cjs/tools/PipetteTool.js +0 -69
  124. package/dist/cjs/tools/ScrollbarTool.d.ts +0 -18
  125. package/dist/cjs/tools/ScrollbarTool.js +0 -85
  126. package/dist/cjs/tools/SelectionTool/SelectAllShortcutHandler.d.ts +0 -9
  127. package/dist/cjs/tools/SelectionTool/SelectAllShortcutHandler.js +0 -32
  128. package/dist/cjs/tools/SelectionTool/Selection.d.ts +0 -71
  129. package/dist/cjs/tools/SelectionTool/Selection.js +0 -620
  130. package/dist/cjs/tools/SelectionTool/SelectionHandle.d.ts +0 -62
  131. package/dist/cjs/tools/SelectionTool/SelectionHandle.js +0 -141
  132. package/dist/cjs/tools/SelectionTool/SelectionTool.d.ts +0 -40
  133. package/dist/cjs/tools/SelectionTool/SelectionTool.js +0 -494
  134. package/dist/cjs/tools/SelectionTool/SelectionTool.selecting.test.d.ts +0 -1
  135. package/dist/cjs/tools/SelectionTool/SelectionTool.test.d.ts +0 -1
  136. package/dist/cjs/tools/SelectionTool/ToPointerAutoscroller.d.ts +0 -23
  137. package/dist/cjs/tools/SelectionTool/ToPointerAutoscroller.js +0 -83
  138. package/dist/cjs/tools/SelectionTool/TransformMode.d.ts +0 -42
  139. package/dist/cjs/tools/SelectionTool/TransformMode.js +0 -155
  140. package/dist/cjs/tools/SelectionTool/types.d.ts +0 -28
  141. package/dist/cjs/tools/SelectionTool/types.js +0 -14
  142. package/dist/cjs/tools/SoundUITool.d.ts +0 -26
  143. package/dist/cjs/tools/SoundUITool.js +0 -171
  144. package/dist/cjs/tools/TextTool.d.ts +0 -36
  145. package/dist/cjs/tools/TextTool.js +0 -285
  146. package/dist/cjs/tools/TextTool.test.d.ts +0 -1
  147. package/dist/cjs/tools/ToolController.d.ts +0 -73
  148. package/dist/cjs/tools/ToolController.js +0 -304
  149. package/dist/cjs/tools/ToolController.test.d.ts +0 -1
  150. package/dist/cjs/tools/ToolEnabledGroup.d.ts +0 -6
  151. package/dist/cjs/tools/ToolEnabledGroup.js +0 -13
  152. package/dist/cjs/tools/ToolSwitcherShortcut.d.ts +0 -16
  153. package/dist/cjs/tools/ToolSwitcherShortcut.js +0 -40
  154. package/dist/cjs/tools/ToolbarShortcutHandler.d.ts +0 -12
  155. package/dist/cjs/tools/ToolbarShortcutHandler.js +0 -34
  156. package/dist/cjs/tools/UndoRedoShortcut.d.ts +0 -8
  157. package/dist/cjs/tools/UndoRedoShortcut.js +0 -27
  158. package/dist/cjs/tools/UndoRedoShortcut.test.d.ts +0 -1
  159. package/dist/cjs/tools/keybindings.d.ts +0 -18
  160. package/dist/cjs/tools/keybindings.js +0 -49
  161. package/dist/cjs/tools/lib.d.ts +0 -14
  162. package/dist/cjs/tools/lib.js +0 -36
  163. package/dist/cjs/tools/localization.d.ts +0 -34
  164. package/dist/cjs/tools/localization.js +0 -36
  165. package/dist/cjs/tools/util/StationaryPenDetector.d.ts +0 -22
  166. package/dist/cjs/tools/util/StationaryPenDetector.js +0 -95
  167. package/dist/mjs/tools/BaseTool.d.ts +0 -60
  168. package/dist/mjs/tools/BaseTool.mjs +0 -172
  169. package/dist/mjs/tools/Eraser.d.ts +0 -56
  170. package/dist/mjs/tools/Eraser.mjs +0 -288
  171. package/dist/mjs/tools/Eraser.test.d.ts +0 -1
  172. package/dist/mjs/tools/FindTool.d.ts +0 -21
  173. package/dist/mjs/tools/FindTool.mjs +0 -131
  174. package/dist/mjs/tools/FindTool.test.d.ts +0 -1
  175. package/dist/mjs/tools/InputFilter/FunctionMapper.d.ts +0 -12
  176. package/dist/mjs/tools/InputFilter/FunctionMapper.mjs +0 -15
  177. package/dist/mjs/tools/InputFilter/InputMapper.d.ts +0 -23
  178. package/dist/mjs/tools/InputFilter/InputMapper.mjs +0 -36
  179. package/dist/mjs/tools/InputFilter/InputPipeline.d.ts +0 -15
  180. package/dist/mjs/tools/InputFilter/InputPipeline.mjs +0 -49
  181. package/dist/mjs/tools/InputFilter/InputPipeline.test.d.ts +0 -1
  182. package/dist/mjs/tools/InputFilter/InputStabilizer.d.ts +0 -29
  183. package/dist/mjs/tools/InputFilter/InputStabilizer.mjs +0 -175
  184. package/dist/mjs/tools/InputFilter/StrokeKeyboardControl.d.ts +0 -21
  185. package/dist/mjs/tools/InputFilter/StrokeKeyboardControl.mjs +0 -78
  186. package/dist/mjs/tools/PanZoom.d.ts +0 -119
  187. package/dist/mjs/tools/PanZoom.mjs +0 -501
  188. package/dist/mjs/tools/PanZoom.test.d.ts +0 -1
  189. package/dist/mjs/tools/PasteHandler.d.ts +0 -23
  190. package/dist/mjs/tools/PasteHandler.mjs +0 -103
  191. package/dist/mjs/tools/Pen.d.ts +0 -53
  192. package/dist/mjs/tools/Pen.mjs +0 -312
  193. package/dist/mjs/tools/Pen.test.d.ts +0 -1
  194. package/dist/mjs/tools/PipetteTool.d.ts +0 -28
  195. package/dist/mjs/tools/PipetteTool.mjs +0 -63
  196. package/dist/mjs/tools/ScrollbarTool.d.ts +0 -18
  197. package/dist/mjs/tools/ScrollbarTool.mjs +0 -79
  198. package/dist/mjs/tools/SelectionTool/SelectAllShortcutHandler.d.ts +0 -9
  199. package/dist/mjs/tools/SelectionTool/SelectAllShortcutHandler.mjs +0 -26
  200. package/dist/mjs/tools/SelectionTool/Selection.d.ts +0 -71
  201. package/dist/mjs/tools/SelectionTool/Selection.mjs +0 -592
  202. package/dist/mjs/tools/SelectionTool/SelectionHandle.d.ts +0 -62
  203. package/dist/mjs/tools/SelectionTool/SelectionHandle.mjs +0 -137
  204. package/dist/mjs/tools/SelectionTool/SelectionTool.d.ts +0 -40
  205. package/dist/mjs/tools/SelectionTool/SelectionTool.mjs +0 -488
  206. package/dist/mjs/tools/SelectionTool/SelectionTool.selecting.test.d.ts +0 -1
  207. package/dist/mjs/tools/SelectionTool/SelectionTool.test.d.ts +0 -1
  208. package/dist/mjs/tools/SelectionTool/ToPointerAutoscroller.d.ts +0 -23
  209. package/dist/mjs/tools/SelectionTool/ToPointerAutoscroller.mjs +0 -77
  210. package/dist/mjs/tools/SelectionTool/TransformMode.d.ts +0 -42
  211. package/dist/mjs/tools/SelectionTool/TransformMode.mjs +0 -146
  212. package/dist/mjs/tools/SelectionTool/types.d.ts +0 -28
  213. package/dist/mjs/tools/SelectionTool/types.mjs +0 -11
  214. package/dist/mjs/tools/SoundUITool.d.ts +0 -26
  215. package/dist/mjs/tools/SoundUITool.mjs +0 -165
  216. package/dist/mjs/tools/TextTool.d.ts +0 -36
  217. package/dist/mjs/tools/TextTool.mjs +0 -279
  218. package/dist/mjs/tools/TextTool.test.d.ts +0 -1
  219. package/dist/mjs/tools/ToolController.d.ts +0 -73
  220. package/dist/mjs/tools/ToolController.mjs +0 -275
  221. package/dist/mjs/tools/ToolController.test.d.ts +0 -1
  222. package/dist/mjs/tools/ToolEnabledGroup.d.ts +0 -6
  223. package/dist/mjs/tools/ToolEnabledGroup.mjs +0 -10
  224. package/dist/mjs/tools/ToolSwitcherShortcut.d.ts +0 -16
  225. package/dist/mjs/tools/ToolSwitcherShortcut.mjs +0 -34
  226. package/dist/mjs/tools/ToolbarShortcutHandler.d.ts +0 -12
  227. package/dist/mjs/tools/ToolbarShortcutHandler.mjs +0 -28
  228. package/dist/mjs/tools/UndoRedoShortcut.d.ts +0 -8
  229. package/dist/mjs/tools/UndoRedoShortcut.mjs +0 -21
  230. package/dist/mjs/tools/UndoRedoShortcut.test.d.ts +0 -1
  231. package/dist/mjs/tools/keybindings.d.ts +0 -18
  232. package/dist/mjs/tools/keybindings.mjs +0 -43
  233. package/dist/mjs/tools/lib.d.ts +0 -14
  234. package/dist/mjs/tools/lib.mjs +0 -14
  235. package/dist/mjs/tools/localization.d.ts +0 -34
  236. package/dist/mjs/tools/localization.mjs +0 -33
  237. package/dist/mjs/tools/util/StationaryPenDetector.d.ts +0 -22
  238. package/dist/mjs/tools/util/StationaryPenDetector.mjs +0 -92
  239. package/src/tools/FindTool.css +0 -7
  240. package/src/tools/ScrollbarTool.scss +0 -57
  241. package/src/tools/SelectionTool/SelectionTool.scss +0 -137
  242. package/src/tools/SoundUITool.scss +0 -22
  243. package/src/tools/tools.scss +0 -5
@@ -1,508 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.PanZoomMode = void 0;
7
- const math_1 = require("@js-draw/math");
8
- const Pointer_1 = require("../Pointer");
9
- const types_1 = require("../types");
10
- const untilNextAnimationFrame_1 = __importDefault(require("../util/untilNextAnimationFrame"));
11
- const Viewport_1 = require("../Viewport");
12
- const BaseTool_1 = __importDefault(require("./BaseTool"));
13
- const keybindings_1 = require("./keybindings");
14
- var PanZoomMode;
15
- (function (PanZoomMode) {
16
- /** Touch gestures with a single pointer. Ignores non-touch gestures. */
17
- PanZoomMode[PanZoomMode["OneFingerTouchGestures"] = 1] = "OneFingerTouchGestures";
18
- /** Touch gestures with exactly two pointers. Ignores non-touch gestures. */
19
- PanZoomMode[PanZoomMode["TwoFingerTouchGestures"] = 2] = "TwoFingerTouchGestures";
20
- PanZoomMode[PanZoomMode["RightClickDrags"] = 4] = "RightClickDrags";
21
- /** Single-pointer gestures of *any* type (including touch). */
22
- PanZoomMode[PanZoomMode["SinglePointerGestures"] = 8] = "SinglePointerGestures";
23
- /** Keyboard navigation (e.g. LeftArrow to move left). */
24
- PanZoomMode[PanZoomMode["Keyboard"] = 16] = "Keyboard";
25
- /** If provided, prevents **this** tool from rotating the viewport (other tools may still do so). */
26
- PanZoomMode[PanZoomMode["RotationLocked"] = 32] = "RotationLocked";
27
- })(PanZoomMode || (exports.PanZoomMode = PanZoomMode = {}));
28
- class InertialScroller {
29
- constructor(initialVelocity, scrollBy, onComplete) {
30
- this.initialVelocity = initialVelocity;
31
- this.scrollBy = scrollBy;
32
- this.onComplete = onComplete;
33
- this.running = false;
34
- this.start();
35
- }
36
- async start() {
37
- if (this.running) {
38
- return;
39
- }
40
- this.currentVelocity = this.initialVelocity;
41
- let lastTime = performance.now();
42
- this.running = true;
43
- const maxSpeed = 5000; // units/s
44
- const minSpeed = 200; // units/s
45
- if (this.currentVelocity.magnitude() > maxSpeed) {
46
- this.currentVelocity = this.currentVelocity.normalized().times(maxSpeed);
47
- }
48
- while (this.running && this.currentVelocity.magnitude() > minSpeed) {
49
- const nowTime = performance.now();
50
- const dt = (nowTime - lastTime) / 1000;
51
- this.currentVelocity = this.currentVelocity.times(Math.pow(1 / 8, dt));
52
- this.scrollBy(this.currentVelocity.times(dt));
53
- await (0, untilNextAnimationFrame_1.default)();
54
- lastTime = nowTime;
55
- }
56
- if (this.running) {
57
- this.stop();
58
- }
59
- }
60
- getCurrentVelocity() {
61
- if (!this.running) {
62
- return null;
63
- }
64
- return this.currentVelocity;
65
- }
66
- stop() {
67
- if (this.running) {
68
- this.running = false;
69
- this.onComplete();
70
- }
71
- }
72
- }
73
- /**
74
- * This tool moves the viewport in response to touchpad, touchscreen, mouse, and keyboard events.
75
- *
76
- * Which events are handled, and which are skipped, are determined by the tool's `mode`. For example,
77
- * a `PanZoom` tool with `mode = PanZoomMode.TwoFingerTouchGestures|PanZoomMode.RightClickDrags` would
78
- * respond to right-click drag events and two-finger touch gestures.
79
- *
80
- * @see {@link setModeEnabled}
81
- */
82
- class PanZoom extends BaseTool_1.default {
83
- constructor(editor, mode, description) {
84
- super(editor.notifier, description);
85
- this.editor = editor;
86
- this.mode = mode;
87
- this.transform = null;
88
- // Constants
89
- // initialRotationSnapAngle is larger than afterRotationStartSnapAngle to
90
- // make it more difficult to start rotating (and easier to continue rotating).
91
- this.initialRotationSnapAngle = 0.22; // radians
92
- this.afterRotationStartSnapAngle = 0.07; // radians
93
- this.pinchZoomStartThreshold = 1.08; // scale factor
94
- // Last timestamp at which a pointerdown event was received
95
- this.lastPointerDownTimestamp = 0;
96
- this.initialTouchAngle = 0;
97
- this.initialViewportRotation = 0;
98
- this.initialViewportScale = 0;
99
- // Set to `true` only when scaling has started (if two fingers are down and have moved
100
- // far enough).
101
- this.isScaling = false;
102
- this.isRotating = false;
103
- this.inertialScroller = null;
104
- this.velocity = null;
105
- }
106
- // The pan/zoom tool can be used in a read-only editor.
107
- canReceiveInputInReadOnlyEditor() {
108
- return true;
109
- }
110
- // Returns information about the pointers in a gesture
111
- computePinchData(p1, p2) {
112
- // Swap the pointers to ensure consistent ordering.
113
- if (p1.id < p2.id) {
114
- const tmp = p1;
115
- p1 = p2;
116
- p2 = tmp;
117
- }
118
- const screenBetween = p2.screenPos.minus(p1.screenPos);
119
- const angle = screenBetween.angle();
120
- const dist = screenBetween.magnitude();
121
- const canvasCenter = p2.canvasPos.plus(p1.canvasPos).times(0.5);
122
- const screenCenter = p2.screenPos.plus(p1.screenPos).times(0.5);
123
- return { canvasCenter, screenCenter, angle, dist };
124
- }
125
- allPointersAreOfType(pointers, kind) {
126
- return pointers.every(pointer => pointer.device === kind);
127
- }
128
- onPointerDown({ allPointers: pointers, current: currentPointer }) {
129
- let handlingGesture = false;
130
- const inertialScrollerVelocity = this.inertialScroller?.getCurrentVelocity() ?? math_1.Vec2.zero;
131
- this.inertialScroller?.stop();
132
- this.velocity = inertialScrollerVelocity;
133
- this.lastPointerDownTimestamp = currentPointer.timeStamp;
134
- const allAreTouch = this.allPointersAreOfType(pointers, Pointer_1.PointerDevice.Touch);
135
- const isRightClick = this.allPointersAreOfType(pointers, Pointer_1.PointerDevice.RightButtonMouse);
136
- if (allAreTouch && pointers.length === 2 && this.mode & PanZoomMode.TwoFingerTouchGestures) {
137
- const { screenCenter, angle, dist } = this.computePinchData(pointers[0], pointers[1]);
138
- this.lastTouchDist = dist;
139
- this.startTouchDist = dist;
140
- this.lastScreenCenter = screenCenter;
141
- this.initialTouchAngle = angle;
142
- this.initialViewportRotation = this.editor.viewport.getRotationAngle();
143
- this.initialViewportScale = this.editor.viewport.getScaleFactor();
144
- this.isScaling = false;
145
- // We're initially rotated if `initialViewportRotation` isn't near a multiple of pi/2.
146
- // In other words, if sin(2 initialViewportRotation) is near zero.
147
- this.isRotating = Math.abs(Math.sin(this.initialViewportRotation * 2)) > 1e-3;
148
- handlingGesture = true;
149
- }
150
- else if (pointers.length === 1 && ((this.mode & PanZoomMode.OneFingerTouchGestures && allAreTouch)
151
- || (isRightClick && this.mode & PanZoomMode.RightClickDrags)
152
- || (this.mode & PanZoomMode.SinglePointerGestures))) {
153
- this.lastScreenCenter = pointers[0].screenPos;
154
- this.isScaling = false;
155
- handlingGesture = true;
156
- }
157
- if (handlingGesture) {
158
- this.lastTimestamp = performance.now();
159
- this.transform ??= Viewport_1.Viewport.transformBy(math_1.Mat33.identity);
160
- this.editor.display.setDraftMode(true);
161
- }
162
- return handlingGesture;
163
- }
164
- updateVelocity(currentCenter) {
165
- const deltaPos = currentCenter.minus(this.lastScreenCenter);
166
- let deltaTime = (performance.now() - this.lastTimestamp) / 1000;
167
- // Ignore duplicate events, unless there has been enough time between them.
168
- if (deltaPos.magnitude() === 0 && deltaTime < 0.1) {
169
- return;
170
- }
171
- // We divide by deltaTime. Don't divide by zero.
172
- if (deltaTime === 0) {
173
- return;
174
- }
175
- // Don't divide by almost zero, either
176
- deltaTime = Math.max(deltaTime, 0.01);
177
- const currentVelocity = deltaPos.times(1 / deltaTime);
178
- let smoothedVelocity = currentVelocity;
179
- if (this.velocity) {
180
- smoothedVelocity = this.velocity.lerp(currentVelocity, 0.5);
181
- }
182
- this.velocity = smoothedVelocity;
183
- }
184
- // Returns the change in position of the center of the given group of pointers.
185
- // Assumes this.lastScreenCenter has been set appropriately.
186
- getCenterDelta(screenCenter) {
187
- // Use transformVec3 to avoid translating the delta
188
- const delta = this.editor.viewport.screenToCanvasTransform.transformVec3(screenCenter.minus(this.lastScreenCenter));
189
- return delta;
190
- }
191
- // Snaps `angle` to common desired rotations. For example, if `touchAngle` corresponds
192
- // to a viewport rotation of 90.1 degrees, this function returns a rotation delta that,
193
- // when applied to the viewport, rotates the viewport to 90.0 degrees.
194
- //
195
- // Returns a snapped rotation delta that, when applied to the viewport, rotates the viewport,
196
- // from its position on the last touchDown event, by `touchAngle - initialTouchAngle`.
197
- toSnappedRotationDelta(touchAngle) {
198
- const deltaAngle = touchAngle - this.initialTouchAngle;
199
- let fullRotation = deltaAngle + this.initialViewportRotation;
200
- const snapToMultipleOf = Math.PI / 2;
201
- const roundedFullRotation = Math.round(fullRotation / snapToMultipleOf) * snapToMultipleOf;
202
- // The maximum angle for which we snap the given angle to a multiple of
203
- // `snapToMultipleOf`.
204
- // Use a smaller snap angle if already rotated (to avoid pinch zoom gestures from
205
- // starting rotation).
206
- const maxSnapAngle = this.isRotating ? this.afterRotationStartSnapAngle : this.initialRotationSnapAngle;
207
- // Snap the rotation
208
- if (Math.abs(fullRotation - roundedFullRotation) < maxSnapAngle) {
209
- fullRotation = roundedFullRotation;
210
- // Work around a rotation/matrix multiply bug.
211
- // (See commit after 4abe27ff8e7913155828f98dee77b09c57c51d30).
212
- // TODO: Fix the underlying issue and remove this.
213
- if (fullRotation !== 0) {
214
- fullRotation += 0.0001;
215
- }
216
- }
217
- return fullRotation - this.editor.viewport.getRotationAngle();
218
- }
219
- /**
220
- * Given a scale update, `scaleFactor`, returns a new scale factor snapped
221
- * to a power of two (if within some tolerance of that scale).
222
- */
223
- toSnappedScaleFactor(touchDist) {
224
- // scaleFactor is applied to the current transformation of the viewport.
225
- const newScale = this.initialViewportScale * touchDist / this.startTouchDist;
226
- const currentScale = this.editor.viewport.getScaleFactor();
227
- const logNewScale = Math.log(newScale) / Math.log(10);
228
- const roundedLogNewScale = Math.round(logNewScale);
229
- const logTolerance = 0.04;
230
- if (Math.abs(roundedLogNewScale - logNewScale) < logTolerance) {
231
- return Math.pow(10, roundedLogNewScale) / currentScale;
232
- }
233
- return touchDist / this.lastTouchDist;
234
- }
235
- handleTwoFingerMove(allPointers) {
236
- const { screenCenter, canvasCenter, angle, dist } = this.computePinchData(allPointers[0], allPointers[1]);
237
- const delta = this.getCenterDelta(screenCenter);
238
- let deltaRotation;
239
- if (this.isRotationLocked()) {
240
- deltaRotation = 0;
241
- }
242
- else {
243
- deltaRotation = this.toSnappedRotationDelta(angle);
244
- }
245
- // If any rotation, make a note of this (affects rotation snap
246
- // angles).
247
- if (Math.abs(deltaRotation) > 1e-8) {
248
- this.isRotating = true;
249
- }
250
- this.updateVelocity(screenCenter);
251
- if (!this.isScaling) {
252
- const initialScaleFactor = dist / this.startTouchDist;
253
- // Only start scaling if scaling done so far exceeds some threshold.
254
- const upperBound = this.pinchZoomStartThreshold;
255
- const lowerBound = 1 / this.pinchZoomStartThreshold;
256
- if (initialScaleFactor > upperBound || initialScaleFactor < lowerBound) {
257
- this.isScaling = true;
258
- }
259
- }
260
- let scaleFactor = 1;
261
- if (this.isScaling) {
262
- scaleFactor = this.toSnappedScaleFactor(dist);
263
- // Don't set lastDist until we start scaling --
264
- this.lastTouchDist = dist;
265
- }
266
- const transformUpdate = math_1.Mat33.translation(delta)
267
- .rightMul(math_1.Mat33.scaling2D(scaleFactor, canvasCenter))
268
- .rightMul(math_1.Mat33.zRotation(deltaRotation, canvasCenter));
269
- this.lastScreenCenter = screenCenter;
270
- this.transform = Viewport_1.Viewport.transformBy(this.transform.transform.rightMul(transformUpdate));
271
- return transformUpdate;
272
- }
273
- handleOneFingerMove(pointer) {
274
- const delta = this.getCenterDelta(pointer.screenPos);
275
- const transformUpdate = math_1.Mat33.translation(delta);
276
- this.transform = Viewport_1.Viewport.transformBy(this.transform.transform.rightMul(transformUpdate));
277
- this.updateVelocity(pointer.screenPos);
278
- this.lastScreenCenter = pointer.screenPos;
279
- return transformUpdate;
280
- }
281
- onPointerMove({ allPointers }) {
282
- this.transform ??= Viewport_1.Viewport.transformBy(math_1.Mat33.identity);
283
- let transformUpdate = math_1.Mat33.identity;
284
- if (allPointers.length === 2) {
285
- transformUpdate = this.handleTwoFingerMove(allPointers);
286
- }
287
- else if (allPointers.length === 1) {
288
- transformUpdate = this.handleOneFingerMove(allPointers[0]);
289
- }
290
- Viewport_1.Viewport.transformBy(transformUpdate).apply(this.editor);
291
- this.lastTimestamp = performance.now();
292
- }
293
- onPointerUp(event) {
294
- const onComplete = () => {
295
- if (this.transform) {
296
- this.transform.unapply(this.editor);
297
- this.editor.dispatch(this.transform, false);
298
- }
299
- this.editor.display.setDraftMode(false);
300
- this.transform = null;
301
- this.velocity = math_1.Vec2.zero;
302
- };
303
- const minInertialScrollDt = 30;
304
- const shouldInertialScroll = event.current.device === Pointer_1.PointerDevice.Touch
305
- && event.allPointers.length === 1
306
- && this.velocity !== null
307
- && event.current.timeStamp - this.lastPointerDownTimestamp > minInertialScrollDt;
308
- if (shouldInertialScroll && this.velocity !== null) {
309
- const oldVelocity = this.velocity;
310
- // If the user drags the screen, then stops, then lifts the pointer,
311
- // we want the final velocity to reflect the stop at the end (so the velocity
312
- // should be near zero). Handle this:
313
- this.updateVelocity(event.current.screenPos);
314
- // Work around an input issue. Some devices that disable the touchscreen when a stylus
315
- // comes near the screen fire a touch-end event at the position of the stylus when a
316
- // touch gesture is canceled. Because the stylus is often far away from the last touch,
317
- // this causes a great displacement between the second-to-last (from the touchscreen) and
318
- // last (from the pen that is now near the screen) events. Only allow velocity to decrease
319
- // to work around this:
320
- if (oldVelocity.magnitude() < this.velocity.magnitude()) {
321
- this.velocity = oldVelocity;
322
- }
323
- // Cancel any ongoing inertial scrolling.
324
- this.inertialScroller?.stop();
325
- this.inertialScroller = new InertialScroller(this.velocity, (scrollDelta) => {
326
- if (!this.transform) {
327
- return;
328
- }
329
- const canvasDelta = this.editor.viewport.screenToCanvasTransform.transformVec3(scrollDelta);
330
- // Scroll by scrollDelta
331
- this.transform.unapply(this.editor);
332
- this.transform = Viewport_1.Viewport.transformBy(this.transform.transform.rightMul(math_1.Mat33.translation(canvasDelta)));
333
- this.transform.apply(this.editor);
334
- }, onComplete);
335
- }
336
- else {
337
- onComplete();
338
- }
339
- }
340
- onGestureCancel() {
341
- this.inertialScroller?.stop();
342
- this.velocity = math_1.Vec2.zero;
343
- this.transform?.unapply(this.editor);
344
- this.editor.display.setDraftMode(false);
345
- this.transform = null;
346
- }
347
- // Applies [transformUpdate] to the editor. This stacks on top of the
348
- // current transformation, if it exists.
349
- updateTransform(transformUpdate, announce = false) {
350
- let newTransform = transformUpdate;
351
- if (this.transform) {
352
- newTransform = this.transform.transform.rightMul(transformUpdate);
353
- }
354
- this.transform?.unapply(this.editor);
355
- this.transform = Viewport_1.Viewport.transformBy(newTransform);
356
- this.transform.apply(this.editor);
357
- if (announce) {
358
- this.editor.announceForAccessibility(this.transform.description(this.editor, this.editor.localization));
359
- }
360
- }
361
- onWheel({ delta, screenPos }) {
362
- this.inertialScroller?.stop();
363
- // Reset the transformation -- wheel events are individual events, so we don't
364
- // need to unapply/reapply.
365
- this.transform = Viewport_1.Viewport.transformBy(math_1.Mat33.identity);
366
- const canvasPos = this.editor.viewport.screenToCanvas(screenPos);
367
- const toCanvas = this.editor.viewport.screenToCanvasTransform;
368
- // Transform without including translation
369
- const translation = toCanvas.transformVec3(math_1.Vec3.of(-delta.x, -delta.y, 0));
370
- let pinchAmount = delta.z;
371
- // Clamp the magnitude of pinchAmount
372
- pinchAmount = Math.atan(pinchAmount / 2) * 2;
373
- const pinchZoomScaleFactor = 1.04;
374
- const transformUpdate = math_1.Mat33.scaling2D(Math.max(0.4, Math.min(Math.pow(pinchZoomScaleFactor, -pinchAmount), 4)), canvasPos).rightMul(math_1.Mat33.translation(translation));
375
- this.updateTransform(transformUpdate, true);
376
- return true;
377
- }
378
- onKeyPress(event) {
379
- this.inertialScroller?.stop();
380
- if (!(this.mode & PanZoomMode.Keyboard)) {
381
- return false;
382
- }
383
- // No need to keep the same the transform for keyboard events.
384
- this.transform = Viewport_1.Viewport.transformBy(math_1.Mat33.identity);
385
- let translation = math_1.Vec2.zero;
386
- let scale = 1;
387
- let rotation = 0;
388
- // Keyboard shortcut handling
389
- const shortcucts = this.editor.shortcuts;
390
- if (shortcucts.matchesShortcut(keybindings_1.moveLeftKeyboardShortcutId, event)) {
391
- translation = math_1.Vec2.of(-1, 0);
392
- }
393
- else if (shortcucts.matchesShortcut(keybindings_1.moveRightKeyboardShortcutId, event)) {
394
- translation = math_1.Vec2.of(1, 0);
395
- }
396
- else if (shortcucts.matchesShortcut(keybindings_1.moveUpKeyboardShortcutId, event)) {
397
- translation = math_1.Vec2.of(0, -1);
398
- }
399
- else if (shortcucts.matchesShortcut(keybindings_1.moveDownKeyboardShortcutId, event)) {
400
- translation = math_1.Vec2.of(0, 1);
401
- }
402
- else if (shortcucts.matchesShortcut(keybindings_1.zoomInKeyboardShortcutId, event)) {
403
- scale = 1 / 2;
404
- }
405
- else if (shortcucts.matchesShortcut(keybindings_1.zoomOutKeyboardShortcutId, event)) {
406
- scale = 2;
407
- }
408
- else if (shortcucts.matchesShortcut(keybindings_1.rotateClockwiseKeyboardShortcutId, event)) {
409
- rotation = 1;
410
- }
411
- else if (shortcucts.matchesShortcut(keybindings_1.rotateCounterClockwiseKeyboardShortcutId, event)) {
412
- rotation = -1;
413
- }
414
- else {
415
- return false;
416
- }
417
- // For each keypress,
418
- translation = translation.times(30); // Move at most 30 units
419
- rotation *= Math.PI / 8; // Rotate at least a sixteenth of a rotation
420
- // Transform the canvas, not the viewport:
421
- translation = translation.times(-1);
422
- rotation = rotation * -1;
423
- scale = 1 / scale;
424
- // Work around an issue that seems to be related to rotation matricies losing precision on inversion.
425
- // TODO: Figure out why and implement a better solution.
426
- if (rotation !== 0) {
427
- rotation += 0.0001;
428
- }
429
- if (this.isRotationLocked()) {
430
- rotation = 0;
431
- }
432
- const toCanvas = this.editor.viewport.screenToCanvasTransform;
433
- // Transform without translating (treat toCanvas as a linear instead of
434
- // an affine transformation).
435
- translation = toCanvas.transformVec3(translation);
436
- // Rotate/scale about the center of the canvas
437
- const transformCenter = this.editor.viewport.visibleRect.center;
438
- const transformUpdate = math_1.Mat33.scaling2D(scale, transformCenter).rightMul(math_1.Mat33.zRotation(rotation, transformCenter)).rightMul(math_1.Mat33.translation(translation));
439
- this.updateTransform(transformUpdate, true);
440
- return true;
441
- }
442
- isRotationLocked() {
443
- return !!(this.mode & PanZoomMode.RotationLocked);
444
- }
445
- /**
446
- * Changes the types of gestures used by this pan/zoom tool.
447
- *
448
- * @see {@link PanZoomMode} {@link setMode}
449
- *
450
- * @example
451
- * ```ts,runnable
452
- * import { Editor, PanZoomTool, PanZoomMode } from 'js-draw';
453
- *
454
- * const editor = new Editor(document.body);
455
- *
456
- * // By default, there are multiple PanZoom tools that handle different events.
457
- * // This gets all PanZoomTools.
458
- * const panZoomToolList = editor.toolController.getMatchingTools(PanZoomTool);
459
- *
460
- * // The first PanZoomTool is the highest priority -- by default,
461
- * // this tool is responsible for handling multi-finger touch gestures.
462
- * //
463
- * // Lower-priority PanZoomTools handle one-finger touch gestures and
464
- * // key-presses.
465
- * const panZoomTool = panZoomToolList[0];
466
- *
467
- * // Lock rotation for multi-finger touch gestures.
468
- * panZoomTool.setModeEnabled(PanZoomMode.RotationLocked, true);
469
- * ```
470
- */
471
- setModeEnabled(mode, enabled) {
472
- let newMode = this.mode;
473
- if (enabled) {
474
- newMode |= mode;
475
- }
476
- else {
477
- newMode &= ~mode;
478
- }
479
- this.setMode(newMode);
480
- }
481
- /**
482
- * Sets all modes for this tool using a bitmask.
483
- *
484
- * @see {@link setModeEnabled}
485
- *
486
- * @example
487
- * ```ts
488
- * tool.setMode(PanZoomMode.RotationLocked|PanZoomMode.TwoFingerTouchGestures);
489
- * ```
490
- */
491
- setMode(mode) {
492
- if (mode !== this.mode) {
493
- this.mode = mode;
494
- this.editor.notifier.dispatch(types_1.EditorEventType.ToolUpdated, {
495
- kind: types_1.EditorEventType.ToolUpdated,
496
- tool: this,
497
- });
498
- }
499
- }
500
- /**
501
- * Returns a bitmask indicating the currently-enabled modes.
502
- * @see {@link setModeEnabled}
503
- */
504
- getMode() {
505
- return this.mode;
506
- }
507
- }
508
- exports.default = PanZoom;
@@ -1 +0,0 @@
1
- export {};
@@ -1,23 +0,0 @@
1
- import Editor from '../Editor';
2
- import { PasteEvent } from '../inputEvents';
3
- import BaseTool from './BaseTool';
4
- /**
5
- * A tool that handles paste events (e.g. as triggered by ctrl+V).
6
- *
7
- * @example
8
- * While `ToolController` has a `PasteHandler` in its default list of tools,
9
- * if a non-default set is being used, `PasteHandler` can be added as follows:
10
- * ```ts
11
- * const toolController = editor.toolController;
12
- * toolController.addTool(new PasteHandler(editor));
13
- * ```
14
- */
15
- export default class PasteHandler extends BaseTool {
16
- private editor;
17
- constructor(editor: Editor);
18
- onPaste(event: PasteEvent): boolean;
19
- private addComponentsFromPaste;
20
- private doSVGPaste;
21
- private doTextPaste;
22
- private doImagePaste;
23
- }
@@ -1,109 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- const TextComponent_1 = __importDefault(require("../components/TextComponent"));
7
- const SVGLoader_1 = __importDefault(require("../SVGLoader/SVGLoader"));
8
- const math_1 = require("@js-draw/math");
9
- const BaseTool_1 = __importDefault(require("./BaseTool"));
10
- const TextTool_1 = __importDefault(require("./TextTool"));
11
- const ImageComponent_1 = __importDefault(require("../components/ImageComponent"));
12
- /**
13
- * A tool that handles paste events (e.g. as triggered by ctrl+V).
14
- *
15
- * @example
16
- * While `ToolController` has a `PasteHandler` in its default list of tools,
17
- * if a non-default set is being used, `PasteHandler` can be added as follows:
18
- * ```ts
19
- * const toolController = editor.toolController;
20
- * toolController.addTool(new PasteHandler(editor));
21
- * ```
22
- */
23
- class PasteHandler extends BaseTool_1.default {
24
- constructor(editor) {
25
- super(editor.notifier, editor.localization.pasteHandler);
26
- this.editor = editor;
27
- }
28
- // @internal
29
- onPaste(event) {
30
- const mime = event.mime.toLowerCase();
31
- const svgData = (() => {
32
- if (mime === 'image/svg+xml') {
33
- return event.data;
34
- }
35
- if (mime !== 'text/html') {
36
- return false;
37
- }
38
- // text/html is sometimes handlable SVG data. Use a hueristic
39
- // to determine if this is the case:
40
- // We use [^] and not . so that newlines are included.
41
- const match = event.data.match(/^[^]{0,200}<svg.*/i); // [^]{0,200} <- Allow for metadata near start
42
- if (!match) {
43
- return false;
44
- }
45
- // Extract the SVG element from the pasted data
46
- let svgEnd = event.data.toLowerCase().lastIndexOf('</svg>');
47
- if (svgEnd === -1)
48
- svgEnd = event.data.length;
49
- return event.data.substring(event.data.search(/<svg/i), svgEnd);
50
- })();
51
- if (svgData) {
52
- void this.doSVGPaste(svgData);
53
- return true;
54
- }
55
- else if (mime === 'text/plain') {
56
- void this.doTextPaste(event.data);
57
- return true;
58
- }
59
- else if (mime === 'image/png' || mime === 'image/jpeg') {
60
- void this.doImagePaste(event.data);
61
- return true;
62
- }
63
- return false;
64
- }
65
- async addComponentsFromPaste(components) {
66
- await this.editor.addAndCenterComponents(components, true, this.editor.localization.pasted(components.length));
67
- }
68
- async doSVGPaste(data) {
69
- this.editor.showLoadingWarning(0);
70
- try {
71
- const loader = SVGLoader_1.default.fromString(data, true);
72
- const components = [];
73
- await loader.start((component) => {
74
- components.push(component);
75
- }, (_countProcessed, _totalToProcess) => null);
76
- await this.addComponentsFromPaste(components);
77
- }
78
- finally {
79
- this.editor.hideLoadingWarning();
80
- }
81
- }
82
- async doTextPaste(text) {
83
- const textTools = this.editor.toolController.getMatchingTools(TextTool_1.default);
84
- textTools.sort((a, b) => {
85
- if (!a.isEnabled() && b.isEnabled()) {
86
- return -1;
87
- }
88
- if (!b.isEnabled() && a.isEnabled()) {
89
- return 1;
90
- }
91
- return 0;
92
- });
93
- const defaultTextStyle = { size: 12, fontFamily: 'sans', renderingStyle: { fill: math_1.Color4.red } };
94
- const pastedTextStyle = textTools[0]?.getTextStyle() ?? defaultTextStyle;
95
- // Don't paste text that would be invisible.
96
- if (text.trim() === '') {
97
- return;
98
- }
99
- const lines = text.split('\n');
100
- await this.addComponentsFromPaste([TextComponent_1.default.fromLines(lines, math_1.Mat33.identity, pastedTextStyle)]);
101
- }
102
- async doImagePaste(dataURL) {
103
- const image = new Image();
104
- image.src = dataURL;
105
- const component = await ImageComponent_1.default.fromImage(image, math_1.Mat33.identity);
106
- await this.addComponentsFromPaste([component]);
107
- }
108
- }
109
- exports.default = PasteHandler;