js-draw 0.17.2 → 0.17.4
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.
- package/CHANGELOG.md +10 -1
- package/README.md +17 -8
- package/dist/bundle.js +1 -1
- package/dist/src/Editor.d.ts +62 -1
- package/dist/src/Editor.js +75 -24
- package/dist/src/EditorImage.d.ts +4 -2
- package/dist/src/EditorImage.js +4 -2
- package/dist/src/SVGLoader.d.ts +4 -0
- package/dist/src/SVGLoader.js +4 -0
- package/dist/src/components/lib.d.ts +2 -2
- package/dist/src/components/lib.js +2 -2
- package/dist/src/lib.d.ts +2 -1
- package/dist/src/lib.js +2 -1
- package/dist/src/rendering/lib.d.ts +2 -0
- package/dist/src/rendering/lib.js +2 -0
- package/dist/src/rendering/renderers/CanvasRenderer.d.ts +25 -0
- package/dist/src/rendering/renderers/CanvasRenderer.js +27 -0
- package/dist/src/rendering/renderers/SVGRenderer.d.ts +15 -0
- package/dist/src/rendering/renderers/SVGRenderer.js +27 -1
- package/dist/src/testing/lib.d.ts +2 -0
- package/dist/src/testing/lib.js +2 -0
- package/dist/src/testing/sendPenEvent.d.ts +12 -0
- package/dist/src/testing/sendPenEvent.js +19 -0
- package/dist/src/testing/sendTouchEvent.d.ts +36 -0
- package/dist/src/testing/sendTouchEvent.js +36 -0
- package/dist/src/toolbar/widgets/DocumentPropertiesWidget.d.ts +0 -1
- package/dist/src/toolbar/widgets/DocumentPropertiesWidget.js +5 -20
- package/dist/src/toolbar/widgets/PenToolWidget.js +1 -0
- package/dist/src/toolbar/widgets/TextToolWidget.js +4 -1
- package/dist/src/tools/SelectionTool/SelectionTool.js +5 -6
- package/package.json +1 -1
- package/src/Editor.ts +78 -28
- package/src/EditorImage.ts +4 -2
- package/src/SVGLoader.ts +4 -0
- package/src/components/lib.ts +2 -1
- package/src/lib.ts +2 -1
- package/src/rendering/lib.ts +2 -0
- package/src/rendering/renderers/CanvasRenderer.ts +27 -0
- package/src/rendering/renderers/SVGRenderer.ts +32 -1
- package/src/testing/lib.ts +3 -0
- package/src/testing/sendPenEvent.ts +31 -0
- package/src/testing/sendTouchEvent.ts +36 -1
- package/src/toolbar/toolbar.css +5 -0
- package/src/toolbar/widgets/DocumentPropertiesWidget.ts +5 -23
- package/src/toolbar/widgets/PenToolWidget.ts +1 -0
- package/src/toolbar/widgets/TextToolWidget.ts +4 -1
- package/src/tools/Eraser.test.ts +11 -10
- package/src/tools/PanZoom.test.ts +1 -1
- package/src/tools/Pen.test.ts +63 -62
- package/src/tools/SelectionTool/SelectionTool.test.ts +15 -14
- package/src/tools/SelectionTool/SelectionTool.ts +5 -7
@@ -3,7 +3,42 @@ import { Vec2 } from '../math/Vec2';
|
|
3
3
|
import Pointer, { PointerDevice } from '../Pointer';
|
4
4
|
import { InputEvtType } from '../types';
|
5
5
|
|
6
|
-
|
6
|
+
/**
|
7
|
+
* Dispatch a touch event to the currently selected tool. Intended for unit tests.
|
8
|
+
*
|
9
|
+
* @see {@link sendPenEvent}
|
10
|
+
*
|
11
|
+
* @example
|
12
|
+
* **Simulating a horizontal swipe gesture:**
|
13
|
+
* ```ts
|
14
|
+
* sendTouchEvent(editor, InputEvtType.PointerDownEvt, Vec2.of(0, 0));
|
15
|
+
* for (let i = 1; i <= 10; i++) {
|
16
|
+
* jest.advanceTimersByTime(10);
|
17
|
+
* sendTouchEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(i * 10, 0));
|
18
|
+
* }
|
19
|
+
* ```
|
20
|
+
*
|
21
|
+
* @example
|
22
|
+
* **Simulating a pinch gesture.** This example assumes that you're using [Jest with timer mocks enabled](https://jestjs.io/docs/timer-mocks).
|
23
|
+
* ```ts
|
24
|
+
* let firstPointer = sendTouchEvent(editor, InputEvtType.PointerDownEvt, Vec2.of(0, 0));
|
25
|
+
* let secondPointer = sendTouchEvent(editor, InputEvtType.PointerDownEvt, Vec2.of(100, 0), [ firstPointer ]);
|
26
|
+
*
|
27
|
+
* // Simulate a pinch
|
28
|
+
* const maxIterations = 10;
|
29
|
+
* for (let i = 0; i < maxIterations; i++) {
|
30
|
+
* // Use the unit testing framework's tool for increasing the current time
|
31
|
+
* // returned by (new Date()).getTime(), etc.
|
32
|
+
* jest.advanceTimersByTime(100);
|
33
|
+
*
|
34
|
+
* const point1 = Vec2.of(-i * 5, 0);
|
35
|
+
* const point2 = Vec2.of(i * 5 + 100, 0);
|
36
|
+
*
|
37
|
+
* firstPointer = sendTouchEvent(editor, InputEvtType.PointerMoveEvt, point1, [ secondPointer ]);
|
38
|
+
* secondPointer = sendTouchEvent(editor, InputEvtType.PointerMoveEvt, point2, [ firstPointer ]);
|
39
|
+
* }
|
40
|
+
* ```
|
41
|
+
*/
|
7
42
|
const sendTouchEvent = (
|
8
43
|
editor: Editor,
|
9
44
|
eventType: InputEvtType.PointerDownEvt|InputEvtType.PointerMoveEvt|InputEvtType.PointerUpEvt,
|
package/src/toolbar/toolbar.css
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
import Color4 from '../../Color4';
|
2
|
-
import ImageBackground from '../../components/ImageBackground';
|
3
2
|
import Editor from '../../Editor';
|
4
3
|
import { EditorImageEventType } from '../../EditorImage';
|
5
4
|
import Rect2 from '../../math/Rect2';
|
6
5
|
import { EditorEventType } from '../../types';
|
6
|
+
import { toolbarCSSPrefix } from '../HTMLToolbar';
|
7
7
|
import { ToolbarLocalization } from '../localization';
|
8
8
|
import makeColorInput from '../makeColorInput';
|
9
9
|
import BaseWidget from './BaseWidget';
|
@@ -56,31 +56,12 @@ export default class DocumentPropertiesWidget extends BaseWidget {
|
|
56
56
|
}
|
57
57
|
}
|
58
58
|
|
59
|
-
private getBackgroundElem() {
|
60
|
-
const backgroundComponents = [];
|
61
|
-
|
62
|
-
for (const component of this.editor.image.getBackgroundComponents()) {
|
63
|
-
if (component instanceof ImageBackground) {
|
64
|
-
backgroundComponents.push(component);
|
65
|
-
}
|
66
|
-
}
|
67
|
-
|
68
|
-
if (backgroundComponents.length === 0) {
|
69
|
-
return null;
|
70
|
-
}
|
71
|
-
|
72
|
-
// Return the last background component in the list — the component with highest z-index.
|
73
|
-
return backgroundComponents[backgroundComponents.length - 1];
|
74
|
-
}
|
75
|
-
|
76
59
|
private setBackgroundColor(color: Color4) {
|
77
60
|
this.editor.dispatch(this.editor.setBackgroundColor(color));
|
78
61
|
}
|
79
62
|
|
80
63
|
private getBackgroundColor() {
|
81
|
-
|
82
|
-
|
83
|
-
return background?.getStyle()?.color ?? Color4.transparent;
|
64
|
+
return this.editor.estimateBackgroundColor();
|
84
65
|
}
|
85
66
|
|
86
67
|
private updateImportExportRectSize(size: { width?: number, height?: number }) {
|
@@ -109,6 +90,7 @@ export default class DocumentPropertiesWidget extends BaseWidget {
|
|
109
90
|
|
110
91
|
protected fillDropdown(dropdown: HTMLElement): boolean {
|
111
92
|
const container = document.createElement('div');
|
93
|
+
container.classList.add(`${toolbarCSSPrefix}spacedList`);
|
112
94
|
|
113
95
|
const backgroundColorRow = document.createElement('div');
|
114
96
|
const backgroundColorLabel = document.createElement('label');
|
@@ -121,7 +103,7 @@ export default class DocumentPropertiesWidget extends BaseWidget {
|
|
121
103
|
}
|
122
104
|
});
|
123
105
|
|
124
|
-
colorInput.id =
|
106
|
+
colorInput.id = `${toolbarCSSPrefix}docPropertiesColorInput-${DocumentPropertiesWidget.idCounter++}`;
|
125
107
|
backgroundColorLabel.htmlFor = colorInput.id;
|
126
108
|
|
127
109
|
backgroundColorRow.replaceChildren(backgroundColorLabel, backgroundColorInputContainer);
|
@@ -135,7 +117,7 @@ export default class DocumentPropertiesWidget extends BaseWidget {
|
|
135
117
|
label.innerText = labelContent;
|
136
118
|
input.type = 'number';
|
137
119
|
input.min = '0';
|
138
|
-
input.id =
|
120
|
+
input.id = `${toolbarCSSPrefix}docPropertiesDimensionRow-${DocumentPropertiesWidget.idCounter++}`;
|
139
121
|
label.htmlFor = input.id;
|
140
122
|
|
141
123
|
spacer.style.flexGrow = '1';
|
@@ -134,6 +134,7 @@ export default class PenToolWidget extends BaseToolWidget {
|
|
134
134
|
private static idCounter: number = 0;
|
135
135
|
protected fillDropdown(dropdown: HTMLElement): boolean {
|
136
136
|
const container = document.createElement('div');
|
137
|
+
container.classList.add(`${toolbarCSSPrefix}spacedList`);
|
137
138
|
|
138
139
|
const thicknessRow = document.createElement('div');
|
139
140
|
const objectTypeRow = document.createElement('div');
|
@@ -32,6 +32,8 @@ export default class TextToolWidget extends BaseToolWidget {
|
|
32
32
|
|
33
33
|
private static idCounter: number = 0;
|
34
34
|
protected fillDropdown(dropdown: HTMLElement): boolean {
|
35
|
+
const container = document.createElement('div');
|
36
|
+
container.classList.add(`${toolbarCSSPrefix}spacedList`);
|
35
37
|
const fontRow = document.createElement('div');
|
36
38
|
const colorRow = document.createElement('div');
|
37
39
|
const sizeRow = document.createElement('div');
|
@@ -108,7 +110,8 @@ export default class TextToolWidget extends BaseToolWidget {
|
|
108
110
|
};
|
109
111
|
this.updateDropdownInputs();
|
110
112
|
|
111
|
-
|
113
|
+
container.replaceChildren(colorRow, sizeRow, fontRow);
|
114
|
+
dropdown.appendChild(container);
|
112
115
|
return true;
|
113
116
|
}
|
114
117
|
|
package/src/tools/Eraser.test.ts
CHANGED
@@ -3,6 +3,7 @@ import Editor from '../Editor';
|
|
3
3
|
import { EditorImage, Rect2, StrokeComponent } from '../lib';
|
4
4
|
import { Vec2 } from '../math/Vec2';
|
5
5
|
import createEditor from '../testing/createEditor';
|
6
|
+
import sendPenEvent from '../testing/sendPenEvent';
|
6
7
|
import { InputEvtType } from '../types';
|
7
8
|
import Eraser from './Eraser';
|
8
9
|
|
@@ -23,9 +24,9 @@ describe('Eraser', () => {
|
|
23
24
|
const editor = createEditor();
|
24
25
|
|
25
26
|
// Draw a line
|
26
|
-
|
27
|
+
sendPenEvent(editor, InputEvtType.PointerDownEvt, Vec2.of(0, 0));
|
27
28
|
jest.advanceTimersByTime(100);
|
28
|
-
|
29
|
+
sendPenEvent(editor, InputEvtType.PointerUpEvt, Vec2.of(200, 200));
|
29
30
|
|
30
31
|
// Should have drawn a line
|
31
32
|
const strokes = getAllStrokes(editor);
|
@@ -35,9 +36,9 @@ describe('Eraser', () => {
|
|
35
36
|
selectEraser(editor);
|
36
37
|
|
37
38
|
// Erase the line.
|
38
|
-
|
39
|
+
sendPenEvent(editor, InputEvtType.PointerDownEvt, Vec2.of(200, 0));
|
39
40
|
jest.advanceTimersByTime(400);
|
40
|
-
|
41
|
+
sendPenEvent(editor, InputEvtType.PointerUpEvt, Vec2.of(0, 200));
|
41
42
|
|
42
43
|
// Should have erased the line
|
43
44
|
expect(getAllStrokes(editor)).toHaveLength(0);
|
@@ -64,16 +65,16 @@ describe('Eraser', () => {
|
|
64
65
|
eraser.setThickness(10);
|
65
66
|
|
66
67
|
// Erase the first stroke
|
67
|
-
|
68
|
+
sendPenEvent(editor, InputEvtType.PointerDownEvt, Vec2.of(3, 0));
|
68
69
|
jest.advanceTimersByTime(100);
|
69
|
-
|
70
|
+
sendPenEvent(editor, InputEvtType.PointerUpEvt, Vec2.of(3, 0));
|
70
71
|
|
71
72
|
expect(getAllStrokes(editor)).toHaveLength(1);
|
72
73
|
|
73
74
|
// Erase the remaining stroke
|
74
|
-
|
75
|
+
sendPenEvent(editor, InputEvtType.PointerDownEvt, Vec2.of(47, 47));
|
75
76
|
jest.advanceTimersByTime(100);
|
76
|
-
|
77
|
+
sendPenEvent(editor, InputEvtType.PointerUpEvt, Vec2.of(47, 47));
|
77
78
|
|
78
79
|
expect(getAllStrokes(editor)).toHaveLength(0);
|
79
80
|
});
|
@@ -92,9 +93,9 @@ describe('Eraser', () => {
|
|
92
93
|
eraser.setThickness(100);
|
93
94
|
|
94
95
|
// Try to erase it.
|
95
|
-
|
96
|
+
sendPenEvent(editor, InputEvtType.PointerDownEvt, Vec2.of(0, 0));
|
96
97
|
jest.advanceTimersByTime(100);
|
97
|
-
|
98
|
+
sendPenEvent(editor, InputEvtType.PointerUpEvt, Vec2.of(3, 0));
|
98
99
|
|
99
100
|
// Should not have been erased
|
100
101
|
expect(editor.image.getAllElements()).toHaveLength(1);
|
@@ -68,7 +68,7 @@ describe('PanZoom', () => {
|
|
68
68
|
firstPointer = sendTouchEvent(editor, eventType, point1, [ secondPointer ]);
|
69
69
|
secondPointer = sendTouchEvent(editor, eventType, point2, [ firstPointer ]);
|
70
70
|
expectedScale = point1.minus(point2).magnitude() / 100;
|
71
|
-
|
71
|
+
|
72
72
|
if (i === maxIterations - 1) {
|
73
73
|
jest.advanceTimersByTime(10);
|
74
74
|
|
package/src/tools/Pen.test.ts
CHANGED
@@ -7,16 +7,17 @@ import Rect2 from '../math/Rect2';
|
|
7
7
|
import StrokeComponent from '../components/Stroke';
|
8
8
|
import Mat33 from '../math/Mat33';
|
9
9
|
import { makeFreehandLineBuilder } from '../components/builders/FreehandLineBuilder';
|
10
|
+
import sendPenEvent from '../testing/sendPenEvent';
|
10
11
|
|
11
12
|
describe('Pen', () => {
|
12
13
|
it('should draw horizontal lines', () => {
|
13
14
|
const editor = createEditor();
|
14
|
-
|
15
|
+
sendPenEvent(editor, InputEvtType.PointerDownEvt, Vec2.of(0, 0));
|
15
16
|
for (let i = 0; i < 10; i++) {
|
16
|
-
|
17
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(i, 0));
|
17
18
|
jest.advanceTimersByTime(200);
|
18
19
|
}
|
19
|
-
|
20
|
+
sendPenEvent(editor, InputEvtType.PointerUpEvt, Vec2.of(200, 0));
|
20
21
|
|
21
22
|
const elems = editor.image.getElementsIntersectingRegion(new Rect2(0, 10, 10, -10));
|
22
23
|
expect(elems).toHaveLength(1);
|
@@ -29,12 +30,12 @@ describe('Pen', () => {
|
|
29
30
|
|
30
31
|
it('should draw vertical line', () => {
|
31
32
|
const editor = createEditor();
|
32
|
-
|
33
|
+
sendPenEvent(editor, InputEvtType.PointerDownEvt, Vec2.of(0, 0));
|
33
34
|
for (let i = 0; i < 10; i++) {
|
34
|
-
|
35
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(0, i * 20));
|
35
36
|
jest.advanceTimersByTime(200);
|
36
37
|
}
|
37
|
-
|
38
|
+
sendPenEvent(editor, InputEvtType.PointerUpEvt, Vec2.of(0, 150));
|
38
39
|
|
39
40
|
const elems = editor.image.getElementsIntersectingRegion(Rect2.unitSquare);
|
40
41
|
expect(elems).toHaveLength(1);
|
@@ -46,104 +47,104 @@ describe('Pen', () => {
|
|
46
47
|
it('should draw vertical line with slight bend', () => {
|
47
48
|
const editor = createEditor();
|
48
49
|
|
49
|
-
|
50
|
+
sendPenEvent(editor, InputEvtType.PointerDownEvt, Vec2.of(417, 24));
|
50
51
|
jest.advanceTimersByTime(245);
|
51
|
-
|
52
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(423, 197));
|
52
53
|
jest.advanceTimersByTime(20);
|
53
|
-
|
54
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(423, 199));
|
54
55
|
jest.advanceTimersByTime(12);
|
55
|
-
|
56
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(423, 201));
|
56
57
|
jest.advanceTimersByTime(40);
|
57
|
-
|
58
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(423, 203));
|
58
59
|
jest.advanceTimersByTime(14);
|
59
|
-
|
60
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(423, 206));
|
60
61
|
jest.advanceTimersByTime(35);
|
61
|
-
|
62
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(423, 208));
|
62
63
|
jest.advanceTimersByTime(16);
|
63
|
-
|
64
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(423, 211));
|
64
65
|
jest.advanceTimersByTime(51);
|
65
|
-
|
66
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(423, 215));
|
66
67
|
jest.advanceTimersByTime(32);
|
67
|
-
|
68
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(423, 218));
|
68
69
|
jest.advanceTimersByTime(30);
|
69
|
-
|
70
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(423, 220));
|
70
71
|
jest.advanceTimersByTime(24);
|
71
|
-
|
72
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(423, 222));
|
72
73
|
jest.advanceTimersByTime(14);
|
73
|
-
|
74
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(423, 224));
|
74
75
|
jest.advanceTimersByTime(32);
|
75
|
-
|
76
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(423, 227));
|
76
77
|
jest.advanceTimersByTime(17);
|
77
|
-
|
78
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(423, 229));
|
78
79
|
jest.advanceTimersByTime(53);
|
79
|
-
|
80
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(423, 234));
|
80
81
|
jest.advanceTimersByTime(34);
|
81
|
-
|
82
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(423, 236));
|
82
83
|
jest.advanceTimersByTime(17);
|
83
|
-
|
84
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(423, 238));
|
84
85
|
jest.advanceTimersByTime(39);
|
85
|
-
|
86
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(423, 240));
|
86
87
|
jest.advanceTimersByTime(10);
|
87
|
-
|
88
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(423, 243));
|
88
89
|
jest.advanceTimersByTime(34);
|
89
|
-
|
90
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(423, 250));
|
90
91
|
jest.advanceTimersByTime(57);
|
91
|
-
|
92
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(423, 252));
|
92
93
|
jest.advanceTimersByTime(8);
|
93
|
-
|
94
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(422, 256));
|
94
95
|
jest.advanceTimersByTime(28);
|
95
|
-
|
96
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(422, 258));
|
96
97
|
jest.advanceTimersByTime(21);
|
97
|
-
|
98
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(421, 262));
|
98
99
|
jest.advanceTimersByTime(34);
|
99
|
-
|
100
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(420, 264));
|
100
101
|
jest.advanceTimersByTime(5);
|
101
|
-
|
102
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(420, 266));
|
102
103
|
jest.advanceTimersByTime(22);
|
103
|
-
|
104
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(420, 268));
|
104
105
|
jest.advanceTimersByTime(22);
|
105
|
-
|
106
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(420, 271));
|
106
107
|
jest.advanceTimersByTime(18);
|
107
|
-
|
108
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(420, 274));
|
108
109
|
jest.advanceTimersByTime(33);
|
109
|
-
|
110
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(420, 277));
|
110
111
|
jest.advanceTimersByTime(16);
|
111
|
-
|
112
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(419, 279));
|
112
113
|
jest.advanceTimersByTime(36);
|
113
|
-
|
114
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(419, 282));
|
114
115
|
jest.advanceTimersByTime(15);
|
115
|
-
|
116
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(419, 284));
|
116
117
|
jest.advanceTimersByTime(48);
|
117
|
-
|
118
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(419, 289));
|
118
119
|
jest.advanceTimersByTime(16);
|
119
|
-
|
120
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(419, 291));
|
120
121
|
jest.advanceTimersByTime(31);
|
121
|
-
|
122
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(419, 295));
|
122
123
|
jest.advanceTimersByTime(23);
|
123
|
-
|
124
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(419, 301));
|
124
125
|
jest.advanceTimersByTime(31);
|
125
|
-
|
126
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(419, 306));
|
126
127
|
jest.advanceTimersByTime(18);
|
127
|
-
|
128
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(419, 308));
|
128
129
|
jest.advanceTimersByTime(20);
|
129
|
-
|
130
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(419, 310));
|
130
131
|
jest.advanceTimersByTime(13);
|
131
|
-
|
132
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(419, 313));
|
132
133
|
jest.advanceTimersByTime(17);
|
133
|
-
|
134
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(419, 317));
|
134
135
|
jest.advanceTimersByTime(33);
|
135
|
-
|
136
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(419, 321));
|
136
137
|
jest.advanceTimersByTime(15);
|
137
|
-
|
138
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(419, 324));
|
138
139
|
jest.advanceTimersByTime(23);
|
139
|
-
|
140
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(419, 326));
|
140
141
|
jest.advanceTimersByTime(14);
|
141
|
-
|
142
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(419, 329));
|
142
143
|
jest.advanceTimersByTime(36);
|
143
|
-
|
144
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(420, 333));
|
144
145
|
jest.advanceTimersByTime(8);
|
145
|
-
|
146
|
-
|
146
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(420, 340));
|
147
|
+
sendPenEvent(editor, InputEvtType.PointerUpEvt, Vec2.of(420, 340));
|
147
148
|
|
148
149
|
const elems = editor.image.getElementsIntersectingRegion(new Rect2(0, 0, 1000, 1000));
|
149
150
|
expect(elems).toHaveLength(1);
|
@@ -157,9 +158,9 @@ describe('Pen', () => {
|
|
157
158
|
|
158
159
|
expect(editor.history.undoStackSize).toBe(0);
|
159
160
|
|
160
|
-
|
161
|
+
sendPenEvent(editor, InputEvtType.PointerDownEvt, Vec2.of(10, 10));
|
161
162
|
jest.advanceTimersByTime(100);
|
162
|
-
|
163
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(20, 10));
|
163
164
|
|
164
165
|
const ctrlKeyDown = true;
|
165
166
|
editor.sendKeyboardEvent(InputEvtType.KeyPressEvent, 'z', ctrlKeyDown);
|
@@ -168,7 +169,7 @@ describe('Pen', () => {
|
|
168
169
|
expect(editor.history.redoStackSize).toBe(1);
|
169
170
|
|
170
171
|
// Lifting the pointer up shouldn't clear the redo stack.
|
171
|
-
|
172
|
+
sendPenEvent(editor, InputEvtType.PointerUpEvt, Vec2.of(420, 340));
|
172
173
|
expect(editor.history.redoStackSize).toBe(1);
|
173
174
|
});
|
174
175
|
|
@@ -179,10 +180,10 @@ describe('Pen', () => {
|
|
179
180
|
const penTool = editor.toolController.getMatchingTools(PenTool)[0];
|
180
181
|
penTool.setStrokeFactory(makeFreehandLineBuilder);
|
181
182
|
|
182
|
-
|
183
|
+
sendPenEvent(editor, InputEvtType.PointerDownEvt, Vec2.of(0.1, 0.1));
|
183
184
|
jest.advanceTimersByTime(100);
|
184
|
-
|
185
|
-
|
185
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(10.1, 10.1));
|
186
|
+
sendPenEvent(editor, InputEvtType.PointerUpEvt, Vec2.of(10.1, 10.1));
|
186
187
|
|
187
188
|
const allElems = editor.image.getAllElements();
|
188
189
|
expect(allElems).toHaveLength(1);
|
@@ -10,6 +10,7 @@ import SelectionTool from './SelectionTool';
|
|
10
10
|
import createEditor from '../../testing/createEditor';
|
11
11
|
import Pointer from '../../Pointer';
|
12
12
|
import { Rect2 } from '../../lib';
|
13
|
+
import sendPenEvent from '../../testing/sendPenEvent';
|
13
14
|
|
14
15
|
const getSelectionTool = (editor: Editor): SelectionTool => {
|
15
16
|
return editor.toolController.getMatchingTools(SelectionTool)[0];
|
@@ -33,9 +34,9 @@ const createEditorWithSingleObjectSelection = (objectSize: number = 50) => {
|
|
33
34
|
// Select the object
|
34
35
|
const selectionTool = getSelectionTool(editor);
|
35
36
|
selectionTool.setEnabled(true);
|
36
|
-
|
37
|
-
|
38
|
-
|
37
|
+
sendPenEvent(editor, InputEvtType.PointerDownEvt, Vec2.of(0, 0));
|
38
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(10, 10));
|
39
|
+
sendPenEvent(editor, InputEvtType.PointerUpEvt, Vec2.of(5, 5));
|
39
40
|
|
40
41
|
return { editor, testStroke, selectionTool };
|
41
42
|
};
|
@@ -61,9 +62,9 @@ describe('SelectionTool', () => {
|
|
61
62
|
|
62
63
|
const selectionTool = getSelectionTool(editor);
|
63
64
|
selectionTool.setEnabled(true);
|
64
|
-
|
65
|
-
|
66
|
-
|
65
|
+
sendPenEvent(editor, InputEvtType.PointerDownEvt, Vec2.of(0, 0));
|
66
|
+
sendPenEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(0.1, 0.1));
|
67
|
+
sendPenEvent(editor, InputEvtType.PointerUpEvt, Vec2.of(0.1, 0.1));
|
67
68
|
|
68
69
|
// Should surround the selected object (which has bbox = (0, 0, 1, 1))
|
69
70
|
// with extra space.
|
@@ -125,8 +126,8 @@ describe('SelectionTool', () => {
|
|
125
126
|
selectionTool.setEnabled(true);
|
126
127
|
|
127
128
|
// Select the smaller rectangle
|
128
|
-
|
129
|
-
|
129
|
+
sendPenEvent(editor, InputEvtType.PointerDownEvt, Vec2.of(40, 40));
|
130
|
+
sendPenEvent(editor, InputEvtType.PointerUpEvt, Vec2.of(100, 100));
|
130
131
|
|
131
132
|
expect(selectionTool.getSelectedObjects()).toHaveLength(1);
|
132
133
|
|
@@ -134,21 +135,21 @@ describe('SelectionTool', () => {
|
|
134
135
|
editor.sendKeyboardEvent(InputEvtType.KeyPressEvent, 'Shift');
|
135
136
|
|
136
137
|
// Select the larger stroke.
|
137
|
-
|
138
|
-
|
138
|
+
sendPenEvent(editor, InputEvtType.PointerDownEvt, Vec2.of(200, 200));
|
139
|
+
sendPenEvent(editor, InputEvtType.PointerUpEvt, Vec2.of(600, 600));
|
139
140
|
|
140
141
|
expect(selectionTool.getSelectedObjects()).toHaveLength(2);
|
141
142
|
|
142
143
|
editor.sendKeyboardEvent(InputEvtType.KeyUpEvent, 'Shift');
|
143
144
|
|
144
145
|
// Select the larger stroke without shift pressed
|
145
|
-
|
146
|
-
|
146
|
+
sendPenEvent(editor, InputEvtType.PointerDownEvt, Vec2.of(200, 200));
|
147
|
+
sendPenEvent(editor, InputEvtType.PointerUpEvt, Vec2.of(600, 600));
|
147
148
|
expect(selectionTool.getSelectedObjects()).toHaveLength(1);
|
148
149
|
|
149
150
|
// Select nothing
|
150
|
-
|
151
|
-
|
151
|
+
sendPenEvent(editor, InputEvtType.PointerDownEvt, Vec2.of(200, 200));
|
152
|
+
sendPenEvent(editor, InputEvtType.PointerUpEvt, Vec2.of(201, 201));
|
152
153
|
expect(selectionTool.getSelectedObjects()).toHaveLength(0);
|
153
154
|
});
|
154
155
|
|
@@ -379,24 +379,22 @@ export default class SelectionTool extends BaseTool {
|
|
379
379
|
|
380
380
|
const exportViewport = new Viewport(() => {});
|
381
381
|
exportViewport.updateScreenSize(Vec2.of(bbox.w, bbox.h));
|
382
|
-
exportViewport.resetTransform(Mat33.translation(bbox.topLeft));
|
383
|
-
|
384
|
-
const svgNameSpace = 'http://www.w3.org/2000/svg';
|
385
|
-
const exportElem = document.createElementNS(svgNameSpace, 'svg');
|
382
|
+
exportViewport.resetTransform(Mat33.translation(bbox.topLeft.times(-1)));
|
386
383
|
|
387
384
|
const sanitize = true;
|
388
|
-
const renderer =
|
385
|
+
const { element: svgExportElem, renderer: svgRenderer } = SVGRenderer.fromViewport(exportViewport, sanitize);
|
389
386
|
|
390
387
|
const text: string[] = [];
|
391
388
|
for (const elem of selectedElems) {
|
392
|
-
elem.render(
|
389
|
+
elem.render(svgRenderer);
|
393
390
|
|
394
391
|
if (elem instanceof TextComponent) {
|
395
392
|
text.push(elem.getText());
|
396
393
|
}
|
397
394
|
}
|
398
395
|
|
399
|
-
event.setData('image/svg+xml',
|
396
|
+
event.setData('image/svg+xml', svgExportElem.outerHTML);
|
397
|
+
event.setData('text/html', svgExportElem.outerHTML);
|
400
398
|
if (text.length > 0) {
|
401
399
|
event.setData('text/plain', text.join('\n'));
|
402
400
|
}
|