js-draw 0.1.11 → 0.1.12
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 +7 -0
- package/dist/bundle.js +1 -1
- package/dist/src/Editor.d.ts +4 -2
- package/dist/src/Editor.js +30 -10
- package/dist/src/EditorImage.d.ts +1 -1
- package/dist/src/EditorImage.js +2 -2
- package/dist/src/Pointer.d.ts +1 -1
- package/dist/src/Pointer.js +1 -1
- package/dist/src/SVGLoader.d.ts +1 -1
- package/dist/src/SVGLoader.js +14 -6
- package/dist/src/Viewport.d.ts +8 -25
- package/dist/src/Viewport.js +15 -10
- package/dist/src/commands/Command.d.ts +2 -2
- package/dist/src/commands/Command.js +4 -4
- package/dist/src/commands/Duplicate.d.ts +1 -1
- package/dist/src/commands/Duplicate.js +1 -1
- package/dist/src/commands/Erase.d.ts +1 -1
- package/dist/src/commands/Erase.js +1 -1
- package/dist/src/commands/localization.d.ts +1 -1
- package/dist/src/components/AbstractComponent.d.ts +3 -3
- package/dist/src/components/AbstractComponent.js +2 -2
- package/dist/src/components/SVGGlobalAttributesObject.d.ts +3 -3
- package/dist/src/components/SVGGlobalAttributesObject.js +1 -1
- package/dist/src/components/Stroke.d.ts +4 -4
- package/dist/src/components/Stroke.js +2 -2
- package/dist/src/components/Text.d.ts +3 -3
- package/dist/src/components/Text.js +3 -3
- package/dist/src/components/UnknownSVGObject.d.ts +3 -3
- package/dist/src/components/UnknownSVGObject.js +1 -1
- package/dist/src/components/builders/ArrowBuilder.d.ts +1 -1
- package/dist/src/components/builders/ArrowBuilder.js +1 -1
- package/dist/src/components/builders/FreehandLineBuilder.d.ts +8 -3
- package/dist/src/components/builders/FreehandLineBuilder.js +142 -71
- package/dist/src/components/builders/LineBuilder.d.ts +1 -1
- package/dist/src/components/builders/LineBuilder.js +1 -1
- package/dist/src/components/builders/RectangleBuilder.d.ts +1 -1
- package/dist/src/components/builders/RectangleBuilder.js +3 -3
- package/dist/src/components/builders/types.d.ts +1 -1
- package/dist/src/localization.d.ts +1 -0
- package/dist/src/localization.js +5 -1
- package/dist/src/localizations/es.js +1 -1
- package/dist/src/{geometry → math}/LineSegment2.d.ts +0 -0
- package/dist/src/{geometry → math}/LineSegment2.js +0 -0
- package/dist/src/{geometry → math}/Mat33.d.ts +0 -0
- package/dist/src/{geometry → math}/Mat33.js +0 -0
- package/dist/src/{geometry → math}/Path.d.ts +2 -1
- package/dist/src/{geometry → math}/Path.js +58 -51
- package/dist/src/{geometry → math}/Rect2.d.ts +0 -0
- package/dist/src/{geometry → math}/Rect2.js +0 -0
- package/dist/src/{geometry → math}/Vec2.d.ts +0 -0
- package/dist/src/{geometry → math}/Vec2.js +0 -0
- package/dist/src/{geometry → math}/Vec3.d.ts +1 -1
- package/dist/src/{geometry → math}/Vec3.js +1 -1
- package/dist/src/math/rounding.d.ts +3 -0
- package/dist/src/math/rounding.js +120 -0
- package/dist/src/rendering/Display.d.ts +3 -1
- package/dist/src/rendering/Display.js +16 -10
- package/dist/src/rendering/caching/CacheRecord.d.ts +2 -2
- package/dist/src/rendering/caching/CacheRecord.js +1 -1
- package/dist/src/rendering/caching/CacheRecordManager.d.ts +1 -1
- package/dist/src/rendering/caching/RenderingCache.js +1 -1
- package/dist/src/rendering/caching/RenderingCacheNode.d.ts +2 -1
- package/dist/src/rendering/caching/RenderingCacheNode.js +18 -7
- package/dist/src/rendering/caching/testUtils.js +1 -1
- package/dist/src/rendering/caching/types.d.ts +1 -1
- package/dist/src/rendering/localization.d.ts +2 -0
- package/dist/src/rendering/localization.js +2 -0
- package/dist/src/rendering/renderers/AbstractRenderer.d.ts +4 -4
- package/dist/src/rendering/renderers/AbstractRenderer.js +2 -2
- package/dist/src/rendering/renderers/CanvasRenderer.d.ts +4 -4
- package/dist/src/rendering/renderers/CanvasRenderer.js +1 -1
- package/dist/src/rendering/renderers/DummyRenderer.d.ts +4 -4
- package/dist/src/rendering/renderers/DummyRenderer.js +1 -1
- package/dist/src/rendering/renderers/SVGRenderer.d.ts +3 -3
- package/dist/src/rendering/renderers/SVGRenderer.js +8 -2
- package/dist/src/rendering/renderers/TextOnlyRenderer.d.ts +5 -3
- package/dist/src/rendering/renderers/TextOnlyRenderer.js +13 -3
- package/dist/src/toolbar/icons.d.ts +3 -0
- package/dist/src/toolbar/icons.js +142 -132
- package/dist/src/toolbar/localization.d.ts +2 -1
- package/dist/src/toolbar/localization.js +2 -1
- package/dist/src/toolbar/makeColorInput.js +2 -1
- package/dist/src/toolbar/widgets/ActionButtonWidget.d.ts +13 -0
- package/dist/src/toolbar/widgets/ActionButtonWidget.js +21 -0
- package/dist/src/toolbar/widgets/BaseWidget.js +2 -0
- package/dist/src/toolbar/widgets/HandToolWidget.js +3 -3
- package/dist/src/toolbar/widgets/SelectionWidget.d.ts +0 -1
- package/dist/src/toolbar/widgets/SelectionWidget.js +23 -30
- package/dist/src/tools/Eraser.js +1 -1
- package/dist/src/tools/PanZoom.d.ts +1 -1
- package/dist/src/tools/PanZoom.js +24 -14
- package/dist/src/tools/SelectionTool.d.ts +3 -3
- package/dist/src/tools/SelectionTool.js +6 -6
- package/dist/src/tools/TextTool.js +1 -1
- package/dist/src/types.d.ts +4 -4
- package/package.json +1 -1
- package/src/Editor.ts +34 -12
- package/src/EditorImage.test.ts +2 -4
- package/src/EditorImage.ts +2 -2
- package/src/Pointer.ts +1 -1
- package/src/SVGLoader.ts +14 -6
- package/src/Viewport.ts +19 -17
- package/src/commands/Command.ts +5 -5
- package/src/commands/Duplicate.ts +1 -1
- package/src/commands/Erase.ts +1 -1
- package/src/commands/localization.ts +1 -1
- package/src/components/AbstractComponent.ts +4 -4
- package/src/components/SVGGlobalAttributesObject.ts +3 -3
- package/src/components/Stroke.test.ts +3 -5
- package/src/components/Stroke.ts +4 -4
- package/src/components/Text.test.ts +2 -2
- package/src/components/Text.ts +3 -3
- package/src/components/UnknownSVGObject.ts +3 -3
- package/src/components/builders/ArrowBuilder.ts +2 -2
- package/src/components/builders/FreehandLineBuilder.ts +190 -80
- package/src/components/builders/LineBuilder.ts +2 -2
- package/src/components/builders/RectangleBuilder.ts +3 -3
- package/src/components/builders/types.ts +1 -1
- package/src/localization.ts +6 -0
- package/src/localizations/es.ts +2 -1
- package/src/{geometry → math}/LineSegment2.test.ts +0 -0
- package/src/{geometry → math}/LineSegment2.ts +0 -0
- package/src/{geometry → math}/Mat33.test.ts +0 -0
- package/src/{geometry → math}/Mat33.ts +0 -0
- package/src/{geometry → math}/Path.fromString.test.ts +0 -0
- package/src/{geometry → math}/Path.test.ts +0 -0
- package/src/{geometry → math}/Path.toString.test.ts +11 -2
- package/src/{geometry → math}/Path.ts +60 -57
- package/src/{geometry → math}/Rect2.test.ts +0 -0
- package/src/{geometry → math}/Rect2.ts +0 -0
- package/src/{geometry → math}/Vec2.test.ts +0 -0
- package/src/{geometry → math}/Vec2.ts +0 -0
- package/src/{geometry → math}/Vec3.test.ts +0 -0
- package/src/{geometry → math}/Vec3.ts +2 -2
- package/src/math/rounding.test.ts +40 -0
- package/src/math/rounding.ts +145 -0
- package/src/rendering/Display.ts +18 -10
- package/src/rendering/caching/CacheRecord.test.ts +2 -2
- package/src/rendering/caching/CacheRecord.ts +2 -2
- package/src/rendering/caching/CacheRecordManager.ts +1 -1
- package/src/rendering/caching/RenderingCache.test.ts +3 -3
- package/src/rendering/caching/RenderingCache.ts +1 -1
- package/src/rendering/caching/RenderingCacheNode.ts +23 -7
- package/src/rendering/caching/testUtils.ts +1 -1
- package/src/rendering/caching/types.ts +1 -1
- package/src/rendering/localization.ts +4 -0
- package/src/rendering/renderers/AbstractRenderer.ts +4 -4
- package/src/rendering/renderers/CanvasRenderer.ts +4 -4
- package/src/rendering/renderers/DummyRenderer.test.ts +2 -2
- package/src/rendering/renderers/DummyRenderer.ts +4 -4
- package/src/rendering/renderers/SVGRenderer.ts +10 -4
- package/src/rendering/renderers/TextOnlyRenderer.ts +17 -6
- package/src/toolbar/icons.ts +157 -137
- package/src/toolbar/localization.ts +4 -2
- package/src/toolbar/makeColorInput.ts +2 -1
- package/src/toolbar/toolbar.css +1 -1
- package/src/toolbar/widgets/ActionButtonWidget.ts +31 -0
- package/src/toolbar/widgets/BaseWidget.ts +2 -0
- package/src/toolbar/widgets/HandToolWidget.ts +3 -3
- package/src/toolbar/widgets/SelectionWidget.ts +46 -41
- package/src/tools/Eraser.ts +2 -2
- package/src/tools/PanZoom.ts +28 -16
- package/src/tools/SelectionTool.test.ts +2 -4
- package/src/tools/SelectionTool.ts +6 -6
- package/src/tools/TextTool.ts +2 -2
- package/src/tools/UndoRedoShortcut.test.ts +1 -1
- package/src/types.ts +4 -4
@@ -1,5 +1,5 @@
|
|
1
1
|
import EventDispatcher from '../EventDispatcher';
|
2
|
-
import { Vec2 } from '../
|
2
|
+
import { Vec2 } from '../math/Vec2';
|
3
3
|
import SVGRenderer from '../rendering/renderers/SVGRenderer';
|
4
4
|
import Viewport from '../Viewport';
|
5
5
|
const svgNamespace = 'http://www.w3.org/2000/svg';
|
@@ -88,147 +88,130 @@ export const makeSelectionIcon = () => {
|
|
88
88
|
icon.setAttribute('viewBox', '0 0 100 100');
|
89
89
|
return icon;
|
90
90
|
};
|
91
|
-
|
91
|
+
const pathIcon = (pathData, fill = 'var(--icon-color)', strokeColor = 'none', strokeWidth = '0px') => {
|
92
92
|
const icon = document.createElementNS(svgNamespace, 'svg');
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
H 90
|
100
|
-
V 30
|
101
|
-
C 90,20 75,20 75,30
|
102
|
-
V 60
|
103
|
-
20
|
104
|
-
C 75,10 60,10 60,20
|
105
|
-
V 60
|
106
|
-
15
|
107
|
-
C 60,5 45,5 45,15
|
108
|
-
V 60
|
109
|
-
25
|
110
|
-
C 45,15 30,15 30,25
|
111
|
-
V 60
|
112
|
-
75
|
113
|
-
L 25,60
|
114
|
-
C 20,45 10,50 10,60
|
115
|
-
Z'
|
116
|
-
|
117
|
-
fill='none'
|
118
|
-
style='
|
119
|
-
stroke: var(--icon-color);
|
120
|
-
stroke-width: 2;
|
121
|
-
'
|
122
|
-
/>
|
123
|
-
</g>
|
124
|
-
`;
|
93
|
+
const path = document.createElementNS(svgNamespace, 'path');
|
94
|
+
path.setAttribute('d', pathData);
|
95
|
+
path.style.fill = fill;
|
96
|
+
path.style.stroke = strokeColor;
|
97
|
+
path.style.strokeWidth = strokeWidth;
|
98
|
+
icon.appendChild(path);
|
125
99
|
icon.setAttribute('viewBox', '0 0 100 100');
|
126
100
|
return icon;
|
127
101
|
};
|
102
|
+
export const makeHandToolIcon = () => {
|
103
|
+
const fill = 'none';
|
104
|
+
const strokeColor = 'var(--icon-color)';
|
105
|
+
const strokeWidth = '3';
|
106
|
+
// Draw a cursor-like shape (like some of the other icons, made with Inkscape)
|
107
|
+
return pathIcon(`
|
108
|
+
m 10,60
|
109
|
+
5,30
|
110
|
+
H 90
|
111
|
+
V 30
|
112
|
+
C 90,20 75,20 75,30
|
113
|
+
V 60
|
114
|
+
20
|
115
|
+
C 75,10 60,10 60,20
|
116
|
+
V 60
|
117
|
+
15
|
118
|
+
C 60,5 45,5 45,15
|
119
|
+
V 60
|
120
|
+
25
|
121
|
+
C 45,15 30,15 30,25
|
122
|
+
V 60
|
123
|
+
75
|
124
|
+
L 25,60
|
125
|
+
C 20,45 10,50 10,60
|
126
|
+
Z
|
127
|
+
`, fill, strokeColor, strokeWidth);
|
128
|
+
};
|
128
129
|
export const makeTouchPanningIcon = () => {
|
129
|
-
const
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
130
|
+
const fill = 'none';
|
131
|
+
const strokeColor = 'var(--icon-color)';
|
132
|
+
const strokeWidth = '3';
|
133
|
+
return pathIcon(`
|
134
|
+
M 5,5.5
|
135
|
+
V 17.2
|
136
|
+
L 16.25,5.46
|
137
|
+
Z
|
137
138
|
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
139
|
+
m 33.75,0
|
140
|
+
L 50,17
|
141
|
+
V 5.5
|
142
|
+
Z
|
142
143
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
fill='none'
|
160
|
-
style='
|
161
|
-
stroke: var(--icon-color);
|
162
|
-
stroke-width: 2;
|
163
|
-
'
|
164
|
-
/>
|
165
|
-
`;
|
166
|
-
icon.setAttribute('viewBox', '0 0 100 100');
|
167
|
-
return icon;
|
144
|
+
M 5,40.7
|
145
|
+
v 11.7
|
146
|
+
h 11.25
|
147
|
+
z
|
148
|
+
|
149
|
+
M 26,19
|
150
|
+
C 19.8,19.4 17.65,30.4 21.9,34.8
|
151
|
+
L 50,70
|
152
|
+
H 27.5
|
153
|
+
c -11.25,0 -11.25,17.6 0,17.6
|
154
|
+
H 61.25
|
155
|
+
C 94.9,87.8 95,87.6 95,40.7 78.125,23 67,29 55.6,46.5
|
156
|
+
L 33.1,23
|
157
|
+
C 30.3125,20.128192 27.9,19 25.830078,19.119756
|
158
|
+
Z
|
159
|
+
`, fill, strokeColor, strokeWidth);
|
168
160
|
};
|
169
161
|
export const makeAllDevicePanningIcon = () => {
|
170
|
-
const
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
M 42.5 5
|
181
|
-
L 55 17.5
|
182
|
-
55 5
|
183
|
-
42.5 5
|
184
|
-
z
|
185
|
-
|
186
|
-
M 70 10
|
187
|
-
L 70 21
|
188
|
-
61 15
|
189
|
-
55.5 23
|
190
|
-
66 30
|
191
|
-
56 37
|
192
|
-
61 45
|
193
|
-
70 39
|
194
|
-
70 50
|
195
|
-
80 50
|
196
|
-
80 39
|
197
|
-
89 45
|
198
|
-
95 36
|
199
|
-
84 30
|
200
|
-
95 23
|
201
|
-
89 15
|
202
|
-
80 21
|
203
|
-
80 10
|
204
|
-
70 10
|
205
|
-
z
|
162
|
+
const fill = 'none';
|
163
|
+
const strokeColor = 'var(--icon-color)';
|
164
|
+
const strokeWidth = '3';
|
165
|
+
return pathIcon(`
|
166
|
+
M 5 5
|
167
|
+
L 5 17.5
|
168
|
+
17.5 5
|
169
|
+
5 5
|
170
|
+
z
|
206
171
|
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
172
|
+
M 42.5 5
|
173
|
+
L 55 17.5
|
174
|
+
55 5
|
175
|
+
42.5 5
|
176
|
+
z
|
177
|
+
|
178
|
+
M 70 10
|
179
|
+
L 70 21
|
180
|
+
61 15
|
181
|
+
55.5 23
|
182
|
+
66 30
|
183
|
+
56 37
|
184
|
+
61 45
|
185
|
+
70 39
|
186
|
+
70 50
|
187
|
+
80 50
|
188
|
+
80 39
|
189
|
+
89 45
|
190
|
+
95 36
|
191
|
+
84 30
|
192
|
+
95 23
|
193
|
+
89 15
|
194
|
+
80 21
|
195
|
+
80 10
|
196
|
+
70 10
|
197
|
+
z
|
198
|
+
|
199
|
+
M 27.5 26.25
|
200
|
+
L 27.5 91.25
|
201
|
+
L 43.75 83.125
|
202
|
+
L 52 99
|
203
|
+
L 68 91
|
204
|
+
L 60 75
|
205
|
+
L 76.25 66.875
|
206
|
+
L 27.5 26.25
|
207
|
+
z
|
208
|
+
|
209
|
+
M 5 42.5
|
210
|
+
L 5 55
|
211
|
+
L 17.5 55
|
212
|
+
L 5 42.5
|
213
|
+
z
|
214
|
+
`, fill, strokeColor, strokeWidth);
|
232
215
|
};
|
233
216
|
export const makeZoomIcon = () => {
|
234
217
|
const icon = document.createElementNS(svgNamespace, 'svg');
|
@@ -369,3 +352,30 @@ export const makePipetteIcon = (color) => {
|
|
369
352
|
icon.setAttribute('viewBox', '0 0 100 100');
|
370
353
|
return icon;
|
371
354
|
};
|
355
|
+
export const makeResizeViewportIcon = () => {
|
356
|
+
return pathIcon(`
|
357
|
+
M 75 5 75 10 90 10 90 25 95 25 95 5 75 5 z
|
358
|
+
M 15 15 15 30 20 30 20 20 30 20 30 15 15 15 z
|
359
|
+
M 84 15 82 17 81 16 81 20 85 20 84 19 86 17 84 15 z
|
360
|
+
M 26 24 24 26 26 28 25 29 29 29 29 25 28 26 26 24 z
|
361
|
+
M 25 71 26 72 24 74 26 76 28 74 29 75 29 71 25 71 z
|
362
|
+
M 15 75 15 85 25 85 25 80 20 80 20 75 15 75 z
|
363
|
+
M 90 75 90 90 75 90 75 95 95 95 95 75 90 75 z
|
364
|
+
M 81 81 81 85 82 84 84 86 86 84 84 82 85 81 81 81 z
|
365
|
+
`);
|
366
|
+
};
|
367
|
+
export const makeDuplicateSelectionIcon = () => {
|
368
|
+
return pathIcon(`
|
369
|
+
M 45,10 45,55 90,55 90,10 45,10 z
|
370
|
+
M 10,25 10,90 70,90 70,60 40,60 40,25 10,25 z
|
371
|
+
`);
|
372
|
+
};
|
373
|
+
export const makeDeleteSelectionIcon = () => {
|
374
|
+
const strokeWidth = '5px';
|
375
|
+
const strokeColor = 'var(--icon-color)';
|
376
|
+
const fillColor = 'none';
|
377
|
+
return pathIcon(`
|
378
|
+
M 10,10 90,90
|
379
|
+
M 10,90 90,10
|
380
|
+
`, fillColor, strokeColor, strokeWidth);
|
381
|
+
};
|
@@ -17,7 +17,8 @@ export interface ToolbarLocalization {
|
|
17
17
|
resizeImageToSelection: string;
|
18
18
|
deleteSelection: string;
|
19
19
|
duplicateSelection: string;
|
20
|
-
|
20
|
+
pickColorFromScreen: string;
|
21
|
+
clickToPickColorAnnouncement: string;
|
21
22
|
undo: string;
|
22
23
|
redo: string;
|
23
24
|
zoom: string;
|
@@ -14,7 +14,8 @@ export const defaultToolbarLocalization = {
|
|
14
14
|
undo: 'Undo',
|
15
15
|
redo: 'Redo',
|
16
16
|
selectObjectType: 'Object type: ',
|
17
|
-
|
17
|
+
pickColorFromScreen: 'Pick color from screen',
|
18
|
+
clickToPickColorAnnouncement: 'Click on the screen to pick a color',
|
18
19
|
selectionToolKeyboardShortcuts: 'Selection tool: Use arrow keys to move selected items, lowercase/uppercase ‘i’ and ‘o’ to resize.',
|
19
20
|
touchPanning: 'Touchscreen panning',
|
20
21
|
anyDevicePanning: 'Any device panning',
|
@@ -53,7 +53,7 @@ export const makeColorInput = (editor, onColorChange) => {
|
|
53
53
|
const addPipetteTool = (editor, container, onColorChange) => {
|
54
54
|
const pipetteButton = document.createElement('button');
|
55
55
|
pipetteButton.classList.add('pipetteButton');
|
56
|
-
pipetteButton.title = editor.localization.
|
56
|
+
pipetteButton.title = editor.localization.pickColorFromScreen;
|
57
57
|
pipetteButton.setAttribute('alt', pipetteButton.title);
|
58
58
|
const updatePipetteIcon = (color) => {
|
59
59
|
pipetteButton.replaceChildren(makePipetteIcon(color));
|
@@ -88,6 +88,7 @@ const addPipetteTool = (editor, container, onColorChange) => {
|
|
88
88
|
pipetteTool === null || pipetteTool === void 0 ? void 0 : pipetteTool.setColorListener(pipetteColorPreview, pipetteColorSelect);
|
89
89
|
if (pipetteTool) {
|
90
90
|
pipetteButton.classList.add('active');
|
91
|
+
editor.announceForAccessibility(editor.localization.clickToPickColorAnnouncement);
|
91
92
|
}
|
92
93
|
};
|
93
94
|
container.appendChild(pipetteButton);
|
@@ -0,0 +1,13 @@
|
|
1
|
+
import Editor from '../../Editor';
|
2
|
+
import { ToolbarLocalization } from '../localization';
|
3
|
+
import BaseWidget from './BaseWidget';
|
4
|
+
export default class ActionButtonWidget extends BaseWidget {
|
5
|
+
protected makeIcon: () => Element;
|
6
|
+
protected title: string;
|
7
|
+
protected clickAction: () => void;
|
8
|
+
constructor(editor: Editor, localizationTable: ToolbarLocalization, makeIcon: () => Element, title: string, clickAction: () => void);
|
9
|
+
protected handleClick(): void;
|
10
|
+
protected getTitle(): string;
|
11
|
+
protected createIcon(): Element;
|
12
|
+
protected fillDropdown(_dropdown: HTMLElement): boolean;
|
13
|
+
}
|
@@ -0,0 +1,21 @@
|
|
1
|
+
import BaseWidget from './BaseWidget';
|
2
|
+
export default class ActionButtonWidget extends BaseWidget {
|
3
|
+
constructor(editor, localizationTable, makeIcon, title, clickAction) {
|
4
|
+
super(editor, localizationTable);
|
5
|
+
this.makeIcon = makeIcon;
|
6
|
+
this.title = title;
|
7
|
+
this.clickAction = clickAction;
|
8
|
+
}
|
9
|
+
handleClick() {
|
10
|
+
this.clickAction();
|
11
|
+
}
|
12
|
+
getTitle() {
|
13
|
+
return this.title;
|
14
|
+
}
|
15
|
+
createIcon() {
|
16
|
+
return this.makeIcon();
|
17
|
+
}
|
18
|
+
fillDropdown(_dropdown) {
|
19
|
+
return false;
|
20
|
+
}
|
21
|
+
}
|
@@ -114,9 +114,11 @@ export default class BaseWidget {
|
|
114
114
|
this.disabled = disabled;
|
115
115
|
if (this.disabled) {
|
116
116
|
this.button.classList.add('disabled');
|
117
|
+
this.button.setAttribute('aria-disabled', 'true');
|
117
118
|
}
|
118
119
|
else {
|
119
120
|
this.button.classList.remove('disabled');
|
121
|
+
this.button.removeAttribute('aria-disabled');
|
120
122
|
}
|
121
123
|
}
|
122
124
|
setSelected(selected) {
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import Mat33 from '../../
|
1
|
+
import Mat33 from '../../math/Mat33';
|
2
2
|
import { PanZoomMode } from '../../tools/PanZoom';
|
3
3
|
import { EditorEventType } from '../../types';
|
4
4
|
import Viewport from '../../Viewport';
|
@@ -43,7 +43,7 @@ const makeZoomControl = (localizationTable, editor) => {
|
|
43
43
|
const zoomBy = (factor) => {
|
44
44
|
const screenCenter = editor.viewport.visibleRect.center;
|
45
45
|
const transformUpdate = Mat33.scaling2D(factor, screenCenter);
|
46
|
-
editor.dispatch(
|
46
|
+
editor.dispatch(Viewport.transformBy(transformUpdate), false);
|
47
47
|
};
|
48
48
|
increaseButton.onclick = () => {
|
49
49
|
zoomBy(5.0 / 4);
|
@@ -52,7 +52,7 @@ const makeZoomControl = (localizationTable, editor) => {
|
|
52
52
|
zoomBy(4.0 / 5);
|
53
53
|
};
|
54
54
|
resetViewButton.onclick = () => {
|
55
|
-
editor.dispatch(
|
55
|
+
editor.dispatch(Viewport.transformBy(editor.viewport.canvasToScreenTransform.inverse()), true);
|
56
56
|
};
|
57
57
|
return zoomLevelRow;
|
58
58
|
};
|
@@ -7,5 +7,4 @@ export declare class SelectionWidget extends BaseToolWidget {
|
|
7
7
|
constructor(editor: Editor, tool: SelectionTool, localization: ToolbarLocalization);
|
8
8
|
protected getTitle(): string;
|
9
9
|
protected createIcon(): Element;
|
10
|
-
protected fillDropdown(dropdown: HTMLElement): boolean;
|
11
10
|
}
|
@@ -1,41 +1,33 @@
|
|
1
1
|
import { EditorEventType } from '../../types';
|
2
|
-
import { makeSelectionIcon } from '../icons';
|
2
|
+
import { makeDeleteSelectionIcon, makeDuplicateSelectionIcon, makeResizeViewportIcon, makeSelectionIcon } from '../icons';
|
3
|
+
import ActionButtonWidget from './ActionButtonWidget';
|
3
4
|
import BaseToolWidget from './BaseToolWidget';
|
4
5
|
export class SelectionWidget extends BaseToolWidget {
|
5
6
|
constructor(editor, tool, localization) {
|
6
7
|
super(editor, tool, localization);
|
7
8
|
this.tool = tool;
|
8
|
-
|
9
|
-
getTitle() {
|
10
|
-
return this.localizationTable.select;
|
11
|
-
}
|
12
|
-
createIcon() {
|
13
|
-
return makeSelectionIcon();
|
14
|
-
}
|
15
|
-
fillDropdown(dropdown) {
|
16
|
-
const container = document.createElement('div');
|
17
|
-
const resizeButton = document.createElement('button');
|
18
|
-
const duplicateButton = document.createElement('button');
|
19
|
-
const deleteButton = document.createElement('button');
|
20
|
-
resizeButton.innerText = this.localizationTable.resizeImageToSelection;
|
21
|
-
resizeButton.disabled = true;
|
22
|
-
deleteButton.innerText = this.localizationTable.deleteSelection;
|
23
|
-
deleteButton.disabled = true;
|
24
|
-
duplicateButton.innerText = this.localizationTable.duplicateSelection;
|
25
|
-
duplicateButton.disabled = true;
|
26
|
-
resizeButton.onclick = () => {
|
9
|
+
const resizeButton = new ActionButtonWidget(editor, localization, makeResizeViewportIcon, this.localizationTable.resizeImageToSelection, () => {
|
27
10
|
const selection = this.tool.getSelection();
|
28
11
|
this.editor.dispatch(this.editor.setImportExportRect(selection.region));
|
29
|
-
};
|
30
|
-
deleteButton
|
12
|
+
});
|
13
|
+
const deleteButton = new ActionButtonWidget(editor, localization, makeDeleteSelectionIcon, this.localizationTable.deleteSelection, () => {
|
31
14
|
const selection = this.tool.getSelection();
|
32
15
|
this.editor.dispatch(selection.deleteSelectedObjects());
|
33
16
|
this.tool.clearSelection();
|
34
|
-
};
|
35
|
-
duplicateButton
|
17
|
+
});
|
18
|
+
const duplicateButton = new ActionButtonWidget(editor, localization, makeDuplicateSelectionIcon, this.localizationTable.duplicateSelection, () => {
|
36
19
|
const selection = this.tool.getSelection();
|
37
20
|
this.editor.dispatch(selection.duplicateSelectedObjects());
|
21
|
+
});
|
22
|
+
this.addSubWidget(resizeButton);
|
23
|
+
this.addSubWidget(deleteButton);
|
24
|
+
this.addSubWidget(duplicateButton);
|
25
|
+
const updateDisabled = (disabled) => {
|
26
|
+
resizeButton.setDisabled(disabled);
|
27
|
+
deleteButton.setDisabled(disabled);
|
28
|
+
duplicateButton.setDisabled(disabled);
|
38
29
|
};
|
30
|
+
updateDisabled(true);
|
39
31
|
// Enable/disable actions based on whether items are selected
|
40
32
|
this.editor.notifier.on(EditorEventType.ToolUpdated, toolEvt => {
|
41
33
|
if (toolEvt.kind !== EditorEventType.ToolUpdated) {
|
@@ -44,13 +36,14 @@ export class SelectionWidget extends BaseToolWidget {
|
|
44
36
|
if (toolEvt.tool === this.tool) {
|
45
37
|
const selection = this.tool.getSelection();
|
46
38
|
const hasSelection = selection && selection.region.area > 0;
|
47
|
-
|
48
|
-
deleteButton.disabled = resizeButton.disabled;
|
49
|
-
duplicateButton.disabled = resizeButton.disabled;
|
39
|
+
updateDisabled(!hasSelection);
|
50
40
|
}
|
51
41
|
});
|
52
|
-
|
53
|
-
|
54
|
-
return
|
42
|
+
}
|
43
|
+
getTitle() {
|
44
|
+
return this.localizationTable.select;
|
45
|
+
}
|
46
|
+
createIcon() {
|
47
|
+
return makeSelectionIcon();
|
55
48
|
}
|
56
49
|
}
|
package/dist/src/tools/Eraser.js
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
import BaseTool from './BaseTool';
|
2
|
-
import LineSegment2 from '../
|
2
|
+
import LineSegment2 from '../math/LineSegment2';
|
3
3
|
import Erase from '../commands/Erase';
|
4
4
|
import { ToolType } from './ToolController';
|
5
5
|
import { PointerDevice } from '../Pointer';
|
@@ -1,6 +1,6 @@
|
|
1
|
-
import Mat33 from '../
|
2
|
-
import { Vec2 } from '../
|
3
|
-
import Vec3 from '../
|
1
|
+
import Mat33 from '../math/Mat33';
|
2
|
+
import { Vec2 } from '../math/Vec2';
|
3
|
+
import Vec3 from '../math/Vec3';
|
4
4
|
import { PointerDevice } from '../Pointer';
|
5
5
|
import { EditorEventType } from '../types';
|
6
6
|
import { Viewport } from '../Viewport';
|
@@ -53,7 +53,7 @@ export default class PanZoom extends BaseTool {
|
|
53
53
|
handlingGesture = true;
|
54
54
|
}
|
55
55
|
if (handlingGesture) {
|
56
|
-
(_a = this.transform) !== null && _a !== void 0 ? _a : (this.transform =
|
56
|
+
(_a = this.transform) !== null && _a !== void 0 ? _a : (this.transform = Viewport.transformBy(Mat33.identity));
|
57
57
|
this.editor.display.setDraftMode(true);
|
58
58
|
}
|
59
59
|
return handlingGesture;
|
@@ -74,16 +74,16 @@ export default class PanZoom extends BaseTool {
|
|
74
74
|
this.lastScreenCenter = screenCenter;
|
75
75
|
this.lastDist = dist;
|
76
76
|
this.lastAngle = angle;
|
77
|
-
this.transform =
|
77
|
+
this.transform = Viewport.transformBy(this.transform.transform.rightMul(transformUpdate));
|
78
78
|
}
|
79
79
|
handleOneFingerMove(pointer) {
|
80
80
|
const delta = this.getCenterDelta(pointer.screenPos);
|
81
|
-
this.transform =
|
81
|
+
this.transform = Viewport.transformBy(this.transform.transform.rightMul(Mat33.translation(delta)));
|
82
82
|
this.lastScreenCenter = pointer.screenPos;
|
83
83
|
}
|
84
84
|
onPointerMove({ allPointers }) {
|
85
85
|
var _a;
|
86
|
-
(_a = this.transform) !== null && _a !== void 0 ? _a : (this.transform =
|
86
|
+
(_a = this.transform) !== null && _a !== void 0 ? _a : (this.transform = Viewport.transformBy(Mat33.identity));
|
87
87
|
const lastTransform = this.transform;
|
88
88
|
if (allPointers.length === 2) {
|
89
89
|
this.handleTwoFingerMove(allPointers);
|
@@ -110,27 +110,30 @@ export default class PanZoom extends BaseTool {
|
|
110
110
|
}
|
111
111
|
// Applies [transformUpdate] to the editor. This stacks on top of the
|
112
112
|
// current transformation, if it exists.
|
113
|
-
updateTransform(transformUpdate) {
|
113
|
+
updateTransform(transformUpdate, announce = false) {
|
114
114
|
var _a;
|
115
115
|
let newTransform = transformUpdate;
|
116
116
|
if (this.transform) {
|
117
117
|
newTransform = this.transform.transform.rightMul(transformUpdate);
|
118
118
|
}
|
119
119
|
(_a = this.transform) === null || _a === void 0 ? void 0 : _a.unapply(this.editor);
|
120
|
-
this.transform =
|
120
|
+
this.transform = Viewport.transformBy(newTransform);
|
121
121
|
this.transform.apply(this.editor);
|
122
|
+
if (announce) {
|
123
|
+
this.editor.announceForAccessibility(this.transform.description(this.editor, this.editor.localization));
|
124
|
+
}
|
122
125
|
}
|
123
126
|
onWheel({ delta, screenPos }) {
|
124
127
|
// Reset the transformation -- wheel events are individual events, so we don't
|
125
128
|
// need to unapply/reapply.
|
126
|
-
this.transform =
|
129
|
+
this.transform = Viewport.transformBy(Mat33.identity);
|
127
130
|
const canvasPos = this.editor.viewport.screenToCanvas(screenPos);
|
128
131
|
const toCanvas = this.editor.viewport.screenToCanvasTransform;
|
129
132
|
// Transform without including translation
|
130
133
|
const translation = toCanvas.transformVec3(Vec3.of(-delta.x, -delta.y, 0));
|
131
134
|
const pinchZoomScaleFactor = 1.04;
|
132
135
|
const transformUpdate = Mat33.scaling2D(Math.max(0.25, Math.min(Math.pow(pinchZoomScaleFactor, -delta.z), 4)), canvasPos).rightMul(Mat33.translation(translation));
|
133
|
-
this.updateTransform(transformUpdate);
|
136
|
+
this.updateTransform(transformUpdate, true);
|
134
137
|
return true;
|
135
138
|
}
|
136
139
|
onKeyPress({ key }) {
|
@@ -138,7 +141,7 @@ export default class PanZoom extends BaseTool {
|
|
138
141
|
return false;
|
139
142
|
}
|
140
143
|
// No need to keep the same the transform for keyboard events.
|
141
|
-
this.transform =
|
144
|
+
this.transform = Viewport.transformBy(Mat33.identity);
|
142
145
|
let translation = Vec2.zero;
|
143
146
|
let scale = 1;
|
144
147
|
let rotation = 0;
|
@@ -154,10 +157,12 @@ export default class PanZoom extends BaseTool {
|
|
154
157
|
case 'ArrowRight':
|
155
158
|
translation = Vec2.of(1, 0);
|
156
159
|
break;
|
160
|
+
case 'q':
|
157
161
|
case 'k':
|
158
162
|
case 'ArrowUp':
|
159
163
|
translation = Vec2.of(0, -1);
|
160
164
|
break;
|
165
|
+
case 'e':
|
161
166
|
case 'j':
|
162
167
|
case 'ArrowDown':
|
163
168
|
translation = Vec2.of(0, 1);
|
@@ -179,11 +184,16 @@ export default class PanZoom extends BaseTool {
|
|
179
184
|
}
|
180
185
|
// For each keypress,
|
181
186
|
translation = translation.times(30); // Move at most 30 units
|
182
|
-
rotation *= Math.PI / 8; // Rotate at
|
187
|
+
rotation *= Math.PI / 8; // Rotate at least a sixteenth of a rotation
|
183
188
|
// Transform the canvas, not the viewport:
|
184
189
|
translation = translation.times(-1);
|
185
190
|
rotation = rotation * -1;
|
186
191
|
scale = 1 / scale;
|
192
|
+
// Work around an issue that seems to be related to rotation matricies losing precision on inversion.
|
193
|
+
// TODO: Figure out why and implement a better solution.
|
194
|
+
if (rotation !== 0) {
|
195
|
+
rotation += 0.0001;
|
196
|
+
}
|
187
197
|
const toCanvas = this.editor.viewport.screenToCanvasTransform;
|
188
198
|
// Transform without translating (treat toCanvas as a linear instead of
|
189
199
|
// an affine transformation).
|
@@ -191,7 +201,7 @@ export default class PanZoom extends BaseTool {
|
|
191
201
|
// Rotate/scale about the center of the canvas
|
192
202
|
const transformCenter = this.editor.viewport.visibleRect.center;
|
193
203
|
const transformUpdate = Mat33.scaling2D(scale, transformCenter).rightMul(Mat33.zRotation(rotation, transformCenter)).rightMul(Mat33.translation(translation));
|
194
|
-
this.updateTransform(transformUpdate);
|
204
|
+
this.updateTransform(transformUpdate, true);
|
195
205
|
return true;
|
196
206
|
}
|
197
207
|
setMode(mode) {
|
@@ -1,8 +1,8 @@
|
|
1
1
|
import Command from '../commands/Command';
|
2
2
|
import Editor from '../Editor';
|
3
|
-
import Mat33 from '../
|
4
|
-
import Rect2 from '../
|
5
|
-
import { Point2, Vec2 } from '../
|
3
|
+
import Mat33 from '../math/Mat33';
|
4
|
+
import Rect2 from '../math/Rect2';
|
5
|
+
import { Point2, Vec2 } from '../math/Vec2';
|
6
6
|
import { KeyPressEvent, KeyUpEvent, PointerEvt } from '../types';
|
7
7
|
import BaseTool from './BaseTool';
|
8
8
|
import { ToolType } from './ToolController';
|