js-draw 0.11.3 → 0.13.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/CHANGELOG.md +15 -0
- package/dist/bundle.js +1 -1
- package/dist/src/Color4.d.ts +13 -0
- package/dist/src/Color4.js +17 -0
- package/dist/src/Editor.d.ts +33 -18
- package/dist/src/Editor.js +26 -24
- package/dist/src/EditorImage.d.ts +12 -0
- package/dist/src/EditorImage.js +12 -0
- package/dist/src/Pointer.d.ts +1 -0
- package/dist/src/Pointer.js +8 -0
- package/dist/src/SVGLoader.d.ts +5 -0
- package/dist/src/SVGLoader.js +49 -36
- package/dist/src/Viewport.d.ts +30 -1
- package/dist/src/Viewport.js +39 -9
- package/dist/src/commands/invertCommand.js +1 -1
- package/dist/src/components/AbstractComponent.d.ts +20 -0
- package/dist/src/components/AbstractComponent.js +32 -2
- package/dist/src/lib.d.ts +6 -3
- package/dist/src/lib.js +4 -1
- package/dist/src/math/Mat33.d.ts +1 -1
- package/dist/src/math/Mat33.js +1 -1
- package/dist/src/rendering/Display.d.ts +9 -11
- package/dist/src/rendering/Display.js +12 -14
- package/dist/src/rendering/lib.d.ts +3 -0
- package/dist/src/rendering/lib.js +3 -0
- package/dist/src/rendering/renderers/DummyRenderer.js +2 -2
- package/dist/src/rendering/renderers/SVGRenderer.js +4 -0
- package/dist/src/toolbar/HTMLToolbar.d.ts +51 -0
- package/dist/src/toolbar/HTMLToolbar.js +63 -5
- package/dist/src/toolbar/IconProvider.d.ts +2 -2
- package/dist/src/toolbar/IconProvider.js +123 -35
- package/dist/src/toolbar/widgets/EraserToolWidget.d.ts +8 -1
- package/dist/src/toolbar/widgets/EraserToolWidget.js +45 -4
- package/dist/src/toolbar/widgets/PenToolWidget.js +2 -2
- package/dist/src/toolbar/widgets/SelectionToolWidget.js +12 -3
- package/dist/src/tools/Eraser.d.ts +10 -1
- package/dist/src/tools/Eraser.js +65 -13
- package/dist/src/tools/PanZoom.js +1 -1
- package/dist/src/tools/PasteHandler.d.ts +11 -4
- package/dist/src/tools/PasteHandler.js +12 -5
- package/dist/src/tools/Pen.d.ts +7 -2
- package/dist/src/tools/Pen.js +39 -6
- package/dist/src/tools/SelectionTool/Selection.d.ts +4 -1
- package/dist/src/tools/SelectionTool/Selection.js +64 -27
- package/dist/src/tools/SelectionTool/SelectionHandle.d.ts +3 -0
- package/dist/src/tools/SelectionTool/SelectionHandle.js +6 -0
- package/dist/src/tools/SelectionTool/SelectionTool.d.ts +3 -1
- package/dist/src/tools/SelectionTool/SelectionTool.js +56 -16
- package/dist/src/tools/TextTool.js +10 -6
- package/dist/src/tools/ToolSwitcherShortcut.d.ts +8 -0
- package/dist/src/tools/ToolSwitcherShortcut.js +9 -3
- package/dist/src/tools/UndoRedoShortcut.js +2 -4
- package/dist/src/types.d.ts +2 -2
- package/package.json +2 -2
- package/src/Color4.test.ts +11 -0
- package/src/Color4.ts +23 -0
- package/src/Editor.ts +39 -26
- package/src/EditorImage.ts +12 -0
- package/src/Pointer.ts +19 -0
- package/src/SVGLoader.ts +20 -15
- package/src/Viewport.ts +50 -11
- package/src/commands/invertCommand.ts +1 -1
- package/src/components/AbstractComponent.ts +52 -2
- package/src/lib.ts +6 -3
- package/src/math/Mat33.ts +1 -1
- package/src/rendering/Display.ts +12 -15
- package/src/rendering/RenderingStyle.ts +1 -1
- package/src/rendering/lib.ts +4 -0
- package/src/rendering/renderers/DummyRenderer.ts +2 -3
- package/src/rendering/renderers/SVGRenderer.ts +4 -0
- package/src/rendering/renderers/TextOnlyRenderer.ts +0 -1
- package/src/toolbar/HTMLToolbar.ts +81 -5
- package/src/toolbar/IconProvider.ts +132 -37
- package/src/toolbar/widgets/EraserToolWidget.ts +64 -5
- package/src/toolbar/widgets/PenToolWidget.ts +2 -2
- package/src/toolbar/widgets/SelectionToolWidget.ts +2 -2
- package/src/tools/Eraser.test.ts +79 -0
- package/src/tools/Eraser.ts +81 -17
- package/src/tools/PanZoom.ts +1 -1
- package/src/tools/PasteHandler.ts +12 -6
- package/src/tools/Pen.test.ts +44 -1
- package/src/tools/Pen.ts +53 -8
- package/src/tools/SelectionTool/Selection.ts +73 -23
- package/src/tools/SelectionTool/SelectionHandle.ts +9 -0
- package/src/tools/SelectionTool/SelectionTool.test.ts +138 -21
- package/src/tools/SelectionTool/SelectionTool.ts +70 -16
- package/src/tools/TextTool.ts +14 -8
- package/src/tools/ToolSwitcherShortcut.ts +10 -5
- package/src/tools/UndoRedoShortcut.ts +2 -5
- package/src/types.ts +2 -2
- package/typedoc.json +2 -2
@@ -2,12 +2,15 @@ var _a;
|
|
2
2
|
import SerializableCommand from '../commands/SerializableCommand';
|
3
3
|
import EditorImage from '../EditorImage';
|
4
4
|
import Mat33 from '../math/Mat33';
|
5
|
+
/**
|
6
|
+
* A base class for everything that can be added to an {@link EditorImage}.
|
7
|
+
*/
|
5
8
|
export default class AbstractComponent {
|
6
9
|
constructor(
|
7
10
|
// A unique identifier for the type of component
|
8
11
|
componentKind) {
|
9
12
|
this.componentKind = componentKind;
|
10
|
-
//
|
13
|
+
// Stores data attached by a loader.
|
11
14
|
this.loadSaveData = {};
|
12
15
|
this.lastChangedTime = (new Date()).getTime();
|
13
16
|
this.zIndex = AbstractComponent.zIndexCounter++;
|
@@ -18,7 +21,7 @@ export default class AbstractComponent {
|
|
18
21
|
}
|
19
22
|
}
|
20
23
|
// Returns a unique ID for this element.
|
21
|
-
// @see { @link EditorImage
|
24
|
+
// @see { @link lib!EditorImage.lookupElement }
|
22
25
|
getId() {
|
23
26
|
return this.id;
|
24
27
|
}
|
@@ -28,21 +31,47 @@ export default class AbstractComponent {
|
|
28
31
|
static registerComponent(componentKind, deserialize) {
|
29
32
|
this.deserializationCallbacks[componentKind] = deserialize !== null && deserialize !== void 0 ? deserialize : null;
|
30
33
|
}
|
34
|
+
/**
|
35
|
+
* Attach data that can be used while exporting the component (e.g. to SVG).
|
36
|
+
*
|
37
|
+
* This is intended for use by a {@link ImageLoader}.
|
38
|
+
*/
|
31
39
|
attachLoadSaveData(key, data) {
|
32
40
|
if (!this.loadSaveData[key]) {
|
33
41
|
this.loadSaveData[key] = [];
|
34
42
|
}
|
35
43
|
this.loadSaveData[key].push(data);
|
36
44
|
}
|
45
|
+
/** See {@link attachLoadSaveData} */
|
37
46
|
getLoadSaveData() {
|
38
47
|
return this.loadSaveData;
|
39
48
|
}
|
40
49
|
getZIndex() {
|
41
50
|
return this.zIndex;
|
42
51
|
}
|
52
|
+
/** @returns the bounding box of */
|
43
53
|
getBBox() {
|
44
54
|
return this.contentBBox;
|
45
55
|
}
|
56
|
+
/**
|
57
|
+
* @returns true if this component intersects `rect` -- it is entirely contained
|
58
|
+
* within the rectangle or one of the rectangle's edges intersects this component.
|
59
|
+
*/
|
60
|
+
intersectsRect(rect) {
|
61
|
+
// If this component intersects rect,
|
62
|
+
// it is either contained entirely within rect or intersects one of rect's edges.
|
63
|
+
// If contained within,
|
64
|
+
if (rect.containsRect(this.getBBox())) {
|
65
|
+
return true;
|
66
|
+
}
|
67
|
+
// Calculated bounding boxes can be slightly larger than their actual contents' bounding box.
|
68
|
+
// As such, test with more lines than just the rect's edges.
|
69
|
+
const testLines = [];
|
70
|
+
for (const subregion of rect.divideIntoGrid(2, 2)) {
|
71
|
+
testLines.push(...subregion.getEdges());
|
72
|
+
}
|
73
|
+
return testLines.some(edge => this.intersects(edge));
|
74
|
+
}
|
46
75
|
// Returns a command that, when applied, transforms this by [affineTransfm] and
|
47
76
|
// updates the editor.
|
48
77
|
transformBy(affineTransfm) {
|
@@ -183,6 +212,7 @@ AbstractComponent.TransformElementCommand = (_a = class extends SerializableComm
|
|
183
212
|
hadParent = true;
|
184
213
|
}
|
185
214
|
this.component.applyTransformation(newTransfm);
|
215
|
+
this.component.lastChangedTime = (new Date()).getTime();
|
186
216
|
// Add the element back to the document.
|
187
217
|
if (hadParent) {
|
188
218
|
EditorImage.addElement(this.component).apply(editor);
|
package/dist/src/lib.d.ts
CHANGED
@@ -8,22 +8,25 @@
|
|
8
8
|
* ```
|
9
9
|
*
|
10
10
|
* @see
|
11
|
-
* {@link Editor
|
11
|
+
* {@link Editor}
|
12
12
|
*
|
13
13
|
* @packageDocumentation
|
14
14
|
*/
|
15
|
-
import Editor from './Editor';
|
15
|
+
import Editor, { EditorSettings } from './Editor';
|
16
16
|
export { default as EditorImage } from './EditorImage';
|
17
17
|
export * from './types';
|
18
18
|
export { default as getLocalizationTable } from './localizations/getLocalizationTable';
|
19
19
|
export * from './localization';
|
20
20
|
export { default as Color4 } from './Color4';
|
21
|
+
export { default as SVGLoader } from './SVGLoader';
|
22
|
+
export { default as Viewport } from './Viewport';
|
21
23
|
export * from './math/lib';
|
22
24
|
export * from './components/lib';
|
23
25
|
export * from './commands/lib';
|
24
26
|
export * from './tools/lib';
|
25
27
|
export * from './toolbar/lib';
|
28
|
+
export * from './rendering/lib';
|
26
29
|
export { default as Pointer, PointerDevice } from './Pointer';
|
27
30
|
export { default as HTMLToolbar } from './toolbar/HTMLToolbar';
|
28
|
-
export { Editor };
|
31
|
+
export { Editor, EditorSettings };
|
29
32
|
export default Editor;
|
package/dist/src/lib.js
CHANGED
@@ -8,7 +8,7 @@
|
|
8
8
|
* ```
|
9
9
|
*
|
10
10
|
* @see
|
11
|
-
* {@link Editor
|
11
|
+
* {@link Editor}
|
12
12
|
*
|
13
13
|
* @packageDocumentation
|
14
14
|
*/
|
@@ -18,11 +18,14 @@ export * from './types';
|
|
18
18
|
export { default as getLocalizationTable } from './localizations/getLocalizationTable';
|
19
19
|
export * from './localization';
|
20
20
|
export { default as Color4 } from './Color4';
|
21
|
+
export { default as SVGLoader } from './SVGLoader';
|
22
|
+
export { default as Viewport } from './Viewport';
|
21
23
|
export * from './math/lib';
|
22
24
|
export * from './components/lib';
|
23
25
|
export * from './commands/lib';
|
24
26
|
export * from './tools/lib';
|
25
27
|
export * from './toolbar/lib';
|
28
|
+
export * from './rendering/lib';
|
26
29
|
export { default as Pointer, PointerDevice } from './Pointer';
|
27
30
|
export { default as HTMLToolbar } from './toolbar/HTMLToolbar';
|
28
31
|
export { Editor };
|
package/dist/src/math/Mat33.d.ts
CHANGED
@@ -102,7 +102,7 @@ export default class Mat33 {
|
|
102
102
|
static translation(amount: Vec2): Mat33;
|
103
103
|
static zRotation(radians: number, center?: Point2): Mat33;
|
104
104
|
static scaling2D(amount: number | Vec2, center?: Point2): Mat33;
|
105
|
-
/** @see {@link
|
105
|
+
/** @see {@link fromCSSMatrix} */
|
106
106
|
toCSSMatrix(): string;
|
107
107
|
/**
|
108
108
|
* Converts a CSS-form `matrix(a, b, c, d, e, f)` to a Mat33.
|
package/dist/src/math/Mat33.js
CHANGED
@@ -241,7 +241,7 @@ export default class Mat33 {
|
|
241
241
|
// Translate such that [center] goes to (0, 0)
|
242
242
|
return result.rightMul(Mat33.translation(center.times(-1)));
|
243
243
|
}
|
244
|
-
/** @see {@link
|
244
|
+
/** @see {@link fromCSSMatrix} */
|
245
245
|
toCSSMatrix() {
|
246
246
|
return `matrix(${this.a1},${this.b1},${this.a2},${this.b2},${this.a3},${this.b3})`;
|
247
247
|
}
|
@@ -1,3 +1,12 @@
|
|
1
|
+
import AbstractRenderer from './renderers/AbstractRenderer';
|
2
|
+
import { Editor } from '../Editor';
|
3
|
+
import { Point2 } from '../math/Vec2';
|
4
|
+
import RenderingCache from './caching/RenderingCache';
|
5
|
+
import Color4 from '../Color4';
|
6
|
+
export declare enum RenderingMode {
|
7
|
+
DummyRenderer = 0,
|
8
|
+
CanvasRenderer = 1
|
9
|
+
}
|
1
10
|
/**
|
2
11
|
* Handles `HTMLCanvasElement`s (or other drawing surfaces if being used) used to display the editor's contents.
|
3
12
|
*
|
@@ -9,18 +18,7 @@
|
|
9
18
|
* const center = Vec2.of(w / 2, h / 2);
|
10
19
|
* const colorAtCenter = editor.display.getColorAt(center);
|
11
20
|
* ```
|
12
|
-
*
|
13
|
-
* @packageDocumentation
|
14
21
|
*/
|
15
|
-
import AbstractRenderer from './renderers/AbstractRenderer';
|
16
|
-
import { Editor } from '../Editor';
|
17
|
-
import { Point2 } from '../math/Vec2';
|
18
|
-
import RenderingCache from './caching/RenderingCache';
|
19
|
-
import Color4 from '../Color4';
|
20
|
-
export declare enum RenderingMode {
|
21
|
-
DummyRenderer = 0,
|
22
|
-
CanvasRenderer = 1
|
23
|
-
}
|
24
22
|
export default class Display {
|
25
23
|
private editor;
|
26
24
|
private parent;
|
@@ -1,17 +1,3 @@
|
|
1
|
-
/**
|
2
|
-
* Handles `HTMLCanvasElement`s (or other drawing surfaces if being used) used to display the editor's contents.
|
3
|
-
*
|
4
|
-
* @example
|
5
|
-
* ```
|
6
|
-
* const editor = new Editor(document.body);
|
7
|
-
* const w = editor.display.width;
|
8
|
-
* const h = editor.display.height;
|
9
|
-
* const center = Vec2.of(w / 2, h / 2);
|
10
|
-
* const colorAtCenter = editor.display.getColorAt(center);
|
11
|
-
* ```
|
12
|
-
*
|
13
|
-
* @packageDocumentation
|
14
|
-
*/
|
15
1
|
import CanvasRenderer from './renderers/CanvasRenderer';
|
16
2
|
import { EditorEventType } from '../types';
|
17
3
|
import DummyRenderer from './renderers/DummyRenderer';
|
@@ -25,6 +11,18 @@ export var RenderingMode;
|
|
25
11
|
RenderingMode[RenderingMode["CanvasRenderer"] = 1] = "CanvasRenderer";
|
26
12
|
// SVGRenderer is not supported by the main display
|
27
13
|
})(RenderingMode || (RenderingMode = {}));
|
14
|
+
/**
|
15
|
+
* Handles `HTMLCanvasElement`s (or other drawing surfaces if being used) used to display the editor's contents.
|
16
|
+
*
|
17
|
+
* @example
|
18
|
+
* ```
|
19
|
+
* const editor = new Editor(document.body);
|
20
|
+
* const w = editor.display.width;
|
21
|
+
* const h = editor.display.height;
|
22
|
+
* const center = Vec2.of(w / 2, h / 2);
|
23
|
+
* const colorAtCenter = editor.display.getColorAt(center);
|
24
|
+
* ```
|
25
|
+
*/
|
28
26
|
export default class Display {
|
29
27
|
/** @internal */
|
30
28
|
constructor(editor, mode, parent) {
|
@@ -1,6 +1,6 @@
|
|
1
|
-
// Renderer that outputs nothing. Useful for automated tests.
|
2
1
|
import { Vec2 } from '../../math/Vec2';
|
3
2
|
import AbstractRenderer from './AbstractRenderer';
|
3
|
+
// Renderer that outputs almost nothing. Useful for automated tests.
|
4
4
|
export default class DummyRenderer extends AbstractRenderer {
|
5
5
|
constructor(viewport) {
|
6
6
|
super(viewport);
|
@@ -17,7 +17,7 @@ export default class DummyRenderer extends AbstractRenderer {
|
|
17
17
|
}
|
18
18
|
displaySize() {
|
19
19
|
// Do we have a stored viewport size?
|
20
|
-
const viewportSize = this.getViewport().
|
20
|
+
const viewportSize = this.getViewport().getScreenRectSize();
|
21
21
|
// Don't use a 0x0 viewport — DummyRenderer is often used
|
22
22
|
// for tests that run without a display, so pretend we have a
|
23
23
|
// reasonable-sized display.
|
@@ -31,6 +31,10 @@ export default class SVGRenderer extends AbstractRenderer {
|
|
31
31
|
stroke-linecap: round;
|
32
32
|
stroke-linejoin: round;
|
33
33
|
}
|
34
|
+
|
35
|
+
text {
|
36
|
+
white-space: pre;
|
37
|
+
}
|
34
38
|
`.replace(/\s+/g, '');
|
35
39
|
styleSheet.setAttribute('id', renderedStylesheetId);
|
36
40
|
this.elem.appendChild(styleSheet);
|
@@ -3,6 +3,11 @@ import { ToolbarLocalization } from './localization';
|
|
3
3
|
import { ActionButtonIcon } from './types';
|
4
4
|
import BaseWidget from './widgets/BaseWidget';
|
5
5
|
export declare const toolbarCSSPrefix = "toolbar-";
|
6
|
+
interface SpacerOptions {
|
7
|
+
grow: number;
|
8
|
+
minSize: string;
|
9
|
+
maxSize: string;
|
10
|
+
}
|
6
11
|
export default class HTMLToolbar {
|
7
12
|
private editor;
|
8
13
|
private localizationTable;
|
@@ -13,8 +18,45 @@ export default class HTMLToolbar {
|
|
13
18
|
/** @internal */
|
14
19
|
constructor(editor: Editor, parent: HTMLElement, localizationTable?: ToolbarLocalization);
|
15
20
|
setupColorPickers(): void;
|
21
|
+
/**
|
22
|
+
* Adds an `ActionButtonWidget` or `BaseToolWidget`. The widget should not have already have a parent
|
23
|
+
* (i.e. its `addTo` method should not have been called).
|
24
|
+
*
|
25
|
+
* @example
|
26
|
+
* ```ts
|
27
|
+
* const toolbar = editor.addToolbar();
|
28
|
+
* const insertImageWidget = new InsertImageWidget(editor);
|
29
|
+
* toolbar.addWidget(insertImageWidget);
|
30
|
+
* ```
|
31
|
+
*/
|
16
32
|
addWidget(widget: BaseWidget): void;
|
33
|
+
/**
|
34
|
+
* Adds a spacer.
|
35
|
+
*
|
36
|
+
* @example
|
37
|
+
* Adding a save button that moves to the very right edge of the toolbar
|
38
|
+
* while keeping the other buttons centered:
|
39
|
+
* ```ts
|
40
|
+
* const toolbar = editor.addToolbar(false);
|
41
|
+
*
|
42
|
+
* toolbar.addSpacer({ grow: 1 });
|
43
|
+
* toolbar.addDefaults();
|
44
|
+
* toolbar.addSpacer({ grow: 1 });
|
45
|
+
*
|
46
|
+
* toolbar.addActionButton({
|
47
|
+
* label: 'Save',
|
48
|
+
* icon: editor.icons.makeSaveIcon(),
|
49
|
+
* }, () => {
|
50
|
+
* saveCallback();
|
51
|
+
* });
|
52
|
+
* ```
|
53
|
+
*/
|
54
|
+
addSpacer(options?: Partial<SpacerOptions>): void;
|
17
55
|
serializeState(): string;
|
56
|
+
/**
|
57
|
+
* Deserialize toolbar widgets from the given state.
|
58
|
+
* Assumes that toolbar widgets are in the same order as when state was serialized.
|
59
|
+
*/
|
18
60
|
deserializeState(state: string): void;
|
19
61
|
/**
|
20
62
|
* Adds an action button with `title` to this toolbar (or to the given `parent` element).
|
@@ -25,4 +67,13 @@ export default class HTMLToolbar {
|
|
25
67
|
addUndoRedoButtons(): void;
|
26
68
|
addDefaultToolWidgets(): void;
|
27
69
|
addDefaultActionButtons(): void;
|
70
|
+
/**
|
71
|
+
* Adds both the default tool widgets and action buttons. Equivalent to
|
72
|
+
* ```ts
|
73
|
+
* toolbar.addDefaultToolWidgets();
|
74
|
+
* toolbar.addDefaultActionButtons();
|
75
|
+
* ```
|
76
|
+
*/
|
77
|
+
addDefaults(): void;
|
28
78
|
}
|
79
|
+
export {};
|
@@ -12,7 +12,8 @@ import EraserWidget from './widgets/EraserToolWidget';
|
|
12
12
|
import SelectionToolWidget from './widgets/SelectionToolWidget';
|
13
13
|
import TextToolWidget from './widgets/TextToolWidget';
|
14
14
|
import HandToolWidget from './widgets/HandToolWidget';
|
15
|
-
import
|
15
|
+
import ActionButtonWidget from './widgets/ActionButtonWidget';
|
16
|
+
import InsertImageWidget from './widgets/InsertImageWidget';
|
16
17
|
export const toolbarCSSPrefix = 'toolbar-';
|
17
18
|
export default class HTMLToolbar {
|
18
19
|
/** @internal */
|
@@ -94,8 +95,17 @@ export default class HTMLToolbar {
|
|
94
95
|
}
|
95
96
|
});
|
96
97
|
}
|
97
|
-
|
98
|
-
|
98
|
+
/**
|
99
|
+
* Adds an `ActionButtonWidget` or `BaseToolWidget`. The widget should not have already have a parent
|
100
|
+
* (i.e. its `addTo` method should not have been called).
|
101
|
+
*
|
102
|
+
* @example
|
103
|
+
* ```ts
|
104
|
+
* const toolbar = editor.addToolbar();
|
105
|
+
* const insertImageWidget = new InsertImageWidget(editor);
|
106
|
+
* toolbar.addWidget(insertImageWidget);
|
107
|
+
* ```
|
108
|
+
*/
|
99
109
|
addWidget(widget) {
|
100
110
|
// Prevent name collisions
|
101
111
|
const id = widget.getUniqueIdIn(this.widgets);
|
@@ -105,6 +115,41 @@ export default class HTMLToolbar {
|
|
105
115
|
widget.addTo(this.container);
|
106
116
|
this.setupColorPickers();
|
107
117
|
}
|
118
|
+
/**
|
119
|
+
* Adds a spacer.
|
120
|
+
*
|
121
|
+
* @example
|
122
|
+
* Adding a save button that moves to the very right edge of the toolbar
|
123
|
+
* while keeping the other buttons centered:
|
124
|
+
* ```ts
|
125
|
+
* const toolbar = editor.addToolbar(false);
|
126
|
+
*
|
127
|
+
* toolbar.addSpacer({ grow: 1 });
|
128
|
+
* toolbar.addDefaults();
|
129
|
+
* toolbar.addSpacer({ grow: 1 });
|
130
|
+
*
|
131
|
+
* toolbar.addActionButton({
|
132
|
+
* label: 'Save',
|
133
|
+
* icon: editor.icons.makeSaveIcon(),
|
134
|
+
* }, () => {
|
135
|
+
* saveCallback();
|
136
|
+
* });
|
137
|
+
* ```
|
138
|
+
*/
|
139
|
+
addSpacer(options = {}) {
|
140
|
+
const spacer = document.createElement('div');
|
141
|
+
spacer.classList.add(`${toolbarCSSPrefix}spacer`);
|
142
|
+
if (options.grow) {
|
143
|
+
spacer.style.flexGrow = `${options.grow}`;
|
144
|
+
}
|
145
|
+
if (options.minSize) {
|
146
|
+
spacer.style.minWidth = options.minSize;
|
147
|
+
}
|
148
|
+
if (options.maxSize) {
|
149
|
+
spacer.style.maxWidth = options.maxSize;
|
150
|
+
}
|
151
|
+
this.container.appendChild(spacer);
|
152
|
+
}
|
108
153
|
serializeState() {
|
109
154
|
const result = {};
|
110
155
|
for (const widgetId in this.widgets) {
|
@@ -112,8 +157,10 @@ export default class HTMLToolbar {
|
|
112
157
|
}
|
113
158
|
return JSON.stringify(result);
|
114
159
|
}
|
115
|
-
|
116
|
-
|
160
|
+
/**
|
161
|
+
* Deserialize toolbar widgets from the given state.
|
162
|
+
* Assumes that toolbar widgets are in the same order as when state was serialized.
|
163
|
+
*/
|
117
164
|
deserializeState(state) {
|
118
165
|
const data = JSON.parse(state);
|
119
166
|
for (const widgetId in data) {
|
@@ -188,5 +235,16 @@ export default class HTMLToolbar {
|
|
188
235
|
addDefaultActionButtons() {
|
189
236
|
this.addUndoRedoButtons();
|
190
237
|
}
|
238
|
+
/**
|
239
|
+
* Adds both the default tool widgets and action buttons. Equivalent to
|
240
|
+
* ```ts
|
241
|
+
* toolbar.addDefaultToolWidgets();
|
242
|
+
* toolbar.addDefaultActionButtons();
|
243
|
+
* ```
|
244
|
+
*/
|
245
|
+
addDefaults() {
|
246
|
+
this.addDefaultToolWidgets();
|
247
|
+
this.addDefaultActionButtons();
|
248
|
+
}
|
191
249
|
}
|
192
250
|
HTMLToolbar.colorisStarted = false;
|
@@ -7,7 +7,7 @@ export default class IconProvider {
|
|
7
7
|
makeUndoIcon(): IconType;
|
8
8
|
makeRedoIcon(mirror?: boolean): IconType;
|
9
9
|
makeDropdownIcon(): IconType;
|
10
|
-
makeEraserIcon(): IconType;
|
10
|
+
makeEraserIcon(eraserSize?: number): IconType;
|
11
11
|
makeSelectionIcon(): IconType;
|
12
12
|
/**
|
13
13
|
* @param pathData - SVG path data (e.g. `m10,10l30,30z`)
|
@@ -21,7 +21,7 @@ export default class IconProvider {
|
|
21
21
|
makeRotationLockIcon(): IconType;
|
22
22
|
makeInsertImageIcon(): IconType;
|
23
23
|
makeTextIcon(textStyle: TextStyle): IconType;
|
24
|
-
makePenIcon(
|
24
|
+
makePenIcon(strokeSize: number, color: string | Color4, rounded?: boolean): IconType;
|
25
25
|
makeIconFromFactory(pen: Pen, factory: ComponentBuilderFactory): IconType;
|
26
26
|
makePipetteIcon(color?: Color4): IconType;
|
27
27
|
makeResizeViewportIcon(): IconType;
|
@@ -30,7 +30,7 @@ export default class IconProvider {
|
|
30
30
|
makeUndoIcon() {
|
31
31
|
return this.makeRedoIcon(true);
|
32
32
|
}
|
33
|
-
// @param mirror - reflect across the x-axis
|
33
|
+
// @param mirror - reflect across the x-axis. This parameter is internal.
|
34
34
|
// @returns a redo icon.
|
35
35
|
makeRedoIcon(mirror = false) {
|
36
36
|
const icon = document.createElementNS(svgNamespace, 'svg');
|
@@ -67,19 +67,46 @@ export default class IconProvider {
|
|
67
67
|
icon.setAttribute('viewBox', '0 0 100 100');
|
68
68
|
return icon;
|
69
69
|
}
|
70
|
-
makeEraserIcon() {
|
70
|
+
makeEraserIcon(eraserSize) {
|
71
71
|
const icon = document.createElementNS(svgNamespace, 'svg');
|
72
|
-
|
72
|
+
eraserSize !== null && eraserSize !== void 0 ? eraserSize : (eraserSize = 10);
|
73
|
+
const scaledSize = eraserSize / 4;
|
74
|
+
const eraserColor = '#ff70af';
|
75
|
+
// Draw an eraser-like shape. Created with Inkscape
|
73
76
|
icon.innerHTML = `
|
74
77
|
<g>
|
75
|
-
<
|
78
|
+
<path
|
79
|
+
style="fill:${eraserColor}"
|
80
|
+
stroke="black"
|
81
|
+
transform="rotate(41.35)"
|
82
|
+
d="M 52.5 27
|
83
|
+
C 50 28.9 48.9 31.7 48.9 34.8
|
84
|
+
L 48.9 39.8
|
85
|
+
C 48.9 45.3 53.4 49.8 58.9 49.8
|
86
|
+
L 103.9 49.8
|
87
|
+
C 105.8 49.8 107.6 49.2 109.1 48.3
|
88
|
+
L 110.2 ${scaledSize + 49.5} L 159.7 ${scaledSize + 5}
|
89
|
+
L 157.7 ${-scaledSize + 5.2} L 112.4 ${49.5 - scaledSize}
|
90
|
+
C 113.4 43.5 113.9 41.7 113.9 39.8
|
91
|
+
L 113.9 34.8
|
92
|
+
C 113.9 29.3 109.4 24.8 103.9 24.8
|
93
|
+
L 58.9 24.8
|
94
|
+
C 56.5 24.8 54.3 25.7 52.5 27
|
95
|
+
z "
|
96
|
+
id="path438" />
|
97
|
+
|
76
98
|
<rect
|
77
|
-
|
99
|
+
stroke="#cc8077"
|
78
100
|
${iconColorFill}
|
79
|
-
|
101
|
+
id="rect218"
|
102
|
+
width="65"
|
103
|
+
height="75"
|
104
|
+
x="48.9"
|
105
|
+
y="-38.7"
|
106
|
+
transform="rotate(41.35)" />
|
80
107
|
</g>
|
81
108
|
`;
|
82
|
-
icon.setAttribute('viewBox', '0 0
|
109
|
+
icon.setAttribute('viewBox', '0 0 120 120');
|
83
110
|
return icon;
|
84
111
|
}
|
85
112
|
makeSelectionIcon() {
|
@@ -309,45 +336,106 @@ export default class IconProvider {
|
|
309
336
|
icon.appendChild(textNode);
|
310
337
|
return icon;
|
311
338
|
}
|
312
|
-
makePenIcon(
|
339
|
+
makePenIcon(strokeSize, color, rounded) {
|
313
340
|
if (color instanceof Color4) {
|
314
341
|
color = color.toHexString();
|
315
342
|
}
|
316
343
|
const icon = document.createElementNS(svgNamespace, 'svg');
|
317
344
|
icon.setAttribute('viewBox', '0 0 100 100');
|
318
|
-
const
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
345
|
+
const tipThickness = strokeSize / 2;
|
346
|
+
const inkTipPath = `
|
347
|
+
M ${15 - tipThickness},${80 - tipThickness}
|
348
|
+
${15 - tipThickness},${80 + tipThickness}
|
349
|
+
30,83
|
350
|
+
15,65
|
351
|
+
Z
|
352
|
+
`;
|
353
|
+
const trailStartEndY = 80 + tipThickness;
|
354
|
+
const inkTrailPath = `
|
355
|
+
m ${15 - tipThickness * 1.1},${trailStartEndY}
|
356
|
+
c 35,10 55,15 60,30
|
357
|
+
l ${35 + tipThickness * 1.2},${-10 - tipThickness}
|
358
|
+
C 80.47,98.32 50.5,${90 + tipThickness} 20,${trailStartEndY} Z
|
359
|
+
`;
|
360
|
+
const colorBubblePath = `
|
361
|
+
M 72.45,35.67
|
362
|
+
A 10,15 41.8 0 1 55,40.2 10,15 41.8 0 1 57.55,22.3 10,15 41.8 0 1 75,17.8 10,15 41.8 0 1 72.5,35.67
|
363
|
+
Z
|
364
|
+
`;
|
365
|
+
let gripMainPath = 'M 85,-25 25,35 h 10 v 10 h 10 v 10 h 10 v 10 h 10 l -5,10 60,-60 z';
|
366
|
+
let gripShadow1Path = 'M 25,35 H 35 L 90,-15 85,-25 Z';
|
367
|
+
let gripShadow2Path = 'M 60,75 65,65 H 55 l 55,-55 10,5 z';
|
368
|
+
if (rounded) {
|
369
|
+
gripMainPath = 'M 85,-25 25,35 c 15,0 40,30 35,40 l 60,-60 z';
|
370
|
+
gripShadow1Path = 'm 25,35 c 3.92361,0.384473 7.644275,0.980572 10,3 l 55,-53 -5,-10 z';
|
371
|
+
gripShadow2Path = 'M 60,75 C 61,66 59,65 56,59 l 54,-54 10,10 z';
|
327
372
|
}
|
328
|
-
const
|
329
|
-
const
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
373
|
+
const penTipPath = `M 25,35 ${10 - tipThickness / 4},${70 - tipThickness / 2} 20,75 25,85 60,75 70,55 45,25 Z`;
|
374
|
+
const pencilTipColor = Color4.fromHex('#f4d7d7');
|
375
|
+
const tipColor = pencilTipColor.mix(Color4.fromString(color), tipThickness / 40 - 0.1).toHexString();
|
376
|
+
const ink = `
|
377
|
+
<path
|
378
|
+
fill="${checkerboardPatternRef}"
|
379
|
+
d="${inkTipPath}"
|
380
|
+
/>
|
381
|
+
<path
|
382
|
+
fill="${checkerboardPatternRef}"
|
383
|
+
d="${inkTrailPath}"
|
384
|
+
/>
|
385
|
+
<path
|
386
|
+
fill="${color}"
|
387
|
+
d="${inkTipPath}"
|
388
|
+
/>
|
389
|
+
<path
|
390
|
+
fill="${color}"
|
391
|
+
d="${inkTrailPath}"
|
392
|
+
/>
|
393
|
+
`;
|
394
|
+
const penTip = `
|
395
|
+
<path
|
396
|
+
fill="${checkerboardPatternRef}"
|
397
|
+
d="${penTipPath}"
|
398
|
+
/>
|
399
|
+
<path
|
400
|
+
fill="${tipColor}"
|
401
|
+
stroke="${color}"
|
402
|
+
d="${penTipPath}"
|
403
|
+
/>
|
404
|
+
`;
|
405
|
+
const grip = `
|
336
406
|
<path
|
337
|
-
d='M10,10 L90,10 L90,60 L${50 + halfThickness},80 L${50 - halfThickness},80 L10,60 Z'
|
338
407
|
${iconColorStrokeFill}
|
408
|
+
d="${gripMainPath}"
|
409
|
+
/>
|
410
|
+
|
411
|
+
<!-- shadows -->
|
412
|
+
<path
|
413
|
+
fill="rgba(150, 150, 150, 0.3)"
|
414
|
+
d="${gripShadow1Path}"
|
339
415
|
/>
|
340
|
-
</g>
|
341
|
-
<g>
|
342
|
-
<!-- Checkerboard background for slightly transparent pens -->
|
343
|
-
<path d='${backgroundStrokeTipPath}' fill='${checkerboardPatternRef}'/>
|
344
|
-
|
345
|
-
<!-- Actual pen tip -->
|
346
416
|
<path
|
347
|
-
|
348
|
-
|
349
|
-
stroke='${color}'
|
417
|
+
fill="rgba(100, 100, 100, 0.2)"
|
418
|
+
d="${gripShadow2Path}"
|
350
419
|
/>
|
420
|
+
|
421
|
+
<!-- color bubble -->
|
422
|
+
<path
|
423
|
+
fill="${checkerboardPatternRef}"
|
424
|
+
d="${colorBubblePath}"
|
425
|
+
/>
|
426
|
+
<path
|
427
|
+
fill="${color}"
|
428
|
+
d="${colorBubblePath}"
|
429
|
+
/>
|
430
|
+
`;
|
431
|
+
icon.innerHTML = `
|
432
|
+
<defs>
|
433
|
+
${checkerboardPatternDef}
|
434
|
+
</defs>
|
435
|
+
<g>
|
436
|
+
${ink}
|
437
|
+
${penTip}
|
438
|
+
${grip}
|
351
439
|
</g>
|
352
440
|
`;
|
353
441
|
return icon;
|
@@ -2,9 +2,16 @@ import Editor from '../../Editor';
|
|
2
2
|
import Eraser from '../../tools/Eraser';
|
3
3
|
import { ToolbarLocalization } from '../localization';
|
4
4
|
import BaseToolWidget from './BaseToolWidget';
|
5
|
+
import { SavedToolbuttonState } from './BaseWidget';
|
5
6
|
export default class EraserToolWidget extends BaseToolWidget {
|
7
|
+
private tool;
|
8
|
+
private thicknessInput;
|
6
9
|
constructor(editor: Editor, tool: Eraser, localizationTable?: ToolbarLocalization);
|
7
10
|
protected getTitle(): string;
|
8
11
|
protected createIcon(): Element;
|
9
|
-
|
12
|
+
private updateInputs;
|
13
|
+
private static nextThicknessInputId;
|
14
|
+
protected fillDropdown(dropdown: HTMLElement): boolean;
|
15
|
+
serializeState(): SavedToolbuttonState;
|
16
|
+
deserializeFrom(state: SavedToolbuttonState): void;
|
10
17
|
}
|