js-draw 0.3.2 → 0.4.1

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.
Files changed (104) hide show
  1. package/.github/pull_request_template.md +15 -0
  2. package/.github/workflows/firebase-hosting-merge.yml +7 -0
  3. package/.github/workflows/firebase-hosting-pull-request.yml +10 -0
  4. package/.github/workflows/github-pages.yml +2 -0
  5. package/CHANGELOG.md +16 -1
  6. package/README.md +1 -3
  7. package/dist/bundle.js +1 -1
  8. package/dist/src/Editor.d.ts +11 -0
  9. package/dist/src/Editor.js +107 -77
  10. package/dist/src/Pointer.d.ts +1 -1
  11. package/dist/src/Pointer.js +8 -3
  12. package/dist/src/Viewport.d.ts +1 -0
  13. package/dist/src/Viewport.js +14 -1
  14. package/dist/src/components/AbstractComponent.js +1 -0
  15. package/dist/src/components/ImageComponent.d.ts +2 -2
  16. package/dist/src/components/Stroke.js +15 -9
  17. package/dist/src/components/Text.d.ts +1 -1
  18. package/dist/src/components/Text.js +1 -1
  19. package/dist/src/components/builders/FreehandLineBuilder.d.ts +1 -0
  20. package/dist/src/components/builders/FreehandLineBuilder.js +34 -36
  21. package/dist/src/language/assertions.d.ts +1 -0
  22. package/dist/src/language/assertions.js +5 -0
  23. package/dist/src/math/Mat33.d.ts +38 -2
  24. package/dist/src/math/Mat33.js +30 -1
  25. package/dist/src/math/Path.d.ts +1 -1
  26. package/dist/src/math/Path.js +10 -8
  27. package/dist/src/math/Vec3.d.ts +12 -2
  28. package/dist/src/math/Vec3.js +16 -1
  29. package/dist/src/math/rounding.d.ts +1 -0
  30. package/dist/src/math/rounding.js +13 -6
  31. package/dist/src/rendering/renderers/AbstractRenderer.js +2 -1
  32. package/dist/src/testing/beforeEachFile.d.ts +1 -0
  33. package/dist/src/testing/beforeEachFile.js +3 -0
  34. package/dist/src/testing/createEditor.d.ts +1 -0
  35. package/dist/src/testing/createEditor.js +7 -1
  36. package/dist/src/testing/loadExpectExtensions.d.ts +0 -15
  37. package/dist/src/toolbar/HTMLToolbar.js +5 -4
  38. package/dist/src/toolbar/widgets/SelectionToolWidget.d.ts +1 -1
  39. package/dist/src/tools/PasteHandler.js +3 -1
  40. package/dist/src/tools/Pen.js +1 -1
  41. package/dist/src/tools/SelectionTool/Selection.d.ts +54 -0
  42. package/dist/src/tools/SelectionTool/Selection.js +337 -0
  43. package/dist/src/tools/SelectionTool/SelectionHandle.d.ts +35 -0
  44. package/dist/src/tools/SelectionTool/SelectionHandle.js +75 -0
  45. package/dist/src/tools/SelectionTool/SelectionTool.d.ts +31 -0
  46. package/dist/src/tools/SelectionTool/SelectionTool.js +284 -0
  47. package/dist/src/tools/SelectionTool/TransformMode.d.ts +34 -0
  48. package/dist/src/tools/SelectionTool/TransformMode.js +98 -0
  49. package/dist/src/tools/SelectionTool/types.d.ts +9 -0
  50. package/dist/src/tools/SelectionTool/types.js +11 -0
  51. package/dist/src/tools/ToolController.js +1 -1
  52. package/dist/src/tools/lib.d.ts +1 -1
  53. package/dist/src/tools/lib.js +1 -1
  54. package/dist/src/types.d.ts +1 -1
  55. package/jest.config.js +5 -0
  56. package/package.json +15 -14
  57. package/src/Editor.css +1 -0
  58. package/src/Editor.ts +147 -108
  59. package/src/Pointer.ts +8 -3
  60. package/src/Viewport.ts +17 -2
  61. package/src/components/AbstractComponent.ts +4 -6
  62. package/src/components/ImageComponent.ts +2 -6
  63. package/src/components/Stroke.test.ts +0 -3
  64. package/src/components/Stroke.ts +14 -7
  65. package/src/components/Text.test.ts +0 -3
  66. package/src/components/Text.ts +4 -8
  67. package/src/components/builders/FreehandLineBuilder.ts +37 -43
  68. package/src/language/assertions.ts +6 -0
  69. package/src/math/LineSegment2.test.ts +8 -10
  70. package/src/math/Mat33.test.ts +14 -2
  71. package/src/math/Mat33.ts +43 -2
  72. package/src/math/Path.toString.test.ts +12 -1
  73. package/src/math/Path.ts +11 -9
  74. package/src/math/Rect2.test.ts +0 -3
  75. package/src/math/Vec2.test.ts +0 -3
  76. package/src/math/Vec3.test.ts +0 -3
  77. package/src/math/Vec3.ts +23 -2
  78. package/src/math/rounding.test.ts +30 -5
  79. package/src/math/rounding.ts +16 -7
  80. package/src/rendering/renderers/AbstractRenderer.ts +3 -2
  81. package/src/testing/beforeEachFile.ts +3 -0
  82. package/src/testing/createEditor.ts +8 -1
  83. package/src/testing/global.d.ts +17 -0
  84. package/src/testing/loadExpectExtensions.ts +0 -15
  85. package/src/toolbar/HTMLToolbar.ts +5 -4
  86. package/src/toolbar/toolbar.css +3 -2
  87. package/src/toolbar/widgets/SelectionToolWidget.ts +1 -1
  88. package/src/tools/PasteHandler.ts +4 -1
  89. package/src/tools/Pen.test.ts +150 -0
  90. package/src/tools/Pen.ts +1 -1
  91. package/src/tools/SelectionTool/Selection.ts +455 -0
  92. package/src/tools/SelectionTool/SelectionHandle.ts +99 -0
  93. package/src/tools/SelectionTool/SelectionTool.css +22 -0
  94. package/src/tools/{SelectionTool.test.ts → SelectionTool/SelectionTool.test.ts} +21 -21
  95. package/src/tools/SelectionTool/SelectionTool.ts +344 -0
  96. package/src/tools/SelectionTool/TransformMode.ts +114 -0
  97. package/src/tools/SelectionTool/types.ts +11 -0
  98. package/src/tools/ToolController.ts +1 -1
  99. package/src/tools/lib.ts +1 -1
  100. package/src/types.ts +1 -1
  101. package/tsconfig.json +3 -1
  102. package/dist/src/tools/SelectionTool.d.ts +0 -65
  103. package/dist/src/tools/SelectionTool.js +0 -647
  104. package/src/tools/SelectionTool.ts +0 -797
