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
@@ -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 PanZoom from '../tools/PanZoom';
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(PanZoom)[0];
204
+ const panZoomTool = toolController.getMatchingTools(PanZoomTool)[0];
204
205
  if (panZoomTool) {
205
206
  this.addWidget(new HandToolWidget(this.editor, panZoomTool, this.localizationTable));
206
207
  }
@@ -34,7 +34,8 @@
34
34
  }
35
35
 
36
36
  .toolbar-button.disabled {
37
- filter: opacity(0.8) saturate(0.1);
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), 128);
174
+ newThickness = Math.min(Math.max(1, newThickness), 256);
175
175
  this.setThickness(newThickness);
176
176
  return true;
177
177
  }