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.
- package/.github/pull_request_template.md +15 -0
- package/.github/workflows/firebase-hosting-merge.yml +7 -0
- package/.github/workflows/firebase-hosting-pull-request.yml +10 -0
- package/.github/workflows/github-pages.yml +2 -0
- package/CHANGELOG.md +16 -1
- package/README.md +1 -3
- package/dist/bundle.js +1 -1
- package/dist/src/Editor.d.ts +11 -0
- package/dist/src/Editor.js +107 -77
- package/dist/src/Pointer.d.ts +1 -1
- package/dist/src/Pointer.js +8 -3
- package/dist/src/Viewport.d.ts +1 -0
- package/dist/src/Viewport.js +14 -1
- package/dist/src/components/AbstractComponent.js +1 -0
- package/dist/src/components/ImageComponent.d.ts +2 -2
- package/dist/src/components/Stroke.js +15 -9
- package/dist/src/components/Text.d.ts +1 -1
- package/dist/src/components/Text.js +1 -1
- package/dist/src/components/builders/FreehandLineBuilder.d.ts +1 -0
- package/dist/src/components/builders/FreehandLineBuilder.js +34 -36
- package/dist/src/language/assertions.d.ts +1 -0
- package/dist/src/language/assertions.js +5 -0
- package/dist/src/math/Mat33.d.ts +38 -2
- package/dist/src/math/Mat33.js +30 -1
- package/dist/src/math/Path.d.ts +1 -1
- package/dist/src/math/Path.js +10 -8
- package/dist/src/math/Vec3.d.ts +12 -2
- package/dist/src/math/Vec3.js +16 -1
- package/dist/src/math/rounding.d.ts +1 -0
- package/dist/src/math/rounding.js +13 -6
- package/dist/src/rendering/renderers/AbstractRenderer.js +2 -1
- package/dist/src/testing/beforeEachFile.d.ts +1 -0
- package/dist/src/testing/beforeEachFile.js +3 -0
- package/dist/src/testing/createEditor.d.ts +1 -0
- package/dist/src/testing/createEditor.js +7 -1
- package/dist/src/testing/loadExpectExtensions.d.ts +0 -15
- package/dist/src/toolbar/HTMLToolbar.js +5 -4
- package/dist/src/toolbar/widgets/SelectionToolWidget.d.ts +1 -1
- package/dist/src/tools/PasteHandler.js +3 -1
- package/dist/src/tools/Pen.js +1 -1
- package/dist/src/tools/SelectionTool/Selection.d.ts +54 -0
- package/dist/src/tools/SelectionTool/Selection.js +337 -0
- package/dist/src/tools/SelectionTool/SelectionHandle.d.ts +35 -0
- package/dist/src/tools/SelectionTool/SelectionHandle.js +75 -0
- package/dist/src/tools/SelectionTool/SelectionTool.d.ts +31 -0
- package/dist/src/tools/SelectionTool/SelectionTool.js +284 -0
- package/dist/src/tools/SelectionTool/TransformMode.d.ts +34 -0
- package/dist/src/tools/SelectionTool/TransformMode.js +98 -0
- package/dist/src/tools/SelectionTool/types.d.ts +9 -0
- package/dist/src/tools/SelectionTool/types.js +11 -0
- package/dist/src/tools/ToolController.js +1 -1
- package/dist/src/tools/lib.d.ts +1 -1
- package/dist/src/tools/lib.js +1 -1
- package/dist/src/types.d.ts +1 -1
- package/jest.config.js +5 -0
- package/package.json +15 -14
- package/src/Editor.css +1 -0
- package/src/Editor.ts +147 -108
- package/src/Pointer.ts +8 -3
- package/src/Viewport.ts +17 -2
- package/src/components/AbstractComponent.ts +4 -6
- package/src/components/ImageComponent.ts +2 -6
- package/src/components/Stroke.test.ts +0 -3
- package/src/components/Stroke.ts +14 -7
- package/src/components/Text.test.ts +0 -3
- package/src/components/Text.ts +4 -8
- package/src/components/builders/FreehandLineBuilder.ts +37 -43
- package/src/language/assertions.ts +6 -0
- package/src/math/LineSegment2.test.ts +8 -10
- package/src/math/Mat33.test.ts +14 -2
- package/src/math/Mat33.ts +43 -2
- package/src/math/Path.toString.test.ts +12 -1
- package/src/math/Path.ts +11 -9
- package/src/math/Rect2.test.ts +0 -3
- package/src/math/Vec2.test.ts +0 -3
- package/src/math/Vec3.test.ts +0 -3
- package/src/math/Vec3.ts +23 -2
- package/src/math/rounding.test.ts +30 -5
- package/src/math/rounding.ts +16 -7
- package/src/rendering/renderers/AbstractRenderer.ts +3 -2
- package/src/testing/beforeEachFile.ts +3 -0
- package/src/testing/createEditor.ts +8 -1
- package/src/testing/global.d.ts +17 -0
- package/src/testing/loadExpectExtensions.ts +0 -15
- package/src/toolbar/HTMLToolbar.ts +5 -4
- package/src/toolbar/toolbar.css +3 -2
- package/src/toolbar/widgets/SelectionToolWidget.ts +1 -1
- package/src/tools/PasteHandler.ts +4 -1
- package/src/tools/Pen.test.ts +150 -0
- package/src/tools/Pen.ts +1 -1
- package/src/tools/SelectionTool/Selection.ts +455 -0
- package/src/tools/SelectionTool/SelectionHandle.ts +99 -0
- package/src/tools/SelectionTool/SelectionTool.css +22 -0
- package/src/tools/{SelectionTool.test.ts → SelectionTool/SelectionTool.test.ts} +21 -21
- package/src/tools/SelectionTool/SelectionTool.ts +344 -0
- package/src/tools/SelectionTool/TransformMode.ts +114 -0
- package/src/tools/SelectionTool/types.ts +11 -0
- package/src/tools/ToolController.ts +1 -1
- package/src/tools/lib.ts +1 -1
- package/src/types.ts +1 -1
- package/tsconfig.json +3 -1
- package/dist/src/tools/SelectionTool.d.ts +0 -65
- package/dist/src/tools/SelectionTool.js +0 -647
- package/src/tools/SelectionTool.ts +0 -797
@@ -22,19 +22,4 @@ export const loadExpectExtensions = () => {
|
|
22
22
|
});
|
23
23
|
};
|
24
24
|
|
25
|
-
// Type declarations for custom matchers
|
26
|
-
export interface CustomMatchers<R = unknown> {
|
27
|
-
objEq(expected: {
|
28
|
-
eq: (other: any, ...args: any)=> boolean;
|
29
|
-
}, ...opts: any): R;
|
30
|
-
}
|
31
|
-
|
32
|
-
declare global {
|
33
|
-
export namespace jest {
|
34
|
-
interface Expect extends CustomMatchers {}
|
35
|
-
interface Matchers<R> extends CustomMatchers<R> {}
|
36
|
-
interface AsyncAsymmetricMatchers extends CustomMatchers {}
|
37
|
-
}
|
38
|
-
}
|
39
|
-
|
40
25
|
export default loadExpectExtensions;
|
@@ -3,19 +3,20 @@ import { EditorEventType } from '../types';
|
|
3
3
|
|
4
4
|
import { coloris, init as colorisInit } from '@melloware/coloris';
|
5
5
|
import Color4 from '../Color4';
|
6
|
-
import SelectionTool from '../tools/SelectionTool';
|
7
6
|
import { defaultToolbarLocalization, ToolbarLocalization } from './localization';
|
8
7
|
import { ActionButtonIcon } from './types';
|
9
8
|
import { makeRedoIcon, makeUndoIcon } from './icons';
|
10
|
-
import
|
9
|
+
import SelectionTool from '../tools/SelectionTool/SelectionTool';
|
10
|
+
import PanZoomTool from '../tools/PanZoom';
|
11
11
|
import TextTool from '../tools/TextTool';
|
12
|
+
import EraserTool from '../tools/Eraser';
|
13
|
+
import PenTool from '../tools/Pen';
|
12
14
|
import PenToolWidget from './widgets/PenToolWidget';
|
13
15
|
import EraserWidget from './widgets/EraserToolWidget';
|
14
16
|
import SelectionToolWidget from './widgets/SelectionToolWidget';
|
15
17
|
import TextToolWidget from './widgets/TextToolWidget';
|
16
18
|
import HandToolWidget from './widgets/HandToolWidget';
|
17
19
|
import BaseWidget from './widgets/BaseWidget';
|
18
|
-
import { EraserTool, PenTool } from '../tools/lib';
|
19
20
|
|
20
21
|
export const toolbarCSSPrefix = 'toolbar-';
|
21
22
|
|
@@ -200,7 +201,7 @@ export default class HTMLToolbar {
|
|
200
201
|
this.addWidget(new TextToolWidget(this.editor, tool, this.localizationTable));
|
201
202
|
}
|
202
203
|
|
203
|
-
const panZoomTool = toolController.getMatchingTools(
|
204
|
+
const panZoomTool = toolController.getMatchingTools(PanZoomTool)[0];
|
204
205
|
if (panZoomTool) {
|
205
206
|
this.addWidget(new HandToolWidget(this.editor, panZoomTool, this.localizationTable));
|
206
207
|
}
|
package/src/toolbar/toolbar.css
CHANGED
@@ -34,7 +34,8 @@
|
|
34
34
|
}
|
35
35
|
|
36
36
|
.toolbar-button.disabled {
|
37
|
-
filter: opacity(0.
|
37
|
+
filter: opacity(0.5) sepia(0.2);
|
38
|
+
cursor: unset;
|
38
39
|
}
|
39
40
|
|
40
41
|
.toolbar-button, .toolbar-root button {
|
@@ -75,7 +76,7 @@
|
|
75
76
|
width: 6em;
|
76
77
|
}
|
77
78
|
|
78
|
-
.toolbar-button:hover, .toolbar-root button:not(:disabled):hover {
|
79
|
+
.toolbar-button:not(.disabled):hover, .toolbar-root button:not(:disabled):hover {
|
79
80
|
box-shadow: 0px 2px 4px var(--primary-shadow-color);
|
80
81
|
}
|
81
82
|
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import Editor from '../../Editor';
|
2
|
-
import SelectionTool from '../../tools/SelectionTool';
|
2
|
+
import SelectionTool from '../../tools/SelectionTool/SelectionTool';
|
3
3
|
import { EditorEventType } from '../../types';
|
4
4
|
import { makeDeleteSelectionIcon, makeDuplicateSelectionIcon, makeResizeViewportIcon, makeSelectionIcon } from '../icons';
|
5
5
|
import { ToolbarLocalization } from '../localization';
|
@@ -11,11 +11,12 @@ import { PasteEvent } from '../types';
|
|
11
11
|
import { Mat33, Rect2, Vec2 } from '../math/lib';
|
12
12
|
import BaseTool from './BaseTool';
|
13
13
|
import EditorImage from '../EditorImage';
|
14
|
-
import SelectionTool from './SelectionTool';
|
14
|
+
import SelectionTool from './SelectionTool/SelectionTool';
|
15
15
|
import TextTool from './TextTool';
|
16
16
|
import Color4 from '../Color4';
|
17
17
|
import { TextStyle } from '../components/Text';
|
18
18
|
import ImageComponent from '../components/ImageComponent';
|
19
|
+
import Viewport from '../Viewport';
|
19
20
|
|
20
21
|
// { @inheritDoc PasteHandler! }
|
21
22
|
export default class PasteHandler extends BaseTool {
|
@@ -67,6 +68,8 @@ export default class PasteHandler extends BaseTool {
|
|
67
68
|
}
|
68
69
|
scaleRatio *= 2 / 3;
|
69
70
|
|
71
|
+
scaleRatio = Viewport.roundScaleRatio(scaleRatio);
|
72
|
+
|
70
73
|
const transfm = Mat33.translation(
|
71
74
|
visibleRect.center.minus(bbox.center)
|
72
75
|
).rightMul(
|
@@ -0,0 +1,150 @@
|
|
1
|
+
|
2
|
+
import { Rect2 } from '../lib';
|
3
|
+
import { Vec2 } from '../math/Vec2';
|
4
|
+
import createEditor from '../testing/createEditor';
|
5
|
+
import { InputEvtType } from '../types';
|
6
|
+
|
7
|
+
describe('Pen', () => {
|
8
|
+
it('should draw horizontal lines', () => {
|
9
|
+
const editor = createEditor();
|
10
|
+
editor.sendPenEvent(InputEvtType.PointerDownEvt, Vec2.of(0, 0));
|
11
|
+
for (let i = 0; i < 10; i++) {
|
12
|
+
editor.sendPenEvent(InputEvtType.PointerMoveEvt, Vec2.of(i, 0));
|
13
|
+
jest.advanceTimersByTime(200);
|
14
|
+
}
|
15
|
+
editor.sendPenEvent(InputEvtType.PointerUpEvt, Vec2.of(200, 0));
|
16
|
+
|
17
|
+
const elems = editor.image.getElementsIntersectingRegion(new Rect2(0, 10, 10, -10));
|
18
|
+
expect(elems).toHaveLength(1);
|
19
|
+
|
20
|
+
// Account for stroke width
|
21
|
+
const tolerableError = 8;
|
22
|
+
expect(elems[0].getBBox().topLeft).objEq(Vec2.of(0, 0), tolerableError);
|
23
|
+
expect(elems[0].getBBox().bottomRight).objEq(Vec2.of(200, 0), tolerableError);
|
24
|
+
});
|
25
|
+
|
26
|
+
it('should draw vertical line', () => {
|
27
|
+
const editor = createEditor();
|
28
|
+
editor.sendPenEvent(InputEvtType.PointerDownEvt, Vec2.of(0, 0));
|
29
|
+
for (let i = 0; i < 10; i++) {
|
30
|
+
editor.sendPenEvent(InputEvtType.PointerMoveEvt, Vec2.of(0, i * 20));
|
31
|
+
jest.advanceTimersByTime(200);
|
32
|
+
}
|
33
|
+
editor.sendPenEvent(InputEvtType.PointerUpEvt, Vec2.of(0, 150));
|
34
|
+
|
35
|
+
const elems = editor.image.getElementsIntersectingRegion(Rect2.unitSquare);
|
36
|
+
expect(elems).toHaveLength(1);
|
37
|
+
|
38
|
+
expect(elems[0].getBBox().topLeft).objEq(Vec2.of(0, 0), 8); // ± 8
|
39
|
+
expect(elems[0].getBBox().bottomRight).objEq(Vec2.of(0, 175), 25); // ± 25
|
40
|
+
});
|
41
|
+
|
42
|
+
it('should draw vertical line with slight bend', () => {
|
43
|
+
const editor = createEditor();
|
44
|
+
|
45
|
+
editor.sendPenEvent(InputEvtType.PointerDownEvt, Vec2.of(417, 24));
|
46
|
+
jest.advanceTimersByTime(245);
|
47
|
+
editor.sendPenEvent(InputEvtType.PointerMoveEvt, Vec2.of(423, 197));
|
48
|
+
jest.advanceTimersByTime(20);
|
49
|
+
editor.sendPenEvent(InputEvtType.PointerMoveEvt, Vec2.of(423, 199));
|
50
|
+
jest.advanceTimersByTime(12);
|
51
|
+
editor.sendPenEvent(InputEvtType.PointerMoveEvt, Vec2.of(423, 201));
|
52
|
+
jest.advanceTimersByTime(40);
|
53
|
+
editor.sendPenEvent(InputEvtType.PointerMoveEvt, Vec2.of(423, 203));
|
54
|
+
jest.advanceTimersByTime(14);
|
55
|
+
editor.sendPenEvent(InputEvtType.PointerMoveEvt, Vec2.of(423, 206));
|
56
|
+
jest.advanceTimersByTime(35);
|
57
|
+
editor.sendPenEvent(InputEvtType.PointerMoveEvt, Vec2.of(423, 208));
|
58
|
+
jest.advanceTimersByTime(16);
|
59
|
+
editor.sendPenEvent(InputEvtType.PointerMoveEvt, Vec2.of(423, 211));
|
60
|
+
jest.advanceTimersByTime(51);
|
61
|
+
editor.sendPenEvent(InputEvtType.PointerMoveEvt, Vec2.of(423, 215));
|
62
|
+
jest.advanceTimersByTime(32);
|
63
|
+
editor.sendPenEvent(InputEvtType.PointerMoveEvt, Vec2.of(423, 218));
|
64
|
+
jest.advanceTimersByTime(30);
|
65
|
+
editor.sendPenEvent(InputEvtType.PointerMoveEvt, Vec2.of(423, 220));
|
66
|
+
jest.advanceTimersByTime(24);
|
67
|
+
editor.sendPenEvent(InputEvtType.PointerMoveEvt, Vec2.of(423, 222));
|
68
|
+
jest.advanceTimersByTime(14);
|
69
|
+
editor.sendPenEvent(InputEvtType.PointerMoveEvt, Vec2.of(423, 224));
|
70
|
+
jest.advanceTimersByTime(32);
|
71
|
+
editor.sendPenEvent(InputEvtType.PointerMoveEvt, Vec2.of(423, 227));
|
72
|
+
jest.advanceTimersByTime(17);
|
73
|
+
editor.sendPenEvent(InputEvtType.PointerMoveEvt, Vec2.of(423, 229));
|
74
|
+
jest.advanceTimersByTime(53);
|
75
|
+
editor.sendPenEvent(InputEvtType.PointerMoveEvt, Vec2.of(423, 234));
|
76
|
+
jest.advanceTimersByTime(34);
|
77
|
+
editor.sendPenEvent(InputEvtType.PointerMoveEvt, Vec2.of(423, 236));
|
78
|
+
jest.advanceTimersByTime(17);
|
79
|
+
editor.sendPenEvent(InputEvtType.PointerMoveEvt, Vec2.of(423, 238));
|
80
|
+
jest.advanceTimersByTime(39);
|
81
|
+
editor.sendPenEvent(InputEvtType.PointerMoveEvt, Vec2.of(423, 240));
|
82
|
+
jest.advanceTimersByTime(10);
|
83
|
+
editor.sendPenEvent(InputEvtType.PointerMoveEvt, Vec2.of(423, 243));
|
84
|
+
jest.advanceTimersByTime(34);
|
85
|
+
editor.sendPenEvent(InputEvtType.PointerMoveEvt, Vec2.of(423, 250));
|
86
|
+
jest.advanceTimersByTime(57);
|
87
|
+
editor.sendPenEvent(InputEvtType.PointerMoveEvt, Vec2.of(423, 252));
|
88
|
+
jest.advanceTimersByTime(8);
|
89
|
+
editor.sendPenEvent(InputEvtType.PointerMoveEvt, Vec2.of(422, 256));
|
90
|
+
jest.advanceTimersByTime(28);
|
91
|
+
editor.sendPenEvent(InputEvtType.PointerMoveEvt, Vec2.of(422, 258));
|
92
|
+
jest.advanceTimersByTime(21);
|
93
|
+
editor.sendPenEvent(InputEvtType.PointerMoveEvt, Vec2.of(421, 262));
|
94
|
+
jest.advanceTimersByTime(34);
|
95
|
+
editor.sendPenEvent(InputEvtType.PointerMoveEvt, Vec2.of(420, 264));
|
96
|
+
jest.advanceTimersByTime(5);
|
97
|
+
editor.sendPenEvent(InputEvtType.PointerMoveEvt, Vec2.of(420, 266));
|
98
|
+
jest.advanceTimersByTime(22);
|
99
|
+
editor.sendPenEvent(InputEvtType.PointerMoveEvt, Vec2.of(420, 268));
|
100
|
+
jest.advanceTimersByTime(22);
|
101
|
+
editor.sendPenEvent(InputEvtType.PointerMoveEvt, Vec2.of(420, 271));
|
102
|
+
jest.advanceTimersByTime(18);
|
103
|
+
editor.sendPenEvent(InputEvtType.PointerMoveEvt, Vec2.of(420, 274));
|
104
|
+
jest.advanceTimersByTime(33);
|
105
|
+
editor.sendPenEvent(InputEvtType.PointerMoveEvt, Vec2.of(420, 277));
|
106
|
+
jest.advanceTimersByTime(16);
|
107
|
+
editor.sendPenEvent(InputEvtType.PointerMoveEvt, Vec2.of(419, 279));
|
108
|
+
jest.advanceTimersByTime(36);
|
109
|
+
editor.sendPenEvent(InputEvtType.PointerMoveEvt, Vec2.of(419, 282));
|
110
|
+
jest.advanceTimersByTime(15);
|
111
|
+
editor.sendPenEvent(InputEvtType.PointerMoveEvt, Vec2.of(419, 284));
|
112
|
+
jest.advanceTimersByTime(48);
|
113
|
+
editor.sendPenEvent(InputEvtType.PointerMoveEvt, Vec2.of(419, 289));
|
114
|
+
jest.advanceTimersByTime(16);
|
115
|
+
editor.sendPenEvent(InputEvtType.PointerMoveEvt, Vec2.of(419, 291));
|
116
|
+
jest.advanceTimersByTime(31);
|
117
|
+
editor.sendPenEvent(InputEvtType.PointerMoveEvt, Vec2.of(419, 295));
|
118
|
+
jest.advanceTimersByTime(23);
|
119
|
+
editor.sendPenEvent(InputEvtType.PointerMoveEvt, Vec2.of(419, 301));
|
120
|
+
jest.advanceTimersByTime(31);
|
121
|
+
editor.sendPenEvent(InputEvtType.PointerMoveEvt, Vec2.of(419, 306));
|
122
|
+
jest.advanceTimersByTime(18);
|
123
|
+
editor.sendPenEvent(InputEvtType.PointerMoveEvt, Vec2.of(419, 308));
|
124
|
+
jest.advanceTimersByTime(20);
|
125
|
+
editor.sendPenEvent(InputEvtType.PointerMoveEvt, Vec2.of(419, 310));
|
126
|
+
jest.advanceTimersByTime(13);
|
127
|
+
editor.sendPenEvent(InputEvtType.PointerMoveEvt, Vec2.of(419, 313));
|
128
|
+
jest.advanceTimersByTime(17);
|
129
|
+
editor.sendPenEvent(InputEvtType.PointerMoveEvt, Vec2.of(419, 317));
|
130
|
+
jest.advanceTimersByTime(33);
|
131
|
+
editor.sendPenEvent(InputEvtType.PointerMoveEvt, Vec2.of(419, 321));
|
132
|
+
jest.advanceTimersByTime(15);
|
133
|
+
editor.sendPenEvent(InputEvtType.PointerMoveEvt, Vec2.of(419, 324));
|
134
|
+
jest.advanceTimersByTime(23);
|
135
|
+
editor.sendPenEvent(InputEvtType.PointerMoveEvt, Vec2.of(419, 326));
|
136
|
+
jest.advanceTimersByTime(14);
|
137
|
+
editor.sendPenEvent(InputEvtType.PointerMoveEvt, Vec2.of(419, 329));
|
138
|
+
jest.advanceTimersByTime(36);
|
139
|
+
editor.sendPenEvent(InputEvtType.PointerMoveEvt, Vec2.of(420, 333));
|
140
|
+
jest.advanceTimersByTime(8);
|
141
|
+
editor.sendPenEvent(InputEvtType.PointerMoveEvt, Vec2.of(420, 340));
|
142
|
+
editor.sendPenEvent(InputEvtType.PointerUpEvt, Vec2.of(420, 340));
|
143
|
+
|
144
|
+
const elems = editor.image.getElementsIntersectingRegion(new Rect2(0, 0, 1000, 1000));
|
145
|
+
expect(elems).toHaveLength(1);
|
146
|
+
|
147
|
+
expect(elems[0].getBBox().topLeft).objEq(Vec2.of(420, 24), 8); // ± 8
|
148
|
+
expect(elems[0].getBBox().bottomRight).objEq(Vec2.of(420, 340), 25); // ± 25
|
149
|
+
});
|
150
|
+
});
|
package/src/tools/Pen.ts
CHANGED
@@ -171,7 +171,7 @@ export default class Pen extends BaseTool {
|
|
171
171
|
}
|
172
172
|
|
173
173
|
if (newThickness !== undefined) {
|
174
|
-
newThickness = Math.min(Math.max(1, newThickness),
|
174
|
+
newThickness = Math.min(Math.max(1, newThickness), 256);
|
175
175
|
this.setThickness(newThickness);
|
176
176
|
return true;
|
177
177
|
}
|