@@ -0,0 +1,284 @@
1
+ // Allows users to select/transform portions of the `EditorImage`.
2
+ // With respect to `extend`ing, `SelectionTool` is not stable.
3
+ // @packageDocumentation
4
+ import Mat33 from '../../math/Mat33';
5
+ import { Vec2 } from '../../math/Vec2';
6
+ import { EditorEventType } from '../../types';
7
+ import Viewport from '../../Viewport';
8
+ import BaseTool from '../BaseTool';
9
+ import SVGRenderer from '../../rendering/renderers/SVGRenderer';
10
+ import Selection from './Selection';
11
+ import TextComponent from '../../components/Text';
12
+ export const cssPrefix = 'selection-tool-';
13
+ // {@inheritDoc SelectionTool!}
14
+ export default class SelectionTool extends BaseTool {
15
+ constructor(editor, description) {
16
+ super(editor.notifier, description);
17
+ this.editor = editor;
18
+ this.lastEvtTarget = null;
19
+ this.selectionBoxHandlingEvt = false;
20
+ this.handleOverlay = document.createElement('div');
21
+ editor.createHTMLOverlay(this.handleOverlay);
22
+ this.handleOverlay.style.display = 'none';
23
+ this.handleOverlay.classList.add('handleOverlay');
24
+ editor.notifier.on(EditorEventType.ViewportChanged, _data => {
25
+ var _a;
26
+ (_a = this.selectionBox) === null || _a === void 0 ? void 0 : _a.updateUI();
27
+ });
28
+ this.editor.handleKeyEventsFrom(this.handleOverlay);
29
+ this.editor.handlePointerEventsFrom(this.handleOverlay, (eventName, htmlEvent) => {
30
+ if (eventName === 'pointerdown') {
31
+ this.lastEvtTarget = htmlEvent.target;
32
+ }
33
+ return true;
34
+ });
35
+ }
36
+ makeSelectionBox(selectionStartPos) {
37
+ this.prevSelectionBox = this.selectionBox;
38
+ this.selectionBox = new Selection(selectionStartPos, this.editor);
39
+ // Remove any previous selection rects
40
+ this.handleOverlay.replaceChildren();
41
+ this.selectionBox.addTo(this.handleOverlay);
42
+ }
43
+ onPointerDown(event) {
44
+ var _a;
45
+ if (event.allPointers.length === 1 && event.current.isPrimary) {
46
+ if (this.lastEvtTarget && ((_a = this.selectionBox) === null || _a === void 0 ? void 0 : _a.onDragStart(event.current, this.lastEvtTarget))) {
47
+ this.selectionBoxHandlingEvt = true;
48
+ }
49
+ else {
50
+ this.makeSelectionBox(event.current.canvasPos);
51
+ }
52
+ return true;
53
+ }
54
+ return false;
55
+ }
56
+ onPointerMove(event) {
57
+ if (!this.selectionBox)
58
+ return;
59
+ if (this.selectionBoxHandlingEvt) {
60
+ this.selectionBox.onDragUpdate(event.current);
61
+ }
62
+ else {
63
+ this.selectionBox.setToPoint(event.current.canvasPos);
64
+ }
65
+ }
66
+ onSelectionUpdated() {
67
+ var _a, _b;
68
+ // Note that the selection has changed
69
+ this.editor.notifier.dispatch(EditorEventType.ToolUpdated, {
70
+ kind: EditorEventType.ToolUpdated,
71
+ tool: this,
72
+ });
73
+ const selectedItemCount = (_b = (_a = this.selectionBox) === null || _a === void 0 ? void 0 : _a.getSelectedItemCount()) !== null && _b !== void 0 ? _b : 0;
74
+ if (selectedItemCount > 0) {
75
+ this.editor.announceForAccessibility(this.editor.localization.selectedElements(selectedItemCount));
76
+ this.zoomToSelection();
77
+ }
78
+ else if (this.selectionBox) {
79
+ this.selectionBox.cancelSelection();
80
+ this.prevSelectionBox = this.selectionBox;
81
+ this.selectionBox = null;
82
+ }
83
+ }
84
+ onGestureEnd() {
85
+ this.lastEvtTarget = null;
86
+ if (!this.selectionBox)
87
+ return;
88
+ if (!this.selectionBoxHandlingEvt) {
89
+ // Expand/shrink the selection rectangle, if applicable
90
+ this.selectionBox.resolveToObjects();
91
+ this.onSelectionUpdated();
92
+ }
93
+ else {
94
+ this.selectionBox.onDragEnd();
95
+ }
96
+ this.selectionBoxHandlingEvt = false;
97
+ }
98
+ zoomToSelection() {
99
+ if (this.selectionBox) {
100
+ const selectionRect = this.selectionBox.region;
101
+ this.editor.dispatchNoAnnounce(this.editor.viewport.zoomTo(selectionRect, false), false);
102
+ }
103
+ }
104
+ onPointerUp(event) {
105
+ if (!this.selectionBox)
106
+ return;
107
+ this.selectionBox.setToPoint(event.current.canvasPos);
108
+ this.onGestureEnd();
109
+ }
110
+ onGestureCancel() {
111
+ var _a, _b, _c;
112
+ if (this.selectionBoxHandlingEvt) {
113
+ (_a = this.selectionBox) === null || _a === void 0 ? void 0 : _a.onDragCancel();
114
+ }
115
+ else {
116
+ // Revert to the previous selection, if any.
117
+ (_b = this.selectionBox) === null || _b === void 0 ? void 0 : _b.cancelSelection();
118
+ this.selectionBox = this.prevSelectionBox;
119
+ (_c = this.selectionBox) === null || _c === void 0 ? void 0 : _c.addTo(this.handleOverlay);
120
+ }
121
+ }
122
+ onKeyPress(event) {
123
+ let rotationSteps = 0;
124
+ let xTranslateSteps = 0;
125
+ let yTranslateSteps = 0;
126
+ let xScaleSteps = 0;
127
+ let yScaleSteps = 0;
128
+ switch (event.key) {
129
+ case 'a':
130
+ case 'h':
131
+ case 'ArrowLeft':
132
+ xTranslateSteps -= 1;
133
+ break;
134
+ case 'd':
135
+ case 'l':
136
+ case 'ArrowRight':
137
+ xTranslateSteps += 1;
138
+ break;
139
+ case 'q':
140
+ case 'k':
141
+ case 'ArrowUp':
142
+ yTranslateSteps -= 1;
143
+ break;
144
+ case 'e':
145
+ case 'j':
146
+ case 'ArrowDown':
147
+ yTranslateSteps += 1;
148
+ break;
149
+ case 'r':
150
+ rotationSteps += 1;
151
+ break;
152
+ case 'R':
153
+ rotationSteps -= 1;
154
+ break;
155
+ case 'i':
156
+ xScaleSteps -= 1;
157
+ break;
158
+ case 'I':
159
+ xScaleSteps += 1;
160
+ break;
161
+ case 'o':
162
+ yScaleSteps -= 1;
163
+ break;
164
+ case 'O':
165
+ yScaleSteps += 1;
166
+ break;
167
+ }
168
+ let handled = xTranslateSteps !== 0
169
+ || yTranslateSteps !== 0
170
+ || rotationSteps !== 0
171
+ || xScaleSteps !== 0
172
+ || yScaleSteps !== 0;
173
+ if (!this.selectionBox) {
174
+ handled = false;
175
+ }
176
+ else if (handled) {
177
+ const translateStepSize = 10 * this.editor.viewport.getSizeOfPixelOnCanvas();
178
+ const rotateStepSize = Math.PI / 8;
179
+ const scaleStepSize = 5 / 4;
180
+ const region = this.selectionBox.region;
181
+ const scaleFactor = Vec2.of(Math.pow(scaleStepSize, xScaleSteps), Math.pow(scaleStepSize, yScaleSteps));
182
+ const rotationMat = Mat33.zRotation(rotationSteps * rotateStepSize);
183
+ const roundedRotationMatrix = rotationMat.mapEntries(component => Viewport.roundScaleRatio(component));
184
+ const regionCenter = this.editor.viewport.roundPoint(region.center);
185
+ 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))));
186
+ const oldTransform = this.selectionBox.getTransform();
187
+ this.selectionBox.setTransform(oldTransform.rightMul(transform));
188
+ }
189
+ if (this.selectionBox && !handled && (event.key === 'Delete' || event.key === 'Backspace')) {
190
+ this.editor.dispatch(this.selectionBox.deleteSelectedObjects());
191
+ this.clearSelection();
192
+ handled = true;
193
+ }
194
+ return handled;
195
+ }
196
+ onKeyUp(evt) {
197
+ if (this.selectionBox && SelectionTool.handleableKeys.some(key => key === evt.key)) {
198
+ this.selectionBox.finalizeTransform();
199
+ return true;
200
+ }
201
+ return false;
202
+ }
203
+ onCopy(event) {
204
+ if (!this.selectionBox) {
205
+ return false;
206
+ }
207
+ const selectedElems = this.selectionBox.getSelectedObjects();
208
+ const bbox = this.selectionBox.region;
209
+ if (selectedElems.length === 0) {
210
+ return false;
211
+ }
212
+ const exportViewport = new Viewport(this.editor.notifier);
213
+ exportViewport.updateScreenSize(Vec2.of(bbox.w, bbox.h));
214
+ exportViewport.resetTransform(Mat33.translation(bbox.topLeft));
215
+ const svgNameSpace = 'http://www.w3.org/2000/svg';
216
+ const exportElem = document.createElementNS(svgNameSpace, 'svg');
217
+ const sanitize = true;
218
+ const renderer = new SVGRenderer(exportElem, exportViewport, sanitize);
219
+ const text = [];
220
+ for (const elem of selectedElems) {
221
+ elem.render(renderer);
222
+ if (elem instanceof TextComponent) {
223
+ text.push(elem.getText());
224
+ }
225
+ }
226
+ event.setData('image/svg+xml', exportElem.outerHTML);
227
+ if (text.length > 0) {
228
+ event.setData('text/plain', text.join('\n'));
229
+ }
230
+ return true;
231
+ }
232
+ setEnabled(enabled) {
233
+ super.setEnabled(enabled);
234
+ // Clear the selection
235
+ this.handleOverlay.replaceChildren();
236
+ this.selectionBox = null;
237
+ this.handleOverlay.style.display = enabled ? 'block' : 'none';
238
+ if (enabled) {
239
+ this.handleOverlay.tabIndex = 0;
240
+ this.handleOverlay.setAttribute('aria-label', this.editor.localization.selectionToolKeyboardShortcuts);
241
+ }
242
+ else {
243
+ this.handleOverlay.tabIndex = -1;
244
+ }
245
+ }
246
+ // Get the object responsible for displaying this' selection.
247
+ getSelection() {
248
+ return this.selectionBox;
249
+ }
250
+ setSelection(objects) {
251
+ let bbox = null;
252
+ for (const object of objects) {
253
+ if (bbox) {
254
+ bbox = bbox.union(object.getBBox());
255
+ }
256
+ else {
257
+ bbox = object.getBBox();
258
+ }
259
+ }
260
+ if (!bbox) {
261
+ return;
262
+ }
263
+ this.clearSelection();
264
+ if (!this.selectionBox) {
265
+ this.makeSelectionBox(bbox.topLeft);
266
+ }
267
+ this.selectionBox.setSelectedObjects(objects, bbox);
268
+ this.onSelectionUpdated();
269
+ }
270
+ clearSelection() {
271
+ this.handleOverlay.replaceChildren();
272
+ this.prevSelectionBox = this.selectionBox;
273
+ this.selectionBox = null;
274
+ this.onSelectionUpdated();
275
+ }
276
+ }
277
+ SelectionTool.handleableKeys = [
278
+ 'a', 'h', 'ArrowLeft',
279
+ 'd', 'l', 'ArrowRight',
280
+ 'q', 'k', 'ArrowUp',
281
+ 'e', 'j', 'ArrowDown',
282
+ 'r', 'R',
283
+ 'i', 'I', 'o', 'O',
284
+ ];
@@ -0,0 +1,34 @@
1
+ import Editor from '../../Editor';
2
+ import Vec3 from '../../math/Vec3';
3
+ import Selection from './Selection';
4
+ import { ResizeMode } from './types';
5
+ export declare class DragTransformer {
6
+ private readonly editor;
7
+ private selection;
8
+ private dragStartPoint;
9
+ constructor(editor: Editor, selection: Selection);
10
+ onDragStart(startPoint: Vec3): void;
11
+ onDragUpdate(canvasPos: Vec3): void;
12
+ onDragEnd(): void;
13
+ }
14
+ export declare class ResizeTransformer {
15
+ private readonly editor;
16
+ private selection;
17
+ private mode;
18
+ private dragStartPoint;
19
+ constructor(editor: Editor, selection: Selection);
20
+ onDragStart(startPoint: Vec3, mode: ResizeMode): void;
21
+ onDragUpdate(canvasPos: Vec3): void;
22
+ onDragEnd(): void;
23
+ }
24
+ export declare class RotateTransformer {
25
+ private readonly editor;
26
+ private selection;
27
+ private startAngle;
28
+ constructor(editor: Editor, selection: Selection);
29
+ private getAngle;
30
+ private roundAngle;
31
+ onDragStart(startPoint: Vec3): void;
32
+ onDragUpdate(canvasPos: Vec3): void;
33
+ onDragEnd(): void;
34
+ }
@@ -0,0 +1,98 @@
1
+ import Mat33 from '../../math/Mat33';
2
+ import { Vec2 } from '../../math/Vec2';
3
+ import Viewport from '../../Viewport';
4
+ import { ResizeMode } from './types';
5
+ export class DragTransformer {
6
+ constructor(editor, selection) {
7
+ this.editor = editor;
8
+ this.selection = selection;
9
+ }
10
+ onDragStart(startPoint) {
11
+ this.selection.setTransform(Mat33.identity);
12
+ this.dragStartPoint = startPoint;
13
+ }
14
+ onDragUpdate(canvasPos) {
15
+ const delta = this.editor.viewport.roundPoint(canvasPos.minus(this.dragStartPoint));
16
+ this.selection.setTransform(Mat33.translation(delta));
17
+ }
18
+ onDragEnd() {
19
+ this.selection.finalizeTransform();
20
+ }
21
+ }
22
+ export class ResizeTransformer {
23
+ constructor(editor, selection) {
24
+ this.editor = editor;
25
+ this.selection = selection;
26
+ this.mode = ResizeMode.Both;
27
+ }
28
+ onDragStart(startPoint, mode) {
29
+ this.selection.setTransform(Mat33.identity);
30
+ this.mode = mode;
31
+ this.dragStartPoint = startPoint;
32
+ }
33
+ onDragUpdate(canvasPos) {
34
+ const canvasDelta = canvasPos.minus(this.dragStartPoint);
35
+ const origWidth = this.selection.preTransformRegion.width;
36
+ const origHeight = this.selection.preTransformRegion.height;
37
+ let scale = Vec2.of(1, 1);
38
+ if (this.mode === ResizeMode.HorizontalOnly) {
39
+ const newWidth = origWidth + canvasDelta.x;
40
+ scale = Vec2.of(newWidth / origWidth, scale.y);
41
+ }
42
+ if (this.mode === ResizeMode.VerticalOnly) {
43
+ const newHeight = origHeight + canvasDelta.y;
44
+ scale = Vec2.of(scale.x, newHeight / origHeight);
45
+ }
46
+ if (this.mode === ResizeMode.Both) {
47
+ const delta = Math.abs(canvasDelta.x) > Math.abs(canvasDelta.y) ? canvasDelta.x : canvasDelta.y;
48
+ const newWidth = origWidth + delta;
49
+ scale = Vec2.of(newWidth / origWidth, newWidth / origWidth);
50
+ }
51
+ // Round: If this isn't done, scaling can create numbers with long decimal representations.
52
+ // long decimal representations => large file sizes.
53
+ scale = scale.map(component => Viewport.roundScaleRatio(component, 2));
54
+ if (scale.x > 0 && scale.y > 0) {
55
+ const origin = this.editor.viewport.roundPoint(this.selection.preTransformRegion.topLeft);
56
+ this.selection.setTransform(Mat33.scaling2D(scale, origin));
57
+ }
58
+ }
59
+ onDragEnd() {
60
+ this.selection.finalizeTransform();
61
+ }
62
+ }
63
+ export class RotateTransformer {
64
+ constructor(editor, selection) {
65
+ this.editor = editor;
66
+ this.selection = selection;
67
+ this.startAngle = 0;
68
+ }
69
+ getAngle(canvasPoint) {
70
+ const selectionCenter = this.selection.preTransformRegion.center;
71
+ const offset = canvasPoint.minus(selectionCenter);
72
+ return offset.angle();
73
+ }
74
+ roundAngle(angle) {
75
+ // Round angles to the nearest 16th of a turn
76
+ const roundingFactor = 16 / 2 / Math.PI;
77
+ return Math.round(angle * roundingFactor) / roundingFactor;
78
+ }
79
+ onDragStart(startPoint) {
80
+ this.selection.setTransform(Mat33.identity);
81
+ this.startAngle = this.getAngle(startPoint);
82
+ }
83
+ onDragUpdate(canvasPos) {
84
+ const targetRotation = this.roundAngle(this.getAngle(canvasPos) - this.startAngle);
85
+ // Transform in canvas space
86
+ const canvasSelCenter = this.editor.viewport.roundPoint(this.selection.preTransformRegion.center);
87
+ const unrounded = Mat33.zRotation(targetRotation);
88
+ const roundedRotationTransform = unrounded.mapEntries(entry => Viewport.roundScaleRatio(entry));
89
+ const fullRoundedTransform = Mat33
90
+ .translation(canvasSelCenter)
91
+ .rightMul(roundedRotationTransform)
92
+ .rightMul(Mat33.translation(canvasSelCenter.times(-1)));
93
+ this.selection.setTransform(fullRoundedTransform);
94
+ }
95
+ onDragEnd() {
96
+ this.selection.finalizeTransform();
97
+ }
98
+ }
@@ -0,0 +1,9 @@
1
+ export declare enum ResizeMode {
2
+ Both = 0,
3
+ HorizontalOnly = 1,
4
+ VerticalOnly = 2
5
+ }
6
+ export declare enum TransformMode {
7
+ Snap = 0,
8
+ NoSnap = 1
9
+ }
@@ -0,0 +1,11 @@
1
+ export var ResizeMode;
2
+ (function (ResizeMode) {
3
+ ResizeMode[ResizeMode["Both"] = 0] = "Both";
4
+ ResizeMode[ResizeMode["HorizontalOnly"] = 1] = "HorizontalOnly";
5
+ ResizeMode[ResizeMode["VerticalOnly"] = 2] = "VerticalOnly";
6
+ })(ResizeMode || (ResizeMode = {}));
7
+ export var TransformMode;
8
+ (function (TransformMode) {
9
+ TransformMode[TransformMode["Snap"] = 0] = "Snap";
10
+ TransformMode[TransformMode["NoSnap"] = 1] = "NoSnap";
11
+ })(TransformMode || (TransformMode = {}));
@@ -3,7 +3,7 @@ import PanZoom, { PanZoomMode } from './PanZoom';
3
3
  import Pen from './Pen';
