js-draw 1.10.0 → 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/bundle.js +2 -2
- package/dist/cjs/commands/invertCommand.js +5 -0
- package/dist/cjs/components/AbstractComponent.d.ts +8 -0
- package/dist/cjs/components/AbstractComponent.js +28 -8
- package/dist/cjs/components/builders/types.d.ts +11 -0
- package/dist/cjs/toolbar/AbstractToolbar.d.ts +18 -2
- package/dist/cjs/toolbar/AbstractToolbar.js +46 -30
- 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.js +1 -1
- 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.js +5 -0
- 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/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/version.js +1 -1
- package/dist/mjs/commands/invertCommand.mjs +5 -0
- package/dist/mjs/components/AbstractComponent.d.ts +8 -0
- package/dist/mjs/components/AbstractComponent.mjs +28 -8
- package/dist/mjs/components/builders/types.d.ts +11 -0
- package/dist/mjs/toolbar/AbstractToolbar.d.ts +18 -2
- package/dist/mjs/toolbar/AbstractToolbar.mjs +46 -30
- 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.mjs +1 -1
- 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.mjs +5 -0
- 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/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/version.mjs +1 -1
- package/package.json +2 -2
@@ -96,34 +96,45 @@ class HandModeWidget extends BaseWidget {
|
|
96
96
|
}
|
97
97
|
export default class HandToolWidget extends BaseToolWidget {
|
98
98
|
constructor(editor,
|
99
|
-
//
|
100
|
-
//
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
99
|
+
// Can either be the primary pan/zoom tool (in the primary tools list) or
|
100
|
+
// the override pan/zoom tool.
|
101
|
+
// If the override pan/zoom tool, the primary will be gotten from the editor's
|
102
|
+
// tool controller.
|
103
|
+
// If the primary, the override will be gotten from the editor's tool controller.
|
104
|
+
tool, localizationTable) {
|
105
|
+
const isGivenToolPrimary = editor.toolController.getPrimaryTools().includes(tool);
|
106
|
+
const primaryTool = (isGivenToolPrimary ? tool : HandToolWidget.getPrimaryHandTool(editor.toolController))
|
107
|
+
?? tool;
|
108
|
+
super(editor, primaryTool, 'hand-tool-widget', localizationTable);
|
109
|
+
this.overridePanZoomTool =
|
110
|
+
(isGivenToolPrimary ? HandToolWidget.getOverrideHandTool(editor.toolController) : tool)
|
111
|
+
?? tool;
|
106
112
|
// Only allow toggling a hand tool if we're using the primary hand tool and not the override
|
107
113
|
// hand tool for this button.
|
108
|
-
this.allowTogglingBaseTool =
|
114
|
+
this.allowTogglingBaseTool = primaryTool !== null;
|
109
115
|
// Allow showing/hiding the dropdown, even if `overridePanZoomTool` isn't enabled.
|
110
116
|
if (!this.allowTogglingBaseTool) {
|
111
117
|
this.container.classList.add('dropdownShowable');
|
112
118
|
}
|
113
119
|
// Controls for the overriding hand tool.
|
114
|
-
const touchPanningWidget = new HandModeWidget(editor, overridePanZoomTool, PanZoomMode.OneFingerTouchGestures, () => this.editor.icons.makeTouchPanningIcon(), localizationTable.touchPanning, localizationTable);
|
115
|
-
const rotationLockWidget = new HandModeWidget(editor, overridePanZoomTool, PanZoomMode.RotationLocked, () => this.editor.icons.makeRotationLockIcon(), localizationTable.lockRotation, localizationTable);
|
120
|
+
const touchPanningWidget = new HandModeWidget(editor, this.overridePanZoomTool, PanZoomMode.OneFingerTouchGestures, () => this.editor.icons.makeTouchPanningIcon(), localizationTable.touchPanning, localizationTable);
|
121
|
+
const rotationLockWidget = new HandModeWidget(editor, this.overridePanZoomTool, PanZoomMode.RotationLocked, () => this.editor.icons.makeRotationLockIcon(), localizationTable.lockRotation, localizationTable);
|
116
122
|
this.addSubWidget(touchPanningWidget);
|
117
123
|
this.addSubWidget(rotationLockWidget);
|
118
124
|
}
|
119
|
-
shouldAutoDisableInReadOnlyEditor() {
|
120
|
-
return false;
|
121
|
-
}
|
122
125
|
static getPrimaryHandTool(toolController) {
|
123
126
|
const primaryPanZoomToolList = toolController.getPrimaryTools().filter(tool => tool instanceof PanZoom);
|
124
127
|
const primaryPanZoomTool = primaryPanZoomToolList[0];
|
125
128
|
return primaryPanZoomTool;
|
126
129
|
}
|
130
|
+
static getOverrideHandTool(toolController) {
|
131
|
+
const panZoomToolList = toolController.getMatchingTools(PanZoom);
|
132
|
+
const panZoomTool = panZoomToolList[0];
|
133
|
+
return panZoomTool;
|
134
|
+
}
|
135
|
+
shouldAutoDisableInReadOnlyEditor() {
|
136
|
+
return false;
|
137
|
+
}
|
127
138
|
getTitle() {
|
128
139
|
return this.localizationTable.handTool;
|
129
140
|
}
|
@@ -169,7 +169,7 @@ class InsertImageWidget extends BaseWidget {
|
|
169
169
|
this.image?.reset();
|
170
170
|
};
|
171
171
|
this.statusView.replaceChildren(sizeText);
|
172
|
-
const largeImageThreshold = 0.
|
172
|
+
const largeImageThreshold = 0.12; // MiB
|
173
173
|
if (sizeInMiB > largeImageThreshold) {
|
174
174
|
this.statusView.appendChild(decreaseSizeButton);
|
175
175
|
}
|
@@ -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";
|
@@ -11,3 +11,6 @@ for (let i = 0; i < selectStrokeTypeKeyboardShortcutIds.length; i++) {
|
|
11
11
|
// Save
|
12
12
|
export const saveKeyboardShortcut = 'jsdraw.toolbar.SaveActionWidget.save';
|
13
13
|
KeyboardShortcutManager.registerDefaultKeyboardShortcut(saveKeyboardShortcut, ['ctrlOrMeta+KeyS'], 'Save');
|
14
|
+
// Exit
|
15
|
+
export const exitKeyboardShortcut = 'jsdraw.toolbar.ExitActionWidget.exit';
|
16
|
+
KeyboardShortcutManager.registerDefaultKeyboardShortcut(exitKeyboardShortcut, ['Alt+KeyQ'], 'Exit');
|
package/dist/mjs/tools/Pen.mjs
CHANGED
@@ -187,6 +187,11 @@ export default class Pen extends BaseTool {
|
|
187
187
|
if (!this.builder || !correctedShape) {
|
188
188
|
return;
|
189
189
|
}
|
190
|
+
// Don't complete to empty shapes.
|
191
|
+
const bboxArea = correctedShape.getBBox().area;
|
192
|
+
if (bboxArea === 0 || !isFinite(bboxArea)) {
|
193
|
+
return;
|
194
|
+
}
|
190
195
|
this.autocorrectedShape = correctedShape;
|
191
196
|
this.lastAutocorrectedShape = correctedShape;
|
192
197
|
this.previewStroke();
|
@@ -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;
|
@@ -13,6 +13,7 @@ import Duplicate from '../../commands/Duplicate.mjs';
|
|
13
13
|
import { DragTransformer, ResizeTransformer, RotateTransformer } from './TransformMode.mjs';
|
14
14
|
import { ResizeMode } from './types.mjs';
|
15
15
|
import EditorImage from '../../image/EditorImage.mjs';
|
16
|
+
import uniteCommands from '../../commands/uniteCommands.mjs';
|
16
17
|
const updateChunkSize = 100;
|
17
18
|
const maxPreviewElemCount = 500;
|
18
19
|
// @internal
|
@@ -23,6 +24,7 @@ class Selection {
|
|
23
24
|
// @see getTightBoundingBox
|
24
25
|
this.selectionTightBoundingBox = null;
|
25
26
|
this.transform = Mat33.identity;
|
27
|
+
// invariant: sorted by increasing z-index
|
26
28
|
this.selectedElems = [];
|
27
29
|
this.hasParent = true;
|
28
30
|
// Maps IDs to whether we removed the component from the image
|
@@ -133,6 +135,16 @@ class Selection {
|
|
133
135
|
this.previewTransformCmds();
|
134
136
|
}
|
135
137
|
}
|
138
|
+
getDeltaZIndexToMoveSelectionToTop() {
|
139
|
+
if (this.selectedElems.length === 0) {
|
140
|
+
return 0;
|
141
|
+
}
|
142
|
+
const selectedBottommostZIndex = this.selectedElems[0].getZIndex();
|
143
|
+
const visibleObjects = this.editor.image.getElementsIntersectingRegion(this.region);
|
144
|
+
const topMostVisibleZIndex = visibleObjects[visibleObjects.length - 1]?.getZIndex() ?? selectedBottommostZIndex;
|
145
|
+
const deltaZIndex = (topMostVisibleZIndex + 1) - selectedBottommostZIndex;
|
146
|
+
return deltaZIndex;
|
147
|
+
}
|
136
148
|
// Applies the current transformation to the selection
|
137
149
|
finalizeTransform() {
|
138
150
|
const fullTransform = this.transform;
|
@@ -141,17 +153,35 @@ class Selection {
|
|
141
153
|
this.originalRegion = this.originalRegion.transformedBoundingBox(this.transform);
|
142
154
|
this.transform = Mat33.identity;
|
143
155
|
this.scrollTo();
|
156
|
+
let transformPromise = undefined;
|
144
157
|
// Make the commands undo-able.
|
145
158
|
// Don't check for non-empty transforms because this breaks changing the
|
146
159
|
// z-index of the just-transformed commands.
|
147
|
-
|
148
|
-
|
149
|
-
|
160
|
+
if (this.selectedElems.length > 0) {
|
161
|
+
const deltaZIndex = this.getDeltaZIndexToMoveSelectionToTop();
|
162
|
+
transformPromise = this.editor.dispatch(new _a.ApplyTransformationCommand(this, selectedElems, fullTransform, deltaZIndex));
|
163
|
+
}
|
150
164
|
// Clear renderings of any in-progress transformations
|
151
165
|
const wetInkRenderer = this.editor.display.getWetInkRenderer();
|
152
166
|
wetInkRenderer.clear();
|
153
167
|
return transformPromise;
|
154
168
|
}
|
169
|
+
/** Sends all selected elements to the bottom of the visible image. */
|
170
|
+
sendToBack() {
|
171
|
+
const visibleObjects = this.editor.image.getElementsIntersectingRegion(this.editor.viewport.visibleRect);
|
172
|
+
// VisibleObjects and selectedElems should both be sorted by z-index
|
173
|
+
const lowestVisibleZIndex = visibleObjects[0]?.getZIndex() ?? 0;
|
174
|
+
const highestSelectedZIndex = this.selectedElems[this.selectedElems.length - 1]?.getZIndex() ?? 0;
|
175
|
+
const targetHighestZIndex = lowestVisibleZIndex - 1;
|
176
|
+
const deltaZIndex = targetHighestZIndex - highestSelectedZIndex;
|
177
|
+
if (deltaZIndex !== 0) {
|
178
|
+
const commands = this.selectedElems.map(elem => {
|
179
|
+
return elem.setZIndex(elem.getZIndex() + deltaZIndex);
|
180
|
+
});
|
181
|
+
return uniteCommands(commands, updateChunkSize);
|
182
|
+
}
|
183
|
+
return null;
|
184
|
+
}
|
155
185
|
// Preview the effects of the current transformation on the selection
|
156
186
|
previewTransformCmds() {
|
157
187
|
if (this.selectedElems.length === 0) {
|
@@ -165,7 +195,7 @@ class Selection {
|
|
165
195
|
const wetInkRenderer = this.editor.display.getWetInkRenderer();
|
166
196
|
wetInkRenderer.clear();
|
167
197
|
wetInkRenderer.pushTransform(this.transform);
|
168
|
-
const viewportVisibleRect = this.editor.viewport.visibleRect;
|
198
|
+
const viewportVisibleRect = this.editor.viewport.visibleRect.union(this.region);
|
169
199
|
const visibleRect = viewportVisibleRect.transformedBoundingBox(this.transform.inverse());
|
170
200
|
for (const elem of this.selectedElems) {
|
171
201
|
elem.render(wetInkRenderer, visibleRect);
|
@@ -411,7 +441,8 @@ class Selection {
|
|
411
441
|
if (wasTransforming) {
|
412
442
|
// Don't update the selection's focus when redoing/undoing
|
413
443
|
const selectionToUpdate = null;
|
414
|
-
|
444
|
+
const deltaZIndex = this.getDeltaZIndexToMoveSelectionToTop();
|
445
|
+
tmpApplyCommand = new _a.ApplyTransformationCommand(selectionToUpdate, this.selectedElems, this.transform, deltaZIndex);
|
415
446
|
// Transform to ensure that the duplicates are in the correct location
|
416
447
|
await tmpApplyCommand.apply(this.editor);
|
417
448
|
// Show items again
|
@@ -452,6 +483,8 @@ class Selection {
|
|
452
483
|
this.originalRegion = bbox;
|
453
484
|
this.selectionTightBoundingBox = bbox;
|
454
485
|
this.selectedElems = objects.filter(object => object.isSelectable());
|
486
|
+
// Enforce increasing z-index invariant
|
487
|
+
this.selectedElems.sort((a, b) => a.getZIndex() - b.getZIndex());
|
455
488
|
this.padRegion();
|
456
489
|
this.updateUI();
|
457
490
|
}
|
@@ -465,7 +498,8 @@ _a = Selection;
|
|
465
498
|
// The selection box is lost when serializing/deserializing. No need to store box rotation
|
466
499
|
const fullTransform = new Mat33(...json.transform);
|
467
500
|
const elemIds = (json.elems ?? []);
|
468
|
-
|
501
|
+
const deltaZIndex = parseInt(json.deltaZIndex ?? 0);
|
502
|
+
return new _a.ApplyTransformationCommand(null, elemIds, fullTransform, deltaZIndex);
|
469
503
|
});
|
470
504
|
})();
|
471
505
|
Selection.ApplyTransformationCommand = class extends SerializableCommand {
|
@@ -473,10 +507,11 @@ Selection.ApplyTransformationCommand = class extends SerializableCommand {
|
|
473
507
|
// If a `string[]`, selectedElems is a list of element IDs.
|
474
508
|
selectedElems,
|
475
509
|
// Full transformation used to transform elements.
|
476
|
-
fullTransform) {
|
510
|
+
fullTransform, deltaZIndex) {
|
477
511
|
super('selection-tool-transform');
|
478
512
|
this.selection = selection;
|
479
513
|
this.fullTransform = fullTransform;
|
514
|
+
this.deltaZIndex = deltaZIndex;
|
480
515
|
const isIDList = (arr) => {
|
481
516
|
return typeof arr[0] === 'string';
|
482
517
|
};
|
@@ -487,11 +522,11 @@ Selection.ApplyTransformationCommand = class extends SerializableCommand {
|
|
487
522
|
else {
|
488
523
|
this.selectedElemIds = selectedElems.map(elem => elem.getId());
|
489
524
|
this.transformCommands = selectedElems.map(elem => {
|
490
|
-
return elem.
|
525
|
+
return elem.setZIndexAndTransformBy(this.fullTransform, elem.getZIndex() + deltaZIndex);
|
491
526
|
});
|
492
527
|
}
|
493
528
|
}
|
494
|
-
resolveToElems(editor) {
|
529
|
+
resolveToElems(editor, isUndoing) {
|
495
530
|
if (this.transformCommands) {
|
496
531
|
return;
|
497
532
|
}
|
@@ -500,11 +535,19 @@ Selection.ApplyTransformationCommand = class extends SerializableCommand {
|
|
500
535
|
if (!elem) {
|
501
536
|
throw new Error(`Unable to find element with ID, ${id}.`);
|
502
537
|
}
|
503
|
-
|
538
|
+
let originalZIndex = elem.getZIndex();
|
539
|
+
let targetZIndex = elem.getZIndex() + this.deltaZIndex;
|
540
|
+
// If the command has already been applied, the element should currently
|
541
|
+
// have the target z-index.
|
542
|
+
if (isUndoing) {
|
543
|
+
targetZIndex = elem.getZIndex();
|
544
|
+
originalZIndex = elem.getZIndex() - this.deltaZIndex;
|
545
|
+
}
|
546
|
+
return elem.setZIndexAndTransformBy(this.fullTransform, targetZIndex, originalZIndex);
|
504
547
|
});
|
505
548
|
}
|
506
549
|
async apply(editor) {
|
507
|
-
this.resolveToElems(editor);
|
550
|
+
this.resolveToElems(editor, false);
|
508
551
|
this.selection?.setTransform(this.fullTransform, false);
|
509
552
|
this.selection?.updateUI();
|
510
553
|
await editor.asyncApplyCommands(this.transformCommands, updateChunkSize);
|
@@ -513,7 +556,7 @@ Selection.ApplyTransformationCommand = class extends SerializableCommand {
|
|
513
556
|
this.selection?.updateUI();
|
514
557
|
}
|
515
558
|
async unapply(editor) {
|
516
|
-
this.resolveToElems(editor);
|
559
|
+
this.resolveToElems(editor, true);
|
517
560
|
this.selection?.setTransform(this.fullTransform.inverse(), false);
|
518
561
|
this.selection?.updateUI();
|
519
562
|
await editor.asyncUnapplyCommands(this.transformCommands, updateChunkSize, true);
|
@@ -525,6 +568,7 @@ Selection.ApplyTransformationCommand = class extends SerializableCommand {
|
|
525
568
|
return {
|
526
569
|
elems: this.selectedElemIds,
|
527
570
|
transform: this.fullTransform.toArray(),
|
571
|
+
deltaZIndex: this.deltaZIndex,
|
528
572
|
};
|
529
573
|
}
|
530
574
|
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;
|
@@ -5,7 +5,7 @@ import BaseTool from '../BaseTool.mjs';
|
|
5
5
|
import SVGRenderer from '../../rendering/renderers/SVGRenderer.mjs';
|
6
6
|
import Selection from './Selection.mjs';
|
7
7
|
import TextComponent from '../../components/TextComponent.mjs';
|
8
|
-
import { duplicateSelectionShortcut, selectAllKeyboardShortcut, snapToGridKeyboardShortcutId } from '../keybindings.mjs';
|
8
|
+
import { duplicateSelectionShortcut, selectAllKeyboardShortcut, sendToBackSelectionShortcut, snapToGridKeyboardShortcutId } from '../keybindings.mjs';
|
9
9
|
import ToPointerAutoscroller from './ToPointerAutoscroller.mjs';
|
10
10
|
export const cssPrefix = 'selection-tool-';
|
11
11
|
// Allows users to select/transform portions of the `EditorImage`.
|
@@ -21,6 +21,9 @@ class SelectionTool extends BaseTool {
|
|
21
21
|
this.lastPointer = null;
|
22
22
|
this.selectionBoxHandlingEvt = false;
|
23
23
|
this.lastSelectedObjects = [];
|
24
|
+
// Whether the last keypress corresponded to an action that didn't transform the
|
25
|
+
// selection (and thus does not need to be finalized on onKeyUp).
|
26
|
+
this.hasUnfinalizedTransformFromKeyPress = false;
|
24
27
|
this.autoscroller = new ToPointerAutoscroller(editor.viewport, (scrollBy) => {
|
25
28
|
editor.dispatch(Viewport.transformBy(Mat33.translation(scrollBy)), false);
|
26
29
|
// Update the selection box/content to match the new viewport.
|
@@ -213,7 +216,8 @@ class SelectionTool extends BaseTool {
|
|
213
216
|
this.snapToGrid = true;
|
214
217
|
return true;
|
215
218
|
}
|
216
|
-
if (this.selectionBox && shortcucts.matchesShortcut(duplicateSelectionShortcut, event)
|
219
|
+
if (this.selectionBox && (shortcucts.matchesShortcut(duplicateSelectionShortcut, event)
|
220
|
+
|| shortcucts.matchesShortcut(sendToBackSelectionShortcut, event))) {
|
217
221
|
// Handle duplication on key up — we don't want to accidentally duplicate
|
218
222
|
// many times.
|
219
223
|
return true;
|
@@ -297,6 +301,8 @@ class SelectionTool extends BaseTool {
|
|
297
301
|
const oldTransform = this.selectionBox.getTransform();
|
298
302
|
this.selectionBox.setTransform(oldTransform.rightMul(transform));
|
299
303
|
this.selectionBox.scrollTo();
|
304
|
+
// The transformation needs to be finalized at some point (on key up)
|
305
|
+
this.hasUnfinalizedTransformFromKeyPress = true;
|
300
306
|
}
|
301
307
|
if (this.selectionBox && !handled && (event.key === 'Delete' || event.key === 'Backspace')) {
|
302
308
|
this.editor.dispatch(this.selectionBox.deleteSelectedObjects());
|
@@ -322,12 +328,24 @@ class SelectionTool extends BaseTool {
|
|
322
328
|
});
|
323
329
|
return true;
|
324
330
|
}
|
331
|
+
if (this.selectionBox && shortcucts.matchesShortcut(sendToBackSelectionShortcut, evt)) {
|
332
|
+
const sendToBackCommand = this.selectionBox.sendToBack();
|
333
|
+
if (sendToBackCommand) {
|
334
|
+
this.editor.dispatch(sendToBackCommand);
|
335
|
+
}
|
336
|
+
return true;
|
337
|
+
}
|
325
338
|
if (evt.key === 'Shift') {
|
326
339
|
this.shiftKeyPressed = false;
|
327
340
|
return true;
|
328
341
|
}
|
342
|
+
// If we don't need to finalize the transform
|
343
|
+
if (!this.hasUnfinalizedTransformFromKeyPress) {
|
344
|
+
return true;
|
345
|
+
}
|
329
346
|
if (this.selectionBox && SelectionTool.handleableKeys.some(key => key === evt.key)) {
|
330
347
|
this.selectionBox.finalizeTransform();
|
348
|
+
this.hasUnfinalizedTransformFromKeyPress = false;
|
331
349
|
return true;
|
332
350
|
}
|
333
351
|
return false;
|
@@ -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";
|
@@ -39,3 +39,5 @@ export const selectAllKeyboardShortcut = 'jsdraw.tools.SelectionTool.selectAll';
|
|
39
39
|
KeyboardShortcutManager.registerDefaultKeyboardShortcut(selectAllKeyboardShortcut, ['CtrlOrMeta+KeyA'], 'Select all');
|
40
40
|
export const duplicateSelectionShortcut = 'jsdraw.tools.SelectionTool.duplicateSelection';
|
41
41
|
KeyboardShortcutManager.registerDefaultKeyboardShortcut(duplicateSelectionShortcut, ['CtrlOrMeta+KeyD'], 'Duplicate selection');
|
42
|
+
export const sendToBackSelectionShortcut = 'jsdraw.tools.SelectionTool.sendToBack';
|
43
|
+
KeyboardShortcutManager.registerDefaultKeyboardShortcut(sendToBackSelectionShortcut, ['End'], 'Send to back');
|
package/dist/mjs/version.mjs
CHANGED
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "js-draw",
|
3
|
-
"version": "1.
|
3
|
+
"version": "1.11.0",
|
4
4
|
"description": "Draw pictures using a pen, touchscreen, or mouse! JS-draw is a drawing library for JavaScript and TypeScript. ",
|
5
5
|
"types": "./dist/mjs/lib.d.ts",
|
6
6
|
"main": "./dist/cjs/lib.js",
|
@@ -86,5 +86,5 @@
|
|
86
86
|
"freehand",
|
87
87
|
"svg"
|
88
88
|
],
|
89
|
-
"gitHead": "
|
89
|
+
"gitHead": "01fc3dc7bdbc9f456705bf08d9c30b4549122d97"
|
90
90
|
}
|