js-draw 1.17.0 → 1.18.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/README.md +70 -10
- package/dist/bundle.js +2 -2
- package/dist/cjs/Editor.d.ts +18 -20
- package/dist/cjs/Editor.js +5 -2
- package/dist/cjs/components/AbstractComponent.d.ts +17 -5
- package/dist/cjs/components/AbstractComponent.js +15 -15
- package/dist/cjs/components/Stroke.d.ts +4 -1
- package/dist/cjs/components/Stroke.js +158 -2
- package/dist/cjs/components/builders/PolylineBuilder.d.ts +1 -1
- package/dist/cjs/components/builders/PolylineBuilder.js +9 -2
- package/dist/cjs/components/builders/PressureSensitiveFreehandLineBuilder.d.ts +1 -1
- package/dist/cjs/components/builders/PressureSensitiveFreehandLineBuilder.js +44 -51
- package/dist/cjs/image/EditorImage.js +1 -1
- package/dist/cjs/localizations/de.js +1 -1
- package/dist/cjs/localizations/es.js +1 -1
- package/dist/cjs/testing/createEditor.d.ts +2 -2
- package/dist/cjs/testing/createEditor.js +2 -2
- package/dist/cjs/toolbar/IconProvider.d.ts +3 -1
- package/dist/cjs/toolbar/IconProvider.js +15 -3
- package/dist/cjs/toolbar/localization.d.ts +6 -1
- package/dist/cjs/toolbar/localization.js +7 -2
- package/dist/cjs/toolbar/widgets/EraserToolWidget.d.ts +6 -1
- package/dist/cjs/toolbar/widgets/EraserToolWidget.js +45 -5
- package/dist/cjs/toolbar/widgets/PenToolWidget.js +10 -3
- package/dist/cjs/toolbar/widgets/PenToolWidget.test.d.ts +1 -0
- package/dist/cjs/toolbar/widgets/keybindings.js +1 -1
- package/dist/cjs/tools/Eraser.d.ts +24 -4
- package/dist/cjs/tools/Eraser.js +107 -20
- package/dist/cjs/tools/PasteHandler.js +0 -1
- package/dist/cjs/tools/lib.d.ts +1 -4
- package/dist/cjs/tools/lib.js +2 -4
- package/dist/cjs/version.js +1 -1
- package/dist/mjs/Editor.d.ts +18 -20
- package/dist/mjs/Editor.mjs +5 -2
- package/dist/mjs/components/AbstractComponent.d.ts +17 -5
- package/dist/mjs/components/AbstractComponent.mjs +15 -15
- package/dist/mjs/components/Stroke.d.ts +4 -1
- package/dist/mjs/components/Stroke.mjs +159 -3
- package/dist/mjs/components/builders/PolylineBuilder.d.ts +1 -1
- package/dist/mjs/components/builders/PolylineBuilder.mjs +10 -3
- package/dist/mjs/components/builders/PressureSensitiveFreehandLineBuilder.d.ts +1 -1
- package/dist/mjs/components/builders/PressureSensitiveFreehandLineBuilder.mjs +45 -52
- package/dist/mjs/image/EditorImage.mjs +1 -1
- package/dist/mjs/localizations/de.mjs +1 -1
- package/dist/mjs/localizations/es.mjs +1 -1
- package/dist/mjs/testing/createEditor.d.ts +2 -2
- package/dist/mjs/testing/createEditor.mjs +2 -2
- package/dist/mjs/toolbar/IconProvider.d.ts +3 -1
- package/dist/mjs/toolbar/IconProvider.mjs +15 -3
- package/dist/mjs/toolbar/localization.d.ts +6 -1
- package/dist/mjs/toolbar/localization.mjs +7 -2
- package/dist/mjs/toolbar/widgets/EraserToolWidget.d.ts +6 -1
- package/dist/mjs/toolbar/widgets/EraserToolWidget.mjs +47 -6
- package/dist/mjs/toolbar/widgets/PenToolWidget.mjs +10 -3
- package/dist/mjs/toolbar/widgets/PenToolWidget.test.d.ts +1 -0
- package/dist/mjs/toolbar/widgets/keybindings.mjs +1 -1
- package/dist/mjs/tools/Eraser.d.ts +24 -4
- package/dist/mjs/tools/Eraser.mjs +107 -21
- package/dist/mjs/tools/PasteHandler.mjs +0 -1
- package/dist/mjs/tools/lib.d.ts +1 -4
- package/dist/mjs/tools/lib.mjs +1 -4
- package/dist/mjs/version.mjs +1 -1
- package/package.json +3 -3
@@ -1,19 +1,28 @@
|
|
1
1
|
import { EditorEventType } from '../types.mjs';
|
2
2
|
import BaseTool from './BaseTool.mjs';
|
3
|
-
import { Vec2, LineSegment2, Color4, Rect2 } from '@js-draw/math';
|
3
|
+
import { Vec2, LineSegment2, Color4, Rect2, Path } from '@js-draw/math';
|
4
4
|
import Erase from '../commands/Erase.mjs';
|
5
5
|
import { PointerDevice } from '../Pointer.mjs';
|
6
6
|
import { decreaseSizeKeyboardShortcutId, increaseSizeKeyboardShortcutId } from './keybindings.mjs';
|
7
7
|
import { ReactiveValue } from '../util/ReactiveValue.mjs';
|
8
|
+
import EditorImage from '../image/EditorImage.mjs';
|
9
|
+
import uniteCommands from '../commands/uniteCommands.mjs';
|
10
|
+
import { pathToRenderable } from '../rendering/RenderablePathSpec.mjs';
|
11
|
+
export var EraserMode;
|
12
|
+
(function (EraserMode) {
|
13
|
+
EraserMode["PartialStroke"] = "partial-stroke";
|
14
|
+
EraserMode["FullStroke"] = "full-stroke";
|
15
|
+
})(EraserMode || (EraserMode = {}));
|
8
16
|
export default class Eraser extends BaseTool {
|
9
|
-
constructor(editor, description) {
|
17
|
+
constructor(editor, description, options) {
|
10
18
|
super(editor.notifier, description);
|
11
19
|
this.editor = editor;
|
12
20
|
this.lastPoint = null;
|
13
21
|
this.isFirstEraseEvt = true;
|
14
|
-
this.thickness = 10;
|
15
22
|
// Commands that each remove one element
|
16
|
-
this.
|
23
|
+
this.eraseCommands = [];
|
24
|
+
this.addCommands = [];
|
25
|
+
this.thickness = options?.thickness ?? 10;
|
17
26
|
this.thicknessValue = ReactiveValue.fromInitialValue(this.thickness);
|
18
27
|
this.thicknessValue.onUpdate(value => {
|
19
28
|
this.thickness = value;
|
@@ -22,6 +31,13 @@ export default class Eraser extends BaseTool {
|
|
22
31
|
tool: this,
|
23
32
|
});
|
24
33
|
});
|
34
|
+
this.modeValue = ReactiveValue.fromInitialValue(options?.mode ?? EraserMode.FullStroke);
|
35
|
+
this.modeValue.onUpdate(_value => {
|
36
|
+
this.editor.notifier.dispatch(EditorEventType.ToolUpdated, {
|
37
|
+
kind: EditorEventType.ToolUpdated,
|
38
|
+
tool: this,
|
39
|
+
});
|
40
|
+
});
|
25
41
|
}
|
26
42
|
clearPreview() {
|
27
43
|
this.editor.clearWetInk();
|
@@ -34,16 +50,24 @@ export default class Eraser extends BaseTool {
|
|
34
50
|
const size = this.getSizeOnCanvas();
|
35
51
|
const renderer = this.editor.display.getWetInkRenderer();
|
36
52
|
const rect = this.getEraserRect(point);
|
53
|
+
const rect2 = this.getEraserRect(this.lastPoint ?? point);
|
37
54
|
const fill = {
|
38
|
-
fill: Color4.
|
55
|
+
fill: Color4.transparent,
|
56
|
+
stroke: { width: size / 10, color: Color4.gray },
|
39
57
|
};
|
40
|
-
renderer.
|
58
|
+
renderer.drawPath(pathToRenderable(Path.fromConvexHullOf([...rect.corners, ...rect2.corners]), fill));
|
41
59
|
}
|
60
|
+
/**
|
61
|
+
* @returns the eraser rectangle in canvas coordinates.
|
62
|
+
*
|
63
|
+
* For now, all erasers are rectangles or points.
|
64
|
+
*/
|
42
65
|
getEraserRect(centerPoint) {
|
43
66
|
const size = this.getSizeOnCanvas();
|
44
67
|
const halfSize = Vec2.of(size / 2, size / 2);
|
45
68
|
return Rect2.fromCorners(centerPoint.minus(halfSize), centerPoint.plus(halfSize));
|
46
69
|
}
|
70
|
+
/** Erases in a line from the last point to the current. */
|
47
71
|
eraseTo(currentPoint) {
|
48
72
|
if (!this.isFirstEraseEvt && currentPoint.distanceTo(this.lastPoint) === 0) {
|
49
73
|
return;
|
@@ -60,13 +84,55 @@ export default class Eraser extends BaseTool {
|
|
60
84
|
});
|
61
85
|
// Only erase components that could be selected (and thus interacted with)
|
62
86
|
// by the user.
|
63
|
-
const
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
87
|
+
const eraseableElems = intersectingElems.filter(elem => elem.isSelectable());
|
88
|
+
if (this.modeValue.get() === EraserMode.FullStroke) {
|
89
|
+
// Remove any intersecting elements.
|
90
|
+
this.toRemove.push(...eraseableElems);
|
91
|
+
// Create new Erase commands for the now-to-be-erased elements and apply them.
|
92
|
+
const newPartialCommands = eraseableElems.map(elem => new Erase([elem]));
|
93
|
+
newPartialCommands.forEach(cmd => cmd.apply(this.editor));
|
94
|
+
this.eraseCommands.push(...newPartialCommands);
|
95
|
+
}
|
96
|
+
else {
|
97
|
+
const toErase = [];
|
98
|
+
const toAdd = [];
|
99
|
+
for (const targetElem of eraseableElems) {
|
100
|
+
toErase.push(targetElem);
|
101
|
+
// Completely delete items that can't be divided.
|
102
|
+
if (!targetElem.withRegionErased) {
|
103
|
+
continue;
|
104
|
+
}
|
105
|
+
// Completely delete items that are completely or almost completely
|
106
|
+
// contained within the eraser.
|
107
|
+
const grownRect = eraserRect.grownBy(eraserRect.maxDimension / 3);
|
108
|
+
if (grownRect.containsRect(targetElem.getExactBBox())) {
|
109
|
+
continue;
|
110
|
+
}
|
111
|
+
// Join the current and previous rectangles so that points between events are also
|
112
|
+
// erased.
|
113
|
+
const erasePath = Path.fromConvexHullOf([
|
114
|
+
...eraserRect.corners, ...this.getEraserRect(this.lastPoint ?? currentPoint).corners
|
115
|
+
].map(p => this.editor.viewport.roundPoint(p)));
|
116
|
+
toAdd.push(...targetElem.withRegionErased(erasePath, this.editor.viewport));
|
117
|
+
}
|
118
|
+
const eraseCommand = new Erase(toErase);
|
119
|
+
const newAddCommands = toAdd.map(elem => EditorImage.addElement(elem));
|
120
|
+
eraseCommand.apply(this.editor);
|
121
|
+
newAddCommands.forEach(command => command.apply(this.editor));
|
122
|
+
const finalToErase = [];
|
123
|
+
for (const item of toErase) {
|
124
|
+
if (this.toAdd.includes(item)) {
|
125
|
+
this.toAdd = this.toAdd.filter(i => i !== item);
|
126
|
+
}
|
127
|
+
else {
|
128
|
+
finalToErase.push(item);
|
129
|
+
}
|
130
|
+
}
|
131
|
+
this.toRemove.push(...finalToErase);
|
132
|
+
this.toAdd.push(...toAdd);
|
133
|
+
this.eraseCommands.push(new Erase(finalToErase));
|
134
|
+
this.addCommands.push(...newAddCommands);
|
135
|
+
}
|
70
136
|
this.drawPreviewAt(currentPoint);
|
71
137
|
this.lastPoint = currentPoint;
|
72
138
|
}
|
@@ -74,6 +140,7 @@ export default class Eraser extends BaseTool {
|
|
74
140
|
if (event.allPointers.length === 1 || event.current.device === PointerDevice.Eraser) {
|
75
141
|
this.lastPoint = event.current.canvasPos;
|
76
142
|
this.toRemove = [];
|
143
|
+
this.toAdd = [];
|
77
144
|
this.isFirstEraseEvt = true;
|
78
145
|
this.drawPreviewAt(event.current.canvasPos);
|
79
146
|
return true;
|
@@ -86,18 +153,32 @@ export default class Eraser extends BaseTool {
|
|
86
153
|
}
|
87
154
|
onPointerUp(event) {
|
88
155
|
this.eraseTo(event.current.canvasPos);
|
89
|
-
|
156
|
+
const commands = [];
|
157
|
+
if (this.addCommands.length > 0) {
|
158
|
+
this.addCommands.forEach(cmd => cmd.unapply(this.editor));
|
159
|
+
commands.push(...this.toAdd.map(a => EditorImage.addElement(a)));
|
160
|
+
this.addCommands = [];
|
161
|
+
}
|
162
|
+
if (this.eraseCommands.length > 0) {
|
90
163
|
// Undo commands for each individual component and unite into a single command.
|
91
|
-
this.
|
92
|
-
this.
|
164
|
+
this.eraseCommands.forEach(cmd => cmd.unapply(this.editor));
|
165
|
+
this.eraseCommands = [];
|
93
166
|
const command = new Erase(this.toRemove);
|
94
|
-
|
167
|
+
commands.push(command);
|
168
|
+
}
|
169
|
+
if (commands.length === 1) {
|
170
|
+
this.editor.dispatch(commands[0]); // dispatch: Makes undo-able.
|
171
|
+
}
|
172
|
+
else {
|
173
|
+
this.editor.dispatch(uniteCommands(commands));
|
95
174
|
}
|
96
175
|
this.clearPreview();
|
97
176
|
}
|
98
177
|
onGestureCancel() {
|
99
|
-
this.
|
100
|
-
this.
|
178
|
+
this.addCommands.forEach(cmd => cmd.unapply(this.editor));
|
179
|
+
this.eraseCommands.forEach(cmd => cmd.unapply(this.editor));
|
180
|
+
this.eraseCommands = [];
|
181
|
+
this.addCommands = [];
|
101
182
|
this.clearPreview();
|
102
183
|
}
|
103
184
|
onKeyPress(event) {
|
@@ -116,9 +197,14 @@ export default class Eraser extends BaseTool {
|
|
116
197
|
}
|
117
198
|
return false;
|
118
199
|
}
|
200
|
+
/** Returns the side-length of the tip of this eraser. */
|
119
201
|
getThickness() {
|
120
202
|
return this.thickness;
|
121
203
|
}
|
204
|
+
/** Sets the side-length of this' tip. */
|
205
|
+
setThickness(thickness) {
|
206
|
+
this.thicknessValue.set(thickness);
|
207
|
+
}
|
122
208
|
/**
|
123
209
|
* Returns a {@link MutableReactiveValue} that can be used to watch
|
124
210
|
* this tool's thickness.
|
@@ -126,7 +212,7 @@ export default class Eraser extends BaseTool {
|
|
126
212
|
getThicknessValue() {
|
127
213
|
return this.thicknessValue;
|
128
214
|
}
|
129
|
-
|
130
|
-
this.
|
215
|
+
getModeValue() {
|
216
|
+
return this.modeValue;
|
131
217
|
}
|
132
218
|
}
|
package/dist/mjs/tools/lib.d.ts
CHANGED
@@ -1,6 +1,3 @@
|
|
1
|
-
/**
|
2
|
-
* @packageDocumentation
|
3
|
-
*/
|
4
1
|
export { default as BaseTool } from './BaseTool';
|
5
2
|
export { default as ToolController } from './ToolController';
|
6
3
|
export { default as ToolEnabledGroup } from './ToolEnabledGroup';
|
@@ -11,7 +8,7 @@ export { default as PenTool, PenStyle } from './Pen';
|
|
11
8
|
export { default as TextTool } from './TextTool';
|
12
9
|
export { default as SelectionTool } from './SelectionTool/SelectionTool';
|
13
10
|
export { default as SelectAllShortcutHandler } from './SelectionTool/SelectAllShortcutHandler';
|
14
|
-
export { default as EraserTool } from './Eraser';
|
11
|
+
export { default as EraserTool, EraserMode } from './Eraser';
|
15
12
|
export { default as PasteHandler } from './PasteHandler';
|
16
13
|
export { default as SoundUITool } from './SoundUITool';
|
17
14
|
export { default as ToolbarShortcutHandler } from './ToolbarShortcutHandler';
|
package/dist/mjs/tools/lib.mjs
CHANGED
@@ -1,6 +1,3 @@
|
|
1
|
-
/**
|
2
|
-
* @packageDocumentation
|
3
|
-
*/
|
4
1
|
export { default as BaseTool } from './BaseTool.mjs';
|
5
2
|
export { default as ToolController } from './ToolController.mjs';
|
6
3
|
export { default as ToolEnabledGroup } from './ToolEnabledGroup.mjs';
|
@@ -11,7 +8,7 @@ export { default as PenTool } from './Pen.mjs';
|
|
11
8
|
export { default as TextTool } from './TextTool.mjs';
|
12
9
|
export { default as SelectionTool } from './SelectionTool/SelectionTool.mjs';
|
13
10
|
export { default as SelectAllShortcutHandler } from './SelectionTool/SelectAllShortcutHandler.mjs';
|
14
|
-
export { default as EraserTool } from './Eraser.mjs';
|
11
|
+
export { default as EraserTool, EraserMode } from './Eraser.mjs';
|
15
12
|
export { default as PasteHandler } from './PasteHandler.mjs';
|
16
13
|
export { default as SoundUITool } from './SoundUITool.mjs';
|
17
14
|
export { default as ToolbarShortcutHandler } from './ToolbarShortcutHandler.mjs';
|
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.18.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",
|
@@ -64,7 +64,7 @@
|
|
64
64
|
"postpack": "ts-node tools/copyREADME.ts revert"
|
65
65
|
},
|
66
66
|
"dependencies": {
|
67
|
-
"@js-draw/math": "^1.
|
67
|
+
"@js-draw/math": "^1.18.0",
|
68
68
|
"@melloware/coloris": "0.22.0"
|
69
69
|
},
|
70
70
|
"devDependencies": {
|
@@ -86,5 +86,5 @@
|
|
86
86
|
"freehand",
|
87
87
|
"svg"
|
88
88
|
],
|
89
|
-
"gitHead": "
|
89
|
+
"gitHead": "73c0d802a8439b5d408ba1e60f91be029db7e402"
|
90
90
|
}
|