4
4
  import ToolEnabledGroup from './ToolEnabledGroup';
5
5
  import Eraser from './Eraser';
6
- import SelectionTool from './SelectionTool';
6
+ import SelectionTool from './SelectionTool/SelectionTool';
7
7
  import Color4 from '../Color4';
8
8
  import UndoRedoShortcut from './UndoRedoShortcut';
9
9
  import TextTool from './TextTool';
@@ -9,6 +9,6 @@ export { default as ToolSwitcherShortcut } from './ToolSwitcherShortcut';
9
9
  export { default as PanZoomTool, PanZoomMode } from './PanZoom';
10
10
  export { default as PenTool, PenStyle } from './Pen';
11
11
  export { default as TextTool } from './TextTool';
12
- export { default as SelectionTool } from './SelectionTool';
12
+ export { default as SelectionTool } from './SelectionTool/SelectionTool';
13
13
  export { default as EraserTool } from './Eraser';
14
14
  export { default as PasteHandler } from './PasteHandler';
@@ -9,6 +9,6 @@ export { default as ToolSwitcherShortcut } from './ToolSwitcherShortcut';
9
9
  export { default as PanZoomTool, PanZoomMode } from './PanZoom';
10
10
  export { default as PenTool } from './Pen';
11
11
  export { default as TextTool } from './TextTool';
