js-draw 1.26.0 → 1.27.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
}
|