js-draw 0.1.11 → 0.2.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/.eslintrc.js +1 -0
- package/.firebaserc +5 -0
- package/.github/workflows/firebase-hosting-merge.yml +25 -0
- package/.github/workflows/firebase-hosting-pull-request.yml +22 -0
- package/.github/workflows/github-pages.yml +52 -0
- package/CHANGELOG.md +13 -0
- package/README.md +11 -6
- package/dist/bundle.js +1 -1
- package/dist/src/Color4.d.ts +19 -0
- package/dist/src/Color4.js +24 -3
- package/dist/src/Editor.d.ts +133 -4
- package/dist/src/Editor.js +124 -27
- package/dist/src/EditorImage.d.ts +8 -3
- package/dist/src/EditorImage.js +42 -26
- package/dist/src/EventDispatcher.d.ts +18 -0
- package/dist/src/EventDispatcher.js +19 -4
- package/dist/src/Pointer.d.ts +1 -1
- package/dist/src/Pointer.js +4 -3
- package/dist/src/SVGLoader.d.ts +1 -1
- package/dist/src/SVGLoader.js +14 -6
- package/dist/src/UndoRedoHistory.js +15 -2
- package/dist/src/Viewport.d.ts +8 -25
- package/dist/src/Viewport.js +18 -10
- package/dist/src/bundle/bundled.d.ts +1 -2
- package/dist/src/bundle/bundled.js +1 -2
- package/dist/src/commands/Command.d.ts +2 -2
- package/dist/src/commands/Command.js +4 -4
- package/dist/src/commands/Duplicate.d.ts +2 -2
- package/dist/src/commands/Duplicate.js +4 -5
- package/dist/src/commands/Erase.d.ts +2 -2
- package/dist/src/commands/Erase.js +7 -6
- package/dist/src/commands/SerializableCommand.d.ts +4 -5
- package/dist/src/commands/SerializableCommand.js +12 -4
- package/dist/src/commands/invertCommand.d.ts +4 -0
- package/dist/src/commands/invertCommand.js +44 -0
- package/dist/src/commands/lib.d.ts +6 -0
- package/dist/src/commands/lib.js +6 -0
- package/dist/src/commands/localization.d.ts +2 -1
- package/dist/src/commands/localization.js +1 -0
- package/dist/src/components/AbstractComponent.d.ts +16 -11
- package/dist/src/components/AbstractComponent.js +28 -17
- package/dist/src/components/SVGGlobalAttributesObject.d.ts +4 -4
- package/dist/src/components/SVGGlobalAttributesObject.js +8 -2
- package/dist/src/components/Stroke.d.ts +16 -6
- package/dist/src/components/Stroke.js +12 -9
- package/dist/src/components/Text.d.ts +5 -5
- package/dist/src/components/Text.js +9 -9
- package/dist/src/components/UnknownSVGObject.d.ts +4 -4
- package/dist/src/components/UnknownSVGObject.js +7 -2
- package/dist/src/components/builders/ArrowBuilder.d.ts +1 -1
- package/dist/src/components/builders/ArrowBuilder.js +1 -1
- package/dist/src/components/builders/FreehandLineBuilder.d.ts +8 -3
- package/dist/src/components/builders/FreehandLineBuilder.js +142 -71
- package/dist/src/components/builders/LineBuilder.d.ts +1 -1
- package/dist/src/components/builders/LineBuilder.js +1 -1
- package/dist/src/components/builders/RectangleBuilder.d.ts +1 -1
- package/dist/src/components/builders/RectangleBuilder.js +3 -3
- package/dist/src/components/builders/types.d.ts +1 -1
- package/dist/src/components/lib.d.ts +4 -0
- package/dist/src/components/lib.js +4 -0
- package/dist/src/lib.d.ts +25 -0
- package/dist/src/lib.js +25 -0
- package/dist/src/localization.d.ts +1 -0
- package/dist/src/localization.js +5 -1
- package/dist/src/localizations/es.js +1 -1
- package/dist/src/{geometry → math}/LineSegment2.d.ts +0 -0
- package/dist/src/{geometry → math}/LineSegment2.js +0 -0
- package/dist/src/math/Mat33.d.ts +78 -0
- package/dist/src/{geometry → math}/Mat33.js +48 -20
- package/dist/src/{geometry → math}/Path.d.ts +2 -1
- package/dist/src/{geometry → math}/Path.js +59 -52
- package/dist/src/{geometry → math}/Rect2.d.ts +2 -2
- package/dist/src/{geometry → math}/Rect2.js +0 -0
- package/dist/src/{geometry → math}/Vec2.d.ts +0 -0
- package/dist/src/{geometry → math}/Vec2.js +0 -0
- package/dist/src/math/Vec3.d.ts +96 -0
- package/dist/src/{geometry → math}/Vec3.js +63 -15
- package/dist/src/math/lib.d.ts +7 -0
- package/dist/src/math/lib.js +7 -0
- package/dist/src/math/rounding.d.ts +3 -0
- package/dist/src/math/rounding.js +121 -0
- package/dist/src/rendering/Display.d.ts +47 -1
- package/dist/src/rendering/Display.js +60 -15
- package/dist/src/rendering/caching/CacheRecord.d.ts +3 -2
- package/dist/src/rendering/caching/CacheRecord.js +4 -1
- package/dist/src/rendering/caching/CacheRecordManager.d.ts +5 -4
- package/dist/src/rendering/caching/CacheRecordManager.js +16 -4
- package/dist/src/rendering/caching/RenderingCache.d.ts +2 -3
- package/dist/src/rendering/caching/RenderingCache.js +10 -11
- package/dist/src/rendering/caching/RenderingCacheNode.d.ts +2 -1
- package/dist/src/rendering/caching/RenderingCacheNode.js +18 -7
- package/dist/src/rendering/caching/testUtils.js +1 -1
- package/dist/src/rendering/caching/types.d.ts +2 -4
- package/dist/src/rendering/localization.d.ts +2 -0
- package/dist/src/rendering/localization.js +2 -0
- package/dist/src/rendering/renderers/AbstractRenderer.d.ts +4 -4
- package/dist/src/rendering/renderers/AbstractRenderer.js +2 -2
- package/dist/src/rendering/renderers/CanvasRenderer.d.ts +4 -4
- package/dist/src/rendering/renderers/CanvasRenderer.js +2 -2
- package/dist/src/rendering/renderers/DummyRenderer.d.ts +4 -4
- package/dist/src/rendering/renderers/DummyRenderer.js +1 -1
- package/dist/src/rendering/renderers/SVGRenderer.d.ts +3 -3
- package/dist/src/rendering/renderers/SVGRenderer.js +8 -2
- package/dist/src/rendering/renderers/TextOnlyRenderer.d.ts +5 -3
- package/dist/src/rendering/renderers/TextOnlyRenderer.js +13 -3
- package/dist/src/toolbar/HTMLToolbar.js +1 -0
- package/dist/src/toolbar/icons.d.ts +3 -0
- package/dist/src/toolbar/icons.js +142 -132
- package/dist/src/toolbar/localization.d.ts +2 -1
- package/dist/src/toolbar/localization.js +2 -1
- package/dist/src/toolbar/makeColorInput.js +3 -2
- package/dist/src/toolbar/widgets/ActionButtonWidget.d.ts +13 -0
- package/dist/src/toolbar/widgets/ActionButtonWidget.js +21 -0
- package/dist/src/toolbar/widgets/BaseWidget.js +2 -0
- package/dist/src/toolbar/widgets/HandToolWidget.js +3 -3
- package/dist/src/toolbar/widgets/PenWidget.js +1 -0
- package/dist/src/toolbar/widgets/SelectionWidget.d.ts +0 -1
- package/dist/src/toolbar/widgets/SelectionWidget.js +23 -30
- package/dist/src/tools/Eraser.js +1 -1
- package/dist/src/tools/PanZoom.d.ts +1 -1
- package/dist/src/tools/PanZoom.js +24 -14
- package/dist/src/tools/Pen.d.ts +1 -2
- package/dist/src/tools/Pen.js +8 -1
- package/dist/src/tools/PipetteTool.js +1 -0
- package/dist/src/tools/SelectionTool.d.ts +3 -3
- package/dist/src/tools/SelectionTool.js +51 -28
- package/dist/src/tools/TextTool.js +1 -1
- package/dist/src/types.d.ts +21 -10
- package/dist/src/types.js +7 -5
- package/firebase.json +16 -0
- package/package.json +118 -101
- package/src/Color4.ts +23 -2
- package/src/Editor.ts +181 -37
- package/src/EditorImage.test.ts +2 -4
- package/src/EditorImage.ts +46 -28
- package/src/EventDispatcher.ts +21 -6
- package/src/Pointer.ts +4 -3
- package/src/SVGLoader.ts +14 -6
- package/src/UndoRedoHistory.ts +18 -2
- package/src/Viewport.ts +23 -18
- package/src/bundle/bundled.ts +1 -2
- package/src/commands/Command.ts +5 -5
- package/src/commands/Duplicate.ts +4 -5
- package/src/commands/Erase.ts +7 -6
- package/src/commands/SerializableCommand.ts +17 -9
- package/src/commands/invertCommand.ts +51 -0
- package/src/commands/lib.ts +14 -0
- package/src/commands/localization.ts +3 -1
- package/src/components/AbstractComponent.ts +35 -24
- package/src/components/SVGGlobalAttributesObject.ts +11 -4
- package/src/components/Stroke.test.ts +4 -6
- package/src/components/Stroke.ts +15 -11
- package/src/components/Text.test.ts +2 -2
- package/src/components/Text.ts +9 -10
- package/src/components/UnknownSVGObject.ts +10 -4
- package/src/components/builders/ArrowBuilder.ts +2 -2
- package/src/components/builders/FreehandLineBuilder.ts +190 -80
- package/src/components/builders/LineBuilder.ts +2 -2
- package/src/components/builders/RectangleBuilder.ts +3 -3
- package/src/components/builders/types.ts +1 -1
- package/src/components/lib.ts +9 -0
- package/src/lib.ts +28 -0
- package/src/localization.ts +6 -0
- package/src/localizations/es.ts +2 -1
- package/src/{geometry → math}/LineSegment2.test.ts +0 -0
- package/src/{geometry → math}/LineSegment2.ts +0 -0
- package/src/{geometry → math}/Mat33.test.ts +0 -0
- package/src/{geometry → math}/Mat33.ts +48 -20
- package/src/{geometry → math}/Path.fromString.test.ts +0 -0
- package/src/{geometry → math}/Path.test.ts +0 -0
- package/src/{geometry → math}/Path.toString.test.ts +11 -2
- package/src/{geometry → math}/Path.ts +61 -58
- package/src/{geometry → math}/Rect2.test.ts +0 -0
- package/src/{geometry → math}/Rect2.ts +2 -2
- package/src/{geometry → math}/Vec2.test.ts +0 -0
- package/src/{geometry → math}/Vec2.ts +0 -0
- package/src/{geometry → math}/Vec3.test.ts +0 -0
- package/src/{geometry → math}/Vec3.ts +64 -16
- package/src/math/lib.ts +15 -0
- package/src/math/rounding.test.ts +40 -0
- package/src/math/rounding.ts +147 -0
- package/src/rendering/Display.ts +63 -15
- package/src/rendering/caching/CacheRecord.test.ts +3 -3
- package/src/rendering/caching/CacheRecord.ts +6 -2
- package/src/rendering/caching/CacheRecordManager.ts +34 -8
- package/src/rendering/caching/RenderingCache.test.ts +3 -3
- package/src/rendering/caching/RenderingCache.ts +11 -16
- package/src/rendering/caching/RenderingCacheNode.ts +23 -7
- package/src/rendering/caching/testUtils.ts +1 -1
- package/src/rendering/caching/types.ts +2 -7
- package/src/rendering/localization.ts +4 -0
- package/src/rendering/renderers/AbstractRenderer.ts +4 -4
- package/src/rendering/renderers/CanvasRenderer.ts +5 -5
- package/src/rendering/renderers/DummyRenderer.test.ts +2 -2
- package/src/rendering/renderers/DummyRenderer.ts +4 -4
- package/src/rendering/renderers/SVGRenderer.ts +10 -4
- package/src/rendering/renderers/TextOnlyRenderer.ts +17 -6
- package/src/toolbar/HTMLToolbar.ts +1 -0
- package/src/toolbar/icons.ts +157 -137
- package/src/toolbar/localization.ts +4 -2
- package/src/toolbar/makeColorInput.ts +3 -2
- package/src/toolbar/toolbar.css +1 -1
- package/src/toolbar/widgets/ActionButtonWidget.ts +31 -0
- package/src/toolbar/widgets/BaseWidget.ts +2 -0
- package/src/toolbar/widgets/HandToolWidget.ts +3 -3
- package/src/toolbar/widgets/PenWidget.ts +2 -0
- package/src/toolbar/widgets/SelectionWidget.ts +46 -41
- package/src/tools/Eraser.ts +2 -2
- package/src/tools/PanZoom.ts +28 -17
- package/src/tools/Pen.ts +11 -2
- package/src/tools/PipetteTool.ts +2 -0
- package/src/tools/SelectionTool.test.ts +2 -4
- package/src/tools/SelectionTool.ts +52 -24
- package/src/tools/TextTool.ts +2 -2
- package/src/tools/UndoRedoShortcut.test.ts +1 -1
- package/src/types.ts +23 -7
- package/tsconfig.json +4 -1
- package/typedoc.json +20 -0
- package/dist/src/geometry/Mat33.d.ts +0 -32
- package/dist/src/geometry/Vec3.d.ts +0 -34
package/dist/src/Color4.d.ts
CHANGED
@@ -1,15 +1,34 @@
|
|
1
1
|
export default class Color4 {
|
2
|
+
/** Red component. Should be in the range [0, 1]. */
|
2
3
|
readonly r: number;
|
4
|
+
/** Green component. `g` ∈ [0, 1] */
|
3
5
|
readonly g: number;
|
6
|
+
/** Blue component. `b` ∈ [0, 1] */
|
4
7
|
readonly b: number;
|
8
|
+
/** Alpha/transparent component. `a` ∈ [0, 1] */
|
5
9
|
readonly a: number;
|
6
10
|
private constructor();
|
11
|
+
/**
|
12
|
+
* Create a color from red, green, blue components. The color is fully opaque (`a = 1.0`).
|
13
|
+
*
|
14
|
+
* Each component should be in the range [0, 1].
|
15
|
+
*/
|
7
16
|
static ofRGB(red: number, green: number, blue: number): Color4;
|
8
17
|
static ofRGBA(red: number, green: number, blue: number, alpha: number): Color4;
|
9
18
|
static fromHex(hexString: string): Color4;
|
19
|
+
/** Like fromHex, but can handle additional colors if an `HTMLCanvasElement` is available. */
|
10
20
|
static fromString(text: string): Color4;
|
21
|
+
/** @returns true if `this` and `other` are approximately equal. */
|
11
22
|
eq(other: Color4 | null | undefined): boolean;
|
12
23
|
private hexString;
|
24
|
+
/**
|
25
|
+
* @returns a hexadecimal color string representation of `this`, in the form `#rrggbbaa`.
|
26
|
+
*
|
27
|
+
* @example
|
28
|
+
* ```
|
29
|
+
* Color4.red.toHexString(); // -> #ff0000ff
|
30
|
+
* ```
|
31
|
+
*/
|
13
32
|
toHexString(): string;
|
14
33
|
static transparent: Color4;
|
15
34
|
static red: Color4;
|
package/dist/src/Color4.js
CHANGED
@@ -1,12 +1,24 @@
|
|
1
1
|
export default class Color4 {
|
2
|
-
constructor(
|
2
|
+
constructor(
|
3
|
+
/** Red component. Should be in the range [0, 1]. */
|
4
|
+
r,
|
5
|
+
/** Green component. `g` ∈ [0, 1] */
|
6
|
+
g,
|
7
|
+
/** Blue component. `b` ∈ [0, 1] */
|
8
|
+
b,
|
9
|
+
/** Alpha/transparent component. `a` ∈ [0, 1] */
|
10
|
+
a) {
|
3
11
|
this.r = r;
|
4
12
|
this.g = g;
|
5
13
|
this.b = b;
|
6
14
|
this.a = a;
|
7
15
|
this.hexString = null;
|
8
16
|
}
|
9
|
-
|
17
|
+
/**
|
18
|
+
* Create a color from red, green, blue components. The color is fully opaque (`a = 1.0`).
|
19
|
+
*
|
20
|
+
* Each component should be in the range [0, 1].
|
21
|
+
*/
|
10
22
|
static ofRGB(red, green, blue) {
|
11
23
|
return Color4.ofRGBA(red, green, blue, 1.0);
|
12
24
|
}
|
@@ -46,7 +58,7 @@ export default class Color4 {
|
|
46
58
|
}
|
47
59
|
return Color4.ofRGBA(components[0], components[1], components[2], components[3]);
|
48
60
|
}
|
49
|
-
|
61
|
+
/** Like fromHex, but can handle additional colors if an `HTMLCanvasElement` is available. */
|
50
62
|
static fromString(text) {
|
51
63
|
if (text.startsWith('#')) {
|
52
64
|
return Color4.fromHex(text);
|
@@ -67,12 +79,21 @@ export default class Color4 {
|
|
67
79
|
return Color4.ofRGBA(red, green, blue, alpha);
|
68
80
|
}
|
69
81
|
}
|
82
|
+
/** @returns true if `this` and `other` are approximately equal. */
|
70
83
|
eq(other) {
|
71
84
|
if (other == null) {
|
72
85
|
return false;
|
73
86
|
}
|
74
87
|
return this.toHexString() === other.toHexString();
|
75
88
|
}
|
89
|
+
/**
|
90
|
+
* @returns a hexadecimal color string representation of `this`, in the form `#rrggbbaa`.
|
91
|
+
*
|
92
|
+
* @example
|
93
|
+
* ```
|
94
|
+
* Color4.red.toHexString(); // -> #ff0000ff
|
95
|
+
* ```
|
96
|
+
*/
|
76
97
|
toHexString() {
|
77
98
|
if (this.hexString) {
|
78
99
|
return this.hexString;
|
package/dist/src/Editor.d.ts
CHANGED
@@ -1,48 +1,171 @@
|
|
1
|
+
/**
|
2
|
+
* The main entrypoint for the full editor.
|
3
|
+
*
|
4
|
+
* @example
|
5
|
+
* To create an editor with a toolbar,
|
6
|
+
* ```
|
7
|
+
* const editor = new Editor(document.body);
|
8
|
+
*
|
9
|
+
* const toolbar = editor.addToolbar();
|
10
|
+
* toolbar.addActionButton('Save', () => {
|
11
|
+
* const saveData = editor.toSVG().outerHTML;
|
12
|
+
* // Do something with saveData...
|
13
|
+
* });
|
14
|
+
* ```
|
15
|
+
*
|
16
|
+
* @packageDocumentation
|
17
|
+
*/
|
1
18
|
import EditorImage from './EditorImage';
|
2
19
|
import ToolController from './tools/ToolController';
|
3
20
|
import { InputEvtType, EditorNotifier, ImageLoader } from './types';
|
4
21
|
import Command from './commands/Command';
|
5
22
|
import UndoRedoHistory from './UndoRedoHistory';
|
6
23
|
import Viewport from './Viewport';
|
7
|
-
import { Point2 } from './
|
24
|
+
import { Point2 } from './math/Vec2';
|
8
25
|
import HTMLToolbar from './toolbar/HTMLToolbar';
|
9
26
|
import { RenderablePathSpec } from './rendering/renderers/AbstractRenderer';
|
10
27
|
import Display, { RenderingMode } from './rendering/Display';
|
11
28
|
import Pointer from './Pointer';
|
12
|
-
import Rect2 from './
|
29
|
+
import Rect2 from './math/Rect2';
|
13
30
|
import { EditorLocalization } from './localization';
|
14
31
|
export interface EditorSettings {
|
32
|
+
/** Defaults to `RenderingMode.CanvasRenderer` */
|
15
33
|
renderingMode: RenderingMode;
|
34
|
+
/** Uses a default English localization if a translation is not given. */
|
16
35
|
localization: Partial<EditorLocalization>;
|
36
|
+
/**
|
37
|
+
* `true` if touchpad/mousewheel scrolling should scroll the editor instead of the document.
|
38
|
+
* This does not include pinch-zoom events.
|
39
|
+
* Defaults to true.
|
40
|
+
*/
|
17
41
|
wheelEventsEnabled: boolean | 'only-if-focused';
|
42
|
+
/** Minimum zoom fraction (e.g. 0.5 → 50% zoom). */
|
18
43
|
minZoom: number;
|
19
44
|
maxZoom: number;
|
20
45
|
}
|
21
46
|
export declare class Editor {
|
22
47
|
private container;
|
23
48
|
private renderingRegion;
|
24
|
-
history: UndoRedoHistory;
|
25
49
|
display: Display;
|
50
|
+
/**
|
51
|
+
* Handles undo/redo.
|
52
|
+
*
|
53
|
+
* @example
|
54
|
+
* ```
|
55
|
+
* const editor = new Editor(document.body);
|
56
|
+
*
|
57
|
+
* // Do something undoable.
|
58
|
+
* // ...
|
59
|
+
*
|
60
|
+
* // Undo the last action
|
61
|
+
* editor.history.undo();
|
62
|
+
* ```
|
63
|
+
*/
|
64
|
+
history: UndoRedoHistory;
|
65
|
+
/**
|
66
|
+
* Data structure for adding/removing/querying objects in the image.
|
67
|
+
*
|
68
|
+
* @example
|
69
|
+
* ```
|
70
|
+
* const editor = new Editor(document.body);
|
71
|
+
*
|
72
|
+
* // Create a path.
|
73
|
+
* const stroke = new Stroke([
|
74
|
+
* Path.fromString('M0,0 L30,30 z').toRenderable({ fill: Color4.black }),
|
75
|
+
* ]);
|
76
|
+
* const addElementCommand = editor.image.addElement(stroke);
|
77
|
+
*
|
78
|
+
* // Add the stroke to the editor
|
79
|
+
* editor.dispatch(addElementCommand);
|
80
|
+
* ```
|
81
|
+
*/
|
26
82
|
image: EditorImage;
|
83
|
+
/** Viewport for the exported/imported image. */
|
27
84
|
private importExportViewport;
|
85
|
+
/** @internal */
|
28
86
|
localization: EditorLocalization;
|
29
87
|
viewport: Viewport;
|
30
88
|
toolController: ToolController;
|
89
|
+
/**
|
90
|
+
* Global event dispatcher/subscriber.
|
91
|
+
* @see {@link types.EditorEventType}
|
92
|
+
*/
|
31
93
|
notifier: EditorNotifier;
|
32
94
|
private loadingWarning;
|
33
95
|
private accessibilityAnnounceArea;
|
96
|
+
private accessibilityControlArea;
|
34
97
|
private settings;
|
98
|
+
/**
|
99
|
+
* @example
|
100
|
+
* ```
|
101
|
+
* const container = document.body;
|
102
|
+
*
|
103
|
+
* // Create an editor
|
104
|
+
* const editor = new Editor(container, {
|
105
|
+
* // 2e-10 and 1e12 are the default values for minimum/maximum zoom.
|
106
|
+
* minZoom: 2e-10,
|
107
|
+
* maxZoom: 1e12,
|
108
|
+
* });
|
109
|
+
*
|
110
|
+
* // Add the default toolbar
|
111
|
+
* const toolbar = editor.addToolbar();
|
112
|
+
* toolbar.addActionButton({
|
113
|
+
* label: 'Save'
|
114
|
+
* icon: createSaveIcon(),
|
115
|
+
* }, () => {
|
116
|
+
* const saveData = editor.toSVG().outerHTML;
|
117
|
+
* // Do something with saveData
|
118
|
+
* });
|
119
|
+
* ```
|
120
|
+
*/
|
35
121
|
constructor(parent: HTMLElement, settings?: Partial<EditorSettings>);
|
122
|
+
/**
|
123
|
+
* @returns a reference to the editor's container.
|
124
|
+
*
|
125
|
+
* @example
|
126
|
+
* ```
|
127
|
+
* editor.getRootElement().style.height = '500px';
|
128
|
+
* ```
|
129
|
+
*/
|
36
130
|
getRootElement(): HTMLElement;
|
131
|
+
/** @param fractionLoaded - should be a number from 0 to 1, where 1 represents completely loaded. */
|
37
132
|
showLoadingWarning(fractionLoaded: number): void;
|
38
133
|
hideLoadingWarning(): void;
|
134
|
+
private previousAccessibilityAnnouncement;
|
39
135
|
announceForAccessibility(message: string): void;
|
136
|
+
/**
|
137
|
+
* Creates a toolbar. If `defaultLayout` is true, default buttons are used.
|
138
|
+
* @returns a reference to the toolbar.
|
139
|
+
*/
|
40
140
|
addToolbar(defaultLayout?: boolean): HTMLToolbar;
|
41
141
|
private registerListeners;
|
142
|
+
/** Adds event listners for keypresses to `elem` and forwards those events to the editor. */
|
42
143
|
handleKeyEventsFrom(elem: HTMLElement): void;
|
144
|
+
/** `apply` a command. `command` will be announced for accessibility. */
|
43
145
|
dispatch(command: Command, addToHistory?: boolean): void;
|
146
|
+
/**
|
147
|
+
* Dispatches a command without announcing it. By default, does not add to history.
|
148
|
+
* Use this to show finalized commands that don't need to have `announceForAccessibility`
|
149
|
+
* called.
|
150
|
+
*
|
151
|
+
* Prefer `command.apply(editor)` for incomplete commands. `dispatchNoAnnounce` may allow
|
152
|
+
* clients to listen for the application of commands (e.g. `SerializableCommand`s so they can
|
153
|
+
* be sent across the network), while `apply` does not.
|
154
|
+
*
|
155
|
+
* @example
|
156
|
+
* ```
|
157
|
+
* const addToHistory = false;
|
158
|
+
* editor.dispatchNoAnnounce(editor.viewport.zoomTo(someRectangle), addToHistory);
|
159
|
+
* ```
|
160
|
+
*/
|
44
161
|
dispatchNoAnnounce(command: Command, addToHistory?: boolean): void;
|
45
|
-
|
162
|
+
/**
|
163
|
+
* Apply a large transformation in chunks.
|
164
|
+
* If `apply` is `false`, the commands are unapplied.
|
165
|
+
* Triggers a re-render after each `updateChunkSize`-sized group of commands
|
166
|
+
* has been applied.
|
167
|
+
*/
|
168
|
+
asyncApplyOrUnapplyCommands(commands: Command[], apply: boolean, updateChunkSize: number): Promise<void>;
|
46
169
|
asyncApplyCommands(commands: Command[], chunkSize: number): Promise<void>;
|
47
170
|
asyncUnapplyCommands(commands: Command[], chunkSize: number): Promise<void>;
|
48
171
|
private announceUndoCallback;
|
@@ -62,6 +185,12 @@ export declare class Editor {
|
|
62
185
|
loadFrom(loader: ImageLoader): Promise<void>;
|
63
186
|
getImportExportRect(): Rect2;
|
64
187
|
setImportExportRect(imageRect: Rect2): Command;
|
188
|
+
/**
|
189
|
+
* Alias for loadFrom(SVGLoader.fromString).
|
190
|
+
*
|
191
|
+
* This is particularly useful when accessing a bundled version of the editor,
|
192
|
+
* where `SVGLoader.fromString` is unavailable.
|
193
|
+
*/
|
65
194
|
loadFromSVG(svgData: string): Promise<void>;
|
66
195
|
}
|
67
196
|
export default Editor;
|
package/dist/src/Editor.js
CHANGED
@@ -1,3 +1,20 @@
|
|
1
|
+
/**
|
2
|
+
* The main entrypoint for the full editor.
|
3
|
+
*
|
4
|
+
* @example
|
5
|
+
* To create an editor with a toolbar,
|
6
|
+
* ```
|
7
|
+
* const editor = new Editor(document.body);
|
8
|
+
*
|
9
|
+
* const toolbar = editor.addToolbar();
|
10
|
+
* toolbar.addActionButton('Save', () => {
|
11
|
+
* const saveData = editor.toSVG().outerHTML;
|
12
|
+
* // Do something with saveData...
|
13
|
+
* });
|
14
|
+
* ```
|
15
|
+
*
|
16
|
+
* @packageDocumentation
|
17
|
+
*/
|
1
18
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
2
19
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
3
20
|
return new (P || (P = Promise))(function (resolve, reject) {
|
@@ -14,24 +31,49 @@ import Command from './commands/Command';
|
|
14
31
|
import UndoRedoHistory from './UndoRedoHistory';
|
15
32
|
import Viewport from './Viewport';
|
16
33
|
import EventDispatcher from './EventDispatcher';
|
17
|
-
import { Vec2 } from './
|
18
|
-
import Vec3 from './
|
34
|
+
import { Vec2 } from './math/Vec2';
|
35
|
+
import Vec3 from './math/Vec3';
|
19
36
|
import HTMLToolbar from './toolbar/HTMLToolbar';
|
20
37
|
import Display, { RenderingMode } from './rendering/Display';
|
21
38
|
import SVGRenderer from './rendering/renderers/SVGRenderer';
|
22
39
|
import Color4 from './Color4';
|
23
40
|
import SVGLoader from './SVGLoader';
|
24
41
|
import Pointer from './Pointer';
|
25
|
-
import Mat33 from './
|
42
|
+
import Mat33 from './math/Mat33';
|
26
43
|
import getLocalizationTable from './localizations/getLocalizationTable';
|
44
|
+
// { @inheritDoc Editor! }
|
27
45
|
export class Editor {
|
46
|
+
/**
|
47
|
+
* @example
|
48
|
+
* ```
|
49
|
+
* const container = document.body;
|
50
|
+
*
|
51
|
+
* // Create an editor
|
52
|
+
* const editor = new Editor(container, {
|
53
|
+
* // 2e-10 and 1e12 are the default values for minimum/maximum zoom.
|
54
|
+
* minZoom: 2e-10,
|
55
|
+
* maxZoom: 1e12,
|
56
|
+
* });
|
57
|
+
*
|
58
|
+
* // Add the default toolbar
|
59
|
+
* const toolbar = editor.addToolbar();
|
60
|
+
* toolbar.addActionButton({
|
61
|
+
* label: 'Save'
|
62
|
+
* icon: createSaveIcon(),
|
63
|
+
* }, () => {
|
64
|
+
* const saveData = editor.toSVG().outerHTML;
|
65
|
+
* // Do something with saveData
|
66
|
+
* });
|
67
|
+
* ```
|
68
|
+
*/
|
28
69
|
constructor(parent, settings = {}) {
|
29
70
|
var _a, _b, _c, _d;
|
71
|
+
this.previousAccessibilityAnnouncement = '';
|
30
72
|
this.announceUndoCallback = (command) => {
|
31
|
-
this.announceForAccessibility(this.localization.undoAnnouncement(command.description(this.localization)));
|
73
|
+
this.announceForAccessibility(this.localization.undoAnnouncement(command.description(this, this.localization)));
|
32
74
|
};
|
33
75
|
this.announceRedoCallback = (command) => {
|
34
|
-
this.announceForAccessibility(this.localization.redoAnnouncement(command.description(this.localization)));
|
76
|
+
this.announceForAccessibility(this.localization.redoAnnouncement(command.description(this, this.localization)));
|
35
77
|
};
|
36
78
|
this.rerenderQueued = false;
|
37
79
|
this.localization = Object.assign(Object.assign({}, getLocalizationTable()), settings.localization);
|
@@ -51,14 +93,21 @@ export class Editor {
|
|
51
93
|
this.loadingWarning.classList.add('loadingMessage');
|
52
94
|
this.loadingWarning.ariaLive = 'polite';
|
53
95
|
this.container.appendChild(this.loadingWarning);
|
96
|
+
this.accessibilityControlArea = document.createElement('textarea');
|
97
|
+
this.accessibilityControlArea.setAttribute('placeholder', this.localization.accessibilityInputInstructions);
|
98
|
+
this.accessibilityControlArea.style.opacity = '0';
|
99
|
+
this.accessibilityControlArea.style.width = '0';
|
100
|
+
this.accessibilityControlArea.style.height = '0';
|
101
|
+
this.accessibilityControlArea.style.position = 'absolute';
|
54
102
|
this.accessibilityAnnounceArea = document.createElement('div');
|
55
|
-
this.accessibilityAnnounceArea.
|
103
|
+
this.accessibilityAnnounceArea.setAttribute('aria-live', 'assertive');
|
56
104
|
this.accessibilityAnnounceArea.className = 'accessibilityAnnouncement';
|
57
105
|
this.container.appendChild(this.accessibilityAnnounceArea);
|
58
106
|
this.renderingRegion.style.touchAction = 'none';
|
59
107
|
this.renderingRegion.className = 'imageEditorRenderArea';
|
108
|
+
this.renderingRegion.appendChild(this.accessibilityControlArea);
|
60
109
|
this.renderingRegion.setAttribute('tabIndex', '0');
|
61
|
-
this.renderingRegion.
|
110
|
+
this.renderingRegion.setAttribute('alt', '');
|
62
111
|
this.notifier = new EventDispatcher();
|
63
112
|
this.importExportViewport = new Viewport(this.notifier);
|
64
113
|
this.viewport = new Viewport(this.notifier);
|
@@ -88,13 +137,18 @@ export class Editor {
|
|
88
137
|
}
|
89
138
|
});
|
90
139
|
}
|
91
|
-
|
92
|
-
|
93
|
-
|
140
|
+
/**
|
141
|
+
* @returns a reference to the editor's container.
|
142
|
+
*
|
143
|
+
* @example
|
144
|
+
* ```
|
145
|
+
* editor.getRootElement().style.height = '500px';
|
146
|
+
* ```
|
147
|
+
*/
|
94
148
|
getRootElement() {
|
95
149
|
return this.container;
|
96
150
|
}
|
97
|
-
|
151
|
+
/** @param fractionLoaded - should be a number from 0 to 1, where 1 represents completely loaded. */
|
98
152
|
showLoadingWarning(fractionLoaded) {
|
99
153
|
const loadingPercent = Math.round(fractionLoaded * 100);
|
100
154
|
this.loadingWarning.innerText = this.localization.loading(loadingPercent);
|
@@ -104,9 +158,20 @@ export class Editor {
|
|
104
158
|
this.loadingWarning.style.display = 'none';
|
105
159
|
this.announceForAccessibility(this.localization.doneLoading);
|
106
160
|
}
|
161
|
+
// Announce `message` for screen readers. If `message` is the same as the previous
|
162
|
+
// message, it is re-announced.
|
107
163
|
announceForAccessibility(message) {
|
164
|
+
// Force re-announcing an announcement if announced again.
|
165
|
+
if (message === this.previousAccessibilityAnnouncement) {
|
166
|
+
message = message + '. ';
|
167
|
+
}
|
108
168
|
this.accessibilityAnnounceArea.innerText = message;
|
169
|
+
this.previousAccessibilityAnnouncement = message;
|
109
170
|
}
|
171
|
+
/**
|
172
|
+
* Creates a toolbar. If `defaultLayout` is true, default buttons are used.
|
173
|
+
* @returns a reference to the toolbar.
|
174
|
+
*/
|
110
175
|
addToolbar(defaultLayout = true) {
|
111
176
|
const toolbar = new HTMLToolbar(this, this.container, this.localization);
|
112
177
|
if (defaultLayout) {
|
@@ -237,12 +302,18 @@ export class Editor {
|
|
237
302
|
});
|
238
303
|
this.queueRerender();
|
239
304
|
});
|
305
|
+
this.accessibilityControlArea.addEventListener('input', () => {
|
306
|
+
this.accessibilityControlArea.value = '';
|
307
|
+
});
|
240
308
|
}
|
241
|
-
|
242
|
-
// editor.
|
309
|
+
/** Adds event listners for keypresses to `elem` and forwards those events to the editor. */
|
243
310
|
handleKeyEventsFrom(elem) {
|
244
311
|
elem.addEventListener('keydown', evt => {
|
245
|
-
if (
|
312
|
+
if (evt.key === 't' || evt.key === 'T') {
|
313
|
+
evt.preventDefault();
|
314
|
+
this.display.rerenderAsText();
|
315
|
+
}
|
316
|
+
else if (this.toolController.dispatchInputEvent({
|
246
317
|
kind: InputEvtType.KeyPressEvent,
|
247
318
|
key: evt.key,
|
248
319
|
ctrlKey: evt.ctrlKey,
|
@@ -263,7 +334,7 @@ export class Editor {
|
|
263
334
|
}
|
264
335
|
});
|
265
336
|
}
|
266
|
-
|
337
|
+
/** `apply` a command. `command` will be announced for accessibility. */
|
267
338
|
dispatch(command, addToHistory = true) {
|
268
339
|
if (addToHistory) {
|
269
340
|
// .push applies [command] to this
|
@@ -272,9 +343,23 @@ export class Editor {
|
|
272
343
|
else {
|
273
344
|
command.apply(this);
|
274
345
|
}
|
275
|
-
this.announceForAccessibility(command.description(this.localization));
|
346
|
+
this.announceForAccessibility(command.description(this, this.localization));
|
276
347
|
}
|
277
|
-
|
348
|
+
/**
|
349
|
+
* Dispatches a command without announcing it. By default, does not add to history.
|
350
|
+
* Use this to show finalized commands that don't need to have `announceForAccessibility`
|
351
|
+
* called.
|
352
|
+
*
|
353
|
+
* Prefer `command.apply(editor)` for incomplete commands. `dispatchNoAnnounce` may allow
|
354
|
+
* clients to listen for the application of commands (e.g. `SerializableCommand`s so they can
|
355
|
+
* be sent across the network), while `apply` does not.
|
356
|
+
*
|
357
|
+
* @example
|
358
|
+
* ```
|
359
|
+
* const addToHistory = false;
|
360
|
+
* editor.dispatchNoAnnounce(editor.viewport.zoomTo(someRectangle), addToHistory);
|
361
|
+
* ```
|
362
|
+
*/
|
278
363
|
dispatchNoAnnounce(command, addToHistory = false) {
|
279
364
|
if (addToHistory) {
|
280
365
|
this.history.push(command);
|
@@ -283,10 +368,12 @@ export class Editor {
|
|
283
368
|
command.apply(this);
|
284
369
|
}
|
285
370
|
}
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
371
|
+
/**
|
372
|
+
* Apply a large transformation in chunks.
|
373
|
+
* If `apply` is `false`, the commands are unapplied.
|
374
|
+
* Triggers a re-render after each `updateChunkSize`-sized group of commands
|
375
|
+
* has been applied.
|
376
|
+
*/
|
290
377
|
asyncApplyOrUnapplyCommands(commands, apply, updateChunkSize) {
|
291
378
|
return __awaiter(this, void 0, void 0, function* () {
|
292
379
|
this.display.setDraftMode(true);
|
@@ -313,12 +400,16 @@ export class Editor {
|
|
313
400
|
this.hideLoadingWarning();
|
314
401
|
});
|
315
402
|
}
|
403
|
+
// @see {@link #asyncApplyOrUnapplyCommands }
|
316
404
|
asyncApplyCommands(commands, chunkSize) {
|
317
405
|
return this.asyncApplyOrUnapplyCommands(commands, true, chunkSize);
|
318
406
|
}
|
407
|
+
// @see {@link #asyncApplyOrUnapplyCommands }
|
319
408
|
asyncUnapplyCommands(commands, chunkSize) {
|
320
409
|
return this.asyncApplyOrUnapplyCommands(commands, false, chunkSize);
|
321
410
|
}
|
411
|
+
// Schedule a re-render for some time in the near future. Does not schedule an additional
|
412
|
+
// re-render if a re-render is already queued.
|
322
413
|
queueRerender() {
|
323
414
|
if (!this.rerenderQueued) {
|
324
415
|
this.rerenderQueued = true;
|
@@ -352,10 +443,12 @@ export class Editor {
|
|
352
443
|
clearWetInk() {
|
353
444
|
this.display.getWetInkRenderer().clear();
|
354
445
|
}
|
355
|
-
// Focuses the region used for text input
|
446
|
+
// Focuses the region used for text input/key commands.
|
356
447
|
focus() {
|
357
448
|
this.renderingRegion.focus();
|
358
449
|
}
|
450
|
+
// Creates an element that will be positioned on top of the dry/wet ink
|
451
|
+
// renderers.
|
359
452
|
createHTMLOverlay(overlay) {
|
360
453
|
overlay.classList.add('overlay');
|
361
454
|
this.container.appendChild(overlay);
|
@@ -370,7 +463,7 @@ export class Editor {
|
|
370
463
|
return styleSheet;
|
371
464
|
}
|
372
465
|
// Dispatch a pen event to the currently selected tool.
|
373
|
-
//
|
466
|
+
// Intended primarially for unit tests.
|
374
467
|
sendPenEvent(eventType, point, allPointers) {
|
375
468
|
const mainPointer = Pointer.ofCanvasPoint(point, eventType !== InputEvtType.PointerUpEvt, this.viewport);
|
376
469
|
this.toolController.dispatchInputEvent({
|
@@ -432,7 +525,7 @@ export class Editor {
|
|
432
525
|
getImportExportRect() {
|
433
526
|
return this.importExportViewport.visibleRect;
|
434
527
|
}
|
435
|
-
// Resize the output SVG
|
528
|
+
// Resize the output SVG to match `imageRect`.
|
436
529
|
setImportExportRect(imageRect) {
|
437
530
|
const origSize = this.importExportViewport.visibleRect.size;
|
438
531
|
const origTransform = this.importExportViewport.canvasToScreenTransform;
|
@@ -449,13 +542,17 @@ export class Editor {
|
|
449
542
|
viewport.resetTransform(origTransform);
|
450
543
|
editor.queueRerender();
|
451
544
|
}
|
452
|
-
description(localizationTable) {
|
545
|
+
description(_editor, localizationTable) {
|
453
546
|
return localizationTable.resizeOutputCommand(imageRect);
|
454
547
|
}
|
455
548
|
};
|
456
549
|
}
|
457
|
-
|
458
|
-
|
550
|
+
/**
|
551
|
+
* Alias for loadFrom(SVGLoader.fromString).
|
552
|
+
*
|
553
|
+
* This is particularly useful when accessing a bundled version of the editor,
|
554
|
+
* where `SVGLoader.fromString` is unavailable.
|
555
|
+
*/
|
459
556
|
loadFromSVG(svgData) {
|
460
557
|
return __awaiter(this, void 0, void 0, function* () {
|
461
558
|
const loader = SVGLoader.fromString(svgData);
|
@@ -1,26 +1,31 @@
|
|
1
1
|
import AbstractRenderer from './rendering/renderers/AbstractRenderer';
|
2
|
-
import Command from './commands/Command';
|
3
2
|
import Viewport from './Viewport';
|
4
3
|
import AbstractComponent from './components/AbstractComponent';
|
5
|
-
import Rect2 from './
|
4
|
+
import Rect2 from './math/Rect2';
|
6
5
|
import RenderingCache from './rendering/caching/RenderingCache';
|
6
|
+
import SerializableCommand from './commands/SerializableCommand';
|
7
7
|
export declare const sortLeavesByZIndex: (leaves: Array<ImageNode>) => void;
|
8
8
|
export default class EditorImage {
|
9
9
|
private root;
|
10
10
|
private componentsById;
|
11
11
|
constructor();
|
12
12
|
findParent(elem: AbstractComponent): ImageNode | null;
|
13
|
+
/** @internal */
|
13
14
|
renderWithCache(screenRenderer: AbstractRenderer, cache: RenderingCache, viewport: Viewport): void;
|
15
|
+
/** @internal */
|
14
16
|
render(renderer: AbstractRenderer, viewport: Viewport): void;
|
17
|
+
/** Renders all nodes, even ones not within the viewport. @internal */
|
15
18
|
renderAll(renderer: AbstractRenderer): void;
|
16
19
|
getElementsIntersectingRegion(region: Rect2): AbstractComponent[];
|
20
|
+
/** @internal */
|
17
21
|
onDestroyElement(elem: AbstractComponent): void;
|
18
22
|
lookupElement(id: string): AbstractComponent | null;
|
19
23
|
private addElementDirectly;
|
20
|
-
static addElement(elem: AbstractComponent, applyByFlattening?: boolean):
|
24
|
+
static addElement(elem: AbstractComponent, applyByFlattening?: boolean): SerializableCommand;
|
21
25
|
private static AddElementCommand;
|
22
26
|
}
|
23
27
|
declare type TooSmallToRenderCheck = (rect: Rect2) => boolean;
|
28
|
+
/** Part of the Editor's image. @internal */
|
24
29
|
export declare class ImageNode {
|
25
30
|
private parent;
|
26
31
|
private content;
|