js-draw 1.2.1 → 1.3.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 +30 -30
- package/dist/Editor.css +70 -4
- package/dist/bundle.js +2 -2
- package/dist/bundledStyles.js +1 -1
- package/dist/cjs/Editor.d.ts +73 -40
- package/dist/cjs/Editor.js +90 -24
- package/dist/cjs/EditorImage.d.ts +58 -6
- package/dist/cjs/EditorImage.js +336 -60
- package/dist/cjs/SVGLoader.d.ts +10 -4
- package/dist/cjs/SVGLoader.js +30 -10
- package/dist/cjs/UndoRedoHistory.d.ts +2 -2
- package/dist/cjs/UndoRedoHistory.js +4 -2
- package/dist/cjs/Viewport.d.ts +2 -1
- package/dist/cjs/Viewport.js +12 -3
- package/dist/cjs/commands/Command.d.ts +1 -0
- package/dist/cjs/commands/Command.js +1 -0
- package/dist/cjs/commands/Erase.js +1 -1
- package/dist/cjs/commands/SerializableCommand.d.ts +1 -1
- package/dist/cjs/commands/SerializableCommand.js +16 -2
- package/dist/cjs/commands/localization.d.ts +2 -0
- package/dist/cjs/commands/localization.js +2 -0
- package/dist/cjs/components/AbstractComponent.d.ts +38 -0
- package/dist/cjs/components/AbstractComponent.js +31 -0
- package/dist/cjs/components/BackgroundComponent.d.ts +10 -1
- package/dist/cjs/components/BackgroundComponent.js +60 -6
- package/dist/cjs/components/SVGGlobalAttributesObject.d.ts +2 -1
- package/dist/cjs/components/SVGGlobalAttributesObject.js +30 -1
- package/dist/cjs/components/Stroke.d.ts +1 -0
- package/dist/cjs/components/Stroke.js +44 -0
- package/dist/cjs/components/UnknownSVGObject.d.ts +2 -1
- package/dist/cjs/components/UnknownSVGObject.js +30 -1
- package/dist/cjs/components/lib.d.ts +2 -2
- package/dist/cjs/components/lib.js +15 -2
- package/dist/cjs/lib.d.ts +2 -45
- package/dist/cjs/lib.js +2 -45
- package/dist/cjs/rendering/RenderablePathSpec.d.ts +1 -0
- package/dist/cjs/rendering/RenderablePathSpec.js +1 -0
- package/dist/cjs/rendering/RenderingStyle.d.ts +1 -0
- package/dist/cjs/rendering/lib.d.ts +1 -0
- package/dist/cjs/rendering/lib.js +5 -1
- package/dist/cjs/rendering/renderers/AbstractRenderer.js +1 -1
- package/dist/cjs/shortcuts/KeyboardShortcutManager.d.ts +2 -2
- package/dist/cjs/shortcuts/KeyboardShortcutManager.js +2 -2
- package/dist/cjs/toolbar/localization.d.ts +1 -0
- package/dist/cjs/toolbar/localization.js +1 -0
- package/dist/cjs/toolbar/widgets/BaseWidget.js +5 -0
- package/dist/cjs/toolbar/widgets/DocumentPropertiesWidget.js +54 -25
- package/dist/cjs/toolbar/widgets/components/makeGridSelector.js +8 -0
- package/dist/cjs/tools/PanZoom.js +13 -8
- package/dist/cjs/tools/ScrollbarTool.d.ts +18 -0
- package/dist/cjs/tools/ScrollbarTool.js +85 -0
- package/dist/cjs/tools/SelectionTool/SelectionTool.selecting.test.d.ts +1 -0
- package/dist/cjs/tools/ToolController.js +2 -0
- package/dist/cjs/types.d.ts +3 -1
- package/dist/cjs/util/adjustEditorThemeForContrast.js +1 -0
- package/dist/cjs/util/assertions.d.ts +4 -0
- package/dist/cjs/util/assertions.js +12 -1
- package/dist/cjs/version.js +1 -1
- package/dist/mjs/Editor.d.ts +73 -40
- package/dist/mjs/Editor.mjs +90 -24
- package/dist/mjs/EditorImage.d.ts +58 -6
- package/dist/mjs/EditorImage.mjs +313 -61
- package/dist/mjs/SVGLoader.d.ts +10 -4
- package/dist/mjs/SVGLoader.mjs +29 -9
- package/dist/mjs/UndoRedoHistory.d.ts +2 -2
- package/dist/mjs/UndoRedoHistory.mjs +4 -2
- package/dist/mjs/Viewport.d.ts +2 -1
- package/dist/mjs/Viewport.mjs +12 -3
- package/dist/mjs/commands/Command.d.ts +1 -0
- package/dist/mjs/commands/Command.mjs +1 -0
- package/dist/mjs/commands/Erase.mjs +1 -1
- package/dist/mjs/commands/SerializableCommand.d.ts +1 -1
- package/dist/mjs/commands/SerializableCommand.mjs +16 -2
- package/dist/mjs/commands/localization.d.ts +2 -0
- package/dist/mjs/commands/localization.mjs +2 -0
- package/dist/mjs/components/AbstractComponent.d.ts +38 -0
- package/dist/mjs/components/AbstractComponent.mjs +30 -0
- package/dist/mjs/components/BackgroundComponent.d.ts +10 -1
- package/dist/mjs/components/BackgroundComponent.mjs +37 -6
- package/dist/mjs/components/SVGGlobalAttributesObject.d.ts +2 -1
- package/dist/mjs/components/SVGGlobalAttributesObject.mjs +7 -1
- package/dist/mjs/components/Stroke.d.ts +1 -0
- package/dist/mjs/components/Stroke.mjs +44 -0
- package/dist/mjs/components/UnknownSVGObject.d.ts +2 -1
- package/dist/mjs/components/UnknownSVGObject.mjs +7 -1
- package/dist/mjs/components/lib.d.ts +2 -2
- package/dist/mjs/components/lib.mjs +2 -2
- package/dist/mjs/lib.d.ts +2 -45
- package/dist/mjs/lib.mjs +2 -45
- package/dist/mjs/rendering/RenderablePathSpec.d.ts +1 -0
- package/dist/mjs/rendering/RenderablePathSpec.mjs +1 -0
- package/dist/mjs/rendering/RenderingStyle.d.ts +1 -0
- package/dist/mjs/rendering/lib.d.ts +1 -0
- package/dist/mjs/rendering/lib.mjs +1 -0
- package/dist/mjs/rendering/renderers/AbstractRenderer.mjs +1 -1
- package/dist/mjs/shortcuts/KeyboardShortcutManager.d.ts +2 -2
- package/dist/mjs/shortcuts/KeyboardShortcutManager.mjs +2 -2
- package/dist/mjs/toolbar/localization.d.ts +1 -0
- package/dist/mjs/toolbar/localization.mjs +1 -0
- package/dist/mjs/toolbar/widgets/BaseWidget.mjs +5 -0
- package/dist/mjs/toolbar/widgets/DocumentPropertiesWidget.mjs +54 -25
- package/dist/mjs/toolbar/widgets/components/makeGridSelector.mjs +8 -0
- package/dist/mjs/tools/PanZoom.mjs +13 -8
- package/dist/mjs/tools/ScrollbarTool.d.ts +18 -0
- package/dist/mjs/tools/ScrollbarTool.mjs +79 -0
- package/dist/mjs/tools/SelectionTool/SelectionTool.selecting.test.d.ts +1 -0
- package/dist/mjs/tools/ToolController.mjs +2 -0
- package/dist/mjs/types.d.ts +3 -1
- package/dist/mjs/util/adjustEditorThemeForContrast.mjs +1 -0
- package/dist/mjs/util/assertions.d.ts +4 -0
- package/dist/mjs/util/assertions.mjs +10 -0
- package/dist/mjs/version.mjs +1 -1
- package/package.json +3 -4
- package/src/Editor.scss +8 -0
- package/src/dialogs/dialogs.scss +2 -1
- package/src/toolbar/AbstractToolbar.scss +3 -0
- package/src/toolbar/EdgeToolbar.scss +4 -1
- package/src/toolbar/widgets/DocumentPropertiesWidget.scss +12 -0
- package/src/toolbar/widgets/components/makeGridSelector.scss +6 -1
- package/src/tools/ScrollbarTool.scss +57 -0
- package/src/tools/{SoundUITool.css → SoundUITool.scss} +4 -0
- package/src/tools/tools.scss +2 -1
package/dist/cjs/SVGLoader.js
CHANGED
@@ -26,7 +26,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
26
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
27
27
|
};
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
29
|
-
exports.svgLoaderAttributeContainerID = exports.svgStyleAttributesDataKey = exports.svgAttributesDataKey = exports.defaultSVGViewRect = void 0;
|
29
|
+
exports.svgLoaderAutoresizeClassName = exports.svgLoaderAttributeContainerID = exports.svgStyleAttributesDataKey = exports.svgAttributesDataKey = exports.defaultSVGViewRect = void 0;
|
30
30
|
const math_1 = require("@js-draw/math");
|
31
31
|
const BackgroundComponent_1 = __importStar(require("./components/BackgroundComponent"));
|
32
32
|
const ImageComponent_1 = __importDefault(require("./components/ImageComponent"));
|
@@ -44,13 +44,15 @@ exports.svgStyleAttributesDataKey = 'svgStyleAttrs';
|
|
44
44
|
// Key that specifies the ID of an SVG element that contained a given node when the image
|
45
45
|
// was first loaded.
|
46
46
|
exports.svgLoaderAttributeContainerID = 'svgContainerID';
|
47
|
+
// If present in the exported SVG's class list, the image will be
|
48
|
+
// autoresized when components are added/removed.
|
49
|
+
exports.svgLoaderAutoresizeClassName = 'js-draw--autoresize';
|
47
50
|
const supportedStrokeFillStyleAttrs = ['stroke', 'fill', 'stroke-width'];
|
48
51
|
// Handles loading images from SVG.
|
49
52
|
class SVGLoader {
|
50
|
-
constructor(source, onFinish,
|
53
|
+
constructor(source, onFinish, options) {
|
51
54
|
this.source = source;
|
52
55
|
this.onFinish = onFinish;
|
53
|
-
this.storeUnknown = storeUnknown;
|
54
56
|
this.onAddComponent = null;
|
55
57
|
this.onProgress = null;
|
56
58
|
this.onDetermineExportRect = null;
|
@@ -58,6 +60,8 @@ class SVGLoader {
|
|
58
60
|
this.totalToProcess = 0;
|
59
61
|
this.containerGroupIDs = [];
|
60
62
|
this.encounteredIDs = [];
|
63
|
+
this.storeUnknown = !(options.sanitize ?? false);
|
64
|
+
this.disableUnknownObjectWarnings = !!options.disableUnknownObjectWarnings;
|
61
65
|
}
|
62
66
|
// If [computedStyles] is given, it is preferred to directly accessing node's style object.
|
63
67
|
getStyle(node, computedStyles) {
|
@@ -424,8 +428,9 @@ class SVGLoader {
|
|
424
428
|
console.warn(`node ${node} has an unparsable viewbox. Viewbox: ${viewBoxAttr}. Match: ${components}.`);
|
425
429
|
return;
|
426
430
|
}
|
431
|
+
const autoresize = node.classList.contains(exports.svgLoaderAutoresizeClassName);
|
427
432
|
this.rootViewBox = new math_1.Rect2(x, y, width, height);
|
428
|
-
this.onDetermineExportRect?.(this.rootViewBox);
|
433
|
+
this.onDetermineExportRect?.(this.rootViewBox, { autoresize });
|
429
434
|
}
|
430
435
|
async updateSVGAttrs(node) {
|
431
436
|
if (this.storeUnknown) {
|
@@ -471,9 +476,11 @@ class SVGLoader {
|
|
471
476
|
await this.addUnknownNode(node);
|
472
477
|
break;
|
473
478
|
default:
|
474
|
-
|
475
|
-
|
476
|
-
|
479
|
+
if (!this.disableUnknownObjectWarnings) {
|
480
|
+
console.warn('Unknown SVG element,', node, node.tagName);
|
481
|
+
if (!(node instanceof SVGElement)) {
|
482
|
+
console.warn('Element', node, 'is not an SVGElement!', this.storeUnknown ? 'Continuing anyway.' : 'Skipping.');
|
483
|
+
}
|
477
484
|
}
|
478
485
|
await this.addUnknownNode(node);
|
479
486
|
return;
|
@@ -517,9 +524,9 @@ class SVGLoader {
|
|
517
524
|
*
|
518
525
|
* @see {@link Editor.loadFrom}
|
519
526
|
* @param text - Textual representation of the SVG (e.g. `<svg viewbox='...'>...</svg>`).
|
520
|
-
* @param
|
527
|
+
* @param options - if `true` or `false`, treated as the `sanitize` option -- don't store unknown attributes.
|
521
528
|
*/
|
522
|
-
static fromString(text,
|
529
|
+
static fromString(text, options = false) {
|
523
530
|
const sandbox = document.createElement('iframe');
|
524
531
|
sandbox.src = 'about:blank';
|
525
532
|
sandbox.setAttribute('sandbox', 'allow-same-origin');
|
@@ -557,10 +564,23 @@ class SVGLoader {
|
|
557
564
|
const svgElem = sandboxDoc.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
558
565
|
svgElem.innerHTML = text;
|
559
566
|
sandboxDoc.body.appendChild(svgElem);
|
567
|
+
// Handle options
|
568
|
+
let sanitize;
|
569
|
+
let disableUnknownObjectWarnings;
|
570
|
+
if (typeof options === 'boolean') {
|
571
|
+
sanitize = options;
|
572
|
+
disableUnknownObjectWarnings = false;
|
573
|
+
}
|
574
|
+
else {
|
575
|
+
sanitize = options.sanitize ?? false;
|
576
|
+
disableUnknownObjectWarnings = options.disableUnknownObjectWarnings ?? false;
|
577
|
+
}
|
560
578
|
return new SVGLoader(svgElem, () => {
|
561
579
|
svgElem.remove();
|
562
580
|
sandbox.remove();
|
563
|
-
},
|
581
|
+
}, {
|
582
|
+
sanitize, disableUnknownObjectWarnings,
|
583
|
+
});
|
564
584
|
}
|
565
585
|
}
|
566
586
|
exports.default = SVGLoader;
|
@@ -11,8 +11,8 @@ declare class UndoRedoHistory {
|
|
11
11
|
constructor(editor: Editor, announceRedoCallback: AnnounceRedoCallback, announceUndoCallback: AnnounceUndoCallback);
|
12
12
|
private fireUpdateEvent;
|
13
13
|
push(command: Command, apply?: boolean): void;
|
14
|
-
undo(): void
|
15
|
-
redo(): void
|
14
|
+
undo(): void | Promise<void>;
|
15
|
+
redo(): void | Promise<void>;
|
16
16
|
get undoStackSize(): number;
|
17
17
|
get redoStackSize(): number;
|
18
18
|
}
|
@@ -60,26 +60,28 @@ class UndoRedoHistory {
|
|
60
60
|
const command = __classPrivateFieldGet(this, _UndoRedoHistory_undoStack, "f").pop();
|
61
61
|
if (command) {
|
62
62
|
__classPrivateFieldGet(this, _UndoRedoHistory_redoStack, "f").push(command);
|
63
|
-
command.unapply(this.editor);
|
63
|
+
const result = command.unapply(this.editor);
|
64
64
|
this.announceUndoCallback(command);
|
65
65
|
this.fireUpdateEvent(types_1.UndoEventType.CommandUndone, command);
|
66
66
|
this.editor.notifier.dispatch(types_1.EditorEventType.CommandUndone, {
|
67
67
|
kind: types_1.EditorEventType.CommandUndone,
|
68
68
|
command,
|
69
69
|
});
|
70
|
+
return result;
|
70
71
|
}
|
71
72
|
}
|
72
73
|
redo() {
|
73
74
|
const command = __classPrivateFieldGet(this, _UndoRedoHistory_redoStack, "f").pop();
|
74
75
|
if (command) {
|
75
76
|
__classPrivateFieldGet(this, _UndoRedoHistory_undoStack, "f").push(command);
|
76
|
-
command.apply(this.editor);
|
77
|
+
const result = command.apply(this.editor);
|
77
78
|
this.announceRedoCallback(command);
|
78
79
|
this.fireUpdateEvent(types_1.UndoEventType.CommandRedone, command);
|
79
80
|
this.editor.notifier.dispatch(types_1.EditorEventType.CommandDone, {
|
80
81
|
kind: types_1.EditorEventType.CommandDone,
|
81
82
|
command,
|
82
83
|
});
|
84
|
+
return result;
|
83
85
|
}
|
84
86
|
}
|
85
87
|
get undoStackSize() {
|
package/dist/cjs/Viewport.d.ts
CHANGED
@@ -18,6 +18,7 @@ export declare class Viewport {
|
|
18
18
|
* useful when rendering with a temporarily different viewport.
|
19
19
|
*/
|
20
20
|
getTemporaryClone(): Viewport;
|
21
|
+
/** Resizes the screen rect to the given size. @internal */
|
21
22
|
updateScreenSize(screenSize: Vec2): void;
|
22
23
|
/** Get the screen's visible region transformed into canvas space. */
|
23
24
|
get visibleRect(): Rect2;
|
@@ -34,7 +35,7 @@ export declare class Viewport {
|
|
34
35
|
resetTransform(newTransform?: Mat33): void;
|
35
36
|
get screenToCanvasTransform(): Mat33;
|
36
37
|
get canvasToScreenTransform(): Mat33;
|
37
|
-
/** @returns the size of the visible region in pixels. */
|
38
|
+
/** @returns the size of the visible region in pixels (screen units). */
|
38
39
|
getScreenRectSize(): Vec2;
|
39
40
|
/** Alias for `getScreenRectSize`. @deprecated */
|
40
41
|
getResolution(): Vec3;
|
package/dist/cjs/Viewport.js
CHANGED
@@ -39,7 +39,7 @@ class Viewport {
|
|
39
39
|
result.screenRect = this.screenRect;
|
40
40
|
return result;
|
41
41
|
}
|
42
|
-
|
42
|
+
/** Resizes the screen rect to the given size. @internal */
|
43
43
|
updateScreenSize(screenSize) {
|
44
44
|
this.screenRect = this.screenRect.resizedTo(screenSize);
|
45
45
|
}
|
@@ -75,7 +75,7 @@ class Viewport {
|
|
75
75
|
get canvasToScreenTransform() {
|
76
76
|
return this.transform;
|
77
77
|
}
|
78
|
-
/** @returns the size of the visible region in pixels. */
|
78
|
+
/** @returns the size of the visible region in pixels (screen units). */
|
79
79
|
getScreenRectSize() {
|
80
80
|
return this.screenRect.size;
|
81
81
|
}
|
@@ -157,8 +157,17 @@ class Viewport {
|
|
157
157
|
// Computes and returns an affine transformation that makes `toMakeVisible` visible and roughly centered on the screen.
|
158
158
|
computeZoomToTransform(toMakeVisible, allowZoomIn = true, allowZoomOut = true) {
|
159
159
|
let transform = math_1.Mat33.identity;
|
160
|
+
// Invalid size? (Would divide by zero)
|
160
161
|
if (toMakeVisible.w === 0 || toMakeVisible.h === 0) {
|
161
|
-
|
162
|
+
// Create a new rectangle with a valid size
|
163
|
+
let newSize = Math.max(toMakeVisible.w, toMakeVisible.h);
|
164
|
+
// Choose a reasonable default size, but don't zoom.
|
165
|
+
if (newSize === 0) {
|
166
|
+
newSize = 50;
|
167
|
+
allowZoomIn = false;
|
168
|
+
allowZoomOut = false;
|
169
|
+
}
|
170
|
+
toMakeVisible = new math_1.Rect2(toMakeVisible.x, toMakeVisible.y, newSize, newSize);
|
162
171
|
}
|
163
172
|
if (isNaN(toMakeVisible.size.magnitude())) {
|
164
173
|
throw new Error(`${toMakeVisible.toString()} rectangle has NaN size! Cannot zoom to!`);
|
@@ -5,6 +5,7 @@ export declare abstract class Command {
|
|
5
5
|
abstract unapply(editor: Editor): Promise<void> | void;
|
6
6
|
onDrop(_editor: Editor): void;
|
7
7
|
abstract description(editor: Editor, localizationTable: EditorLocalization): string;
|
8
|
+
/** @deprecated Use {@link uniteCommands} */
|
8
9
|
static union(a: Command, b: Command): Command;
|
9
10
|
static readonly empty: {
|
10
11
|
description(_editor: Editor, _localizationTable: EditorLocalization): string;
|
@@ -37,8 +37,8 @@ class Erase extends SerializableCommand_1.default {
|
|
37
37
|
for (const part of this.toRemove) {
|
38
38
|
const parent = editor.image.findParent(part);
|
39
39
|
if (parent) {
|
40
|
-
editor.image.onDestroyElement(part);
|
41
40
|
parent.remove();
|
41
|
+
editor.image.onDestroyElement(part);
|
42
42
|
}
|
43
43
|
}
|
44
44
|
this.applied = true;
|
@@ -2,7 +2,7 @@ import Editor from '../Editor';
|
|
2
2
|
import Command from './Command';
|
3
3
|
export type DeserializationCallback = (data: Record<string, any> | any[], editor: Editor) => SerializableCommand;
|
4
4
|
export default abstract class SerializableCommand extends Command {
|
5
|
-
private
|
5
|
+
#private;
|
6
6
|
constructor(commandTypeId: string);
|
7
7
|
protected abstract serializeToJSON(): string | Record<string, any> | any[];
|
8
8
|
private static deserializationCallbacks;
|
@@ -1,16 +1,29 @@
|
|
1
1
|
"use strict";
|
2
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
3
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
4
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
5
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
6
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
7
|
+
};
|
8
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
9
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
10
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
11
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
12
|
+
};
|
2
13
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
3
14
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
15
|
};
|
16
|
+
var _SerializableCommand_commandTypeId;
|
5
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
6
18
|
const Command_1 = __importDefault(require("./Command"));
|
7
19
|
class SerializableCommand extends Command_1.default {
|
8
20
|
constructor(commandTypeId) {
|
9
21
|
super();
|
10
|
-
this
|
22
|
+
_SerializableCommand_commandTypeId.set(this, void 0);
|
11
23
|
if (!(commandTypeId in SerializableCommand.deserializationCallbacks)) {
|
12
24
|
throw new Error(`Command ${commandTypeId} must have a registered deserialization callback. To do this, call SerializableCommand.register.`);
|
13
25
|
}
|
26
|
+
__classPrivateFieldSet(this, _SerializableCommand_commandTypeId, commandTypeId, "f");
|
14
27
|
}
|
15
28
|
// Convert this command to an object that can be passed to `JSON.stringify`.
|
16
29
|
//
|
@@ -19,7 +32,7 @@ class SerializableCommand extends Command_1.default {
|
|
19
32
|
serialize() {
|
20
33
|
return {
|
21
34
|
data: this.serializeToJSON(),
|
22
|
-
commandType: this
|
35
|
+
commandType: __classPrivateFieldGet(this, _SerializableCommand_commandTypeId, "f"),
|
23
36
|
};
|
24
37
|
}
|
25
38
|
// Convert a `string` containing JSON data (or the output of `JSON.parse`) into a
|
@@ -38,5 +51,6 @@ class SerializableCommand extends Command_1.default {
|
|
38
51
|
SerializableCommand.deserializationCallbacks[commandTypeId] = deserialize;
|
39
52
|
}
|
40
53
|
}
|
54
|
+
_SerializableCommand_commandTypeId = new WeakMap();
|
41
55
|
SerializableCommand.deserializationCallbacks = {};
|
42
56
|
exports.default = SerializableCommand;
|
@@ -13,6 +13,8 @@ export interface CommandLocalization {
|
|
13
13
|
updatedViewport: string;
|
14
14
|
transformedElements: (elemCount: number) => string;
|
15
15
|
resizeOutputCommand: (newSize: Rect2) => string;
|
16
|
+
enabledAutoresizeOutputCommand: string;
|
17
|
+
disabledAutoresizeOutputCommand: string;
|
16
18
|
addElementAction: (elemDescription: string) => string;
|
17
19
|
eraseAction: (elemDescription: string, numElems: number) => string;
|
18
20
|
duplicateAction: (elemDescription: string, count: number) => string;
|
@@ -5,6 +5,8 @@ exports.defaultCommandLocalization = {
|
|
5
5
|
updatedViewport: 'Transformed Viewport',
|
6
6
|
transformedElements: (elemCount) => `Transformed ${elemCount} element${elemCount === 1 ? '' : 's'}`,
|
7
7
|
resizeOutputCommand: (newSize) => `Resized image to ${newSize.w}x${newSize.h}`,
|
8
|
+
enabledAutoresizeOutputCommand: 'Enabled output autoresize',
|
9
|
+
disabledAutoresizeOutputCommand: 'Disabled output autoresize',
|
8
10
|
addElementAction: (componentDescription) => `Added ${componentDescription}`,
|
9
11
|
eraseAction: (componentDescription, numElems) => `Erased ${numElems} ${componentDescription}`,
|
10
12
|
duplicateAction: (componentDescription, numElems) => `Duplicated ${numElems} ${componentDescription}`,
|
@@ -6,12 +6,41 @@ import { ImageComponentLocalization } from './localization';
|
|
6
6
|
export type LoadSaveData = (string[] | Record<symbol, string | number>);
|
7
7
|
export type LoadSaveDataTable = Record<string, Array<LoadSaveData>>;
|
8
8
|
export type DeserializeCallback = (data: string) => AbstractComponent;
|
9
|
+
export declare enum ComponentSizingMode {
|
10
|
+
/** The default. The compnent gets its size from its bounding box. */
|
11
|
+
BoundingBox = 0,
|
12
|
+
/** Causes the component to fill the entire visible region of the screen */
|
13
|
+
FillScreen = 1,
|
14
|
+
/**
|
15
|
+
* Displays the component anywhere (arbitrary location) on the
|
16
|
+
* canvas. (Ignoring the bounding box).
|
17
|
+
*
|
18
|
+
* These components may be ignored unless a full render is done.
|
19
|
+
*
|
20
|
+
* Intended for compnents that need to be rendered on a full export,
|
21
|
+
* but won't be visible to the user.
|
22
|
+
*
|
23
|
+
* For example, a metadata component.
|
24
|
+
*/
|
25
|
+
Anywhere = 2
|
26
|
+
}
|
9
27
|
/**
|
10
28
|
* A base class for everything that can be added to an {@link EditorImage}.
|
11
29
|
*/
|
12
30
|
export default abstract class AbstractComponent {
|
13
31
|
private readonly componentKind;
|
14
32
|
protected lastChangedTime: number;
|
33
|
+
/**
|
34
|
+
* The bounding box of this component.
|
35
|
+
* {@link getBBox}, by default, returns `contentBBox`.
|
36
|
+
* This must be set by components.
|
37
|
+
*
|
38
|
+
* If this changes, {@link EditorImage.queueRerenderOf} should be called for
|
39
|
+
* this object (provided that this object has been added to the editor.)
|
40
|
+
*
|
41
|
+
* **Note**: This value is ignored if {@link getSizingMode} returns `FillScreen`
|
42
|
+
* or `FillImage`.
|
43
|
+
*/
|
15
44
|
protected abstract contentBBox: Rect2;
|
16
45
|
private zIndex;
|
17
46
|
private id;
|
@@ -39,6 +68,15 @@ export default abstract class AbstractComponent {
|
|
39
68
|
* @returns the bounding box of this. Unlike `getBBox`, this should **not** be a rough estimate.
|
40
69
|
*/
|
41
70
|
getExactBBox(): Rect2;
|
71
|
+
/**
|
72
|
+
* Returns information about how this component should be displayed
|
73
|
+
* (e.g. fill the screen or get its size from {@link getBBox}).
|
74
|
+
*
|
75
|
+
* {@link EditorImage.queueRerenderOf} must be called to apply changes to
|
76
|
+
* the output of this method if this component has already been added to an
|
77
|
+
* {@link EditorImage}.
|
78
|
+
*/
|
79
|
+
getSizingMode(): ComponentSizingMode;
|
42
80
|
/** Called when this component is added to the given image. */
|
43
81
|
onAddToImage(_image: EditorImage): void;
|
44
82
|
onRemoveFromImage(): void;
|
@@ -8,10 +8,30 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
8
8
|
};
|
9
9
|
var _a;
|
10
10
|
Object.defineProperty(exports, "__esModule", { value: true });
|
11
|
+
exports.ComponentSizingMode = void 0;
|
11
12
|
const SerializableCommand_1 = __importDefault(require("../commands/SerializableCommand"));
|
12
13
|
const EditorImage_1 = __importDefault(require("../EditorImage"));
|
13
14
|
const math_1 = require("@js-draw/math");
|
14
15
|
const UnresolvedCommand_1 = __importDefault(require("../commands/UnresolvedCommand"));
|
16
|
+
var ComponentSizingMode;
|
17
|
+
(function (ComponentSizingMode) {
|
18
|
+
/** The default. The compnent gets its size from its bounding box. */
|
19
|
+
ComponentSizingMode[ComponentSizingMode["BoundingBox"] = 0] = "BoundingBox";
|
20
|
+
/** Causes the component to fill the entire visible region of the screen */
|
21
|
+
ComponentSizingMode[ComponentSizingMode["FillScreen"] = 1] = "FillScreen";
|
22
|
+
/**
|
23
|
+
* Displays the component anywhere (arbitrary location) on the
|
24
|
+
* canvas. (Ignoring the bounding box).
|
25
|
+
*
|
26
|
+
* These components may be ignored unless a full render is done.
|
27
|
+
*
|
28
|
+
* Intended for compnents that need to be rendered on a full export,
|
29
|
+
* but won't be visible to the user.
|
30
|
+
*
|
31
|
+
* For example, a metadata component.
|
32
|
+
*/
|
33
|
+
ComponentSizingMode[ComponentSizingMode["Anywhere"] = 2] = "Anywhere";
|
34
|
+
})(ComponentSizingMode || (exports.ComponentSizingMode = ComponentSizingMode = {}));
|
15
35
|
/**
|
16
36
|
* A base class for everything that can be added to an {@link EditorImage}.
|
17
37
|
*/
|
@@ -77,6 +97,17 @@ class AbstractComponent {
|
|
77
97
|
getExactBBox() {
|
78
98
|
return this.getBBox();
|
79
99
|
}
|
100
|
+
/**
|
101
|
+
* Returns information about how this component should be displayed
|
102
|
+
* (e.g. fill the screen or get its size from {@link getBBox}).
|
103
|
+
*
|
104
|
+
* {@link EditorImage.queueRerenderOf} must be called to apply changes to
|
105
|
+
* the output of this method if this component has already been added to an
|
106
|
+
* {@link EditorImage}.
|
107
|
+
*/
|
108
|
+
getSizingMode() {
|
109
|
+
return ComponentSizingMode.BoundingBox;
|
110
|
+
}
|
80
111
|
/** Called when this component is added to the given image. */
|
81
112
|
onAddToImage(_image) { }
|
82
113
|
onRemoveFromImage() { }
|
@@ -3,7 +3,7 @@ import EditorImage from '../EditorImage';
|
|
3
3
|
import SerializableCommand from '../commands/SerializableCommand';
|
4
4
|
import { LineSegment2, Mat33, Rect2, Color4 } from '@js-draw/math';
|
5
5
|
import AbstractRenderer from '../rendering/renderers/AbstractRenderer';
|
6
|
-
import AbstractComponent from './AbstractComponent';
|
6
|
+
import AbstractComponent, { ComponentSizingMode } from './AbstractComponent';
|
7
7
|
import { ImageComponentLocalization } from './localization';
|
8
8
|
import RestyleableComponent, { ComponentStyle } from './RestylableComponent';
|
9
9
|
export declare enum BackgroundType {
|
@@ -24,6 +24,8 @@ export default class BackgroundComponent extends AbstractComponent implements Re
|
|
24
24
|
private mainColor;
|
25
25
|
protected contentBBox: Rect2;
|
26
26
|
private viewportSizeChangeListener;
|
27
|
+
private autoresizeChangedListener;
|
28
|
+
private fillsScreen;
|
27
29
|
private gridSize;
|
28
30
|
private gridStrokeWidth;
|
29
31
|
private secondaryColor;
|
@@ -41,10 +43,17 @@ export default class BackgroundComponent extends AbstractComponent implements Re
|
|
41
43
|
onRemoveFromImage(): void;
|
42
44
|
private recomputeBBox;
|
43
45
|
private generateGridPath;
|
46
|
+
/**
|
47
|
+
* @returns this background's bounding box if the screen size is taken into
|
48
|
+
* account (which may be necessary if this component is configured to fill the
|
49
|
+
* entire screen).
|
50
|
+
*/
|
51
|
+
private getFullBoundingBox;
|
44
52
|
render(canvas: AbstractRenderer, visibleRect?: Rect2): void;
|
45
53
|
intersects(lineSegment: LineSegment2): boolean;
|
46
54
|
isSelectable(): boolean;
|
47
55
|
isBackground(): boolean;
|
56
|
+
getSizingMode(): ComponentSizingMode;
|
48
57
|
protected serializeToJSON(): {
|
49
58
|
mainColor: string;
|
50
59
|
secondaryColor: string | undefined;
|
@@ -1,4 +1,27 @@
|
|
1
1
|
"use strict";
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
3
|
+
if (k2 === undefined) k2 = k;
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
7
|
+
}
|
8
|
+
Object.defineProperty(o, k2, desc);
|
9
|
+
}) : (function(o, m, k, k2) {
|
10
|
+
if (k2 === undefined) k2 = k;
|
11
|
+
o[k2] = m[k];
|
12
|
+
}));
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
15
|
+
}) : function(o, v) {
|
16
|
+
o["default"] = v;
|
17
|
+
});
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
19
|
+
if (mod && mod.__esModule) return mod;
|
20
|
+
var result = {};
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
22
|
+
__setModuleDefault(result, mod);
|
23
|
+
return result;
|
24
|
+
};
|
2
25
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
3
26
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
27
|
};
|
@@ -6,7 +29,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
29
|
exports.backgroundTypeToClassNameMap = exports.imageBackgroundNonAutomaticSecondaryColorCSSClassName = exports.imageBackgroundGridSizeCSSPrefix = exports.imageBackgroundCSSClassName = exports.BackgroundType = void 0;
|
7
30
|
const EditorImage_1 = require("../EditorImage");
|
8
31
|
const math_1 = require("@js-draw/math");
|
9
|
-
const AbstractComponent_1 =
|
32
|
+
const AbstractComponent_1 = __importStar(require("./AbstractComponent"));
|
10
33
|
const RestylableComponent_1 = require("./RestylableComponent");
|
11
34
|
const Viewport_1 = __importDefault(require("../Viewport"));
|
12
35
|
const RenderablePathSpec_1 = require("../rendering/RenderablePathSpec");
|
@@ -34,6 +57,10 @@ class BackgroundComponent extends AbstractComponent_1.default {
|
|
34
57
|
this.backgroundType = backgroundType;
|
35
58
|
this.mainColor = mainColor;
|
36
59
|
this.viewportSizeChangeListener = null;
|
60
|
+
this.autoresizeChangedListener = null;
|
61
|
+
// Whether the background should grow/shrink to match the screen size,
|
62
|
+
// rather than being clipped to the image boundaries.
|
63
|
+
this.fillsScreen = false;
|
37
64
|
this.gridSize = Viewport_1.default.getGridSize(2);
|
38
65
|
this.gridStrokeWidth = 0.7;
|
39
66
|
this.secondaryColor = null;
|
@@ -108,22 +135,37 @@ class BackgroundComponent extends AbstractComponent_1.default {
|
|
108
135
|
this.viewportSizeChangeListener = image.notifier.on(EditorImage_1.EditorImageEventType.ExportViewportChanged, () => {
|
109
136
|
this.recomputeBBox(image);
|
110
137
|
});
|
138
|
+
this.autoresizeChangedListener = image.notifier.on(EditorImage_1.EditorImageEventType.AutoresizeModeChanged, () => {
|
139
|
+
this.recomputeBBox(image);
|
140
|
+
});
|
111
141
|
this.recomputeBBox(image);
|
112
142
|
}
|
113
143
|
onRemoveFromImage() {
|
114
144
|
this.viewportSizeChangeListener?.remove();
|
145
|
+
this.autoresizeChangedListener?.remove();
|
115
146
|
this.viewportSizeChangeListener = null;
|
147
|
+
this.autoresizeChangedListener = null;
|
116
148
|
}
|
117
149
|
recomputeBBox(image) {
|
118
150
|
const importExportRect = image.getImportExportViewport().visibleRect;
|
151
|
+
let needsRerender = false;
|
119
152
|
if (!this.contentBBox.eq(importExportRect)) {
|
120
153
|
this.contentBBox = importExportRect;
|
121
|
-
|
154
|
+
needsRerender = true;
|
155
|
+
}
|
156
|
+
const imageAutoresizes = image.getAutoresizeEnabled();
|
157
|
+
if (imageAutoresizes !== this.fillsScreen) {
|
158
|
+
this.fillsScreen = imageAutoresizes;
|
159
|
+
needsRerender = true;
|
160
|
+
}
|
161
|
+
if (needsRerender) {
|
162
|
+
// Re-renders this if already added to the EditorImage.
|
122
163
|
image.queueRerenderOf(this);
|
123
164
|
}
|
124
165
|
}
|
125
166
|
generateGridPath(visibleRect) {
|
126
|
-
const
|
167
|
+
const contentBBox = this.getFullBoundingBox(visibleRect);
|
168
|
+
const targetRect = visibleRect?.grownBy(this.gridStrokeWidth)?.intersection(contentBBox) ?? contentBBox;
|
127
169
|
const roundDownToGrid = (coord) => Math.floor(coord / this.gridSize) * this.gridSize;
|
128
170
|
const roundUpToGrid = (coord) => Math.ceil(coord / this.gridSize) * this.gridSize;
|
129
171
|
const startY = roundUpToGrid(targetRect.y);
|
@@ -164,24 +206,33 @@ class BackgroundComponent extends AbstractComponent_1.default {
|
|
164
206
|
}
|
165
207
|
return new math_1.Path(startPoint, result);
|
166
208
|
}
|
209
|
+
/**
|
210
|
+
* @returns this background's bounding box if the screen size is taken into
|
211
|
+
* account (which may be necessary if this component is configured to fill the
|
212
|
+
* entire screen).
|
213
|
+
*/
|
214
|
+
getFullBoundingBox(visibleRect) {
|
215
|
+
return (this.fillsScreen ? visibleRect : this.contentBBox) ?? this.contentBBox;
|
216
|
+
}
|
167
217
|
render(canvas, visibleRect) {
|
168
218
|
if (this.backgroundType === BackgroundType.None) {
|
169
219
|
return;
|
170
220
|
}
|
171
221
|
const clip = this.backgroundType === BackgroundType.Grid;
|
172
|
-
|
222
|
+
const contentBBox = this.getFullBoundingBox(visibleRect);
|
223
|
+
canvas.startObject(contentBBox, clip);
|
173
224
|
if (this.backgroundType === BackgroundType.SolidColor || this.backgroundType === BackgroundType.Grid) {
|
174
225
|
// If the rectangle for this region contains the visible rect,
|
175
226
|
// we can fill the entire visible rectangle (which may be more efficient than
|
176
227
|
// filling the entire region for this.)
|
177
228
|
if (visibleRect) {
|
178
|
-
const intersection = visibleRect.intersection(
|
229
|
+
const intersection = visibleRect.intersection(contentBBox);
|
179
230
|
if (intersection) {
|
180
231
|
canvas.fillRect(intersection, this.mainColor);
|
181
232
|
}
|
182
233
|
}
|
183
234
|
else {
|
184
|
-
canvas.fillRect(
|
235
|
+
canvas.fillRect(contentBBox, this.mainColor);
|
185
236
|
}
|
186
237
|
}
|
187
238
|
if (this.backgroundType === BackgroundType.Grid) {
|
@@ -219,6 +270,9 @@ class BackgroundComponent extends AbstractComponent_1.default {
|
|
219
270
|
isBackground() {
|
220
271
|
return true;
|
221
272
|
}
|
273
|
+
getSizingMode() {
|
274
|
+
return this.fillsScreen ? AbstractComponent_1.ComponentSizingMode.FillScreen : AbstractComponent_1.ComponentSizingMode.BoundingBox;
|
275
|
+
}
|
222
276
|
serializeToJSON() {
|
223
277
|
return {
|
224
278
|
mainColor: this.mainColor.toHexString(),
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import { LineSegment2, Mat33, Rect2 } from '@js-draw/math';
|
2
2
|
import AbstractRenderer from '../rendering/renderers/AbstractRenderer';
|
3
|
-
import AbstractComponent from './AbstractComponent';
|
3
|
+
import AbstractComponent, { ComponentSizingMode } from './AbstractComponent';
|
4
4
|
import { ImageComponentLocalization } from './localization';
|
5
5
|
type GlobalAttrsList = Array<[string, string | null]>;
|
6
6
|
export default class SVGGlobalAttributesObject extends AbstractComponent {
|
@@ -11,6 +11,7 @@ export default class SVGGlobalAttributesObject extends AbstractComponent {
|
|
11
11
|
intersects(_lineSegment: LineSegment2): boolean;
|
12
12
|
protected applyTransformation(_affineTransfm: Mat33): void;
|
13
13
|
isSelectable(): boolean;
|
14
|
+
getSizingMode(): ComponentSizingMode;
|
14
15
|
protected createClone(): SVGGlobalAttributesObject;
|
15
16
|
description(localization: ImageComponentLocalization): string;
|
16
17
|
protected serializeToJSON(): string | null;
|
@@ -5,13 +5,36 @@
|
|
5
5
|
// @internal
|
6
6
|
// @packageDocumentation
|
7
7
|
//
|
8
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
9
|
+
if (k2 === undefined) k2 = k;
|
10
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
11
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
12
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
13
|
+
}
|
14
|
+
Object.defineProperty(o, k2, desc);
|
15
|
+
}) : (function(o, m, k, k2) {
|
16
|
+
if (k2 === undefined) k2 = k;
|
17
|
+
o[k2] = m[k];
|
18
|
+
}));
|
19
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
20
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
21
|
+
}) : function(o, v) {
|
22
|
+
o["default"] = v;
|
23
|
+
});
|
24
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
25
|
+
if (mod && mod.__esModule) return mod;
|
26
|
+
var result = {};
|
27
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
28
|
+
__setModuleDefault(result, mod);
|
29
|
+
return result;
|
30
|
+
};
|
8
31
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
9
32
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
10
33
|
};
|
11
34
|
Object.defineProperty(exports, "__esModule", { value: true });
|
12
35
|
const math_1 = require("@js-draw/math");
|
13
36
|
const SVGRenderer_1 = __importDefault(require("../rendering/renderers/SVGRenderer"));
|
14
|
-
const AbstractComponent_1 =
|
37
|
+
const AbstractComponent_1 = __importStar(require("./AbstractComponent"));
|
15
38
|
const componentKind = 'svg-global-attributes';
|
16
39
|
// Stores global SVG attributes (e.g. namespace identifiers.)
|
17
40
|
class SVGGlobalAttributesObject extends AbstractComponent_1.default {
|
@@ -37,6 +60,12 @@ class SVGGlobalAttributesObject extends AbstractComponent_1.default {
|
|
37
60
|
isSelectable() {
|
38
61
|
return false;
|
39
62
|
}
|
63
|
+
getSizingMode() {
|
64
|
+
// This component can be shown anywhere (it won't be
|
65
|
+
// visible to the user, it just needs to be saved with
|
66
|
+
// the image).
|
67
|
+
return AbstractComponent_1.ComponentSizingMode.Anywhere;
|
68
|
+
}
|
40
69
|
createClone() {
|
41
70
|
return new SVGGlobalAttributesObject(this.attrs);
|
42
71
|
}
|
@@ -48,6 +48,7 @@ export default class Stroke extends AbstractComponent implements RestyleableComp
|
|
48
48
|
updateStyle(style: ComponentStyle): SerializableCommand;
|
49
49
|
forceStyle(style: ComponentStyle, editor: Editor | null): void;
|
50
50
|
intersects(line: LineSegment2): boolean;
|
51
|
+
intersectsRect(rect: Rect2): boolean;
|
51
52
|
render(canvas: AbstractRenderer, visibleRect?: Rect2): void;
|
52
53
|
getProportionalRenderingTime(): number;
|
53
54
|
private bboxForPart;
|