js-draw 1.9.1 → 1.11.0
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/dist/Editor.css +48 -1
- package/dist/bundle.js +2 -2
- package/dist/bundledStyles.js +1 -1
- package/dist/cjs/Editor.d.ts +41 -0
- package/dist/cjs/Editor.js +9 -0
- package/dist/cjs/Pointer.js +1 -1
- package/dist/cjs/commands/Erase.d.ts +22 -2
- package/dist/cjs/commands/Erase.js +22 -2
- package/dist/cjs/commands/invertCommand.js +5 -0
- package/dist/cjs/commands/uniteCommands.d.ts +36 -0
- package/dist/cjs/commands/uniteCommands.js +36 -0
- package/dist/cjs/components/AbstractComponent.d.ts +8 -0
- package/dist/cjs/components/AbstractComponent.js +28 -8
- package/dist/cjs/components/ImageComponent.d.ts +12 -0
- package/dist/cjs/components/ImageComponent.js +16 -9
- package/dist/cjs/components/Stroke.d.ts +16 -2
- package/dist/cjs/components/Stroke.js +17 -1
- package/dist/cjs/components/builders/ArrowBuilder.js +3 -3
- package/dist/cjs/components/builders/CircleBuilder.js +3 -3
- package/dist/cjs/components/builders/FreehandLineBuilder.js +3 -3
- package/dist/cjs/components/builders/LineBuilder.js +3 -3
- package/dist/cjs/components/builders/PressureSensitiveFreehandLineBuilder.js +3 -3
- package/dist/cjs/components/builders/RectangleBuilder.js +5 -6
- package/dist/cjs/components/builders/autocorrect/makeShapeFitAutocorrect.d.ts +3 -0
- package/dist/cjs/components/builders/autocorrect/makeShapeFitAutocorrect.js +168 -0
- package/dist/cjs/components/builders/autocorrect/makeSnapToGridAutocorrect.d.ts +3 -0
- package/dist/cjs/components/builders/autocorrect/makeSnapToGridAutocorrect.js +46 -0
- package/dist/cjs/components/builders/types.d.ts +12 -0
- package/dist/cjs/image/EditorImage.d.ts +32 -1
- package/dist/cjs/image/EditorImage.js +32 -1
- package/dist/cjs/rendering/RenderablePathSpec.d.ts +5 -1
- package/dist/cjs/rendering/RenderablePathSpec.js +4 -0
- package/dist/cjs/toolbar/AbstractToolbar.d.ts +18 -2
- package/dist/cjs/toolbar/AbstractToolbar.js +46 -30
- package/dist/cjs/toolbar/IconProvider.d.ts +2 -0
- package/dist/cjs/toolbar/IconProvider.js +17 -0
- package/dist/cjs/toolbar/localization.d.ts +3 -0
- package/dist/cjs/toolbar/localization.js +4 -1
- package/dist/cjs/toolbar/widgets/BaseWidget.js +1 -1
- package/dist/cjs/toolbar/widgets/ExitActionWidget.d.ts +12 -0
- package/dist/cjs/toolbar/widgets/ExitActionWidget.js +32 -0
- package/dist/cjs/toolbar/widgets/HandToolWidget.d.ts +4 -3
- package/dist/cjs/toolbar/widgets/HandToolWidget.js +24 -13
- package/dist/cjs/toolbar/widgets/InsertImageWidget.d.ts +2 -1
- package/dist/cjs/toolbar/widgets/InsertImageWidget.js +102 -22
- package/dist/cjs/toolbar/widgets/PenToolWidget.d.ts +1 -2
- package/dist/cjs/toolbar/widgets/PenToolWidget.js +50 -20
- package/dist/cjs/toolbar/widgets/keybindings.d.ts +1 -0
- package/dist/cjs/toolbar/widgets/keybindings.js +4 -1
- package/dist/cjs/toolbar/widgets/layout/types.d.ts +1 -1
- package/dist/cjs/tools/Pen.d.ts +9 -0
- package/dist/cjs/tools/Pen.js +82 -3
- package/dist/cjs/tools/SelectionTool/Selection.d.ts +4 -0
- package/dist/cjs/tools/SelectionTool/Selection.js +56 -12
- package/dist/cjs/tools/SelectionTool/SelectionTool.d.ts +1 -0
- package/dist/cjs/tools/SelectionTool/SelectionTool.js +19 -1
- package/dist/cjs/tools/TextTool.js +5 -1
- package/dist/cjs/tools/ToolSwitcherShortcut.d.ts +0 -1
- package/dist/cjs/tools/ToolSwitcherShortcut.js +0 -1
- package/dist/cjs/tools/keybindings.d.ts +1 -0
- package/dist/cjs/tools/keybindings.js +3 -1
- package/dist/cjs/tools/util/StationaryPenDetector.d.ts +22 -0
- package/dist/cjs/tools/util/StationaryPenDetector.js +95 -0
- package/dist/cjs/util/ReactiveValue.d.ts +2 -0
- package/dist/cjs/util/ReactiveValue.js +2 -0
- package/dist/cjs/util/lib.d.ts +1 -0
- package/dist/cjs/util/lib.js +4 -1
- package/dist/cjs/util/waitForImageLoaded.d.ts +2 -0
- package/dist/cjs/util/waitForImageLoaded.js +12 -0
- package/dist/cjs/version.js +1 -1
- package/dist/mjs/Editor.d.ts +41 -0
- package/dist/mjs/Editor.mjs +9 -0
- package/dist/mjs/Pointer.mjs +1 -1
- package/dist/mjs/commands/Erase.d.ts +22 -2
- package/dist/mjs/commands/Erase.mjs +22 -2
- package/dist/mjs/commands/invertCommand.mjs +5 -0
- package/dist/mjs/commands/uniteCommands.d.ts +36 -0
- package/dist/mjs/commands/uniteCommands.mjs +36 -0
- package/dist/mjs/components/AbstractComponent.d.ts +8 -0
- package/dist/mjs/components/AbstractComponent.mjs +28 -8
- package/dist/mjs/components/ImageComponent.d.ts +12 -0
- package/dist/mjs/components/ImageComponent.mjs +16 -9
- package/dist/mjs/components/Stroke.d.ts +16 -2
- package/dist/mjs/components/Stroke.mjs +17 -1
- package/dist/mjs/components/builders/ArrowBuilder.mjs +3 -2
- package/dist/mjs/components/builders/CircleBuilder.mjs +3 -2
- package/dist/mjs/components/builders/FreehandLineBuilder.mjs +3 -2
- package/dist/mjs/components/builders/LineBuilder.mjs +3 -2
- package/dist/mjs/components/builders/PressureSensitiveFreehandLineBuilder.mjs +3 -2
- package/dist/mjs/components/builders/RectangleBuilder.mjs +5 -4
- package/dist/mjs/components/builders/autocorrect/makeShapeFitAutocorrect.d.ts +3 -0
- package/dist/mjs/components/builders/autocorrect/makeShapeFitAutocorrect.mjs +166 -0
- package/dist/mjs/components/builders/autocorrect/makeSnapToGridAutocorrect.d.ts +3 -0
- package/dist/mjs/components/builders/autocorrect/makeSnapToGridAutocorrect.mjs +44 -0
- package/dist/mjs/components/builders/types.d.ts +12 -0
- package/dist/mjs/image/EditorImage.d.ts +32 -1
- package/dist/mjs/image/EditorImage.mjs +32 -1
- package/dist/mjs/rendering/RenderablePathSpec.d.ts +5 -1
- package/dist/mjs/rendering/RenderablePathSpec.mjs +4 -0
- package/dist/mjs/toolbar/AbstractToolbar.d.ts +18 -2
- package/dist/mjs/toolbar/AbstractToolbar.mjs +46 -30
- package/dist/mjs/toolbar/IconProvider.d.ts +2 -0
- package/dist/mjs/toolbar/IconProvider.mjs +17 -0
- package/dist/mjs/toolbar/localization.d.ts +3 -0
- package/dist/mjs/toolbar/localization.mjs +4 -1
- package/dist/mjs/toolbar/widgets/BaseWidget.mjs +1 -1
- package/dist/mjs/toolbar/widgets/ExitActionWidget.d.ts +12 -0
- package/dist/mjs/toolbar/widgets/ExitActionWidget.mjs +27 -0
- package/dist/mjs/toolbar/widgets/HandToolWidget.d.ts +4 -3
- package/dist/mjs/toolbar/widgets/HandToolWidget.mjs +24 -13
- package/dist/mjs/toolbar/widgets/InsertImageWidget.d.ts +2 -1
- package/dist/mjs/toolbar/widgets/InsertImageWidget.mjs +102 -22
- package/dist/mjs/toolbar/widgets/PenToolWidget.d.ts +1 -2
- package/dist/mjs/toolbar/widgets/PenToolWidget.mjs +50 -20
- package/dist/mjs/toolbar/widgets/keybindings.d.ts +1 -0
- package/dist/mjs/toolbar/widgets/keybindings.mjs +3 -0
- package/dist/mjs/toolbar/widgets/layout/types.d.ts +1 -1
- package/dist/mjs/tools/Pen.d.ts +9 -0
- package/dist/mjs/tools/Pen.mjs +82 -3
- package/dist/mjs/tools/SelectionTool/Selection.d.ts +4 -0
- package/dist/mjs/tools/SelectionTool/Selection.mjs +56 -12
- package/dist/mjs/tools/SelectionTool/SelectionTool.d.ts +1 -0
- package/dist/mjs/tools/SelectionTool/SelectionTool.mjs +20 -2
- package/dist/mjs/tools/TextTool.mjs +5 -1
- package/dist/mjs/tools/ToolSwitcherShortcut.d.ts +0 -1
- package/dist/mjs/tools/ToolSwitcherShortcut.mjs +0 -1
- package/dist/mjs/tools/keybindings.d.ts +1 -0
- package/dist/mjs/tools/keybindings.mjs +2 -0
- package/dist/mjs/tools/util/StationaryPenDetector.d.ts +22 -0
- package/dist/mjs/tools/util/StationaryPenDetector.mjs +92 -0
- package/dist/mjs/util/ReactiveValue.d.ts +2 -0
- package/dist/mjs/util/ReactiveValue.mjs +2 -0
- package/dist/mjs/util/lib.d.ts +1 -0
- package/dist/mjs/util/lib.mjs +1 -0
- package/dist/mjs/util/waitForImageLoaded.d.ts +2 -0
- package/dist/mjs/util/waitForImageLoaded.mjs +10 -0
- package/dist/mjs/version.mjs +1 -1
- package/package.json +3 -3
- package/src/Editor.scss +7 -0
- package/src/toolbar/AbstractToolbar.scss +20 -0
- package/src/toolbar/toolbar.scss +1 -1
- package/src/toolbar/widgets/InsertImageWidget.scss +6 -1
- package/src/toolbar/widgets/PenToolWidget.scss +33 -0
- package/src/tools/SelectionTool/SelectionTool.scss +6 -0
- package/src/toolbar/widgets/PenToolWidget.css +0 -2
@@ -152,27 +152,51 @@ class PenToolWidget extends BaseToolWidget_1.default {
|
|
152
152
|
},
|
153
153
|
};
|
154
154
|
}
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
155
|
+
createStrokeCorrectionOptions() {
|
156
|
+
const container = document.createElement('div');
|
157
|
+
container.classList.add('action-button-row', `${constants_1.toolbarCSSPrefix}-pen-tool-toggle-buttons`);
|
158
|
+
const addToggleButton = (labelText, icon) => {
|
159
|
+
const button = document.createElement('button');
|
160
|
+
button.classList.add(`${constants_1.toolbarCSSPrefix}-toggle-button`);
|
161
|
+
const iconElement = icon.cloneNode(true);
|
162
|
+
iconElement.classList.add('icon');
|
163
|
+
const label = document.createElement('span');
|
164
|
+
label.innerText = labelText;
|
165
|
+
button.replaceChildren(iconElement, label);
|
166
|
+
button.setAttribute('role', 'switch');
|
167
|
+
container.appendChild(button);
|
168
|
+
let checked = false;
|
169
|
+
let onChangeListener = (_checked) => { };
|
170
|
+
const result = {
|
171
|
+
setChecked(newChecked) {
|
172
|
+
checked = newChecked;
|
173
|
+
button.setAttribute('aria-checked', `${checked}`);
|
174
|
+
onChangeListener(checked);
|
175
|
+
},
|
176
|
+
setOnInputListener(listener) {
|
177
|
+
onChangeListener = listener;
|
178
|
+
},
|
179
|
+
};
|
180
|
+
button.onclick = () => {
|
181
|
+
result.setChecked(!checked);
|
182
|
+
};
|
183
|
+
return result;
|
169
184
|
};
|
185
|
+
const stabilizationOption = addToggleButton(this.localizationTable.inputStabilization, this.editor.icons.makeStrokeSmoothingIcon());
|
186
|
+
stabilizationOption.setOnInputListener(enabled => {
|
187
|
+
this.tool.setHasStabilization(enabled);
|
188
|
+
});
|
189
|
+
const autocorrectOption = addToggleButton(this.localizationTable.strokeAutocorrect, this.editor.icons.makeShapeAutocorrectIcon());
|
190
|
+
autocorrectOption.setOnInputListener(enabled => {
|
191
|
+
this.tool.setStrokeAutocorrectEnabled(enabled);
|
192
|
+
});
|
170
193
|
return {
|
171
194
|
update: () => {
|
172
|
-
|
195
|
+
stabilizationOption.setChecked(!!this.tool.getInputMapper());
|
196
|
+
autocorrectOption.setChecked(this.tool.getStrokeAutocorrectionEnabled());
|
173
197
|
},
|
174
198
|
addTo: (parent) => {
|
175
|
-
parent.appendChild(
|
199
|
+
parent.appendChild(container);
|
176
200
|
}
|
177
201
|
};
|
178
202
|
}
|
@@ -194,20 +218,22 @@ class PenToolWidget extends BaseToolWidget_1.default {
|
|
194
218
|
colorLabel.setAttribute('for', colorInput.id);
|
195
219
|
colorRow.appendChild(colorLabel);
|
196
220
|
colorRow.appendChild(colorInputContainer);
|
197
|
-
const
|
221
|
+
const toggleButtonRow = this.createStrokeCorrectionOptions();
|
198
222
|
this.updateInputs = () => {
|
199
223
|
setColorInputValue(this.tool.getColor());
|
200
224
|
setThickness(this.tool.getThickness());
|
201
225
|
penTypeSelect.updateIcons();
|
202
226
|
// Update the selected stroke factory.
|
203
227
|
penTypeSelect.setValue(this.getCurrentPenTypeIdx());
|
204
|
-
|
228
|
+
toggleButtonRow.update();
|
205
229
|
};
|
206
230
|
this.updateInputs();
|
207
231
|
container.replaceChildren(colorRow, thicknessRow);
|
208
232
|
penTypeSelect.addTo(container);
|
209
|
-
stabilizationOption.addTo(container);
|
210
233
|
dropdown.replaceChildren(container);
|
234
|
+
// Add the toggle button row *outside* of the main content (use different
|
235
|
+
// spacing with respect to the sides of the container).
|
236
|
+
toggleButtonRow.addTo(dropdown);
|
211
237
|
return true;
|
212
238
|
}
|
213
239
|
onKeyPress(event) {
|
@@ -237,6 +263,7 @@ class PenToolWidget extends BaseToolWidget_1.default {
|
|
237
263
|
thickness: this.tool.getThickness(),
|
238
264
|
strokeFactoryId: this.getCurrentPenType()?.id,
|
239
265
|
inputStabilization: !!this.tool.getInputMapper(),
|
266
|
+
strokeAutocorrect: this.tool.getStrokeAutocorrectionEnabled(),
|
240
267
|
};
|
241
268
|
}
|
242
269
|
deserializeFrom(state) {
|
@@ -267,7 +294,10 @@ class PenToolWidget extends BaseToolWidget_1.default {
|
|
267
294
|
}
|
268
295
|
}
|
269
296
|
if (state.inputStabilization !== undefined) {
|
270
|
-
this.
|
297
|
+
this.tool.setHasStabilization(!!state.inputStabilization);
|
298
|
+
}
|
299
|
+
if (state.strokeAutocorrect !== undefined) {
|
300
|
+
this.tool.setStrokeAutocorrectEnabled(!!state.strokeAutocorrect);
|
271
301
|
}
|
272
302
|
}
|
273
303
|
}
|
@@ -1,3 +1,4 @@
|
|
1
1
|
export declare const resizeImageToSelectionKeyboardShortcut = "jsdraw.toolbar.SelectionTool.resizeImageToSelection";
|
2
2
|
export declare const selectStrokeTypeKeyboardShortcutIds: string[];
|
3
3
|
export declare const saveKeyboardShortcut = "jsdraw.toolbar.SaveActionWidget.save";
|
4
|
+
export declare const exitKeyboardShortcut = "jsdraw.toolbar.ExitActionWidget.exit";
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
4
|
};
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
-
exports.saveKeyboardShortcut = exports.selectStrokeTypeKeyboardShortcutIds = exports.resizeImageToSelectionKeyboardShortcut = void 0;
|
6
|
+
exports.exitKeyboardShortcut = exports.saveKeyboardShortcut = exports.selectStrokeTypeKeyboardShortcutIds = exports.resizeImageToSelectionKeyboardShortcut = void 0;
|
7
7
|
const KeyboardShortcutManager_1 = __importDefault(require("../../shortcuts/KeyboardShortcutManager"));
|
8
8
|
// Selection
|
9
9
|
exports.resizeImageToSelectionKeyboardShortcut = 'jsdraw.toolbar.SelectionTool.resizeImageToSelection';
|
@@ -17,3 +17,6 @@ for (let i = 0; i < exports.selectStrokeTypeKeyboardShortcutIds.length; i++) {
|
|
17
17
|
// Save
|
18
18
|
exports.saveKeyboardShortcut = 'jsdraw.toolbar.SaveActionWidget.save';
|
19
19
|
KeyboardShortcutManager_1.default.registerDefaultKeyboardShortcut(exports.saveKeyboardShortcut, ['ctrlOrMeta+KeyS'], 'Save');
|
20
|
+
// Exit
|
21
|
+
exports.exitKeyboardShortcut = 'jsdraw.toolbar.ExitActionWidget.exit';
|
22
|
+
KeyboardShortcutManager_1.default.registerDefaultKeyboardShortcut(exports.exitKeyboardShortcut, ['Alt+KeyQ'], 'Exit');
|
package/dist/cjs/tools/Pen.d.ts
CHANGED
@@ -19,6 +19,11 @@ export default class Pen extends BaseTool {
|
|
19
19
|
private currentDeviceType;
|
20
20
|
private styleValue;
|
21
21
|
private style;
|
22
|
+
private shapeAutocompletionEnabled;
|
23
|
+
private autocorrectedShape;
|
24
|
+
private lastAutocorrectedShape;
|
25
|
+
private removedAutocorrectedShapeTime;
|
26
|
+
private stationaryDetector;
|
22
27
|
constructor(editor: Editor, description: string, style: Partial<PenStyle>);
|
23
28
|
private getPressureMultiplier;
|
24
29
|
protected toStrokePoint(pointer: Pointer): StrokeDataPoint;
|
@@ -30,12 +35,16 @@ export default class Pen extends BaseTool {
|
|
30
35
|
onPointerMove({ current }: PointerEvt): void;
|
31
36
|
onPointerUp({ current }: PointerEvt): boolean;
|
32
37
|
onGestureCancel(): void;
|
38
|
+
private removedAutocorrectedShapeRecently;
|
39
|
+
private autocorrectShape;
|
33
40
|
private finalizeStroke;
|
34
41
|
private noteUpdated;
|
35
42
|
setColor(color: Color4): void;
|
36
43
|
setThickness(thickness: number): void;
|
37
44
|
setStrokeFactory(factory: ComponentBuilderFactory): void;
|
38
45
|
setHasStabilization(hasStabilization: boolean): void;
|
46
|
+
setStrokeAutocorrectEnabled(enabled: boolean): void;
|
47
|
+
getStrokeAutocorrectionEnabled(): boolean;
|
39
48
|
getThickness(): number;
|
40
49
|
getColor(): Color4;
|
41
50
|
getStrokeFactory(): ComponentBuilderFactory;
|
package/dist/cjs/tools/Pen.js
CHANGED
@@ -13,6 +13,7 @@ const keybindings_1 = require("./keybindings");
|
|
13
13
|
const keybindings_2 = require("./keybindings");
|
14
14
|
const InputStabilizer_1 = __importDefault(require("./InputFilter/InputStabilizer"));
|
15
15
|
const ReactiveValue_1 = require("../util/ReactiveValue");
|
16
|
+
const StationaryPenDetector_1 = __importDefault(require("./util/StationaryPenDetector"));
|
16
17
|
class Pen extends BaseTool_1.default {
|
17
18
|
constructor(editor, description, style) {
|
18
19
|
super(editor.notifier, description);
|
@@ -21,6 +22,11 @@ class Pen extends BaseTool_1.default {
|
|
21
22
|
this.lastPoint = null;
|
22
23
|
this.startPoint = null;
|
23
24
|
this.currentDeviceType = null;
|
25
|
+
this.shapeAutocompletionEnabled = false;
|
26
|
+
this.autocorrectedShape = null;
|
27
|
+
this.lastAutocorrectedShape = null;
|
28
|
+
this.removedAutocorrectedShapeTime = 0;
|
29
|
+
this.stationaryDetector = null;
|
24
30
|
this.styleValue = ReactiveValue_1.ReactiveValue.fromInitialValue({
|
25
31
|
factory: FreehandLineBuilder_1.makeFreehandLineBuilder,
|
26
32
|
color: math_1.Color4.blue,
|
@@ -58,7 +64,14 @@ class Pen extends BaseTool_1.default {
|
|
58
64
|
// Displays the stroke that is currently being built with the display's `wetInkRenderer`.
|
59
65
|
previewStroke() {
|
60
66
|
this.editor.clearWetInk();
|
61
|
-
this.
|
67
|
+
const wetInkRenderer = this.editor.display.getWetInkRenderer();
|
68
|
+
if (this.autocorrectedShape) {
|
69
|
+
const visibleRect = this.editor.viewport.visibleRect;
|
70
|
+
this.autocorrectedShape.render(wetInkRenderer, visibleRect);
|
71
|
+
}
|
72
|
+
else {
|
73
|
+
this.builder?.preview(wetInkRenderer);
|
74
|
+
}
|
62
75
|
}
|
63
76
|
// Throws if no stroke builder exists.
|
64
77
|
addPointToStroke(point) {
|
@@ -87,6 +100,19 @@ class Pen extends BaseTool_1.default {
|
|
87
100
|
this.startPoint = this.toStrokePoint(current);
|
88
101
|
this.builder = this.style.factory(this.startPoint, this.editor.viewport);
|
89
102
|
this.currentDeviceType = current.device;
|
103
|
+
if (this.shapeAutocompletionEnabled) {
|
104
|
+
const stationaryDetectionConfig = {
|
105
|
+
maxSpeed: 5,
|
106
|
+
maxRadius: 10,
|
107
|
+
minTimeSeconds: 0.5, // s
|
108
|
+
};
|
109
|
+
this.stationaryDetector = new StationaryPenDetector_1.default(current, stationaryDetectionConfig, pointer => this.autocorrectShape(pointer));
|
110
|
+
}
|
111
|
+
else {
|
112
|
+
this.stationaryDetector = null;
|
113
|
+
}
|
114
|
+
this.lastAutocorrectedShape = null;
|
115
|
+
this.removedAutocorrectedShapeTime = 0;
|
90
116
|
return true;
|
91
117
|
}
|
92
118
|
return false;
|
@@ -114,7 +140,14 @@ class Pen extends BaseTool_1.default {
|
|
114
140
|
return;
|
115
141
|
if (current.device !== this.currentDeviceType)
|
116
142
|
return;
|
117
|
-
this.
|
143
|
+
const isStationary = this.stationaryDetector?.onPointerMove(current);
|
144
|
+
if (!isStationary) {
|
145
|
+
this.addPointToStroke(this.toStrokePoint(current));
|
146
|
+
if (this.autocorrectedShape) {
|
147
|
+
this.removedAutocorrectedShapeTime = performance.now();
|
148
|
+
this.autocorrectedShape = null;
|
149
|
+
}
|
150
|
+
}
|
118
151
|
}
|
119
152
|
onPointerUp({ current }) {
|
120
153
|
if (!this.builder)
|
@@ -124,6 +157,7 @@ class Pen extends BaseTool_1.default {
|
|
124
157
|
// device type.
|
125
158
|
return true;
|
126
159
|
}
|
160
|
+
this.stationaryDetector?.onPointerUp(current);
|
127
161
|
// onPointerUp events can have zero pressure. Use the last pressure instead.
|
128
162
|
const currentPoint = this.toStrokePoint(current);
|
129
163
|
const strokePoint = {
|
@@ -139,10 +173,42 @@ class Pen extends BaseTool_1.default {
|
|
139
173
|
onGestureCancel() {
|
140
174
|
this.builder = null;
|
141
175
|
this.editor.clearWetInk();
|
176
|
+
this.stationaryDetector?.destroy();
|
177
|
+
this.stationaryDetector = null;
|
178
|
+
}
|
179
|
+
removedAutocorrectedShapeRecently() {
|
180
|
+
return this.removedAutocorrectedShapeTime > performance.now() - 320;
|
181
|
+
}
|
182
|
+
async autocorrectShape(_lastPointer) {
|
183
|
+
if (!this.builder || !this.builder.autocorrectShape)
|
184
|
+
return;
|
185
|
+
if (!this.shapeAutocompletionEnabled)
|
186
|
+
return;
|
187
|
+
// If already corrected, do nothing
|
188
|
+
if (this.autocorrectedShape)
|
189
|
+
return;
|
190
|
+
// Activate stroke fitting
|
191
|
+
const correctedShape = await this.builder.autocorrectShape();
|
192
|
+
if (!this.builder || !correctedShape) {
|
193
|
+
return;
|
194
|
+
}
|
195
|
+
// Don't complete to empty shapes.
|
196
|
+
const bboxArea = correctedShape.getBBox().area;
|
197
|
+
if (bboxArea === 0 || !isFinite(bboxArea)) {
|
198
|
+
return;
|
199
|
+
}
|
200
|
+
this.autocorrectedShape = correctedShape;
|
201
|
+
this.lastAutocorrectedShape = correctedShape;
|
202
|
+
this.previewStroke();
|
142
203
|
}
|
143
204
|
finalizeStroke() {
|
144
205
|
if (this.builder) {
|
145
|
-
|
206
|
+
// If autocorrectedShape was cleared recently enough, it was
|
207
|
+
// probably by mistake. Reset it.
|
208
|
+
if (this.lastAutocorrectedShape && this.removedAutocorrectedShapeRecently()) {
|
209
|
+
this.autocorrectedShape = this.lastAutocorrectedShape;
|
210
|
+
}
|
211
|
+
const stroke = this.autocorrectedShape ?? this.builder.build();
|
146
212
|
this.previewStroke();
|
147
213
|
if (stroke.getBBox().area > 0) {
|
148
214
|
const canFlatten = true;
|
@@ -155,7 +221,11 @@ class Pen extends BaseTool_1.default {
|
|
155
221
|
}
|
156
222
|
this.builder = null;
|
157
223
|
this.lastPoint = null;
|
224
|
+
this.autocorrectedShape = null;
|
225
|
+
this.lastAutocorrectedShape = null;
|
158
226
|
this.editor.clearWetInk();
|
227
|
+
this.stationaryDetector?.destroy();
|
228
|
+
this.stationaryDetector = null;
|
159
229
|
}
|
160
230
|
noteUpdated() {
|
161
231
|
this.editor.notifier.dispatch(types_1.EditorEventType.ToolUpdated, {
|
@@ -201,6 +271,15 @@ class Pen extends BaseTool_1.default {
|
|
201
271
|
}
|
202
272
|
this.noteUpdated();
|
203
273
|
}
|
274
|
+
setStrokeAutocorrectEnabled(enabled) {
|
275
|
+
if (enabled !== this.shapeAutocompletionEnabled) {
|
276
|
+
this.shapeAutocompletionEnabled = enabled;
|
277
|
+
this.noteUpdated();
|
278
|
+
}
|
279
|
+
}
|
280
|
+
getStrokeAutocorrectionEnabled() {
|
281
|
+
return this.shapeAutocompletionEnabled;
|
282
|
+
}
|
204
283
|
getThickness() { return this.style.thickness; }
|
205
284
|
getColor() { return this.style.color; }
|
206
285
|
getStrokeFactory() { return this.style.factory; }
|
@@ -2,6 +2,7 @@
|
|
2
2
|
* @internal
|
3
3
|
* @packageDocumentation
|
4
4
|
*/
|
5
|
+
import SerializableCommand from '../../commands/SerializableCommand';
|
5
6
|
import Editor from '../../Editor';
|
6
7
|
import { Mat33, Rect2, Point2 } from '@js-draw/math';
|
7
8
|
import Pointer from '../../Pointer';
|
@@ -36,7 +37,10 @@ export default class Selection {
|
|
36
37
|
getScreenRegion(): Rect2;
|
37
38
|
get screenRegionRotation(): number;
|
38
39
|
setTransform(transform: Mat33, preview?: boolean): void;
|
40
|
+
private getDeltaZIndexToMoveSelectionToTop;
|
39
41
|
finalizeTransform(): void | Promise<void>;
|
42
|
+
/** Sends all selected elements to the bottom of the visible image. */
|
43
|
+
sendToBack(): SerializableCommand | null;
|
40
44
|
private static ApplyTransformationCommand;
|
41
45
|
private previewTransformCmds;
|
42
46
|
resolveToObjects(): boolean;
|
@@ -41,6 +41,7 @@ const Duplicate_1 = __importDefault(require("../../commands/Duplicate"));
|
|
41
41
|
const TransformMode_1 = require("./TransformMode");
|
42
42
|
const types_1 = require("./types");
|
43
43
|
const EditorImage_1 = __importDefault(require("../../image/EditorImage"));
|
44
|
+
const uniteCommands_1 = __importDefault(require("../../commands/uniteCommands"));
|
44
45
|
const updateChunkSize = 100;
|
45
46
|
const maxPreviewElemCount = 500;
|
46
47
|
// @internal
|
@@ -51,6 +52,7 @@ class Selection {
|
|
51
52
|
// @see getTightBoundingBox
|
52
53
|
this.selectionTightBoundingBox = null;
|
53
54
|
this.transform = math_1.Mat33.identity;
|
55
|
+
// invariant: sorted by increasing z-index
|
54
56
|
this.selectedElems = [];
|
55
57
|
this.hasParent = true;
|
56
58
|
// Maps IDs to whether we removed the component from the image
|
@@ -161,6 +163,16 @@ class Selection {
|
|
161
163
|
this.previewTransformCmds();
|
162
164
|
}
|
163
165
|
}
|
166
|
+
getDeltaZIndexToMoveSelectionToTop() {
|
167
|
+
if (this.selectedElems.length === 0) {
|
168
|
+
return 0;
|
169
|
+
}
|
170
|
+
const selectedBottommostZIndex = this.selectedElems[0].getZIndex();
|
171
|
+
const visibleObjects = this.editor.image.getElementsIntersectingRegion(this.region);
|
172
|
+
const topMostVisibleZIndex = visibleObjects[visibleObjects.length - 1]?.getZIndex() ?? selectedBottommostZIndex;
|
173
|
+
const deltaZIndex = (topMostVisibleZIndex + 1) - selectedBottommostZIndex;
|
174
|
+
return deltaZIndex;
|
175
|
+
}
|
164
176
|
// Applies the current transformation to the selection
|
165
177
|
finalizeTransform() {
|
166
178
|
const fullTransform = this.transform;
|
@@ -169,17 +181,35 @@ class Selection {
|
|
169
181
|
this.originalRegion = this.originalRegion.transformedBoundingBox(this.transform);
|
170
182
|
this.transform = math_1.Mat33.identity;
|
171
183
|
this.scrollTo();
|
184
|
+
let transformPromise = undefined;
|
172
185
|
// Make the commands undo-able.
|
173
186
|
// Don't check for non-empty transforms because this breaks changing the
|
174
187
|
// z-index of the just-transformed commands.
|
175
|
-
|
176
|
-
|
177
|
-
|
188
|
+
if (this.selectedElems.length > 0) {
|
189
|
+
const deltaZIndex = this.getDeltaZIndexToMoveSelectionToTop();
|
190
|
+
transformPromise = this.editor.dispatch(new _a.ApplyTransformationCommand(this, selectedElems, fullTransform, deltaZIndex));
|
191
|
+
}
|
178
192
|
// Clear renderings of any in-progress transformations
|
179
193
|
const wetInkRenderer = this.editor.display.getWetInkRenderer();
|
180
194
|
wetInkRenderer.clear();
|
181
195
|
return transformPromise;
|
182
196
|
}
|
197
|
+
/** Sends all selected elements to the bottom of the visible image. */
|
198
|
+
sendToBack() {
|
199
|
+
const visibleObjects = this.editor.image.getElementsIntersectingRegion(this.editor.viewport.visibleRect);
|
200
|
+
// VisibleObjects and selectedElems should both be sorted by z-index
|
201
|
+
const lowestVisibleZIndex = visibleObjects[0]?.getZIndex() ?? 0;
|
202
|
+
const highestSelectedZIndex = this.selectedElems[this.selectedElems.length - 1]?.getZIndex() ?? 0;
|
203
|
+
const targetHighestZIndex = lowestVisibleZIndex - 1;
|
204
|
+
const deltaZIndex = targetHighestZIndex - highestSelectedZIndex;
|
205
|
+
if (deltaZIndex !== 0) {
|
206
|
+
const commands = this.selectedElems.map(elem => {
|
207
|
+
return elem.setZIndex(elem.getZIndex() + deltaZIndex);
|
208
|
+
});
|
209
|
+
return (0, uniteCommands_1.default)(commands, updateChunkSize);
|
210
|
+
}
|
211
|
+
return null;
|
212
|
+
}
|
183
213
|
// Preview the effects of the current transformation on the selection
|
184
214
|
previewTransformCmds() {
|
185
215
|
if (this.selectedElems.length === 0) {
|
@@ -193,7 +223,7 @@ class Selection {
|
|
193
223
|
const wetInkRenderer = this.editor.display.getWetInkRenderer();
|
194
224
|
wetInkRenderer.clear();
|
195
225
|
wetInkRenderer.pushTransform(this.transform);
|
196
|
-
const viewportVisibleRect = this.editor.viewport.visibleRect;
|
226
|
+
const viewportVisibleRect = this.editor.viewport.visibleRect.union(this.region);
|
197
227
|
const visibleRect = viewportVisibleRect.transformedBoundingBox(this.transform.inverse());
|
198
228
|
for (const elem of this.selectedElems) {
|
199
229
|
elem.render(wetInkRenderer, visibleRect);
|
@@ -439,7 +469,8 @@ class Selection {
|
|
439
469
|
if (wasTransforming) {
|
440
470
|
// Don't update the selection's focus when redoing/undoing
|
441
471
|
const selectionToUpdate = null;
|
442
|
-
|
472
|
+
const deltaZIndex = this.getDeltaZIndexToMoveSelectionToTop();
|
473
|
+
tmpApplyCommand = new _a.ApplyTransformationCommand(selectionToUpdate, this.selectedElems, this.transform, deltaZIndex);
|
443
474
|
// Transform to ensure that the duplicates are in the correct location
|
444
475
|
await tmpApplyCommand.apply(this.editor);
|
445
476
|
// Show items again
|
@@ -480,6 +511,8 @@ class Selection {
|
|
480
511
|
this.originalRegion = bbox;
|
481
512
|
this.selectionTightBoundingBox = bbox;
|
482
513
|
this.selectedElems = objects.filter(object => object.isSelectable());
|
514
|
+
// Enforce increasing z-index invariant
|
515
|
+
this.selectedElems.sort((a, b) => a.getZIndex() - b.getZIndex());
|
483
516
|
this.padRegion();
|
484
517
|
this.updateUI();
|
485
518
|
}
|
@@ -493,7 +526,8 @@ _a = Selection;
|
|
493
526
|
// The selection box is lost when serializing/deserializing. No need to store box rotation
|
494
527
|
const fullTransform = new math_1.Mat33(...json.transform);
|
495
528
|
const elemIds = (json.elems ?? []);
|
496
|
-
|
529
|
+
const deltaZIndex = parseInt(json.deltaZIndex ?? 0);
|
530
|
+
return new _a.ApplyTransformationCommand(null, elemIds, fullTransform, deltaZIndex);
|
497
531
|
});
|
498
532
|
})();
|
499
533
|
Selection.ApplyTransformationCommand = class extends SerializableCommand_1.default {
|
@@ -501,10 +535,11 @@ Selection.ApplyTransformationCommand = class extends SerializableCommand_1.defau
|
|
501
535
|
// If a `string[]`, selectedElems is a list of element IDs.
|
502
536
|
selectedElems,
|
503
537
|
// Full transformation used to transform elements.
|
504
|
-
fullTransform) {
|
538
|
+
fullTransform, deltaZIndex) {
|
505
539
|
super('selection-tool-transform');
|
506
540
|
this.selection = selection;
|
507
541
|
this.fullTransform = fullTransform;
|
542
|
+
this.deltaZIndex = deltaZIndex;
|
508
543
|
const isIDList = (arr) => {
|
509
544
|
return typeof arr[0] === 'string';
|
510
545
|
};
|
@@ -515,11 +550,11 @@ Selection.ApplyTransformationCommand = class extends SerializableCommand_1.defau
|
|
515
550
|
else {
|
516
551
|
this.selectedElemIds = selectedElems.map(elem => elem.getId());
|
517
552
|
this.transformCommands = selectedElems.map(elem => {
|
518
|
-
return elem.
|
553
|
+
return elem.setZIndexAndTransformBy(this.fullTransform, elem.getZIndex() + deltaZIndex);
|
519
554
|
});
|
520
555
|
}
|
521
556
|
}
|
522
|
-
resolveToElems(editor) {
|
557
|
+
resolveToElems(editor, isUndoing) {
|
523
558
|
if (this.transformCommands) {
|
524
559
|
return;
|
525
560
|
}
|
@@ -528,11 +563,19 @@ Selection.ApplyTransformationCommand = class extends SerializableCommand_1.defau
|
|
528
563
|
if (!elem) {
|
529
564
|
throw new Error(`Unable to find element with ID, ${id}.`);
|
530
565
|
}
|
531
|
-
|
566
|
+
let originalZIndex = elem.getZIndex();
|
567
|
+
let targetZIndex = elem.getZIndex() + this.deltaZIndex;
|
568
|
+
// If the command has already been applied, the element should currently
|
569
|
+
// have the target z-index.
|
570
|
+
if (isUndoing) {
|
571
|
+
targetZIndex = elem.getZIndex();
|
572
|
+
originalZIndex = elem.getZIndex() - this.deltaZIndex;
|
573
|
+
}
|
574
|
+
return elem.setZIndexAndTransformBy(this.fullTransform, targetZIndex, originalZIndex);
|
532
575
|
});
|
533
576
|
}
|
534
577
|
async apply(editor) {
|
535
|
-
this.resolveToElems(editor);
|
578
|
+
this.resolveToElems(editor, false);
|
536
579
|
this.selection?.setTransform(this.fullTransform, false);
|
537
580
|
this.selection?.updateUI();
|
538
581
|
await editor.asyncApplyCommands(this.transformCommands, updateChunkSize);
|
@@ -541,7 +584,7 @@ Selection.ApplyTransformationCommand = class extends SerializableCommand_1.defau
|
|
541
584
|
this.selection?.updateUI();
|
542
585
|
}
|
543
586
|
async unapply(editor) {
|
544
|
-
this.resolveToElems(editor);
|
587
|
+
this.resolveToElems(editor, true);
|
545
588
|
this.selection?.setTransform(this.fullTransform.inverse(), false);
|
546
589
|
this.selection?.updateUI();
|
547
590
|
await editor.asyncUnapplyCommands(this.transformCommands, updateChunkSize, true);
|
@@ -553,6 +596,7 @@ Selection.ApplyTransformationCommand = class extends SerializableCommand_1.defau
|
|
553
596
|
return {
|
554
597
|
elems: this.selectedElemIds,
|
555
598
|
transform: this.fullTransform.toArray(),
|
599
|
+
deltaZIndex: this.deltaZIndex,
|
556
600
|
};
|
557
601
|
}
|
558
602
|
description(_editor, localizationTable) {
|
@@ -28,6 +28,7 @@ export default class SelectionTool extends BaseTool {
|
|
28
28
|
private onSelectionUpdated;
|
29
29
|
private zoomToSelection;
|
30
30
|
private static handleableKeys;
|
31
|
+
private hasUnfinalizedTransformFromKeyPress;
|
31
32
|
onKeyPress(event: KeyPressEvent): boolean;
|
32
33
|
onKeyUp(evt: KeyUpEvent): boolean;
|
33
34
|
onCopy(event: CopyEvent): boolean;
|
@@ -27,6 +27,9 @@ class SelectionTool extends BaseTool_1.default {
|
|
27
27
|
this.lastPointer = null;
|
28
28
|
this.selectionBoxHandlingEvt = false;
|
29
29
|
this.lastSelectedObjects = [];
|
30
|
+
// Whether the last keypress corresponded to an action that didn't transform the
|
31
|
+
// selection (and thus does not need to be finalized on onKeyUp).
|
32
|
+
this.hasUnfinalizedTransformFromKeyPress = false;
|
30
33
|
this.autoscroller = new ToPointerAutoscroller_1.default(editor.viewport, (scrollBy) => {
|
31
34
|
editor.dispatch(Viewport_1.default.transformBy(math_1.Mat33.translation(scrollBy)), false);
|
32
35
|
// Update the selection box/content to match the new viewport.
|
@@ -219,7 +222,8 @@ class SelectionTool extends BaseTool_1.default {
|
|
219
222
|
this.snapToGrid = true;
|
220
223
|
return true;
|
221
224
|
}
|
222
|
-
if (this.selectionBox && shortcucts.matchesShortcut(keybindings_1.duplicateSelectionShortcut, event)
|
225
|
+
if (this.selectionBox && (shortcucts.matchesShortcut(keybindings_1.duplicateSelectionShortcut, event)
|
226
|
+
|| shortcucts.matchesShortcut(keybindings_1.sendToBackSelectionShortcut, event))) {
|
223
227
|
// Handle duplication on key up — we don't want to accidentally duplicate
|
224
228
|
// many times.
|
225
229
|
return true;
|
@@ -303,6 +307,8 @@ class SelectionTool extends BaseTool_1.default {
|
|
303
307
|
const oldTransform = this.selectionBox.getTransform();
|
304
308
|
this.selectionBox.setTransform(oldTransform.rightMul(transform));
|
305
309
|
this.selectionBox.scrollTo();
|
310
|
+
// The transformation needs to be finalized at some point (on key up)
|
311
|
+
this.hasUnfinalizedTransformFromKeyPress = true;
|
306
312
|
}
|
307
313
|
if (this.selectionBox && !handled && (event.key === 'Delete' || event.key === 'Backspace')) {
|
308
314
|
this.editor.dispatch(this.selectionBox.deleteSelectedObjects());
|
@@ -328,12 +334,24 @@ class SelectionTool extends BaseTool_1.default {
|
|
328
334
|
});
|
329
335
|
return true;
|
330
336
|
}
|
337
|
+
if (this.selectionBox && shortcucts.matchesShortcut(keybindings_1.sendToBackSelectionShortcut, evt)) {
|
338
|
+
const sendToBackCommand = this.selectionBox.sendToBack();
|
339
|
+
if (sendToBackCommand) {
|
340
|
+
this.editor.dispatch(sendToBackCommand);
|
341
|
+
}
|
342
|
+
return true;
|
343
|
+
}
|
331
344
|
if (evt.key === 'Shift') {
|
332
345
|
this.shiftKeyPressed = false;
|
333
346
|
return true;
|
334
347
|
}
|
348
|
+
// If we don't need to finalize the transform
|
349
|
+
if (!this.hasUnfinalizedTransformFromKeyPress) {
|
350
|
+
return true;
|
351
|
+
}
|
335
352
|
if (this.selectionBox && SelectionTool.handleableKeys.some(key => key === evt.key)) {
|
336
353
|
this.selectionBox.finalizeTransform();
|
354
|
+
this.hasUnfinalizedTransformFromKeyPress = false;
|
337
355
|
return true;
|
338
356
|
}
|
339
357
|
return false;
|
@@ -44,6 +44,10 @@ class TextTool extends BaseTool_1.default {
|
|
44
44
|
.${overlayCSSClass} {
|
45
45
|
height: 0;
|
46
46
|
overflow: visible;
|
47
|
+
|
48
|
+
/* Allows absolutely-positioned textareas to scroll with
|
49
|
+
the containing overlay. */
|
50
|
+
position: relative;
|
47
51
|
}
|
48
52
|
|
49
53
|
.${overlayCSSClass} textarea {
|
@@ -126,7 +130,7 @@ class TextTool extends BaseTool_1.default {
|
|
126
130
|
this.textInputElem.style.fontWeight = this.textStyle.fontWeight ?? '';
|
127
131
|
this.textInputElem.style.fontSize = `${this.textStyle.size}px`;
|
128
132
|
this.textInputElem.style.color = this.textStyle.renderingStyle.fill.toHexString();
|
129
|
-
this.textInputElem.style.position = '
|
133
|
+
this.textInputElem.style.position = 'absolute';
|
130
134
|
this.textInputElem.style.left = `${textScreenPos.x}px`;
|
131
135
|
this.textInputElem.style.top = `${textScreenPos.y}px`;
|
132
136
|
this.textInputElem.style.margin = '0';
|
@@ -10,7 +10,6 @@ const BaseTool_1 = __importDefault(require("./BaseTool"));
|
|
10
10
|
*
|
11
11
|
* This is in the default set of {@link ToolController} tools.
|
12
12
|
*
|
13
|
-
* @deprecated This may be replaced in the future.
|
14
13
|
*/
|
15
14
|
class ToolSwitcherShortcut extends BaseTool_1.default {
|
16
15
|
constructor(editor) {
|
@@ -15,3 +15,4 @@ export declare const zoomInKeyboardShortcutId = "jsdraw.tools.PanZoom.zoomIn";
|
|
15
15
|
export declare const zoomOutKeyboardShortcutId = "jsdraw.tools.PanZoom.zoomOut";
|
16
16
|
export declare const selectAllKeyboardShortcut = "jsdraw.tools.SelectionTool.selectAll";
|
17
17
|
export declare const duplicateSelectionShortcut = "jsdraw.tools.SelectionTool.duplicateSelection";
|
18
|
+
export declare const sendToBackSelectionShortcut = "jsdraw.tools.SelectionTool.sendToBack";
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
4
|
};
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
-
exports.duplicateSelectionShortcut = exports.selectAllKeyboardShortcut = exports.zoomOutKeyboardShortcutId = exports.zoomInKeyboardShortcutId = exports.rotateCounterClockwiseKeyboardShortcutId = exports.rotateClockwiseKeyboardShortcutId = exports.moveDownKeyboardShortcutId = exports.moveUpKeyboardShortcutId = exports.moveRightKeyboardShortcutId = exports.moveLeftKeyboardShortcutId = exports.toggleFindVisibleShortcutId = exports.lineLockKeyboardShortcutId = exports.snapToGridKeyboardShortcutId = exports.decreaseSizeKeyboardShortcutId = exports.increaseSizeKeyboardShortcutId = exports.redoKeyboardShortcutId = exports.undoKeyboardShortcutId = void 0;
|
6
|
+
exports.sendToBackSelectionShortcut = exports.duplicateSelectionShortcut = exports.selectAllKeyboardShortcut = exports.zoomOutKeyboardShortcutId = exports.zoomInKeyboardShortcutId = exports.rotateCounterClockwiseKeyboardShortcutId = exports.rotateClockwiseKeyboardShortcutId = exports.moveDownKeyboardShortcutId = exports.moveUpKeyboardShortcutId = exports.moveRightKeyboardShortcutId = exports.moveLeftKeyboardShortcutId = exports.toggleFindVisibleShortcutId = exports.lineLockKeyboardShortcutId = exports.snapToGridKeyboardShortcutId = exports.decreaseSizeKeyboardShortcutId = exports.increaseSizeKeyboardShortcutId = exports.redoKeyboardShortcutId = exports.undoKeyboardShortcutId = void 0;
|
7
7
|
const KeyboardShortcutManager_1 = __importDefault(require("../shortcuts/KeyboardShortcutManager"));
|
8
8
|
// This file contains user-overridable tool-realted keybindings.
|
9
9
|
// Undo/redo
|
@@ -45,3 +45,5 @@ exports.selectAllKeyboardShortcut = 'jsdraw.tools.SelectionTool.selectAll';
|
|
45
45
|
KeyboardShortcutManager_1.default.registerDefaultKeyboardShortcut(exports.selectAllKeyboardShortcut, ['CtrlOrMeta+KeyA'], 'Select all');
|
46
46
|
exports.duplicateSelectionShortcut = 'jsdraw.tools.SelectionTool.duplicateSelection';
|
47
47
|
KeyboardShortcutManager_1.default.registerDefaultKeyboardShortcut(exports.duplicateSelectionShortcut, ['CtrlOrMeta+KeyD'], 'Duplicate selection');
|
48
|
+
exports.sendToBackSelectionShortcut = 'jsdraw.tools.SelectionTool.sendToBack';
|
49
|
+
KeyboardShortcutManager_1.default.registerDefaultKeyboardShortcut(exports.sendToBackSelectionShortcut, ['End'], 'Send to back');
|