js-draw 1.26.0 → 1.27.1
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/Editor.css +1 -1
- package/dist/bundle.js +42 -37
- package/dist/bundledStyles.js +1 -1
- package/dist/cjs/Editor.d.ts +0 -2
- package/dist/cjs/components/AbstractComponent.d.ts +15 -0
- package/dist/cjs/components/AbstractComponent.js +16 -0
- package/dist/cjs/components/Stroke.d.ts +1 -0
- package/dist/cjs/components/Stroke.js +7 -0
- package/dist/cjs/toolbar/IconProvider.d.ts +2 -1
- package/dist/cjs/toolbar/IconProvider.js +18 -8
- package/dist/cjs/toolbar/localization.d.ts +2 -0
- package/dist/cjs/toolbar/localization.js +2 -0
- package/dist/cjs/toolbar/widgets/SelectionToolWidget.d.ts +7 -0
- package/dist/cjs/toolbar/widgets/SelectionToolWidget.js +109 -28
- package/dist/cjs/toolbar/widgets/components/makeButtonGrid.d.ts +17 -0
- package/dist/cjs/toolbar/widgets/components/makeButtonGrid.js +40 -0
- package/dist/cjs/tools/SelectionTool/Selection.d.ts +2 -3
- package/dist/cjs/tools/SelectionTool/Selection.js +19 -40
- package/dist/cjs/tools/SelectionTool/SelectionBuilders/LassoSelectionBuilder.d.ts +17 -0
- package/dist/cjs/tools/SelectionTool/SelectionBuilders/LassoSelectionBuilder.js +67 -0
- package/dist/cjs/tools/SelectionTool/SelectionBuilders/RectSelectionBuilder.d.ts +13 -0
- package/dist/cjs/tools/SelectionTool/SelectionBuilders/RectSelectionBuilder.js +33 -0
- package/dist/cjs/tools/SelectionTool/SelectionBuilders/SelectionBuilder.d.ts +15 -0
- package/dist/cjs/tools/SelectionTool/SelectionBuilders/SelectionBuilder.js +39 -0
- package/dist/cjs/tools/SelectionTool/SelectionTool.d.ts +10 -2
- package/dist/cjs/tools/SelectionTool/SelectionTool.js +68 -55
- package/dist/cjs/tools/SelectionTool/types.d.ts +4 -0
- package/dist/cjs/tools/SelectionTool/types.js +6 -1
- package/dist/cjs/tools/lib.d.ts +1 -1
- package/dist/cjs/tools/lib.js +2 -1
- package/dist/cjs/util/ReactiveValue.js +2 -6
- package/dist/cjs/version.js +1 -1
- package/dist/mjs/Editor.d.ts +0 -2
- package/dist/mjs/components/AbstractComponent.d.ts +15 -0
- package/dist/mjs/components/AbstractComponent.mjs +16 -0
- package/dist/mjs/components/Stroke.d.ts +1 -0
- package/dist/mjs/components/Stroke.mjs +7 -0
- package/dist/mjs/toolbar/IconProvider.d.ts +2 -1
- package/dist/mjs/toolbar/IconProvider.mjs +18 -8
- package/dist/mjs/toolbar/localization.d.ts +2 -0
- package/dist/mjs/toolbar/localization.mjs +2 -0
- package/dist/mjs/toolbar/widgets/SelectionToolWidget.d.ts +7 -0
- package/dist/mjs/toolbar/widgets/SelectionToolWidget.mjs +109 -28
- package/dist/mjs/toolbar/widgets/components/makeButtonGrid.d.ts +17 -0
- package/dist/mjs/toolbar/widgets/components/makeButtonGrid.mjs +35 -0
- package/dist/mjs/tools/SelectionTool/Selection.d.ts +2 -3
- package/dist/mjs/tools/SelectionTool/Selection.mjs +19 -40
- package/dist/mjs/tools/SelectionTool/SelectionBuilders/LassoSelectionBuilder.d.ts +17 -0
- package/dist/mjs/tools/SelectionTool/SelectionBuilders/LassoSelectionBuilder.mjs +61 -0
- package/dist/mjs/tools/SelectionTool/SelectionBuilders/RectSelectionBuilder.d.ts +13 -0
- package/dist/mjs/tools/SelectionTool/SelectionBuilders/RectSelectionBuilder.mjs +27 -0
- package/dist/mjs/tools/SelectionTool/SelectionBuilders/SelectionBuilder.d.ts +15 -0
- package/dist/mjs/tools/SelectionTool/SelectionBuilders/SelectionBuilder.mjs +36 -0
- package/dist/mjs/tools/SelectionTool/SelectionTool.d.ts +10 -2
- package/dist/mjs/tools/SelectionTool/SelectionTool.mjs +68 -55
- package/dist/mjs/tools/SelectionTool/types.d.ts +4 -0
- package/dist/mjs/tools/SelectionTool/types.mjs +5 -0
- package/dist/mjs/tools/lib.d.ts +1 -1
- package/dist/mjs/tools/lib.mjs +1 -1
- package/dist/mjs/util/ReactiveValue.mjs +2 -6
- package/dist/mjs/version.mjs +1 -1
- package/package.json +4 -4
- package/src/toolbar/EdgeToolbar.scss +6 -1
- package/src/toolbar/widgets/components/components.scss +1 -0
- package/src/toolbar/widgets/components/makeButtonGrid.scss +25 -0
- package/src/tools/SelectionTool/SelectionTool.scss +1 -0
- package/src/tools/util/createMenuOverlay.scss +3 -2
@@ -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.cssPrefix = void 0;
|
6
|
+
exports.SelectionMode = exports.cssPrefix = void 0;
|
7
7
|
const math_1 = require("@js-draw/math");
|
8
8
|
const types_1 = require("../../types");
|
9
9
|
const Viewport_1 = __importDefault(require("../../Viewport"));
|
@@ -15,6 +15,11 @@ const TextComponent_1 = __importDefault(require("../../components/TextComponent"
|
|
15
15
|
const keybindings_1 = require("../keybindings");
|
16
16
|
const ToPointerAutoscroller_1 = __importDefault(require("./ToPointerAutoscroller"));
|
17
17
|
const showSelectionContextMenu_1 = __importDefault(require("./util/showSelectionContextMenu"));
|
18
|
+
const ReactiveValue_1 = require("../../util/ReactiveValue");
|
19
|
+
const types_2 = require("./types");
|
20
|
+
Object.defineProperty(exports, "SelectionMode", { enumerable: true, get: function () { return types_2.SelectionMode; } });
|
21
|
+
const LassoSelectionBuilder_1 = __importDefault(require("./SelectionBuilders/LassoSelectionBuilder"));
|
22
|
+
const RectSelectionBuilder_1 = __importDefault(require("./SelectionBuilders/RectSelectionBuilder"));
|
18
23
|
exports.cssPrefix = 'selection-tool-';
|
19
24
|
// Allows users to select/transform portions of the `EditorImage`.
|
20
25
|
// With respect to `extend`ing, `SelectionTool` is not stable.
|
@@ -25,7 +30,7 @@ class SelectionTool extends BaseTool_1.default {
|
|
25
30
|
// True if clearing and recreating the selectionBox has been deferred. This is used to prevent the selection
|
26
31
|
// from vanishing on pointerdown events that are intended to form other gestures (e.g. long press) that would
|
27
32
|
// ultimately restore the selection.
|
28
|
-
this.
|
33
|
+
this.removeSelectionScheduled = false;
|
29
34
|
this.startPoint = null; // canvas position
|
30
35
|
this.expandingSelectionBox = false;
|
31
36
|
this.shiftKeyPressed = false;
|
@@ -39,6 +44,13 @@ class SelectionTool extends BaseTool_1.default {
|
|
39
44
|
// Whether the last keypress corresponded to an action that didn't transform the
|
40
45
|
// selection (and thus does not need to be finalized on onKeyUp).
|
41
46
|
this.hasUnfinalizedTransformFromKeyPress = false;
|
47
|
+
this.modeValue = ReactiveValue_1.MutableReactiveValue.fromInitialValue(types_2.SelectionMode.Rectangle);
|
48
|
+
this.modeValue.onUpdate(() => {
|
49
|
+
this.editor.notifier.dispatch(types_1.EditorEventType.ToolUpdated, {
|
50
|
+
kind: types_1.EditorEventType.ToolUpdated,
|
51
|
+
tool: this,
|
52
|
+
});
|
53
|
+
});
|
42
54
|
this.autoscroller = new ToPointerAutoscroller_1.default(editor.viewport, (scrollBy) => {
|
43
55
|
editor.dispatch(Viewport_1.default.transformBy(math_1.Mat33.translation(scrollBy)), false);
|
44
56
|
// Update the selection box/content to match the new viewport.
|
@@ -67,26 +79,19 @@ class SelectionTool extends BaseTool_1.default {
|
|
67
79
|
this.editor.handleKeyEventsFrom(this.handleOverlay);
|
68
80
|
this.editor.handlePointerEventsFrom(this.handleOverlay);
|
69
81
|
}
|
70
|
-
|
82
|
+
getSelectionColor() {
|
83
|
+
const colorString = getComputedStyle(this.handleOverlay).getPropertyValue('--selection-background-color');
|
84
|
+
return math_1.Color4.fromString(colorString).withAlpha(0.5);
|
85
|
+
}
|
86
|
+
makeSelectionBox(selectedObjects) {
|
71
87
|
this.prevSelectionBox = this.selectionBox;
|
72
|
-
this.selectionBox = new Selection_1.default(
|
88
|
+
this.selectionBox = new Selection_1.default(selectedObjects, this.editor, this.showContextMenu);
|
73
89
|
if (!this.expandingSelectionBox) {
|
74
90
|
// Remove any previous selection rects
|
75
91
|
this.prevSelectionBox?.cancelSelection();
|
76
92
|
}
|
77
93
|
this.selectionBox.addTo(this.handleOverlay);
|
78
94
|
}
|
79
|
-
snapSelectionToGrid() {
|
80
|
-
if (!this.selectionBox)
|
81
|
-
throw new Error('No selection to snap!');
|
82
|
-
// Snap the top left corner of what we have selected.
|
83
|
-
const topLeftOfBBox = this.selectionBox.computeTightBoundingBox().topLeft;
|
84
|
-
const snappedTopLeft = this.editor.viewport.snapToGrid(topLeftOfBBox);
|
85
|
-
const snapDelta = snappedTopLeft.minus(topLeftOfBBox);
|
86
|
-
const oldTransform = this.selectionBox.getTransform();
|
87
|
-
this.selectionBox.setTransform(oldTransform.rightMul(math_1.Mat33.translation(snapDelta)));
|
88
|
-
this.selectionBox.finalizeTransform();
|
89
|
-
}
|
90
95
|
onContextMenu(event) {
|
91
96
|
const canShowSelectionMenu = this.selectionBox
|
92
97
|
?.getScreenRegion()
|
@@ -105,7 +110,7 @@ class SelectionTool extends BaseTool_1.default {
|
|
105
110
|
let transforming = false;
|
106
111
|
if (this.selectionBox) {
|
107
112
|
if (snapToGrid) {
|
108
|
-
this.
|
113
|
+
this.selectionBox.snapSelectedObjectsToGrid();
|
109
114
|
}
|
110
115
|
const dragStartResult = this.selectionBox.onDragStart(current);
|
111
116
|
if (dragStartResult) {
|
@@ -117,7 +122,13 @@ class SelectionTool extends BaseTool_1.default {
|
|
117
122
|
if (!transforming) {
|
118
123
|
// Shift key: Combine the new and old selection boxes at the end of the gesture.
|
119
124
|
this.expandingSelectionBox = this.shiftKeyPressed;
|
120
|
-
this.
|
125
|
+
this.removeSelectionScheduled = !this.expandingSelectionBox;
|
126
|
+
if (this.modeValue.get() === types_2.SelectionMode.Lasso) {
|
127
|
+
this.selectionBuilder = new LassoSelectionBuilder_1.default(current.canvasPos, this.editor.viewport);
|
128
|
+
}
|
129
|
+
else {
|
130
|
+
this.selectionBuilder = new RectSelectionBuilder_1.default(current.canvasPos);
|
131
|
+
}
|
121
132
|
}
|
122
133
|
else {
|
123
134
|
// Only autoscroll if we're transforming an existing selection
|
@@ -132,13 +143,12 @@ class SelectionTool extends BaseTool_1.default {
|
|
132
143
|
}
|
133
144
|
onMainPointerUpdated(currentPointer) {
|
134
145
|
this.lastPointer = currentPointer;
|
135
|
-
if (this.
|
136
|
-
this.
|
137
|
-
this.
|
138
|
-
this.selectionBox
|
146
|
+
if (this.removeSelectionScheduled) {
|
147
|
+
this.removeSelectionScheduled = false;
|
148
|
+
this.handleOverlay.replaceChildren();
|
149
|
+
this.prevSelectionBox = this.selectionBox;
|
150
|
+
this.selectionBox = null;
|
139
151
|
}
|
140
|
-
if (!this.selectionBox)
|
141
|
-
return;
|
142
152
|
this.autoscroller.onPointerMove(currentPointer.screenPos);
|
143
153
|
if (!this.expandingSelectionBox && this.shiftKeyPressed && this.startPoint) {
|
144
154
|
const screenPos = this.editor.viewport.canvasToScreen(this.startPoint);
|
@@ -148,47 +158,46 @@ class SelectionTool extends BaseTool_1.default {
|
|
148
158
|
currentPointer = currentPointer.snappedToGrid(this.editor.viewport);
|
149
159
|
}
|
150
160
|
if (this.selectionBoxHandlingEvt) {
|
151
|
-
this.selectionBox
|
161
|
+
this.selectionBox?.onDragUpdate(currentPointer);
|
152
162
|
}
|
153
163
|
else {
|
154
|
-
this.
|
164
|
+
this.selectionBuilder?.onPointerMove(currentPointer.canvasPos);
|
165
|
+
this.editor.clearWetInk();
|
166
|
+
this.selectionBuilder?.render(this.editor.display.getWetInkRenderer(), this.getSelectionColor());
|
155
167
|
}
|
156
168
|
}
|
157
169
|
onPointerUp(event) {
|
158
170
|
this.onMainPointerUpdated(event.current);
|
159
171
|
this.autoscroller.stop();
|
160
|
-
if (
|
161
|
-
|
162
|
-
this.selectionBox.setHandlesVisible(true);
|
163
|
-
// Were we expanding the previous selection?
|
164
|
-
if (this.expandingSelectionBox && this.prevSelectionBox) {
|
165
|
-
// If so, finish expanding.
|
166
|
-
this.expandingSelectionBox = false;
|
167
|
-
this.selectionBox.resolveToObjects();
|
168
|
-
this.setSelection([
|
169
|
-
...this.selectionBox.getSelectedObjects(),
|
170
|
-
...this.prevSelectionBox.getSelectedObjects(),
|
171
|
-
]);
|
172
|
+
if (this.selectionBoxHandlingEvt) {
|
173
|
+
this.selectionBox?.onDragEnd();
|
172
174
|
}
|
173
|
-
else {
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
175
|
+
else if (this.selectionBuilder) {
|
176
|
+
const newSelection = this.selectionBuilder.resolve(this.editor.image, this.editor.viewport);
|
177
|
+
this.selectionBuilder = null;
|
178
|
+
this.editor.clearWetInk();
|
179
|
+
if (this.expandingSelectionBox && this.selectionBox) {
|
180
|
+
this.setSelection([...this.selectionBox.getSelectedObjects(), ...newSelection]);
|
178
181
|
}
|
179
182
|
else {
|
180
|
-
this.
|
183
|
+
this.setSelection(newSelection);
|
181
184
|
}
|
182
|
-
this.selectionBoxHandlingEvt = false;
|
183
|
-
this.lastPointer = null;
|
184
185
|
}
|
186
|
+
this.expandingSelectionBox = false;
|
187
|
+
this.removeSelectionScheduled = false;
|
188
|
+
this.selectionBoxHandlingEvt = false;
|
189
|
+
this.lastPointer = null;
|
185
190
|
}
|
186
191
|
onGestureCancel() {
|
192
|
+
if (this.selectionBuilder) {
|
193
|
+
this.selectionBuilder = null;
|
194
|
+
this.editor.clearWetInk();
|
195
|
+
}
|
187
196
|
this.autoscroller.stop();
|
188
197
|
if (this.selectionBoxHandlingEvt) {
|
189
198
|
this.selectionBox?.onDragCancel();
|
190
199
|
}
|
191
|
-
else if (!this.
|
200
|
+
else if (!this.removeSelectionScheduled) {
|
192
201
|
// Revert to the previous selection, if any.
|
193
202
|
this.selectionBox?.cancelSelection();
|
194
203
|
this.selectionBox = this.prevSelectionBox;
|
@@ -196,7 +205,7 @@ class SelectionTool extends BaseTool_1.default {
|
|
196
205
|
this.selectionBox?.recomputeRegion();
|
197
206
|
this.prevSelectionBox = null;
|
198
207
|
}
|
199
|
-
this.
|
208
|
+
this.removeSelectionScheduled = false;
|
200
209
|
this.expandingSelectionBox = false;
|
201
210
|
this.lastPointer = null;
|
202
211
|
this.selectionBoxHandlingEvt = false;
|
@@ -464,6 +473,10 @@ class SelectionTool extends BaseTool_1.default {
|
|
464
473
|
getSelection() {
|
465
474
|
return this.selectionBox;
|
466
475
|
}
|
476
|
+
/** @returns true if the selection is currently being created by the user. */
|
477
|
+
isSelecting() {
|
478
|
+
return !!this.selectionBuilder;
|
479
|
+
}
|
467
480
|
getSelectedObjects() {
|
468
481
|
return this.selectionBox?.getSelectedObjects() ?? [];
|
469
482
|
}
|
@@ -489,20 +502,20 @@ class SelectionTool extends BaseTool_1.default {
|
|
489
502
|
bbox = object.getBBox();
|
490
503
|
}
|
491
504
|
}
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
this.clearSelection();
|
496
|
-
if (!this.selectionBox) {
|
497
|
-
this.makeSelectionBox(bbox.topLeft);
|
505
|
+
this.clearSelectionNoUpdateEvent();
|
506
|
+
if (bbox) {
|
507
|
+
this.makeSelectionBox(objects);
|
498
508
|
}
|
499
|
-
this.selectionBox.setSelectedObjects(objects, bbox);
|
500
509
|
this.onSelectionUpdated();
|
501
510
|
}
|
502
|
-
clearSelection
|
511
|
+
// Equivalent to .clearSelection, but does not dispatch an update event
|
512
|
+
clearSelectionNoUpdateEvent() {
|
503
513
|
this.handleOverlay.replaceChildren();
|
504
514
|
this.prevSelectionBox = this.selectionBox;
|
505
515
|
this.selectionBox = null;
|
516
|
+
}
|
517
|
+
clearSelection() {
|
518
|
+
this.clearSelectionNoUpdateEvent();
|
506
519
|
this.onSelectionUpdated();
|
507
520
|
}
|
508
521
|
}
|
@@ -1,6 +1,11 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.TransformMode = exports.ResizeMode = void 0;
|
3
|
+
exports.TransformMode = exports.ResizeMode = exports.SelectionMode = void 0;
|
4
|
+
var SelectionMode;
|
5
|
+
(function (SelectionMode) {
|
6
|
+
SelectionMode["Lasso"] = "lasso";
|
7
|
+
SelectionMode["Rectangle"] = "rect";
|
8
|
+
})(SelectionMode || (exports.SelectionMode = SelectionMode = {}));
|
4
9
|
var ResizeMode;
|
5
10
|
(function (ResizeMode) {
|
6
11
|
ResizeMode[ResizeMode["Both"] = 0] = "Both";
|
package/dist/cjs/tools/lib.d.ts
CHANGED
@@ -7,7 +7,7 @@ export { default as ToolSwitcherShortcut } from './ToolSwitcherShortcut';
|
|
7
7
|
export { default as PanZoomTool, PanZoomMode } from './PanZoom';
|
8
8
|
export { default as PenTool, PenStyle } from './Pen';
|
9
9
|
export { default as TextTool } from './TextTool';
|
10
|
-
export { default as SelectionTool } from './SelectionTool/SelectionTool';
|
10
|
+
export { default as SelectionTool, SelectionMode } from './SelectionTool/SelectionTool';
|
11
11
|
export { default as SelectAllShortcutHandler } from './SelectionTool/SelectAllShortcutHandler';
|
12
12
|
export { default as EraserTool, EraserMode } from './Eraser';
|
13
13
|
export { default as PasteHandler } from './PasteHandler';
|
package/dist/cjs/tools/lib.js
CHANGED
@@ -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.ToolbarShortcutHandler = exports.SoundUITool = exports.PasteHandler = exports.EraserMode = exports.EraserTool = exports.SelectAllShortcutHandler = exports.SelectionTool = exports.TextTool = exports.PenTool = exports.PanZoomMode = exports.PanZoomTool = exports.ToolSwitcherShortcut = exports.UndoRedoShortcut = exports.ToolEnabledGroup = exports.ToolController = exports.BaseTool = exports.InputMapper = void 0;
|
6
|
+
exports.ToolbarShortcutHandler = exports.SoundUITool = exports.PasteHandler = exports.EraserMode = exports.EraserTool = exports.SelectAllShortcutHandler = exports.SelectionMode = exports.SelectionTool = exports.TextTool = exports.PenTool = exports.PanZoomMode = exports.PanZoomTool = exports.ToolSwitcherShortcut = exports.UndoRedoShortcut = exports.ToolEnabledGroup = exports.ToolController = exports.BaseTool = exports.InputMapper = void 0;
|
7
7
|
var InputMapper_1 = require("./InputFilter/InputMapper");
|
8
8
|
Object.defineProperty(exports, "InputMapper", { enumerable: true, get: function () { return __importDefault(InputMapper_1).default; } });
|
9
9
|
var BaseTool_1 = require("./BaseTool");
|
@@ -25,6 +25,7 @@ var TextTool_1 = require("./TextTool");
|
|
25
25
|
Object.defineProperty(exports, "TextTool", { enumerable: true, get: function () { return __importDefault(TextTool_1).default; } });
|
26
26
|
var SelectionTool_1 = require("./SelectionTool/SelectionTool");
|
27
27
|
Object.defineProperty(exports, "SelectionTool", { enumerable: true, get: function () { return __importDefault(SelectionTool_1).default; } });
|
28
|
+
Object.defineProperty(exports, "SelectionMode", { enumerable: true, get: function () { return SelectionTool_1.SelectionMode; } });
|
28
29
|
var SelectAllShortcutHandler_1 = require("./SelectionTool/SelectAllShortcutHandler");
|
29
30
|
Object.defineProperty(exports, "SelectAllShortcutHandler", { enumerable: true, get: function () { return __importDefault(SelectAllShortcutHandler_1).default; } });
|
30
31
|
var Eraser_1 = require("./Eraser");
|
@@ -72,9 +72,7 @@ class ReactiveValue {
|
|
72
72
|
*/
|
73
73
|
static fromCallback(callback, sourceValues) {
|
74
74
|
const result = new ReactiveValueImpl(callback());
|
75
|
-
const resultRef =
|
76
|
-
? new window.WeakRef(result)
|
77
|
-
: { deref: () => result };
|
75
|
+
const resultRef = typeof WeakRef !== 'undefined' ? new WeakRef(result) : { deref: () => result };
|
78
76
|
for (const value of sourceValues) {
|
79
77
|
const listener = value.onUpdate(() => {
|
80
78
|
// Use resultRef to allow `result` to be garbage collected
|
@@ -118,9 +116,7 @@ exports.ReactiveValue = ReactiveValue;
|
|
118
116
|
class MutableReactiveValue extends ReactiveValue {
|
119
117
|
static fromProperty(sourceValue, propertyName) {
|
120
118
|
const child = ReactiveValue.fromInitialValue(sourceValue.get()[propertyName]);
|
121
|
-
const childRef =
|
122
|
-
? new window.WeakRef(child)
|
123
|
-
: { deref: () => child };
|
119
|
+
const childRef = typeof WeakRef !== 'undefined' ? new WeakRef(child) : { deref: () => child };
|
124
120
|
// When the source is updated...
|
125
121
|
const sourceListener = sourceValue.onUpdate((newValue) => {
|
126
122
|
const childValue = childRef.deref();
|
package/dist/cjs/version.js
CHANGED
package/dist/mjs/Editor.d.ts
CHANGED
@@ -116,8 +116,6 @@ export interface EditorSettings {
|
|
116
116
|
*
|
117
117
|
* If not given, the default file picker shown by a [file input](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file)
|
118
118
|
* is shown.
|
119
|
-
*
|
120
|
-
* @beta -- API may change between minor releases.
|
121
119
|
*/
|
122
120
|
showImagePicker?: ShowCustomFilePickerCallback;
|
123
121
|
} | null;
|
@@ -4,6 +4,7 @@ import { LineSegment2, Mat33, Path, Rect2 } from '@js-draw/math';
|
|
4
4
|
import AbstractRenderer from '../rendering/renderers/AbstractRenderer';
|
5
5
|
import { ImageComponentLocalization } from './localization';
|
6
6
|
import Viewport from '../Viewport';
|
7
|
+
import { Point2 } from '@js-draw/math';
|
7
8
|
export type LoadSaveData = string[] | Record<symbol, string | number>;
|
8
9
|
export type LoadSaveDataTable = Record<string, Array<LoadSaveData>>;
|
9
10
|
export type DeserializeCallback = (data: string) => AbstractComponent;
|
@@ -27,6 +28,12 @@ export declare enum ComponentSizingMode {
|
|
27
28
|
}
|
28
29
|
/**
|
29
30
|
* A base class for everything that can be added to an {@link EditorImage}.
|
31
|
+
*
|
32
|
+
* In addition to the `abstract` methods, there are a few methods that should be
|
33
|
+
* overridden when creating a selectable/erasable subclass:
|
34
|
+
* - {@link keyPoints}: Overriding this may improve how the component interacts with the selection tool.
|
35
|
+
* - {@link withRegionErased}: Override/implement this to allow the component to be partially erased
|
36
|
+
* by the partial stroke eraser.
|
30
37
|
*/
|
31
38
|
export default abstract class AbstractComponent {
|
32
39
|
private readonly componentKind;
|
@@ -113,6 +120,14 @@ export default abstract class AbstractComponent {
|
|
113
120
|
* this function.
|
114
121
|
*/
|
115
122
|
intersectsRect(rect: Rect2): boolean;
|
123
|
+
/**
|
124
|
+
* Returns a selection of points within this object. Each contiguous section
|
125
|
+
* of this object should have a point in the returned array.
|
126
|
+
*
|
127
|
+
* Subclasses should override this method if the center of the bounding box is
|
128
|
+
* not contained within the object.
|
129
|
+
*/
|
130
|
+
keyPoints(): Point2[];
|
116
131
|
isSelectable(): boolean;
|
117
132
|
isBackground(): boolean;
|
118
133
|
getProportionalRenderingTime(): number;
|
@@ -28,6 +28,12 @@ export var ComponentSizingMode;
|
|
28
28
|
})(ComponentSizingMode || (ComponentSizingMode = {}));
|
29
29
|
/**
|
30
30
|
* A base class for everything that can be added to an {@link EditorImage}.
|
31
|
+
*
|
32
|
+
* In addition to the `abstract` methods, there are a few methods that should be
|
33
|
+
* overridden when creating a selectable/erasable subclass:
|
34
|
+
* - {@link keyPoints}: Overriding this may improve how the component interacts with the selection tool.
|
35
|
+
* - {@link withRegionErased}: Override/implement this to allow the component to be partially erased
|
36
|
+
* by the partial stroke eraser.
|
31
37
|
*/
|
32
38
|
class AbstractComponent {
|
33
39
|
constructor(
|
@@ -136,6 +142,16 @@ class AbstractComponent {
|
|
136
142
|
const testLines = rect.getEdges();
|
137
143
|
return testLines.some((edge) => this.intersects(edge));
|
138
144
|
}
|
145
|
+
/**
|
146
|
+
* Returns a selection of points within this object. Each contiguous section
|
147
|
+
* of this object should have a point in the returned array.
|
148
|
+
*
|
149
|
+
* Subclasses should override this method if the center of the bounding box is
|
150
|
+
* not contained within the object.
|
151
|
+
*/
|
152
|
+
keyPoints() {
|
153
|
+
return [this.getBBox().center];
|
154
|
+
}
|
139
155
|
// @returns true iff this component can be selected (e.g. by the selection tool.)
|
140
156
|
isSelectable() {
|
141
157
|
return true;
|
@@ -54,6 +54,7 @@ export default class Stroke extends AbstractComponent implements RestyleableComp
|
|
54
54
|
/** @beta -- May fail for concave `path`s */
|
55
55
|
withRegionErased(eraserPath: Path, viewport: Viewport): Stroke[];
|
56
56
|
intersects(line: LineSegment2): boolean;
|
57
|
+
keyPoints(): import("@js-draw/math").Vec3[];
|
57
58
|
intersectsRect(rect: Rect2): boolean;
|
58
59
|
private simplifiedPath;
|
59
60
|
private computeSimplifiedPathFor;
|
@@ -294,6 +294,13 @@ export default class Stroke extends AbstractComponent {
|
|
294
294
|
}
|
295
295
|
return false;
|
296
296
|
}
|
297
|
+
keyPoints() {
|
298
|
+
return this.parts
|
299
|
+
.map((part) => {
|
300
|
+
return part.startPoint;
|
301
|
+
})
|
302
|
+
.flat();
|
303
|
+
}
|
297
304
|
intersectsRect(rect) {
|
298
305
|
// AbstractComponent::intersectsRect can be inexact for strokes with non-zero
|
299
306
|
// stroke radius (has many false negatives). As such, additional checks are
|
@@ -2,6 +2,7 @@ import { Color4 } from '@js-draw/math';
|
|
2
2
|
import TextRenderingStyle from '../rendering/TextRenderingStyle';
|
3
3
|
import { PenStyle } from '../tools/Pen';
|
4
4
|
import { EraserMode } from '../tools/Eraser';
|
5
|
+
import { SelectionMode } from '../tools/SelectionTool/types';
|
5
6
|
export type IconElemType = HTMLImageElement | SVGElement;
|
6
7
|
/**
|
7
8
|
* Provides icons that can be used in the toolbar and other locations.
|
@@ -41,7 +42,7 @@ export default class IconProvider {
|
|
41
42
|
makeRedoIcon(): IconElemType;
|
42
43
|
makeDropdownIcon(): IconElemType;
|
43
44
|
makeEraserIcon(eraserSize?: number, mode?: EraserMode): IconElemType;
|
44
|
-
makeSelectionIcon(): IconElemType;
|
45
|
+
makeSelectionIcon(mode?: SelectionMode): IconElemType;
|
45
46
|
makeRotateIcon(): IconElemType;
|
46
47
|
makeHandToolIcon(): IconElemType;
|
47
48
|
makeTouchPanningIcon(): IconElemType;
|
@@ -11,6 +11,7 @@ import { makeFreehandLineBuilder } from '../components/builders/FreehandLineBu
|
|
11
11
|
import { makePolylineBuilder } from '../components/builders/PolylineBuilder.mjs';
|
12
12
|
import { EraserMode } from '../tools/Eraser.mjs';
|
13
13
|
import { createSvgElement, createSvgElements, createSvgPaths } from '../util/createElement.mjs';
|
14
|
+
import { SelectionMode } from '../tools/SelectionTool/types.mjs';
|
14
15
|
const svgNamespace = 'http://www.w3.org/2000/svg';
|
15
16
|
let checkerboardIdCounter = 0;
|
16
17
|
const makeCheckerboardPattern = () => {
|
@@ -164,15 +165,24 @@ class IconProvider {
|
|
164
165
|
});
|
165
166
|
return icon;
|
166
167
|
}
|
167
|
-
makeSelectionIcon() {
|
168
|
+
makeSelectionIcon(mode = SelectionMode.Rectangle) {
|
168
169
|
const icon = document.createElementNS(svgNamespace, 'svg');
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
170
|
+
if (mode === SelectionMode.Rectangle) {
|
171
|
+
icon.innerHTML = `
|
172
|
+
<g>
|
173
|
+
<rect x="10" y="10" width="70" height="70" fill="pink" stroke="black" stroke-dasharray="32 9"/>
|
174
|
+
<rect x="75" y="75" width="10" height="10" fill="white" stroke="black"/>
|
175
|
+
</g>
|
176
|
+
`;
|
177
|
+
}
|
178
|
+
else {
|
179
|
+
icon.innerHTML = `
|
180
|
+
<g>
|
181
|
+
<rect x="10" y="10" width="76" height="76" rx="50" stroke-dasharray="32 9" fill="pink" stroke="black"/>
|
182
|
+
<rect x="71" y="71" width="10" height="10" fill="white" stroke="black"/>
|
183
|
+
</g>
|
184
|
+
`;
|
185
|
+
}
|
176
186
|
icon.setAttribute('viewBox', '0 0 100 100');
|
177
187
|
return icon;
|
178
188
|
}
|
@@ -44,6 +44,8 @@ export interface ToolbarLocalization extends ToolbarUtilsLocalization {
|
|
44
44
|
resetView: string;
|
45
45
|
reformatSelection: string;
|
46
46
|
selectionToolKeyboardShortcuts: string;
|
47
|
+
selectionTool__lassoSelect: string;
|
48
|
+
selectionTool__lassoSelect__help: string;
|
47
49
|
paste: string;
|
48
50
|
documentProperties: string;
|
49
51
|
backgroundColor: string;
|
@@ -34,6 +34,8 @@ export const defaultToolbarLocalization = {
|
|
34
34
|
pickColorFromScreen: 'Pick color from screen',
|
35
35
|
clickToPickColorAnnouncement: 'Click on the screen to pick a color',
|
36
36
|
colorSelectionCanceledAnnouncement: 'Color selection canceled',
|
37
|
+
selectionTool__lassoSelect: 'Freeform selection',
|
38
|
+
selectionTool__lassoSelect__help: 'When enabled, dragging creates a freeform (lasso) selection.',
|
37
39
|
selectionToolKeyboardShortcuts: 'Selection tool: Use arrow keys to move selected items, lowercase/uppercase ‘i’ and ‘o’ to resize.',
|
38
40
|
documentProperties: 'Page',
|
39
41
|
backgroundColor: 'Background color',
|
@@ -4,14 +4,21 @@ import { KeyPressEvent } from '../../inputEvents';
|
|
4
4
|
import { ToolbarLocalization } from '../localization';
|
5
5
|
import BaseToolWidget from './BaseToolWidget';
|
6
6
|
import HelpDisplay from '../utils/HelpDisplay';
|
7
|
+
import { SavedToolbuttonState } from './BaseWidget';
|
7
8
|
export default class SelectionToolWidget extends BaseToolWidget {
|
8
9
|
private tool;
|
9
10
|
private updateFormatMenu;
|
11
|
+
private hasSelectionValue;
|
10
12
|
constructor(editor: Editor, tool: SelectionTool, localization?: ToolbarLocalization);
|
11
13
|
private resizeImageToSelection;
|
12
14
|
protected onKeyPress(event: KeyPressEvent): boolean;
|
13
15
|
protected getTitle(): string;
|
14
16
|
protected createIcon(): Element;
|
15
17
|
protected getHelpText(): string;
|
18
|
+
protected createSelectionActions(helpDisplay?: HelpDisplay): {
|
19
|
+
container: HTMLDivElement;
|
20
|
+
};
|
16
21
|
protected fillDropdown(dropdown: HTMLElement, helpDisplay?: HelpDisplay): boolean;
|
22
|
+
serializeState(): SavedToolbuttonState;
|
23
|
+
deserializeFrom(state: SavedToolbuttonState): void;
|
17
24
|
}
|