12
- export { default as SelectionTool } from './SelectionTool';
12
+ export { default as SelectionTool } from './SelectionTool/SelectionTool';
13
13
  export { default as EraserTool } from './Eraser';
14
14
  export { default as PasteHandler } from './PasteHandler';
@@ -8,7 +8,7 @@ import Rect2 from './math/Rect2';
8
8
  import Pointer from './Pointer';
9
9
  import Color4 from './Color4';
10
10
  import Command from './commands/Command';
11
- import { BaseWidget } from './lib';
11
+ import BaseWidget from './toolbar/widgets/BaseWidget';
12
12
  export interface PointerEvtListener {
13
13
  onPointerDown(event: PointerEvt): boolean;
14
14
  onPointerMove(event: PointerEvt): void;
package/jest.config.js CHANGED
@@ -10,6 +10,10 @@ const config = {
10
10
  'js',
11
11
  ],
12
12
 
13
+ testPathIgnorePatterns: [
14
+ '<rootDir>/dist/', '<rootDir>/node_modules/'
15
+ ],
16
+
13
17
  // Mocks.
14
18
  // See https://jestjs.io/docs/webpack#handling-static-assets
15
19
  moduleNameMapper: {
@@ -19,6 +23,7 @@ const config = {
19
23
  },
20
24
 
21
25
  testEnvironment: 'jsdom',
26
+ setupFilesAfterEnv: [ '<rootDir>/src/testing/beforeEachFile.ts' ],
22
27
  };
23
28
 
24
29
  module.exports = config;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "js-draw",
3
- "version": "0.3.2",
3
+ "version": "0.4.1",
4
4
  "description": "Draw pictures using a pen, touchscreen, or mouse! JS-draw is a drawing library for JavaScript and TypeScript. ",
5
5
  "main": "./dist/src/lib.d.ts",
6
6
  "types": "./dist/src/lib.js",
@@ -71,36 +71,37 @@
71
71
  "lint": "eslint .",
72
72
  "linter-precommit": "eslint --fix --ext .js --ext .ts",
73
73
  "lint-staged": "lint-staged",
74
+ "lint-ci": "eslint . --max-warnings=0 --ext .js --ext .ts",
74
75
  "prepare": "husky install && yarn build",
75
76
  "prepack": "yarn build && yarn test && pinst --disable",
76
77
  "postpack": "pinst --enable"
77
78
  },
