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,137 +0,0 @@
1
- import { assertUnreachable } from '../../util/assertions.mjs';
2
- import { Rect2, Vec2 } from '@js-draw/math';
3
- import { cssPrefix } from './SelectionTool.mjs';
4
- var HandleShape;
5
- (function (HandleShape) {
6
- HandleShape[HandleShape["Circle"] = 0] = "Circle";
7
- HandleShape[HandleShape["Square"] = 1] = "Square";
8
- })(HandleShape || (HandleShape = {}));
9
- export var HandleAction;
10
- (function (HandleAction) {
11
- HandleAction["ResizeXY"] = "resize-xy";
12
- HandleAction["Rotate"] = "rotate";
13
- HandleAction["ResizeX"] = "resize-x";
14
- HandleAction["ResizeY"] = "resize-y";
15
- })(HandleAction || (HandleAction = {}));
16
- // The *interactable* handle size. The visual size will be slightly smaller.
17
- export const handleSize = 30;
18
- export default class SelectionHandle {
19
- constructor(presentation, parent, viewport, onDragStart, onDragUpdate, onDragEnd) {
20
- this.presentation = presentation;
21
- this.parent = parent;
22
- this.viewport = viewport;
23
- this.onDragStart = onDragStart;
24
- this.onDragUpdate = onDragUpdate;
25
- this.onDragEnd = onDragEnd;
26
- this.dragLastPos = null;
27
- this.element = document.createElement('div');
28
- this.element.classList.add(`${cssPrefix}handle`, `${cssPrefix}${presentation.action}`);
29
- // Create a slightly smaller content/background element.
30
- const visibleContent = document.createElement('div');
31
- visibleContent.classList.add(`${cssPrefix}content`);
32
- this.element.appendChild(visibleContent);
33
- this.parentSide = presentation.side;
34
- const icon = presentation.icon;
35
- if (icon) {
36
- visibleContent.appendChild(icon);
37
- icon.classList.add('icon');
38
- }
39
- if (presentation.action === HandleAction.Rotate) {
40
- this.shape = HandleShape.Circle;
41
- }
42
- else {
43
- this.shape = HandleShape.Square;
44
- }
45
- switch (this.shape) {
46
- case HandleShape.Circle:
47
- this.element.classList.add(`${cssPrefix}circle`);
48
- break;
49
- case HandleShape.Square:
50
- this.element.classList.add(`${cssPrefix}square`);
51
- break;
52
- default:
53
- assertUnreachable(this.shape);
54
- }
55
- this.updatePosition();
56
- }
57
- /**
58
- * Adds this to `container`, where `conatiner` should be the background/selection
59
- * element visible on the screen.
60
- */
61
- addTo(container) {
62
- container.appendChild(this.element);
63
- }
64
- /**
65
- * Removes this element from its container. Should only be called
66
- * after {@link addTo}.
67
- */
68
- remove() { this.element.remove(); }
69
- /**
70
- * Returns this handle's bounding box relative to the top left of the
71
- * selection box.
72
- */
73
- getBBoxParentCoords() {
74
- const parentRect = this.parent.getScreenRegion();
75
- const size = Vec2.of(handleSize, handleSize);
76
- const topLeft = parentRect.size.scale(this.parentSide)
77
- // Center
78
- .minus(size.times(1 / 2));
79
- return new Rect2(topLeft.x, topLeft.y, size.x, size.y);
80
- }
81
- /** @returns this handle's bounding box relative to the canvas. */
82
- getBBoxCanvasCoords() {
83
- const parentRect = this.parent.region;
84
- const size = Vec2.of(handleSize, handleSize).times(1 / this.viewport.getScaleFactor());
85
- const topLeftFromParent = parentRect.size.scale(this.parentSide).minus(size.times(0.5));
86
- return new Rect2(topLeftFromParent.x, topLeftFromParent.y, size.x, size.y).translatedBy(parentRect.topLeft);
87
- }
88
- /**
89
- * Moves the HTML representation of this to the location matching its internal representation.
90
- */
91
- updatePosition() {
92
- const bbox = this.getBBoxParentCoords();
93
- // Position within the selection box.
94
- this.element.style.marginLeft = `${bbox.topLeft.x}px`;
95
- this.element.style.marginTop = `${bbox.topLeft.y}px`;
96
- this.element.style.width = `${bbox.w}px`;
97
- this.element.style.height = `${bbox.h}px`;
98
- }
99
- /** @returns true iff `point` (in editor **canvas** coordinates) is in this. */
100
- containsPoint(point) {
101
- const bbox = this.getBBoxCanvasCoords();
102
- const delta = point.minus(bbox.center);
103
- // Should have same x and y radius
104
- const radius = bbox.size.x / 2;
105
- let result;
106
- if (this.shape === HandleShape.Circle) {
107
- result = delta.magnitude() <= radius;
108
- }
109
- else {
110
- result = Math.abs(delta.x) <= radius && Math.abs(delta.y) <= radius;
111
- }
112
- return result;
113
- }
114
- handleDragStart(pointer) {
115
- this.onDragStart(pointer.canvasPos);
116
- this.dragLastPos = pointer.canvasPos;
117
- return true;
118
- }
119
- handleDragUpdate(pointer) {
120
- if (!this.dragLastPos) {
121
- return;
122
- }
123
- this.onDragUpdate(pointer.canvasPos);
124
- }
125
- handleDragEnd() {
126
- if (!this.dragLastPos) {
127
- return;
128
- }
129
- return this.onDragEnd();
130
- }
131
- setSnapToGrid(snap) {
132
- this.snapToGrid = snap;
133
- }
134
- isSnappingToGrid() {
135
- return this.snapToGrid;
136
- }
137
- }
@@ -1,40 +0,0 @@
1
- import AbstractComponent from '../../components/AbstractComponent';
2
- import Editor from '../../Editor';
3
- import { CopyEvent, KeyPressEvent, KeyUpEvent, PointerEvt } from '../../inputEvents';
4
- import BaseTool from '../BaseTool';
5
- import Selection from './Selection';
6
- export declare const cssPrefix = "selection-tool-";
7
- export default class SelectionTool extends BaseTool {
8
- private editor;
9
- private handleOverlay;
10
- private prevSelectionBox;
11
- private selectionBox;
12
- private startPoint;
13
- private expandingSelectionBox;
14
- private shiftKeyPressed;
15
- private snapToGrid;
16
- private lastPointer;
17
- private autoscroller;
18
- constructor(editor: Editor, description: string);
19
- private makeSelectionBox;
20
- private snapSelectionToGrid;
21
- private selectionBoxHandlingEvt;
22
- onPointerDown({ allPointers, current }: PointerEvt): boolean;
23
- onPointerMove(event: PointerEvt): void;
24
- private onMainPointerUpdated;
25
- onPointerUp(event: PointerEvt): void;
26
- onGestureCancel(): void;
27
- private lastSelectedObjects;
28
- private onSelectionUpdated;
29
- private zoomToSelection;
30
- private static handleableKeys;
31
- private hasUnfinalizedTransformFromKeyPress;
32
- onKeyPress(event: KeyPressEvent): boolean;
33
- onKeyUp(evt: KeyUpEvent): boolean;
34
- onCopy(event: CopyEvent): boolean;
35
- setEnabled(enabled: boolean): void;
36
- getSelection(): Selection | null;
37
- getSelectedObjects(): AbstractComponent[];
38
- setSelection(objects: AbstractComponent[]): void;
39
- clearSelection(): void;
40
- }
@@ -1,488 +0,0 @@
1
- import { Mat33, Vec2 } from '@js-draw/math';
2
- import { EditorEventType } from '../../types.mjs';
3
- import Viewport from '../../Viewport.mjs';
4
- import BaseTool from '../BaseTool.mjs';
5
- import CanvasRenderer from '../../rendering/renderers/CanvasRenderer.mjs';
6
- import SVGRenderer from '../../rendering/renderers/SVGRenderer.mjs';
7
- import Selection from './Selection.mjs';
8
- import TextComponent from '../../components/TextComponent.mjs';
9
- import { duplicateSelectionShortcut, selectAllKeyboardShortcut, sendToBackSelectionShortcut, snapToGridKeyboardShortcutId } from '../keybindings.mjs';
10
- import ToPointerAutoscroller from './ToPointerAutoscroller.mjs';
11
- export const cssPrefix = 'selection-tool-';
12
- // Allows users to select/transform portions of the `EditorImage`.
13
- // With respect to `extend`ing, `SelectionTool` is not stable.
14
- class SelectionTool extends BaseTool {
15
- constructor(editor, description) {
16
- super(editor.notifier, description);
17
- this.editor = editor;
18
- this.startPoint = null; // canvas position
19
- this.expandingSelectionBox = false;
20
- this.shiftKeyPressed = false;
21
- this.snapToGrid = false;
22
- this.lastPointer = null;
23
- this.selectionBoxHandlingEvt = false;
24
- this.lastSelectedObjects = [];
25
- // Whether the last keypress corresponded to an action that didn't transform the
26
- // selection (and thus does not need to be finalized on onKeyUp).
27
- this.hasUnfinalizedTransformFromKeyPress = false;
28
- this.autoscroller = new ToPointerAutoscroller(editor.viewport, (scrollBy) => {
29
- editor.dispatch(Viewport.transformBy(Mat33.translation(scrollBy)), false);
30
- // Update the selection box/content to match the new viewport.
31
- if (this.lastPointer) {
32
- // The viewport has changed -- ensure that the screen and canvas positions
33
- // of the pointer are both correct
34
- const updatedPointer = this.lastPointer.withScreenPosition(this.lastPointer.screenPos, editor.viewport);
35
- this.onMainPointerUpdated(updatedPointer);
36
- }
37
- });
38
- this.handleOverlay = document.createElement('div');
39
- editor.createHTMLOverlay(this.handleOverlay);
40
- this.handleOverlay.style.display = 'none';
41
- this.handleOverlay.classList.add('handleOverlay');
42
- editor.notifier.on(EditorEventType.ViewportChanged, _data => {
43
- // The selection box could be using the wet ink display if its transformation
44
- // hasn't been finalized yet. Clear before updating the UI.
45
- this.editor.clearWetInk();
46
- // If not currently selecting, ensure that the selection box
47
- // is large enough.
48
- if (!this.expandingSelectionBox) {
49
- this.selectionBox?.padRegion();
50
- }
51
- this.selectionBox?.updateUI();
52
- });
53
- this.editor.handleKeyEventsFrom(this.handleOverlay);
54
- this.editor.handlePointerEventsFrom(this.handleOverlay);
55
- }
56
- makeSelectionBox(selectionStartPos) {
57
- this.prevSelectionBox = this.selectionBox;
58
- this.selectionBox = new Selection(selectionStartPos, this.editor);
59
- if (!this.expandingSelectionBox) {
60
- // Remove any previous selection rects
61
- this.prevSelectionBox?.cancelSelection();
62
- }
63
- this.selectionBox.addTo(this.handleOverlay);
64
- }
65
- snapSelectionToGrid() {
66
- if (!this.selectionBox)
67
- throw new Error('No selection to snap!');
68
- // Snap the top left corner of what we have selected.
69
- const topLeftOfBBox = this.selectionBox.computeTightBoundingBox().topLeft;
70
- const snappedTopLeft = this.editor.viewport.snapToGrid(topLeftOfBBox);
71
- const snapDelta = snappedTopLeft.minus(topLeftOfBBox);
72
- const oldTransform = this.selectionBox.getTransform();
73
- this.selectionBox.setTransform(oldTransform.rightMul(Mat33.translation(snapDelta)));
74
- this.selectionBox.finalizeTransform();
75
- }
76
- onPointerDown({ allPointers, current }) {
77
- const snapToGrid = this.snapToGrid;
78
- if (snapToGrid) {
79
- current = current.snappedToGrid(this.editor.viewport);
80
- }
81
- if (allPointers.length === 1 && current.isPrimary) {
82
- this.startPoint = current.canvasPos;
83
- let transforming = false;
84
- if (this.selectionBox) {
85
- if (snapToGrid) {
86
- this.snapSelectionToGrid();
87
- }
88
- const dragStartResult = this.selectionBox.onDragStart(current);
89
- if (dragStartResult) {
90
- transforming = true;
91
- this.selectionBoxHandlingEvt = true;
92
- this.expandingSelectionBox = false;
93
- }
94
- }
95
- if (!transforming) {
96
- // Shift key: Combine the new and old selection boxes at the end of the gesture.
97
- this.expandingSelectionBox = this.shiftKeyPressed;
98
- this.makeSelectionBox(current.canvasPos);
99
- }
100
- else {
101
- // Only autoscroll if we're transforming an existing selection
102
- this.autoscroller.start();
103
- }
104
- return true;
105
- }
106
- return false;
107
- }
108
- onPointerMove(event) {
109
- this.onMainPointerUpdated(event.current);
110
- }
111
- onMainPointerUpdated(currentPointer) {
112
- this.lastPointer = currentPointer;
113
- if (!this.selectionBox)
114
- return;
115
- this.autoscroller.onPointerMove(currentPointer.screenPos);
116
- if (!this.expandingSelectionBox && this.shiftKeyPressed && this.startPoint) {
117
- const screenPos = this.editor.viewport.canvasToScreen(this.startPoint);
118
- currentPointer = currentPointer.lockedToXYAxesScreen(screenPos, this.editor.viewport);
119
- }
120
- if (this.snapToGrid) {
121
- currentPointer = currentPointer.snappedToGrid(this.editor.viewport);
122
- }
123
- if (this.selectionBoxHandlingEvt) {
124
- this.selectionBox.onDragUpdate(currentPointer);
125
- }
126
- else {
127
- this.selectionBox.setToPoint(currentPointer.canvasPos);
128
- }
129
- }
130
- onPointerUp(event) {
131
- this.autoscroller.stop();
132
- if (!this.selectionBox)
133
- return;
134
- let currentPointer = event.current;
135
- if (this.snapToGrid) {
136
- currentPointer = currentPointer.snappedToGrid(this.editor.viewport);
137
- }
138
- this.selectionBox.setToPoint(currentPointer.canvasPos);
139
- // Were we expanding the previous selection?
140
- if (this.expandingSelectionBox && this.prevSelectionBox) {
141
- // If so, finish expanding.
142
- this.expandingSelectionBox = false;
143
- this.selectionBox.resolveToObjects();
144
- this.setSelection([
145
- ...this.selectionBox.getSelectedObjects(),
146
- ...this.prevSelectionBox.getSelectedObjects(),
147
- ]);
148
- }
149
- else {
150
- if (!this.selectionBoxHandlingEvt) {
151
- // Expand/shrink the selection rectangle, if applicable
152
- this.selectionBox.resolveToObjects();
153
- this.onSelectionUpdated();
154
- }
155
- else {
156
- this.selectionBox.onDragEnd();
157
- }
158
- this.selectionBoxHandlingEvt = false;
159
- this.lastPointer = null;
160
- }
161
- }
162
- onGestureCancel() {
163
- this.autoscroller.stop();
164
- if (this.selectionBoxHandlingEvt) {
165
- this.selectionBox?.onDragCancel();
166
- }
167
- else {
168
- // Revert to the previous selection, if any.
169
- this.selectionBox?.cancelSelection();
170
- this.selectionBox = this.prevSelectionBox;
171
- this.selectionBox?.addTo(this.handleOverlay);
172
- this.selectionBox?.recomputeRegion();
173
- this.prevSelectionBox = null;
174
- }
175
- this.expandingSelectionBox = false;
176
- this.lastPointer = null;
177
- this.selectionBoxHandlingEvt = false;
178
- }
179
- onSelectionUpdated() {
180
- const selectedItemCount = this.selectionBox?.getSelectedItemCount() ?? 0;
181
- const selectedObjects = this.selectionBox?.getSelectedObjects() ?? [];
182
- const hasDifferentSelection = this.lastSelectedObjects.length !== selectedItemCount
183
- || selectedObjects.some((obj, i) => this.lastSelectedObjects[i] !== obj);
184
- if (hasDifferentSelection) {
185
- this.lastSelectedObjects = selectedObjects;
186
- // Note that the selection has changed
187
- this.editor.notifier.dispatch(EditorEventType.ToolUpdated, {
188
- kind: EditorEventType.ToolUpdated,
189
- tool: this,
190
- });
191
- // Only fire the SelectionUpdated event if the selection really updated.
192
- this.editor.notifier.dispatch(EditorEventType.SelectionUpdated, {
193
- kind: EditorEventType.SelectionUpdated,
194
- selectedComponents: selectedObjects,
195
- tool: this,
196
- });
197
- if (selectedItemCount > 0) {
198
- this.editor.announceForAccessibility(this.editor.localization.selectedElements(selectedItemCount));
199
- this.zoomToSelection();
200
- }
201
- }
202
- if (selectedItemCount === 0 && this.selectionBox) {
203
- this.selectionBox.cancelSelection();
204
- this.prevSelectionBox = this.selectionBox;
205
- this.selectionBox = null;
206
- }
207
- }
208
- zoomToSelection() {
209
- if (this.selectionBox) {
210
- const selectionRect = this.selectionBox.region;
211
- this.editor.dispatchNoAnnounce(this.editor.viewport.zoomTo(selectionRect, false), false);
212
- }
213
- }
214
- onKeyPress(event) {
215
- const shortcucts = this.editor.shortcuts;
216
- if (shortcucts.matchesShortcut(snapToGridKeyboardShortcutId, event)) {
217
- this.snapToGrid = true;
218
- return true;
219
- }
220
- if (this.selectionBox && (shortcucts.matchesShortcut(duplicateSelectionShortcut, event)
221
- || shortcucts.matchesShortcut(sendToBackSelectionShortcut, event))) {
222
- // Handle duplication on key up — we don't want to accidentally duplicate
223
- // many times.
224
- return true;
225
- }
226
- else if (shortcucts.matchesShortcut(selectAllKeyboardShortcut, event)) {
227
- this.setSelection(this.editor.image.getAllElements());
228
- return true;
229
- }
230
- else if (event.ctrlKey) {
231
- // Don't transform the selection with, for example, ctrl+i.
232
- // Pass it to another tool, if apliccable.
233
- return false;
234
- }
235
- else if (event.shiftKey || event.key === 'Shift') {
236
- this.shiftKeyPressed = true;
237
- if (event.key === 'Shift') {
238
- return true;
239
- }
240
- }
241
- let rotationSteps = 0;
242
- let xTranslateSteps = 0;
243
- let yTranslateSteps = 0;
244
- let xScaleSteps = 0;
245
- let yScaleSteps = 0;
246
- switch (event.key) {
247
- case 'a':
248
- case 'h':
249
- case 'ArrowLeft':
250
- xTranslateSteps -= 1;
251
- break;
252
- case 'd':
253
- case 'l':
254
- case 'ArrowRight':
255
- xTranslateSteps += 1;
256
- break;
257
- case 'q':
258
- case 'k':
259
- case 'ArrowUp':
260
- yTranslateSteps -= 1;
261
- break;
262
- case 'e':
263
- case 'j':
264
- case 'ArrowDown':
265
- yTranslateSteps += 1;
266
- break;
267
- case 'r':
268
- rotationSteps += 1;
269
- break;
270
- case 'R':
271
- rotationSteps -= 1;
272
- break;
273
- case 'i':
274
- xScaleSteps -= 1;
275
- break;
276
- case 'I':
277
- xScaleSteps += 1;
278
- break;
279
- case 'o':
280
- yScaleSteps -= 1;
281
- break;
282
- case 'O':
283
- yScaleSteps += 1;
284
- break;
285
- }
286
- let handled = xTranslateSteps !== 0
287
- || yTranslateSteps !== 0
288
- || rotationSteps !== 0
289
- || xScaleSteps !== 0
290
- || yScaleSteps !== 0;
291
- if (!this.selectionBox) {
292
- handled = false;
293
- }
294
- else if (handled) {
295
- const translateStepSize = 10 * this.editor.viewport.getSizeOfPixelOnCanvas();
296
- const rotateStepSize = Math.PI / 8;
297
- const scaleStepSize = 5 / 4;
298
- const region = this.selectionBox.region;
299
- const scaleFactor = Vec2.of(scaleStepSize ** xScaleSteps, scaleStepSize ** yScaleSteps);
300
- const rotationMat = Mat33.zRotation(rotationSteps * rotateStepSize);
301
- const roundedRotationMatrix = rotationMat.mapEntries(component => Viewport.roundScaleRatio(component));
302
- const regionCenter = this.editor.viewport.roundPoint(region.center);
303
- const transform = Mat33.scaling2D(scaleFactor, this.editor.viewport.roundPoint(region.topLeft)).rightMul(Mat33.translation(regionCenter).rightMul(roundedRotationMatrix).rightMul(Mat33.translation(regionCenter.times(-1)))).rightMul(Mat33.translation(this.editor.viewport.roundPoint(Vec2.of(xTranslateSteps, yTranslateSteps).times(translateStepSize))));
304
- const oldTransform = this.selectionBox.getTransform();
305
- this.selectionBox.setTransform(oldTransform.rightMul(transform));
306
- this.selectionBox.scrollTo();
307
- // The transformation needs to be finalized at some point (on key up)
308
- this.hasUnfinalizedTransformFromKeyPress = true;
309
- }
310
- if (this.selectionBox && !handled && (event.key === 'Delete' || event.key === 'Backspace')) {
311
- this.editor.dispatch(this.selectionBox.deleteSelectedObjects());
312
- this.clearSelection();
313
- handled = true;
314
- }
315
- return handled;
316
- }
317
- onKeyUp(evt) {
318
- const shortcucts = this.editor.shortcuts;
319
- if (shortcucts.matchesShortcut(snapToGridKeyboardShortcutId, evt)) {
320
- this.snapToGrid = false;
321
- return true;
322
- }
323
- if (shortcucts.matchesShortcut(selectAllKeyboardShortcut, evt)) {
324
- // Selected all in onKeyDown. Don't finalizeTransform.
325
- return true;
326
- }
327
- if (this.selectionBox && shortcucts.matchesShortcut(duplicateSelectionShortcut, evt)) {
328
- // Finalize duplicating the selection
329
- this.selectionBox.duplicateSelectedObjects().then(command => {
330
- this.editor.dispatch(command);
331
- });
332
- return true;
333
- }
334
- if (this.selectionBox && shortcucts.matchesShortcut(sendToBackSelectionShortcut, evt)) {
335
- const sendToBackCommand = this.selectionBox.sendToBack();
336
- if (sendToBackCommand) {
337
- this.editor.dispatch(sendToBackCommand);
338
- }
339
- return true;
340
- }
341
- // Here, we check if shiftKey === false because, as of this writing,
342
- // evt.shiftKey is an optional property. Being falsey could just mean
343
- // that it wasn't set.
344
- if (evt.shiftKey === false) {
345
- this.shiftKeyPressed = false;
346
- // Don't return immediately -- event may be otherwise handled
347
- }
348
- // Also check for key === 'Shift' (for the case where shiftKey is undefined)
349
- if (evt.key === 'Shift') {
350
- this.shiftKeyPressed = false;
351
- return true;
352
- }
353
- // If we don't need to finalize the transform
354
- if (!this.hasUnfinalizedTransformFromKeyPress) {
355
- return true;
356
- }
357
- if (this.selectionBox && SelectionTool.handleableKeys.some(key => key === evt.key)) {
358
- this.selectionBox.finalizeTransform();
359
- this.hasUnfinalizedTransformFromKeyPress = false;
360
- return true;
361
- }
362
- return false;
363
- }
364
- onCopy(event) {
365
- if (!this.selectionBox) {
366
- return false;
367
- }
368
- const selectedElems = this.selectionBox.getSelectedObjects();
369
- const bbox = this.selectionBox.region;
370
- if (selectedElems.length === 0) {
371
- return false;
372
- }
373
- const exportViewport = new Viewport(() => { });
374
- const selectionScreenSize = this.selectionBox.getScreenRegion().size.times(this.editor.display.getDevicePixelRatio());
375
- // Update the viewport to have screen size roughly equal to the size of the selection box
376
- let scaleFactor = selectionScreenSize.maximumEntryMagnitude() / (bbox.size.maximumEntryMagnitude() || 1);
377
- // Round to a nearby power of two
378
- scaleFactor = Math.pow(2, Math.ceil(Math.log2(scaleFactor)));
379
- exportViewport.updateScreenSize(bbox.size.times(scaleFactor));
380
- exportViewport.resetTransform(Mat33.scaling2D(scaleFactor)
381
- // Move the selection onto the screen
382
- .rightMul(Mat33.translation(bbox.topLeft.times(-1))));
383
- const { element: svgExportElem, renderer: svgRenderer } = SVGRenderer.fromViewport(exportViewport, { sanitize: true, useViewBoxForPositioning: true });
384
- const { element: canvas, renderer: canvasRenderer } = CanvasRenderer.fromViewport(exportViewport, { maxCanvasDimen: 4096 });
385
- const text = [];
386
- for (const elem of selectedElems) {
387
- elem.render(svgRenderer);
388
- elem.render(canvasRenderer);
389
- if (elem instanceof TextComponent) {
390
- text.push(elem.getText());
391
- }
392
- }
393
- event.setData('image/svg+xml', svgExportElem.outerHTML);
394
- event.setData('text/html', svgExportElem.outerHTML);
395
- event.setData('image/png', new Promise((resolve, reject) => {
396
- canvas.toBlob((blob) => {
397
- if (blob) {
398
- resolve(blob);
399
- }
400
- else {
401
- reject(new Error('Failed to convert canvas to blob.'));
402
- }
403
- }, 'image/png');
404
- }));
405
- if (text.length > 0) {
406
- event.setData('text/plain', text.join('\n'));
407
- }
408
- return true;
409
- }
410
- setEnabled(enabled) {
411
- const wasEnabled = this.isEnabled();
412
- super.setEnabled(enabled);
413
- if (wasEnabled === enabled) {
414
- return;
415
- }
416
- // Clear the selection
417
- this.selectionBox?.cancelSelection();
418
- this.onSelectionUpdated();
419
- this.handleOverlay.replaceChildren();
420
- this.selectionBox = null;
421
- this.shiftKeyPressed = false;
422
- this.snapToGrid = false;
423
- this.handleOverlay.style.display = enabled ? 'block' : 'none';
424
- if (enabled) {
425
- this.handleOverlay.tabIndex = 0;
426
- this.handleOverlay.setAttribute('aria-label', this.editor.localization.selectionToolKeyboardShortcuts);
427
- }
428
- else {
429
- this.handleOverlay.tabIndex = -1;
430
- }
431
- }
432
- // Get the object responsible for displaying this' selection.
433
- // @internal
434
- getSelection() {
435
- return this.selectionBox;
436
- }
437
- getSelectedObjects() {
438
- return this.selectionBox?.getSelectedObjects() ?? [];
439
- }
440
- // Select the given `objects`. Any non-selectable objects in `objects` are ignored.
441
- setSelection(objects) {
442
- // Only select selectable objects.
443
- objects = objects.filter(obj => obj.isSelectable());
444
- // Sort by z-index
445
- objects.sort((a, b) => a.getZIndex() - b.getZIndex());
446
- // Remove duplicates
447
- objects = objects.filter((current, idx) => {
448
- if (idx > 0) {
449
- return current !== objects[idx - 1];
450
- }
451
- return true;
452
- });
453
- let bbox = null;
454
- for (const object of objects) {
455
- if (bbox) {
456
- bbox = bbox.union(object.getBBox());
457
- }
458
- else {
459
- bbox = object.getBBox();
460
- }
461
- }
462
- if (!bbox) {
463
- return;
464
- }
465
- this.clearSelection();
466
- if (!this.selectionBox) {
467
- this.makeSelectionBox(bbox.topLeft);
468
- }
469
- this.selectionBox.setSelectedObjects(objects, bbox);
470
- this.onSelectionUpdated();
471
- }
472
- clearSelection() {
473
- this.handleOverlay.replaceChildren();
474
- this.prevSelectionBox = this.selectionBox;
475
- this.selectionBox = null;
476
- this.onSelectionUpdated();
477
- }
478
- }
479
- SelectionTool.handleableKeys = [
480
- 'a', 'h', 'ArrowLeft',
481
- 'd', 'l', 'ArrowRight',
482
- 'q', 'k', 'ArrowUp',
483
- 'e', 'j', 'ArrowDown',
484
- 'r', 'R',
485
- 'i', 'I', 'o', 'O',
486
- 'Control', 'Meta',
487
- ];
488
- export default SelectionTool;
@@ -1 +0,0 @@
1
- export {};