js-draw 1.27.1 → 1.28.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 +1 -1
- package/build-config.json +2 -1
- package/dist/Editor.css +1 -1
- package/dist/bundle.js +28 -28
- package/dist/bundledStyles.js +1 -1
- package/dist/cjs/Editor.d.ts +7 -2
- package/dist/cjs/Editor.js +11 -5
- package/dist/cjs/SVGLoader/SVGLoader.d.ts +21 -0
- package/dist/cjs/SVGLoader/SVGLoader.js +74 -47
- package/dist/cjs/SVGLoader/SVGLoader.plugins.test.d.ts +1 -0
- package/dist/cjs/Viewport.js +2 -32
- package/dist/cjs/commands/Duplicate.d.ts +7 -4
- package/dist/cjs/commands/Duplicate.js +48 -7
- package/dist/cjs/commands/Duplicate.test.d.ts +1 -0
- package/dist/cjs/commands/Erase.d.ts +1 -1
- package/dist/cjs/commands/Erase.js +2 -2
- package/dist/cjs/commands/localization.d.ts +2 -2
- package/dist/cjs/commands/localization.js +2 -2
- package/dist/cjs/components/AbstractComponent.d.ts +7 -0
- package/dist/cjs/components/AbstractComponent.js +16 -2
- package/dist/cjs/components/Stroke.d.ts +21 -1
- package/dist/cjs/components/Stroke.js +29 -0
- package/dist/cjs/components/TextComponent.d.ts +2 -2
- package/dist/cjs/components/TextComponent.js +2 -2
- package/dist/cjs/components/builders/PolylineBuilder.js +1 -1
- package/dist/cjs/image/EditorImage.d.ts +17 -9
- package/dist/cjs/image/EditorImage.js +33 -17
- package/dist/cjs/lib.d.ts +1 -1
- package/dist/cjs/localizations/de.js +2 -2
- package/dist/cjs/rendering/RenderingStyle.d.ts +7 -6
- package/dist/cjs/rendering/lib.d.ts +1 -1
- package/dist/cjs/rendering/renderers/AbstractRenderer.js +4 -0
- package/dist/cjs/rendering/renderers/CanvasRenderer.d.ts +9 -0
- package/dist/cjs/rendering/renderers/CanvasRenderer.js +14 -0
- package/dist/cjs/rendering/renderers/SVGRenderer.d.ts +18 -0
- package/dist/cjs/rendering/renderers/SVGRenderer.js +21 -1
- package/dist/cjs/toolbar/AbstractToolbar.d.ts +2 -2
- package/dist/cjs/toolbar/AbstractToolbar.js +2 -3
- package/dist/cjs/toolbar/DropdownToolbar.d.ts +1 -1
- package/dist/cjs/toolbar/DropdownToolbar.js +2 -3
- package/dist/cjs/toolbar/DropdownToolbar.test.d.ts +1 -0
- package/dist/cjs/toolbar/utils/HelpDisplay.js +6 -4
- package/dist/cjs/toolbar/utils/localization.d.ts +1 -0
- package/dist/cjs/toolbar/utils/localization.js +1 -0
- package/dist/cjs/toolbar/widgets/DocumentPropertiesWidget.js +1 -1
- package/dist/cjs/toolbar/widgets/InsertImageWidget/InsertImageWidget.js +1 -1
- package/dist/cjs/toolbar/widgets/components/makeGridSelector.js +1 -1
- package/dist/cjs/tools/Eraser.js +3 -3
- package/dist/cjs/tools/FindTool.js +1 -1
- package/dist/cjs/tools/PasteHandler.js +4 -1
- package/dist/cjs/tools/Pen.js +1 -1
- package/dist/cjs/tools/SelectionTool/SelectAllShortcutHandler.js +1 -1
- package/dist/cjs/tools/SelectionTool/Selection.js +23 -10
- package/dist/cjs/tools/SelectionTool/SelectionBuilders/LassoSelectionBuilder.js +1 -1
- package/dist/cjs/tools/SelectionTool/SelectionBuilders/RectSelectionBuilder.js +1 -1
- package/dist/cjs/tools/SelectionTool/SelectionBuilders/SelectionBuilder.js +1 -1
- package/dist/cjs/tools/SelectionTool/SelectionTool.js +3 -2
- package/dist/cjs/tools/SoundUITool.js +1 -1
- package/dist/cjs/tools/TextTool.js +2 -2
- package/dist/cjs/util/assertions.d.ts +6 -0
- package/dist/cjs/util/assertions.js +18 -0
- package/dist/cjs/util/describeTransformation.d.ts +12 -0
- package/dist/cjs/util/describeTransformation.js +44 -0
- package/dist/cjs/version.js +2 -1
- package/dist/mjs/Editor.d.ts +7 -2
- package/dist/mjs/Editor.mjs +11 -5
- package/dist/mjs/SVGLoader/SVGLoader.d.ts +21 -0
- package/dist/mjs/SVGLoader/SVGLoader.mjs +74 -47
- package/dist/mjs/SVGLoader/SVGLoader.plugins.test.d.ts +1 -0
- package/dist/mjs/Viewport.mjs +2 -32
- package/dist/mjs/commands/Duplicate.d.ts +7 -4
- package/dist/mjs/commands/Duplicate.mjs +48 -7
- package/dist/mjs/commands/Duplicate.test.d.ts +1 -0
- package/dist/mjs/commands/Erase.d.ts +1 -1
- package/dist/mjs/commands/Erase.mjs +2 -2
- package/dist/mjs/commands/localization.d.ts +2 -2
- package/dist/mjs/commands/localization.mjs +2 -2
- package/dist/mjs/components/AbstractComponent.d.ts +7 -0
- package/dist/mjs/components/AbstractComponent.mjs +17 -3
- package/dist/mjs/components/Stroke.d.ts +21 -1
- package/dist/mjs/components/Stroke.mjs +31 -2
- package/dist/mjs/components/TextComponent.d.ts +2 -2
- package/dist/mjs/components/TextComponent.mjs +2 -2
- package/dist/mjs/components/builders/PolylineBuilder.mjs +1 -1
- package/dist/mjs/image/EditorImage.d.ts +17 -9
- package/dist/mjs/image/EditorImage.mjs +33 -17
- package/dist/mjs/lib.d.ts +1 -1
- package/dist/mjs/localizations/de.mjs +2 -2
- package/dist/mjs/rendering/RenderingStyle.d.ts +7 -6
- package/dist/mjs/rendering/lib.d.ts +1 -1
- package/dist/mjs/rendering/renderers/AbstractRenderer.mjs +4 -0
- package/dist/mjs/rendering/renderers/CanvasRenderer.d.ts +9 -0
- package/dist/mjs/rendering/renderers/CanvasRenderer.mjs +14 -0
- package/dist/mjs/rendering/renderers/SVGRenderer.d.ts +18 -0
- package/dist/mjs/rendering/renderers/SVGRenderer.mjs +21 -1
- package/dist/mjs/toolbar/AbstractToolbar.d.ts +2 -2
- package/dist/mjs/toolbar/AbstractToolbar.mjs +2 -3
- package/dist/mjs/toolbar/DropdownToolbar.d.ts +1 -1
- package/dist/mjs/toolbar/DropdownToolbar.mjs +2 -3
- package/dist/mjs/toolbar/DropdownToolbar.test.d.ts +1 -0
- package/dist/mjs/toolbar/utils/HelpDisplay.mjs +6 -4
- package/dist/mjs/toolbar/utils/localization.d.ts +1 -0
- package/dist/mjs/toolbar/utils/localization.mjs +1 -0
- package/dist/mjs/toolbar/widgets/DocumentPropertiesWidget.mjs +1 -1
- package/dist/mjs/toolbar/widgets/InsertImageWidget/InsertImageWidget.mjs +1 -1
- package/dist/mjs/toolbar/widgets/components/makeGridSelector.mjs +1 -1
- package/dist/mjs/tools/Eraser.mjs +3 -3
- package/dist/mjs/tools/FindTool.mjs +1 -1
- package/dist/mjs/tools/PasteHandler.mjs +4 -1
- package/dist/mjs/tools/Pen.mjs +1 -1
- package/dist/mjs/tools/SelectionTool/SelectAllShortcutHandler.mjs +1 -1
- package/dist/mjs/tools/SelectionTool/Selection.mjs +23 -10
- package/dist/mjs/tools/SelectionTool/SelectionBuilders/LassoSelectionBuilder.mjs +1 -1
- package/dist/mjs/tools/SelectionTool/SelectionBuilders/RectSelectionBuilder.mjs +1 -1
- package/dist/mjs/tools/SelectionTool/SelectionBuilders/SelectionBuilder.mjs +1 -1
- package/dist/mjs/tools/SelectionTool/SelectionTool.mjs +3 -2
- package/dist/mjs/tools/SoundUITool.mjs +1 -1
- package/dist/mjs/tools/TextTool.mjs +2 -2
- package/dist/mjs/util/assertions.d.ts +6 -0
- package/dist/mjs/util/assertions.mjs +16 -0
- package/dist/mjs/util/describeTransformation.d.ts +12 -0
- package/dist/mjs/util/describeTransformation.mjs +42 -0
- package/dist/mjs/version.mjs +2 -1
- package/package.json +4 -4
- package/src/toolbar/utils/HelpDisplay.scss +7 -1
@@ -1,5 +1,5 @@
|
|
1
|
-
import { Path, Rect2, PathCommandType, comparePathIndices, stepPathIndexBy, } from '@js-draw/math';
|
2
|
-
import { styleFromJSON, styleToJSON } from '../rendering/RenderingStyle.mjs';
|
1
|
+
import { Path, Rect2, PathCommandType, comparePathIndices, stepPathIndexBy, Color4, } from '@js-draw/math';
|
2
|
+
import { styleFromJSON, styleToJSON, } from '../rendering/RenderingStyle.mjs';
|
3
3
|
import AbstractComponent from './AbstractComponent.mjs';
|
4
4
|
import { createRestyleComponentCommand, } from './RestylableComponent.mjs';
|
5
5
|
import { pathFromRenderable, pathToRenderable, simplifyPathToFullScreenOrEmpty, } from '../rendering/RenderablePathSpec.mjs';
|
@@ -69,6 +69,35 @@ export default class Stroke extends AbstractComponent {
|
|
69
69
|
}
|
70
70
|
this.contentBBox ??= Rect2.empty;
|
71
71
|
}
|
72
|
+
/**
|
73
|
+
* Creates a new `Stroke` from a {@link Path} and `style`. Strokes created
|
74
|
+
* with this method have transparent fill.
|
75
|
+
*
|
76
|
+
* Example:
|
77
|
+
* ```ts,runnable
|
78
|
+
* import { Editor, Stroke, Color4 } from 'js-draw';
|
79
|
+
* const editor = new Editor(document.body);
|
80
|
+
* ---visible---
|
81
|
+
* const stroke = Stroke.fromStroked('m0,0 l10,10', { width: 10, color: Color4.red });
|
82
|
+
* editor.dispatch(editor.image.addComponent(stroke));
|
83
|
+
* ```
|
84
|
+
* Notice that `path` can be a string that specifies an SVG path
|
85
|
+
*
|
86
|
+
* @see fromFilled
|
87
|
+
*/
|
88
|
+
static fromStroked(path, style) {
|
89
|
+
if (typeof path === 'string') {
|
90
|
+
path = Path.fromString(path);
|
91
|
+
}
|
92
|
+
return new Stroke([pathToRenderable(path, { fill: Color4.transparent, stroke: style })]);
|
93
|
+
}
|
94
|
+
/** @see fromStroked */
|
95
|
+
static fromFilled(path, fill) {
|
96
|
+
if (typeof path === 'string') {
|
97
|
+
path = Path.fromString(path);
|
98
|
+
}
|
99
|
+
return new Stroke([pathToRenderable(path, { fill })]);
|
100
|
+
}
|
72
101
|
getStyle() {
|
73
102
|
if (this.parts.length === 0) {
|
74
103
|
return {};
|
@@ -38,7 +38,7 @@ type TextElement = TextComponent | string;
|
|
38
38
|
* };
|
39
39
|
*
|
40
40
|
* editor.dispatch(
|
41
|
-
* editor.image.
|
41
|
+
* editor.image.addComponent(new TextComponent(['Hello, world'], positioning1, style)),
|
42
42
|
* );
|
43
43
|
*
|
44
44
|
*
|
@@ -49,7 +49,7 @@ type TextElement = TextComponent | string;
|
|
49
49
|
* // is placed directly after 'Test'.
|
50
50
|
* const positioning2 = Mat33.translation(Vec2.of(10, 50));
|
51
51
|
* editor.dispatch(
|
52
|
-
* editor.image.
|
52
|
+
* editor.image.addComponent(
|
53
53
|
* new TextComponent([ new TextComponent(['Test'], positioning1, style), '[Test]' ], positioning2, style)
|
54
54
|
* ),
|
55
55
|
* );
|
@@ -40,7 +40,7 @@ const defaultTextStyle = {
|
|
40
40
|
* };
|
41
41
|
*
|
42
42
|
* editor.dispatch(
|
43
|
-
* editor.image.
|
43
|
+
* editor.image.addComponent(new TextComponent(['Hello, world'], positioning1, style)),
|
44
44
|
* );
|
45
45
|
*
|
46
46
|
*
|
@@ -51,7 +51,7 @@ const defaultTextStyle = {
|
|
51
51
|
* // is placed directly after 'Test'.
|
52
52
|
* const positioning2 = Mat33.translation(Vec2.of(10, 50));
|
53
53
|
* editor.dispatch(
|
54
|
-
* editor.image.
|
54
|
+
* editor.image.addComponent(
|
55
55
|
* new TextComponent([ new TextComponent(['Test'], positioning1, style), '[Test]' ], positioning2, style)
|
56
56
|
* ),
|
57
57
|
* );
|
@@ -12,7 +12,7 @@ import makeShapeFitAutocorrect from './autocorrect/makeShapeFitAutocorrect.mjs
|
|
12
12
|
export const makePolylineBuilder = makeShapeFitAutocorrect((initialPoint, viewport) => {
|
13
13
|
// Fit to a value slightly smaller than the pixel size. A larger value can
|
14
14
|
// cause the stroke to appear jagged at some zoom levels.
|
15
|
-
const minFit = viewport.getSizeOfPixelOnCanvas() * 0.
|
15
|
+
const minFit = viewport.getSizeOfPixelOnCanvas() * 0.65;
|
16
16
|
return new PolylineBuilder(initialPoint, minFit, viewport);
|
17
17
|
});
|
18
18
|
export default class PolylineBuilder {
|
@@ -22,7 +22,7 @@ export type EditorImageNotifier = EventDispatcher<EditorImageEventType, {
|
|
22
22
|
*/
|
23
23
|
export type PreRenderComponentCallback = (component: AbstractComponent, componentsProcessed: number, totalComponents: number) => Promise<boolean>;
|
24
24
|
/**
|
25
|
-
*
|
25
|
+
* Handles lookup/storage of elements in the image.
|
26
26
|
*
|
27
27
|
* `js-draw` images are made up of a collection of {@link AbstractComponent}s (which
|
28
28
|
* includes {@link Stroke}s, {@link TextComponent}s, etc.). An `EditorImage`
|
@@ -30,9 +30,9 @@ export type PreRenderComponentCallback = (component: AbstractComponent, componen
|
|
30
30
|
*
|
31
31
|
* Here's how to do a few common operations:
|
32
32
|
* - **Get all components in a {@link @js-draw/math!Rect2 | Rect2}**:
|
33
|
-
* {@link EditorImage.
|
33
|
+
* {@link EditorImage.getComponentsIntersecting}.
|
34
34
|
* - **Draw an `EditorImage` onto a canvas/SVG**: {@link EditorImage.render}.
|
35
|
-
* - **Adding a new component**: {@link EditorImage.
|
35
|
+
* - **Adding a new component**: {@link EditorImage.addComponent}.
|
36
36
|
*
|
37
37
|
* **Example**:
|
38
38
|
* [[include:doc-pages/inline-examples/image-add-and-lookup.md]]
|
@@ -82,19 +82,23 @@ export default class EditorImage {
|
|
82
82
|
* @returns all elements in the image, sorted by z-index (low to high).
|
83
83
|
*
|
84
84
|
* This can be slow for large images. If you only need all elemenst in part of the image,
|
85
|
-
* consider using {@link
|
85
|
+
* consider using {@link getComponentsIntersecting} instead.
|
86
86
|
*
|
87
87
|
* **Note**: The result does not include background elements. See {@link getBackgroundComponents}.
|
88
88
|
*/
|
89
|
+
getAllComponents(): AbstractComponent[];
|
90
|
+
/** @deprecated in favor of {@link getAllComponents} */
|
89
91
|
getAllElements(): AbstractComponent[];
|
90
92
|
/** Returns the number of elements added to this image. @internal */
|
91
93
|
estimateNumElements(): number;
|
94
|
+
/** @deprecated @see getComponentsIntersecting */
|
95
|
+
getElementsIntersectingRegion(region: Rect2, includeBackground?: boolean): AbstractComponent[];
|
92
96
|
/**
|
93
97
|
* @returns a list of `AbstractComponent`s intersecting `region`, sorted by increasing z-index.
|
94
98
|
*
|
95
99
|
* Components in the background layer are only included if `includeBackground` is `true`.
|
96
100
|
*/
|
97
|
-
|
101
|
+
getComponentsIntersecting(region: Rect2, includeBackground?: boolean): AbstractComponent[];
|
98
102
|
/** Called whenever (just after) an element is completely removed. @internal */
|
99
103
|
onDestroyElement(elem: AbstractComponent): void;
|
100
104
|
/** Called just after an element is added. @internal */
|
@@ -105,7 +109,7 @@ export default class EditorImage {
|
|
105
109
|
* @see {@link AbstractComponent.getId}
|
106
110
|
*/
|
107
111
|
lookupElement(id: string): AbstractComponent | null;
|
108
|
-
private
|
112
|
+
private addComponentDirectly;
|
109
113
|
private removeElementDirectly;
|
110
114
|
/**
|
111
115
|
* Returns a command that adds the given element to the `EditorImage`.
|
@@ -118,10 +122,14 @@ export default class EditorImage {
|
|
118
122
|
*
|
119
123
|
* [[include:doc-pages/inline-examples/adding-a-stroke.md]]
|
120
124
|
*/
|
121
|
-
static
|
122
|
-
/** @see EditorImage.
|
125
|
+
static addComponent(elem: AbstractComponent, applyByFlattening?: boolean): SerializableCommand;
|
126
|
+
/** @see EditorImage.addComponent */
|
127
|
+
addComponent(component: AbstractComponent, applyByFlattening?: boolean): SerializableCommand;
|
128
|
+
/** Alias for {@link addComponent}. @deprecated Prefer `.addComponent` */
|
123
129
|
addElement(elem: AbstractComponent, applyByFlattening?: boolean): SerializableCommand;
|
124
|
-
|
130
|
+
/** Alias for {@link addComponent}. @deprecated Prefer `.addComponent`. */
|
131
|
+
static addElement(elem: AbstractComponent, applyByFlattening?: boolean): SerializableCommand;
|
132
|
+
private static AddComponentCommand;
|
125
133
|
/**
|
126
134
|
* @returns a `Viewport` for rendering the image when importing/exporting.
|
127
135
|
*/
|
@@ -21,7 +21,7 @@ export var EditorImageEventType;
|
|
21
21
|
})(EditorImageEventType || (EditorImageEventType = {}));
|
22
22
|
let debugMode = false;
|
23
23
|
/**
|
24
|
-
*
|
24
|
+
* Handles lookup/storage of elements in the image.
|
25
25
|
*
|
26
26
|
* `js-draw` images are made up of a collection of {@link AbstractComponent}s (which
|
27
27
|
* includes {@link Stroke}s, {@link TextComponent}s, etc.). An `EditorImage`
|
@@ -29,9 +29,9 @@ let debugMode = false;
|
|
29
29
|
*
|
30
30
|
* Here's how to do a few common operations:
|
31
31
|
* - **Get all components in a {@link @js-draw/math!Rect2 | Rect2}**:
|
32
|
-
* {@link EditorImage.
|
32
|
+
* {@link EditorImage.getComponentsIntersecting}.
|
33
33
|
* - **Draw an `EditorImage` onto a canvas/SVG**: {@link EditorImage.render}.
|
34
|
-
* - **Adding a new component**: {@link EditorImage.
|
34
|
+
* - **Adding a new component**: {@link EditorImage.addComponent}.
|
35
35
|
*
|
36
36
|
* **Example**:
|
37
37
|
* [[include:doc-pages/inline-examples/image-add-and-lookup.md]]
|
@@ -78,7 +78,7 @@ class EditorImage {
|
|
78
78
|
const parent = this.findParent(elem);
|
79
79
|
if (parent) {
|
80
80
|
parent.remove();
|
81
|
-
this.
|
81
|
+
this.addComponentDirectly(elem);
|
82
82
|
}
|
83
83
|
}
|
84
84
|
/** @internal */
|
@@ -133,25 +133,33 @@ class EditorImage {
|
|
133
133
|
* @returns all elements in the image, sorted by z-index (low to high).
|
134
134
|
*
|
135
135
|
* This can be slow for large images. If you only need all elemenst in part of the image,
|
136
|
-
* consider using {@link
|
136
|
+
* consider using {@link getComponentsIntersecting} instead.
|
137
137
|
*
|
138
138
|
* **Note**: The result does not include background elements. See {@link getBackgroundComponents}.
|
139
139
|
*/
|
140
|
-
|
140
|
+
getAllComponents() {
|
141
141
|
const leaves = this.root.getLeaves();
|
142
142
|
sortLeavesByZIndex(leaves);
|
143
143
|
return leaves.map((leaf) => leaf.getContent());
|
144
144
|
}
|
145
|
+
/** @deprecated in favor of {@link getAllComponents} */
|
146
|
+
getAllElements() {
|
147
|
+
return this.getAllComponents();
|
148
|
+
}
|
145
149
|
/** Returns the number of elements added to this image. @internal */
|
146
150
|
estimateNumElements() {
|
147
151
|
return this.componentCount;
|
148
152
|
}
|
153
|
+
/** @deprecated @see getComponentsIntersecting */
|
154
|
+
getElementsIntersectingRegion(region, includeBackground = false) {
|
155
|
+
return this.getComponentsIntersecting(region, includeBackground);
|
156
|
+
}
|
149
157
|
/**
|
150
158
|
* @returns a list of `AbstractComponent`s intersecting `region`, sorted by increasing z-index.
|
151
159
|
*
|
152
160
|
* Components in the background layer are only included if `includeBackground` is `true`.
|
153
161
|
*/
|
154
|
-
|
162
|
+
getComponentsIntersecting(region, includeBackground = false) {
|
155
163
|
let leaves = this.root.getLeavesIntersectingRegion(region);
|
156
164
|
if (includeBackground) {
|
157
165
|
leaves = leaves.concat(this.background.getLeavesIntersectingRegion(region));
|
@@ -179,7 +187,7 @@ class EditorImage {
|
|
179
187
|
lookupElement(id) {
|
180
188
|
return this.componentsById[id] ?? null;
|
181
189
|
}
|
182
|
-
|
190
|
+
addComponentDirectly(elem) {
|
183
191
|
// Because onAddToImage can affect the element's bounding box,
|
184
192
|
// this needs to be called before parentTree.addLeaf.
|
185
193
|
elem.onAddToImage(this);
|
@@ -210,12 +218,20 @@ class EditorImage {
|
|
210
218
|
*
|
211
219
|
* [[include:doc-pages/inline-examples/adding-a-stroke.md]]
|
212
220
|
*/
|
213
|
-
static
|
214
|
-
return new _a.
|
221
|
+
static addComponent(elem, applyByFlattening = false) {
|
222
|
+
return new _a.AddComponentCommand(elem, applyByFlattening);
|
223
|
+
}
|
224
|
+
/** @see EditorImage.addComponent */
|
225
|
+
addComponent(component, applyByFlattening) {
|
226
|
+
return _a.addComponent(component, applyByFlattening);
|
215
227
|
}
|
216
|
-
/** @
|
228
|
+
/** Alias for {@link addComponent}. @deprecated Prefer `.addComponent` */
|
217
229
|
addElement(elem, applyByFlattening) {
|
218
|
-
return
|
230
|
+
return this.addComponent(elem, applyByFlattening);
|
231
|
+
}
|
232
|
+
/** Alias for {@link addComponent}. @deprecated Prefer `.addComponent`. */
|
233
|
+
static addElement(elem, applyByFlattening = false) {
|
234
|
+
return this.addComponent(elem, applyByFlattening);
|
219
235
|
}
|
220
236
|
/**
|
221
237
|
* @returns a `Viewport` for rendering the image when importing/exporting.
|
@@ -346,7 +362,7 @@ class EditorImage {
|
|
346
362
|
}
|
347
363
|
_a = EditorImage;
|
348
364
|
// A Command that can access private [EditorImage] functionality
|
349
|
-
EditorImage.
|
365
|
+
EditorImage.AddComponentCommand = (_b = class extends SerializableCommand {
|
350
366
|
// If [applyByFlattening], then the rendered content of this element
|
351
367
|
// is present on the display's wet ink canvas. As such, no re-render is necessary
|
352
368
|
// the first time this command is applied (the surfaces are joined instead).
|
@@ -366,7 +382,7 @@ EditorImage.AddElementCommand = (_b = class extends SerializableCommand {
|
|
366
382
|
}
|
367
383
|
}
|
368
384
|
apply(editor) {
|
369
|
-
editor.image.
|
385
|
+
editor.image.addComponentDirectly(this.element);
|
370
386
|
if (!this.applyByFlattening) {
|
371
387
|
editor.queueRerender();
|
372
388
|
}
|
@@ -380,7 +396,7 @@ EditorImage.AddElementCommand = (_b = class extends SerializableCommand {
|
|
380
396
|
editor.queueRerender();
|
381
397
|
}
|
382
398
|
description(_editor, localization) {
|
383
|
-
return localization.
|
399
|
+
return localization.addComponentAction(this.element.description(localization));
|
384
400
|
}
|
385
401
|
serializeToJSON() {
|
386
402
|
return {
|
@@ -388,13 +404,13 @@ EditorImage.AddElementCommand = (_b = class extends SerializableCommand {
|
|
388
404
|
};
|
389
405
|
}
|
390
406
|
},
|
391
|
-
__setFunctionName(_b, "
|
407
|
+
__setFunctionName(_b, "AddComponentCommand"),
|
392
408
|
(() => {
|
393
409
|
SerializableCommand.register('add-element', (json, editor) => {
|
394
410
|
const id = json.elemData.id;
|
395
411
|
const foundElem = editor.image.lookupElement(id);
|
396
412
|
const elem = foundElem ?? AbstractComponent.deserialize(json.elemData);
|
397
|
-
const result = new _a.
|
413
|
+
const result = new _a.AddComponentCommand(elem);
|
398
414
|
result.serializedElem = json.elemData;
|
399
415
|
return result;
|
400
416
|
});
|
package/dist/mjs/lib.d.ts
CHANGED
@@ -20,7 +20,7 @@ export * from './types';
|
|
20
20
|
export * from './inputEvents';
|
21
21
|
export { default as getLocalizationTable, matchingLocalizationTable, } from './localizations/getLocalizationTable';
|
22
22
|
export * from './localization';
|
23
|
-
export { default as SVGLoader } from './SVGLoader/SVGLoader';
|
23
|
+
export { default as SVGLoader, SVGLoaderPlugin } from './SVGLoader/SVGLoader';
|
24
24
|
export { default as Viewport } from './Viewport';
|
25
25
|
export * from '@js-draw/math';
|
26
26
|
export * from './components/lib';
|
@@ -65,9 +65,9 @@ const localization = {
|
|
65
65
|
toolEnabledAnnouncement: (toolName) => `${toolName} aktiviert`,
|
66
66
|
toolDisabledAnnouncement: (toolName) => `${toolName} deaktiviert`,
|
67
67
|
updatedViewport: 'Transformierte Ansicht',
|
68
|
-
transformedElements: (elemCount) => `${elemCount} Element${1 === elemCount ? '' : 'e'} transformiert`,
|
68
|
+
transformedElements: (elemCount, action) => `${elemCount} Element${1 === elemCount ? '' : 'e'} transformiert (${action})`,
|
69
69
|
resizeOutputCommand: (newSize) => `Bildgröße auf ${newSize.w}x${newSize.h} geändert`,
|
70
|
-
|
70
|
+
addComponentAction: (componentDescription) => `${componentDescription} hinzugefügt`,
|
71
71
|
eraseAction: (elemDescription, countErased) => `${countErased} ${elemDescription} gelöscht`,
|
72
72
|
duplicateAction: (elemDescription, countErased) => `${countErased} ${elemDescription} dupliziert`,
|
73
73
|
inverseOf: (actionDescription) => `${actionDescription} umgekehrt`,
|
@@ -1,11 +1,12 @@
|
|
1
1
|
import { Color4 } from '@js-draw/math';
|
2
|
-
interface
|
2
|
+
export interface StrokeStyle {
|
3
|
+
readonly color: Color4;
|
4
|
+
/** Note: The stroke `width` is twice the stroke radius. */
|
5
|
+
readonly width: number;
|
6
|
+
}
|
7
|
+
export interface RenderingStyle {
|
3
8
|
readonly fill: Color4;
|
4
|
-
readonly stroke?:
|
5
|
-
readonly color: Color4;
|
6
|
-
/** Note: The stroke `width` is twice the stroke radius. */
|
7
|
-
readonly width: number;
|
8
|
-
};
|
9
|
+
readonly stroke?: StrokeStyle;
|
9
10
|
}
|
10
11
|
export default RenderingStyle;
|
11
12
|
export declare const cloneStyle: (style: RenderingStyle) => {
|
@@ -4,5 +4,5 @@ export { default as SVGRenderer } from './renderers/SVGRenderer';
|
|
4
4
|
export { default as CanvasRenderer } from './renderers/CanvasRenderer';
|
5
5
|
export { default as Display, RenderingMode } from './Display';
|
6
6
|
export { default as TextRenderingStyle } from './TextRenderingStyle';
|
7
|
-
export { default as RenderingStyle } from './RenderingStyle';
|
7
|
+
export { default as RenderingStyle, StrokeStyle as StrokeRenerdingStyle } from './RenderingStyle';
|
8
8
|
export { pathToRenderable, pathFromRenderable, visualEquivalent as pathVisualEquivalent, default as RenderablePathSpec, } from './RenderablePathSpec';
|
@@ -140,6 +140,8 @@ export default class AbstractRenderer {
|
|
140
140
|
this.selfTransform = transform;
|
141
141
|
}
|
142
142
|
pushTransform(transform) {
|
143
|
+
// Draw all pending paths that used the previous transform (if any).
|
144
|
+
this.flushPath();
|
143
145
|
this.transformStack.push(this.selfTransform);
|
144
146
|
this.setTransform(this.getCanvasToScreenTransform().rightMul(transform));
|
145
147
|
}
|
@@ -147,6 +149,8 @@ export default class AbstractRenderer {
|
|
147
149
|
if (this.transformStack.length === 0) {
|
148
150
|
throw new Error('Unable to pop more transforms than have been pushed!');
|
149
151
|
}
|
152
|
+
// Draw all pending paths that used the old transform (if any):
|
153
|
+
this.flushPath();
|
150
154
|
this.setTransform(this.transformStack.pop() ?? null);
|
151
155
|
}
|
152
156
|
// Get the matrix that transforms a vector on the canvas to a vector on this'
|
@@ -42,6 +42,15 @@ export default class CanvasRenderer extends AbstractRenderer {
|
|
42
42
|
private clipLevels;
|
43
43
|
startObject(boundingBox: Rect2, clip?: boolean): void;
|
44
44
|
endObject(): void;
|
45
|
+
/**
|
46
|
+
* Returns a reference to the underlying `CanvasRenderingContext2D`.
|
47
|
+
* This can be used to render custom content not supported by {@link AbstractRenderer}.
|
48
|
+
* However, such content won't support {@link SVGRenderer} or {@link TextOnlyRenderer}
|
49
|
+
* by default.
|
50
|
+
*
|
51
|
+
* Use with caution.
|
52
|
+
*/
|
53
|
+
drawWithRawRenderingContext(callback: (ctx: CanvasRenderingContext2D) => void): void;
|
45
54
|
drawPoints(...points: Point2[]): void;
|
46
55
|
isTooSmallToRender(rect: Rect2): boolean;
|
47
56
|
static fromViewport(exportViewport: Viewport, options?: {
|
@@ -208,6 +208,20 @@ export default class CanvasRenderer extends AbstractRenderer {
|
|
208
208
|
this.ignoringObject = false;
|
209
209
|
}
|
210
210
|
}
|
211
|
+
/**
|
212
|
+
* Returns a reference to the underlying `CanvasRenderingContext2D`.
|
213
|
+
* This can be used to render custom content not supported by {@link AbstractRenderer}.
|
214
|
+
* However, such content won't support {@link SVGRenderer} or {@link TextOnlyRenderer}
|
215
|
+
* by default.
|
216
|
+
*
|
217
|
+
* Use with caution.
|
218
|
+
*/
|
219
|
+
drawWithRawRenderingContext(callback) {
|
220
|
+
this.ctx.save();
|
221
|
+
this.transformBy(this.getCanvasToScreenTransform());
|
222
|
+
callback(this.ctx);
|
223
|
+
this.ctx.restore();
|
224
|
+
}
|
211
225
|
// @internal
|
212
226
|
drawPoints(...points) {
|
213
227
|
const pointRadius = 10;
|
@@ -15,6 +15,9 @@ type FromViewportOptions = {
|
|
15
15
|
*/
|
16
16
|
useViewBoxForPositioning?: boolean;
|
17
17
|
};
|
18
|
+
type DrawWithSVGParentContext = {
|
19
|
+
sanitize: boolean;
|
20
|
+
};
|
18
21
|
/**
|
19
22
|
* Renders onto an `SVGElement`.
|
20
23
|
*
|
@@ -57,7 +60,22 @@ export default class SVGRenderer extends AbstractRenderer {
|
|
57
60
|
protected traceCubicBezierCurve(_controlPoint1: Point2, _controlPoint2: Point2, _endPoint: Point2): void;
|
58
61
|
protected traceQuadraticBezierCurve(_controlPoint: Point2, _endPoint: Point2): void;
|
59
62
|
drawPoints(...points: Point2[]): void;
|
63
|
+
/**
|
64
|
+
* Adds a **copy** of the given element directly to the container
|
65
|
+
* SVG element, **without applying transforms**.
|
66
|
+
*
|
67
|
+
* If `sanitize` is enabled, this does nothing.
|
68
|
+
*/
|
60
69
|
drawSVGElem(elem: SVGElement): void;
|
70
|
+
/**
|
71
|
+
* Allows rendering directly to the underlying SVG element. Rendered
|
72
|
+
* content is added to a `<g>` element that's passed as `parent` to `callback`.
|
73
|
+
*
|
74
|
+
* **Note**: Unlike {@link drawSVGElem}, this method can be used even if `sanitize` is `true`.
|
75
|
+
* In this case, it's the responsibility of `callback` to ensure that everything added
|
76
|
+
* to `parent` is safe to render.
|
77
|
+
*/
|
78
|
+
drawWithSVGParent(callback: (parent: SVGGElement, context: DrawWithSVGParentContext) => void): void;
|
61
79
|
isTooSmallToRender(_rect: Rect2): boolean;
|
62
80
|
/**
|
63
81
|
* Creates a new SVG element and `SVGRenerer` with `width`, `height`, `viewBox`,
|
@@ -341,7 +341,12 @@ export default class SVGRenderer extends AbstractRenderer {
|
|
341
341
|
this.elem.appendChild(elem);
|
342
342
|
});
|
343
343
|
}
|
344
|
-
|
344
|
+
/**
|
345
|
+
* Adds a **copy** of the given element directly to the container
|
346
|
+
* SVG element, **without applying transforms**.
|
347
|
+
*
|
348
|
+
* If `sanitize` is enabled, this does nothing.
|
349
|
+
*/
|
345
350
|
drawSVGElem(elem) {
|
346
351
|
if (this.sanitize) {
|
347
352
|
return;
|
@@ -355,6 +360,21 @@ export default class SVGRenderer extends AbstractRenderer {
|
|
355
360
|
this.elem.appendChild(elemToDraw);
|
356
361
|
this.objectElems?.push(elemToDraw);
|
357
362
|
}
|
363
|
+
/**
|
364
|
+
* Allows rendering directly to the underlying SVG element. Rendered
|
365
|
+
* content is added to a `<g>` element that's passed as `parent` to `callback`.
|
366
|
+
*
|
367
|
+
* **Note**: Unlike {@link drawSVGElem}, this method can be used even if `sanitize` is `true`.
|
368
|
+
* In this case, it's the responsibility of `callback` to ensure that everything added
|
369
|
+
* to `parent` is safe to render.
|
370
|
+
*/
|
371
|
+
drawWithSVGParent(callback) {
|
372
|
+
const parent = document.createElementNS(svgNameSpace, 'g');
|
373
|
+
this.transformFrom(Mat33.identity, parent, true);
|
374
|
+
callback(parent, { sanitize: this.sanitize });
|
375
|
+
this.elem.appendChild(parent);
|
376
|
+
this.objectElems?.push(parent);
|
377
|
+
}
|
358
378
|
isTooSmallToRender(_rect) {
|
359
379
|
return false;
|
360
380
|
}
|
@@ -21,10 +21,10 @@ export type ToolbarActionButtonOptions = {
|
|
21
21
|
export default abstract class AbstractToolbar {
|
22
22
|
#private;
|
23
23
|
protected editor: Editor;
|
24
|
-
protected localizationTable: ToolbarLocalization;
|
25
24
|
private static colorisStarted;
|
25
|
+
protected localizationTable: ToolbarLocalization;
|
26
26
|
/** @internal */
|
27
|
-
constructor(editor: Editor, localizationTable
|
27
|
+
constructor(editor: Editor, localizationTable: ToolbarLocalization);
|
28
28
|
private closeColorPickerOverlay;
|
29
29
|
private setupCloseColorPickerOverlay;
|
30
30
|
setupColorPickers(): void;
|
@@ -12,7 +12,6 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (
|
|
12
12
|
var _AbstractToolbar_listeners, _AbstractToolbar_widgetsById, _AbstractToolbar_widgetList, _AbstractToolbar_updateColoris;
|
13
13
|
import { EditorEventType } from '../types.mjs';
|
14
14
|
import { coloris, close as closeColoris, init as colorisInit } from '@melloware/coloris';
|
15
|
-
import { defaultToolbarLocalization } from './localization.mjs';
|
16
15
|
import SelectionTool from '../tools/SelectionTool/SelectionTool.mjs';
|
17
16
|
import PanZoomTool from '../tools/PanZoom.mjs';
|
18
17
|
import TextTool from '../tools/TextTool.mjs';
|
@@ -39,14 +38,14 @@ import { assertIsObject, assertTruthy } from '../util/assertions.mjs';
|
|
39
38
|
*/
|
40
39
|
class AbstractToolbar {
|
41
40
|
/** @internal */
|
42
|
-
constructor(editor, localizationTable
|
41
|
+
constructor(editor, localizationTable) {
|
43
42
|
this.editor = editor;
|
44
|
-
this.localizationTable = localizationTable;
|
45
43
|
_AbstractToolbar_listeners.set(this, []);
|
46
44
|
_AbstractToolbar_widgetsById.set(this, {});
|
47
45
|
_AbstractToolbar_widgetList.set(this, []);
|
48
46
|
_AbstractToolbar_updateColoris.set(this, null);
|
49
47
|
this.closeColorPickerOverlay = null;
|
48
|
+
this.localizationTable = localizationTable ?? editor.localization;
|
50
49
|
if (!AbstractToolbar.colorisStarted) {
|
51
50
|
colorisInit();
|
52
51
|
AbstractToolbar.colorisStarted = true;
|
@@ -35,7 +35,7 @@ export default class DropdownToolbar extends AbstractToolbar {
|
|
35
35
|
private widgetOrderCounter;
|
36
36
|
private overflowWidget;
|
37
37
|
/** @internal */
|
38
|
-
constructor(editor: Editor, parent: HTMLElement, localizationTable
|
38
|
+
constructor(editor: Editor, parent: HTMLElement, localizationTable: ToolbarLocalization);
|
39
39
|
private reLayoutQueued;
|
40
40
|
private queueReLayout;
|
41
41
|
private reLayout;
|
@@ -1,4 +1,3 @@
|
|
1
|
-
import { defaultToolbarLocalization } from './localization.mjs';
|
2
1
|
import OverflowWidget from './widgets/OverflowWidget.mjs';
|
3
2
|
import AbstractToolbar from './AbstractToolbar.mjs';
|
4
3
|
import { toolbarCSSPrefix } from './constants.mjs';
|
@@ -29,11 +28,11 @@ import { toolbarCSSPrefix } from './constants.mjs';
|
|
29
28
|
* - {@link AbstractToolbar.addExitButton}
|
30
29
|
*/
|
31
30
|
export const makeDropdownToolbar = (editor) => {
|
32
|
-
return new DropdownToolbar(editor, editor.getRootElement());
|
31
|
+
return new DropdownToolbar(editor, editor.getRootElement(), editor.localization);
|
33
32
|
};
|
34
33
|
export default class DropdownToolbar extends AbstractToolbar {
|
35
34
|
/** @internal */
|
36
|
-
constructor(editor, parent, localizationTable
|
35
|
+
constructor(editor, parent, localizationTable) {
|
37
36
|
super(editor, localizationTable);
|
38
37
|
// Flex-order of the next widget to be added.
|
39
38
|
this.widgetOrderCounter = 0;
|
@@ -0,0 +1 @@
|
|
1
|
+
export {};
|
@@ -134,6 +134,8 @@ const createHelpPage = (helpItems, onItemClick, onBackgroundClick, context) => {
|
|
134
134
|
clonedElement.style.margin = '0';
|
135
135
|
const clonedElementContainer = document.createElement('div');
|
136
136
|
clonedElementContainer.classList.add('cloned-element-container');
|
137
|
+
clonedElementContainer.role = 'group';
|
138
|
+
clonedElementContainer.ariaLabel = context.localization.helpControlsAccessibilityLabel;
|
137
139
|
clonedElementContainer.style.position = 'absolute';
|
138
140
|
clonedElementContainer.style.left = `${targetBBox.topLeft.x}px`;
|
139
141
|
clonedElementContainer.style.top = `${targetBBox.topLeft.y}px`;
|
@@ -152,11 +154,11 @@ const createHelpPage = (helpItems, onItemClick, onBackgroundClick, context) => {
|
|
152
154
|
};
|
153
155
|
const onItemChange = () => {
|
154
156
|
const helpTextElement = document.createElement('div');
|
155
|
-
helpTextElement.
|
157
|
+
helpTextElement.textContent = currentItem?.helpText ?? '';
|
156
158
|
// For tests
|
157
159
|
helpTextElement.classList.add('current-item-help');
|
158
160
|
const navigationHelpElement = document.createElement('div');
|
159
|
-
navigationHelpElement.
|
161
|
+
navigationHelpElement.textContent = context.localization.helpScreenNavigationHelp;
|
160
162
|
navigationHelpElement.classList.add('navigation-help');
|
161
163
|
textLabel.replaceChildren(helpTextElement, ...(currentItemIndex === 0 ? [navigationHelpElement] : []));
|
162
164
|
updateClonedElementStates();
|
@@ -273,8 +275,8 @@ class HelpDisplay {
|
|
273
275
|
navigationButtonContainer.classList.add('navigation-buttons');
|
274
276
|
const nextButton = document.createElement('button');
|
275
277
|
const previousButton = document.createElement('button');
|
276
|
-
nextButton.
|
277
|
-
previousButton.
|
278
|
+
nextButton.textContent = this.context.localization.next;
|
279
|
+
previousButton.textContent = this.context.localization.previous;
|
278
280
|
nextButton.classList.add('next');
|
279
281
|
previousButton.classList.add('previous');
|
280
282
|
const updateButtonVisibility = () => {
|
@@ -62,7 +62,7 @@ class DocumentPropertiesWidget extends BaseWidget {
|
|
62
62
|
setBackgroundType(backgroundType) {
|
63
63
|
const prevBackgroundColor = this.editor.estimateBackgroundColor();
|
64
64
|
const newBackground = new BackgroundComponent(backgroundType, prevBackgroundColor);
|
65
|
-
const addBackgroundCommand = this.editor.image.
|
65
|
+
const addBackgroundCommand = this.editor.image.addComponent(newBackground);
|
66
66
|
return uniteCommands([this.removeBackgroundComponents(), addBackgroundCommand]);
|
67
67
|
}
|
68
68
|
/** Returns the type of the topmost background component */
|
@@ -270,7 +270,7 @@ class InsertImageWidget extends BaseWidget {
|
|
270
270
|
const widthAdjustTransform = Mat33.scaling2D(originalWidth / newWidth);
|
271
271
|
const commands = [];
|
272
272
|
for (const component of newComponents) {
|
273
|
-
commands.push(EditorImage.
|
273
|
+
commands.push(EditorImage.addComponent(component), component.transformBy(originalTransform.rightMul(widthAdjustTransform)), component.setZIndex(editingImage.getZIndex()));
|
274
274
|
}
|
275
275
|
this.editor.dispatch(uniteCommands([...commands, eraseCommand]));
|
276
276
|
selectionTools[0]?.setSelection(newComponents);
|
@@ -17,7 +17,7 @@ labelText, defaultId, choices) => {
|
|
17
17
|
outerContainer.classList.add(`${toolbarCSSPrefix}grid-selector`);
|
18
18
|
const selectedValue = MutableReactiveValue.fromInitialValue(defaultId);
|
19
19
|
const menuContainer = document.createElement('div');
|
20
|
-
menuContainer.
|
20
|
+
menuContainer.role = 'group';
|
21
21
|
menuContainer.id = `${toolbarCSSPrefix}-grid-select-id-${idCounter++}`;
|
22
22
|
stopPropagationOfScrollingWheelEvents(menuContainer);
|
23
23
|
const label = document.createElement('label');
|