78
79
  "dependencies": {
79
- "@melloware/coloris": "^0.16.0",
80
+ "@melloware/coloris": "^0.16.1",
80
81
  "bezier-js": "^6.1.0"
81
82
  },
82
83
  "devDependencies": {
83
84
  "@types/bezier-js": "^4.1.0",
84
- "@types/jest": "^28.1.7",
85
+ "@types/jest": "^29.0.3",
85
86
  "@types/jsdom": "^20.0.0",
86
- "@types/node": "^18.7.15",
87
- "@typescript-eslint/eslint-plugin": "^5.36.2",
88
- "@typescript-eslint/parser": "^5.36.2",
87
+ "@types/node": "^18.7.23",
88
+ "@typescript-eslint/eslint-plugin": "^5.38.1",
89
+ "@typescript-eslint/parser": "^5.38.1",
89
90
  "css-loader": "^6.7.1",
90
- "eslint": "^8.23.0",
91
+ "eslint": "^8.24.0",
91
92
  "husky": "^8.0.1",
92
- "jest": "^28.1.3",
93
- "jest-environment-jsdom": "^29.0.2",
93
+ "jest": "^29.0.3",
94
+ "jest-environment-jsdom": "^29.0.3",
94
95
  "jsdom": "^20.0.0",
95
96
  "lint-staged": "^13.0.3",
96
97
  "pinst": "^3.0.0",
97
98
  "style-loader": "^3.3.1",
98
- "terser-webpack-plugin": "^5.3.5",
99
- "ts-jest": "^28.0.8",
100
- "ts-loader": "^9.3.1",
99
+ "terser-webpack-plugin": "^5.3.6",
100
+ "ts-jest": "^29.0.2",
101
+ "ts-loader": "^9.4.1",
101
102
  "ts-node": "^10.9.1",
102
- "typedoc": "^0.23.14",
103
- "typescript": "^4.8.2",
103
+ "typedoc": "^0.23.15",
104
+ "typescript": "^4.8.3",
104
105
  "webpack": "^5.74.0"
105
106
  },
106
107
  "bugs": {
package/src/Editor.css CHANGED
@@ -1,5 +1,6 @@
1
1
 
2
2
  @import url('./toolbar/toolbar.css');
3
+ @import url('./tools/SelectionTool/SelectionTool.css');
3
4
 
4
5
  .imageEditorContainer {
5
6
  /* Deafult colors for the editor */