js-draw 0.15.0 → 0.15.2
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/.github/ISSUE_TEMPLATE/translation.yml +16 -0
- package/CHANGELOG.md +13 -0
- package/dist/bundle.js +1 -1
- package/dist/src/Color4.d.ts +1 -1
- package/dist/src/Color4.js +5 -1
- package/dist/src/Editor.d.ts +0 -2
- package/dist/src/Editor.js +15 -30
- package/dist/src/EditorImage.d.ts +25 -0
- package/dist/src/EditorImage.js +57 -2
- package/dist/src/EventDispatcher.d.ts +4 -3
- package/dist/src/SVGLoader.d.ts +1 -0
- package/dist/src/SVGLoader.js +15 -1
- package/dist/src/Viewport.d.ts +3 -3
- package/dist/src/Viewport.js +4 -8
- package/dist/src/components/AbstractComponent.d.ts +5 -1
- package/dist/src/components/AbstractComponent.js +22 -8
- package/dist/src/components/ImageBackground.d.ts +41 -0
- package/dist/src/components/ImageBackground.js +132 -0
- package/dist/src/components/ImageComponent.js +2 -0
- package/dist/src/components/builders/ArrowBuilder.d.ts +3 -1
- package/dist/src/components/builders/ArrowBuilder.js +43 -40
- package/dist/src/components/builders/LineBuilder.d.ts +3 -1
- package/dist/src/components/builders/LineBuilder.js +25 -28
- package/dist/src/components/builders/RectangleBuilder.js +1 -1
- package/dist/src/components/lib.d.ts +2 -1
- package/dist/src/components/lib.js +2 -1
- package/dist/src/components/localization.d.ts +2 -0
- package/dist/src/components/localization.js +2 -0
- package/dist/src/math/Mat33.js +43 -5
- package/dist/src/math/Path.d.ts +5 -0
- package/dist/src/math/Path.js +80 -28
- package/dist/src/math/Vec3.js +1 -1
- package/dist/src/rendering/Display.js +1 -1
- package/dist/src/rendering/renderers/AbstractRenderer.d.ts +13 -1
- package/dist/src/rendering/renderers/AbstractRenderer.js +18 -3
- package/dist/src/rendering/renderers/CanvasRenderer.d.ts +2 -1
- package/dist/src/rendering/renderers/CanvasRenderer.js +12 -2
- package/dist/src/rendering/renderers/SVGRenderer.d.ts +1 -1
- package/dist/src/rendering/renderers/SVGRenderer.js +8 -2
- package/dist/src/testing/sendTouchEvent.d.ts +6 -0
- package/dist/src/testing/sendTouchEvent.js +26 -0
- package/dist/src/toolbar/IconProvider.js +1 -2
- package/dist/src/toolbar/widgets/HandToolWidget.js +1 -1
- package/dist/src/tools/Eraser.js +5 -2
- package/dist/src/tools/PanZoom.js +12 -0
- package/dist/src/tools/SelectionTool/Selection.js +1 -1
- package/dist/src/tools/SelectionTool/SelectionTool.js +8 -2
- package/package.json +1 -1
- package/src/Color4.test.ts +6 -0
- package/src/Color4.ts +6 -1
- package/src/Editor.ts +15 -36
- package/src/EditorImage.ts +74 -2
- package/src/EventDispatcher.ts +4 -1
- package/src/SVGLoader.ts +12 -1
- package/src/Viewport.ts +4 -7
- package/src/components/AbstractComponent.transformBy.test.ts +22 -0
- package/src/components/AbstractComponent.ts +21 -4
- package/src/components/ImageBackground.ts +167 -0
- package/src/components/ImageComponent.ts +2 -0
- package/src/components/builders/ArrowBuilder.ts +44 -41
- package/src/components/builders/LineBuilder.ts +26 -28
- package/src/components/builders/RectangleBuilder.ts +1 -1
- package/src/components/lib.ts +2 -0
- package/src/components/localization.ts +4 -0
- package/src/math/Mat33.test.ts +20 -1
- package/src/math/Mat33.ts +47 -5
- package/src/math/Path.ts +87 -28
- package/src/math/Vec3.test.ts +4 -0
- package/src/math/Vec3.ts +1 -1
- package/src/rendering/Display.ts +1 -1
- package/src/rendering/renderers/AbstractRenderer.ts +20 -3
- package/src/rendering/renderers/CanvasRenderer.ts +16 -3
- package/src/rendering/renderers/DummyRenderer.test.ts +1 -2
- package/src/rendering/renderers/SVGRenderer.ts +8 -1
- package/src/testing/sendTouchEvent.ts +43 -0
- package/src/toolbar/IconProvider.ts +1 -2
- package/src/toolbar/toolbar.css +7 -0
- package/src/toolbar/widgets/HandToolWidget.ts +1 -1
- package/src/tools/Eraser.test.ts +24 -1
- package/src/tools/Eraser.ts +6 -2
- package/src/tools/PanZoom.test.ts +267 -23
- package/src/tools/PanZoom.ts +15 -1
- package/src/tools/SelectionTool/Selection.ts +1 -1
- package/src/tools/SelectionTool/SelectionTool.ts +8 -1
- package/src/types.ts +1 -0
package/dist/src/Color4.d.ts
CHANGED
@@ -5,7 +5,7 @@ export default class Color4 {
|
|
5
5
|
readonly g: number;
|
6
6
|
/** Blue component. `b` ∈ [0, 1] */
|
7
7
|
readonly b: number;
|
8
|
-
/** Alpha/transparent component. `a` ∈ [0, 1] */
|
8
|
+
/** Alpha/transparent component. `a` ∈ [0, 1]. 0 = transparent */
|
9
9
|
readonly a: number;
|
10
10
|
private constructor();
|
11
11
|
/**
|
package/dist/src/Color4.js
CHANGED
@@ -6,7 +6,7 @@ export default class Color4 {
|
|
6
6
|
g,
|
7
7
|
/** Blue component. `b` ∈ [0, 1] */
|
8
8
|
b,
|
9
|
-
/** Alpha/transparent component. `a` ∈ [0, 1] */
|
9
|
+
/** Alpha/transparent component. `a` ∈ [0, 1]. 0 = transparent */
|
10
10
|
a) {
|
11
11
|
this.r = r;
|
12
12
|
this.g = g;
|
@@ -103,6 +103,10 @@ export default class Color4 {
|
|
103
103
|
if (other == null) {
|
104
104
|
return false;
|
105
105
|
}
|
106
|
+
// If both completely transparent,
|
107
|
+
if (this.a === 0 && other.a === 0) {
|
108
|
+
return true;
|
109
|
+
}
|
106
110
|
return this.toHexString() === other.toHexString();
|
107
111
|
}
|
108
112
|
/**
|
package/dist/src/Editor.d.ts
CHANGED
@@ -84,8 +84,6 @@ export declare class Editor {
|
|
84
84
|
* ```
|
85
85
|
*/
|
86
86
|
readonly image: EditorImage;
|
87
|
-
/** Viewport for the exported/imported image. */
|
88
|
-
private importExportViewport;
|
89
87
|
/**
|
90
88
|
* Allows transforming the view and querying information about
|
91
89
|
* what is currently visible.
|
package/dist/src/Editor.js
CHANGED
@@ -10,7 +10,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
10
10
|
import EditorImage from './EditorImage';
|
11
11
|
import ToolController from './tools/ToolController';
|
12
12
|
import { InputEvtType, EditorEventType } from './types';
|
13
|
-
import Command from './commands/Command';
|
14
13
|
import UndoRedoHistory from './UndoRedoHistory';
|
15
14
|
import Viewport from './Viewport';
|
16
15
|
import EventDispatcher from './EventDispatcher';
|
@@ -119,15 +118,18 @@ export class Editor {
|
|
119
118
|
this.renderingRegion.setAttribute('tabIndex', '0');
|
120
119
|
this.renderingRegion.setAttribute('alt', '');
|
121
120
|
this.notifier = new EventDispatcher();
|
122
|
-
this.
|
123
|
-
|
121
|
+
this.viewport = new Viewport((oldTransform, newTransform) => {
|
122
|
+
this.notifier.dispatch(EditorEventType.ViewportChanged, {
|
123
|
+
kind: EditorEventType.ViewportChanged,
|
124
|
+
newTransform,
|
125
|
+
oldTransform,
|
126
|
+
});
|
127
|
+
});
|
124
128
|
this.display = new Display(this, this.settings.renderingMode, this.renderingRegion);
|
125
129
|
this.image = new EditorImage();
|
126
130
|
this.history = new UndoRedoHistory(this, this.announceRedoCallback, this.announceUndoCallback);
|
127
131
|
this.toolController = new ToolController(this, this.localization);
|
128
132
|
parent.appendChild(this.container);
|
129
|
-
// Default to a 500x500 image
|
130
|
-
this.importExportViewport.updateScreenSize(Vec2.of(500, 500));
|
131
133
|
this.viewport.updateScreenSize(Vec2.of(this.display.width, this.display.height));
|
132
134
|
this.registerListeners();
|
133
135
|
this.queueRerender();
|
@@ -582,7 +584,7 @@ export class Editor {
|
|
582
584
|
if (showImageBounds) {
|
583
585
|
const exportRectFill = { fill: Color4.fromHex('#44444455') };
|
584
586
|
const exportRectStrokeWidth = 5 * this.viewport.getSizeOfPixelOnCanvas();
|
585
|
-
renderer.drawRect(this.
|
587
|
+
renderer.drawRect(this.getImportExportRect(), exportRectStrokeWidth, exportRectFill);
|
586
588
|
}
|
587
589
|
this.rerenderQueued = false;
|
588
590
|
this.nextRerenderListeners.forEach(listener => listener());
|
@@ -693,21 +695,22 @@ export class Editor {
|
|
693
695
|
// The export resolution is the same as the size of the drawing canvas.
|
694
696
|
toDataURL(format = 'image/png') {
|
695
697
|
const canvas = document.createElement('canvas');
|
696
|
-
const
|
698
|
+
const importExportViewport = this.image.getImportExportViewport();
|
699
|
+
const resolution = importExportViewport.getScreenRectSize();
|
697
700
|
canvas.width = resolution.x;
|
698
701
|
canvas.height = resolution.y;
|
699
702
|
const ctx = canvas.getContext('2d');
|
700
|
-
const renderer = new CanvasRenderer(ctx,
|
703
|
+
const renderer = new CanvasRenderer(ctx, importExportViewport);
|
701
704
|
this.image.renderAll(renderer);
|
702
705
|
const dataURL = canvas.toDataURL(format);
|
703
706
|
return dataURL;
|
704
707
|
}
|
705
708
|
toSVG() {
|
706
|
-
const importExportViewport = this.
|
709
|
+
const importExportViewport = this.image.getImportExportViewport();
|
707
710
|
const svgNameSpace = 'http://www.w3.org/2000/svg';
|
708
711
|
const result = document.createElementNS(svgNameSpace, 'svg');
|
709
712
|
const renderer = new SVGRenderer(result, importExportViewport);
|
710
|
-
const origTransform =
|
713
|
+
const origTransform = importExportViewport.canvasToScreenTransform;
|
711
714
|
// Render with (0,0) at (0,0) — we'll handle translation with
|
712
715
|
// the viewBox property.
|
713
716
|
importExportViewport.resetTransform(Mat33.identity);
|
@@ -749,29 +752,11 @@ export class Editor {
|
|
749
752
|
}
|
750
753
|
// Returns the size of the visible region of the output SVG
|
751
754
|
getImportExportRect() {
|
752
|
-
return this.
|
755
|
+
return this.image.getImportExportViewport().visibleRect;
|
753
756
|
}
|
754
757
|
// Resize the output SVG to match `imageRect`.
|
755
758
|
setImportExportRect(imageRect) {
|
756
|
-
|
757
|
-
const origTransform = this.importExportViewport.canvasToScreenTransform;
|
758
|
-
return new class extends Command {
|
759
|
-
apply(editor) {
|
760
|
-
const viewport = editor.importExportViewport;
|
761
|
-
viewport.updateScreenSize(imageRect.size);
|
762
|
-
viewport.resetTransform(Mat33.translation(imageRect.topLeft.times(-1)));
|
763
|
-
editor.queueRerender();
|
764
|
-
}
|
765
|
-
unapply(editor) {
|
766
|
-
const viewport = editor.importExportViewport;
|
767
|
-
viewport.updateScreenSize(origSize);
|
768
|
-
viewport.resetTransform(origTransform);
|
769
|
-
editor.queueRerender();
|
770
|
-
}
|
771
|
-
description(_editor, localizationTable) {
|
772
|
-
return localizationTable.resizeOutputCommand(imageRect);
|
773
|
-
}
|
774
|
-
};
|
759
|
+
return this.image.setImportExportRect(imageRect);
|
775
760
|
}
|
776
761
|
/**
|
777
762
|
* Alias for loadFrom(SVGLoader.fromString).
|
@@ -1,14 +1,36 @@
|
|
1
|
+
import Editor from './Editor';
|
1
2
|
import AbstractRenderer from './rendering/renderers/AbstractRenderer';
|
2
3
|
import Viewport from './Viewport';
|
3
4
|
import AbstractComponent from './components/AbstractComponent';
|
4
5
|
import Rect2 from './math/Rect2';
|
6
|
+
import { EditorLocalization } from './localization';
|
5
7
|
import RenderingCache from './rendering/caching/RenderingCache';
|
6
8
|
import SerializableCommand from './commands/SerializableCommand';
|
9
|
+
import EventDispatcher from './EventDispatcher';
|
7
10
|
export declare const sortLeavesByZIndex: (leaves: Array<ImageNode>) => void;
|
11
|
+
export declare enum EditorImageEventType {
|
12
|
+
ExportViewportChanged = 0
|
13
|
+
}
|
14
|
+
export type EditorImageNotifier = EventDispatcher<EditorImageEventType, {
|
15
|
+
image: EditorImage;
|
16
|
+
}>;
|
8
17
|
export default class EditorImage {
|
9
18
|
private root;
|
10
19
|
private componentsById;
|
20
|
+
/** Viewport for the exported/imported image. */
|
21
|
+
private importExportViewport;
|
22
|
+
readonly notifier: EditorImageNotifier;
|
11
23
|
constructor();
|
24
|
+
/**
|
25
|
+
* @returns a `Viewport` for rendering the image when importing/exporting.
|
26
|
+
*/
|
27
|
+
getImportExportViewport(): Viewport;
|
28
|
+
setImportExportRect(imageRect: Rect2): {
|
29
|
+
apply(editor: Editor): void;
|
30
|
+
unapply(editor: Editor): void;
|
31
|
+
description(_editor: Editor, localizationTable: EditorLocalization): string;
|
32
|
+
onDrop(_editor: Editor): void;
|
33
|
+
};
|
12
34
|
findParent(elem: AbstractComponent): ImageNode | null;
|
13
35
|
queueRerenderOf(elem: AbstractComponent): void;
|
14
36
|
/** @internal */
|
@@ -30,6 +52,7 @@ export default class EditorImage {
|
|
30
52
|
*/
|
31
53
|
lookupElement(id: string): AbstractComponent | null;
|
32
54
|
private addElementDirectly;
|
55
|
+
private removeElementDirectly;
|
33
56
|
/**
|
34
57
|
* Returns a command that adds the given element to the `EditorImage`.
|
35
58
|
* If `applyByFlattening` is true, the content of the wet ink renderer is
|
@@ -38,6 +61,8 @@ export default class EditorImage {
|
|
38
61
|
* @see {@link Display.flatten}
|
39
62
|
*/
|
40
63
|
static addElement(elem: AbstractComponent, applyByFlattening?: boolean): SerializableCommand;
|
64
|
+
/** @see EditorImage.addElement */
|
65
|
+
addElement(elem: AbstractComponent, applyByFlattening?: boolean): SerializableCommand;
|
41
66
|
private static AddElementCommand;
|
42
67
|
}
|
43
68
|
type TooSmallToRenderCheck = (rect: Rect2) => boolean;
|
package/dist/src/EditorImage.js
CHANGED
@@ -1,17 +1,62 @@
|
|
1
1
|
var _a;
|
2
|
+
import Viewport from './Viewport';
|
2
3
|
import AbstractComponent from './components/AbstractComponent';
|
3
4
|
import Rect2 from './math/Rect2';
|
4
5
|
import SerializableCommand from './commands/SerializableCommand';
|
6
|
+
import EventDispatcher from './EventDispatcher';
|
7
|
+
import { Vec2 } from './math/Vec2';
|
8
|
+
import Command from './commands/Command';
|
9
|
+
import Mat33 from './math/Mat33';
|
5
10
|
// @internal Sort by z-index, low to high
|
6
11
|
export const sortLeavesByZIndex = (leaves) => {
|
7
12
|
leaves.sort((a, b) => a.getContent().getZIndex() - b.getContent().getZIndex());
|
8
13
|
};
|
14
|
+
export var EditorImageEventType;
|
15
|
+
(function (EditorImageEventType) {
|
16
|
+
EditorImageEventType[EditorImageEventType["ExportViewportChanged"] = 0] = "ExportViewportChanged";
|
17
|
+
})(EditorImageEventType || (EditorImageEventType = {}));
|
9
18
|
// Handles lookup/storage of elements in the image
|
10
19
|
export default class EditorImage {
|
11
20
|
// @internal
|
12
21
|
constructor() {
|
13
22
|
this.root = new ImageNode();
|
14
23
|
this.componentsById = {};
|
24
|
+
this.notifier = new EventDispatcher();
|
25
|
+
this.importExportViewport = new Viewport(() => {
|
26
|
+
this.notifier.dispatch(EditorImageEventType.ExportViewportChanged, {
|
27
|
+
image: this,
|
28
|
+
});
|
29
|
+
});
|
30
|
+
// Default to a 500x500 image
|
31
|
+
this.importExportViewport.updateScreenSize(Vec2.of(500, 500));
|
32
|
+
}
|
33
|
+
/**
|
34
|
+
* @returns a `Viewport` for rendering the image when importing/exporting.
|
35
|
+
*/
|
36
|
+
getImportExportViewport() {
|
37
|
+
return this.importExportViewport;
|
38
|
+
}
|
39
|
+
setImportExportRect(imageRect) {
|
40
|
+
const importExportViewport = this.getImportExportViewport();
|
41
|
+
const origSize = importExportViewport.visibleRect.size;
|
42
|
+
const origTransform = importExportViewport.canvasToScreenTransform;
|
43
|
+
return new class extends Command {
|
44
|
+
apply(editor) {
|
45
|
+
const viewport = editor.image.getImportExportViewport();
|
46
|
+
viewport.updateScreenSize(imageRect.size);
|
47
|
+
viewport.resetTransform(Mat33.translation(imageRect.topLeft.times(-1)));
|
48
|
+
editor.queueRerender();
|
49
|
+
}
|
50
|
+
unapply(editor) {
|
51
|
+
const viewport = editor.image.getImportExportViewport();
|
52
|
+
viewport.updateScreenSize(origSize);
|
53
|
+
viewport.resetTransform(origTransform);
|
54
|
+
editor.queueRerender();
|
55
|
+
}
|
56
|
+
description(_editor, localizationTable) {
|
57
|
+
return localizationTable.resizeOutputCommand(imageRect);
|
58
|
+
}
|
59
|
+
};
|
15
60
|
}
|
16
61
|
// Returns the parent of the given element, if it exists.
|
17
62
|
findParent(elem) {
|
@@ -76,9 +121,14 @@ export default class EditorImage {
|
|
76
121
|
return (_a = this.componentsById[id]) !== null && _a !== void 0 ? _a : null;
|
77
122
|
}
|
78
123
|
addElementDirectly(elem) {
|
124
|
+
elem.onAddToImage(this);
|
79
125
|
this.componentsById[elem.getId()] = elem;
|
80
126
|
return this.root.addLeaf(elem);
|
81
127
|
}
|
128
|
+
removeElementDirectly(element) {
|
129
|
+
const container = this.findParent(element);
|
130
|
+
container === null || container === void 0 ? void 0 : container.remove();
|
131
|
+
}
|
82
132
|
/**
|
83
133
|
* Returns a command that adds the given element to the `EditorImage`.
|
84
134
|
* If `applyByFlattening` is true, the content of the wet ink renderer is
|
@@ -89,6 +139,10 @@ export default class EditorImage {
|
|
89
139
|
static addElement(elem, applyByFlattening = false) {
|
90
140
|
return new EditorImage.AddElementCommand(elem, applyByFlattening);
|
91
141
|
}
|
142
|
+
/** @see EditorImage.addElement */
|
143
|
+
addElement(elem, applyByFlattening = true) {
|
144
|
+
return EditorImage.addElement(elem, applyByFlattening);
|
145
|
+
}
|
92
146
|
}
|
93
147
|
// A Command that can access private [EditorImage] functionality
|
94
148
|
EditorImage.AddElementCommand = (_a = class extends SerializableCommand {
|
@@ -117,8 +171,7 @@ EditorImage.AddElementCommand = (_a = class extends SerializableCommand {
|
|
117
171
|
}
|
118
172
|
}
|
119
173
|
unapply(editor) {
|
120
|
-
|
121
|
-
container === null || container === void 0 ? void 0 : container.remove();
|
174
|
+
editor.image.removeElementDirectly(this.element);
|
122
175
|
editor.queueRerender();
|
123
176
|
}
|
124
177
|
description(_editor, localization) {
|
@@ -305,11 +358,13 @@ export class ImageNode {
|
|
305
358
|
}
|
306
359
|
// Remove this node and all of its children
|
307
360
|
remove() {
|
361
|
+
var _a;
|
308
362
|
if (!this.parent) {
|
309
363
|
this.content = null;
|
310
364
|
this.children = [];
|
311
365
|
return;
|
312
366
|
}
|
367
|
+
(_a = this.content) === null || _a === void 0 ? void 0 : _a.onRemoveFromImage();
|
313
368
|
const oldChildCount = this.parent.children.length;
|
314
369
|
this.parent.children = this.parent.children.filter(node => {
|
315
370
|
return node !== this;
|
@@ -16,13 +16,14 @@
|
|
16
16
|
* @packageDocumentation
|
17
17
|
*/
|
18
18
|
type CallbackHandler<EventType> = (data: EventType) => void;
|
19
|
+
export interface DispatcherEventListener {
|
20
|
+
remove: () => void;
|
21
|
+
}
|
19
22
|
export default class EventDispatcher<EventKeyType extends string | symbol | number, EventMessageType> {
|
20
23
|
private listeners;
|
21
24
|
constructor();
|
22
25
|
dispatch(eventName: EventKeyType, event: EventMessageType): void;
|
23
|
-
on(eventName: EventKeyType, callback: CallbackHandler<EventMessageType>):
|
24
|
-
remove: () => boolean;
|
25
|
-
};
|
26
|
+
on(eventName: EventKeyType, callback: CallbackHandler<EventMessageType>): DispatcherEventListener;
|
26
27
|
/** Removes an event listener. This is equivalent to calling `.remove()` on the object returned by `.on`. */
|
27
28
|
off(eventName: EventKeyType, callback: CallbackHandler<EventMessageType>): void;
|
28
29
|
}
|
package/dist/src/SVGLoader.d.ts
CHANGED
package/dist/src/SVGLoader.js
CHANGED
@@ -8,6 +8,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
8
8
|
});
|
9
9
|
};
|
10
10
|
import Color4 from './Color4';
|
11
|
+
import ImageBackground, { BackgroundType, imageBackgroundCSSClassName } from './components/ImageBackground';
|
11
12
|
import ImageComponent from './components/ImageComponent';
|
12
13
|
import Stroke from './components/Stroke';
|
13
14
|
import SVGGlobalAttributesObject from './components/SVGGlobalAttributesObject';
|
@@ -145,6 +146,14 @@ export default class SVGLoader {
|
|
145
146
|
yield ((_a = this.onAddComponent) === null || _a === void 0 ? void 0 : _a.call(this, elem));
|
146
147
|
});
|
147
148
|
}
|
149
|
+
addBackground(node) {
|
150
|
+
var _a, _b, _c;
|
151
|
+
return __awaiter(this, void 0, void 0, function* () {
|
152
|
+
const fill = Color4.fromString((_b = (_a = node.getAttribute('fill')) !== null && _a !== void 0 ? _a : node.style.fill) !== null && _b !== void 0 ? _b : 'black');
|
153
|
+
const elem = new ImageBackground(BackgroundType.SolidColor, fill);
|
154
|
+
yield ((_c = this.onAddComponent) === null || _c === void 0 ? void 0 : _c.call(this, elem));
|
155
|
+
});
|
156
|
+
}
|
148
157
|
// If given, 'supportedAttrs' will have x, y, etc. attributes that were used in computing the transform added to it,
|
149
158
|
// to prevent storing duplicate transform information when saving the component.
|
150
159
|
getTransform(elem, supportedAttrs, computedStyles) {
|
@@ -307,7 +316,12 @@ export default class SVGLoader {
|
|
307
316
|
// Continue -- visit the node's children.
|
308
317
|
break;
|
309
318
|
case 'path':
|
310
|
-
|
319
|
+
if (node.classList.contains(imageBackgroundCSSClassName)) {
|
320
|
+
yield this.addBackground(node);
|
321
|
+
}
|
322
|
+
else {
|
323
|
+
yield this.addPath(node);
|
324
|
+
}
|
311
325
|
break;
|
312
326
|
case 'text':
|
313
327
|
yield this.addText(node);
|
package/dist/src/Viewport.d.ts
CHANGED
@@ -4,18 +4,18 @@ import Rect2 from './math/Rect2';
|
|
4
4
|
import { Point2, Vec2 } from './math/Vec2';
|
5
5
|
import Vec3 from './math/Vec3';
|
6
6
|
import { StrokeDataPoint } from './types';
|
7
|
-
import { EditorNotifier } from './types';
|
8
7
|
type PointDataType<T extends Point2 | StrokeDataPoint | number> = T extends Point2 ? Point2 : number;
|
9
8
|
export declare abstract class ViewportTransform extends Command {
|
10
9
|
abstract readonly transform: Mat33;
|
11
10
|
}
|
11
|
+
type TransformChangeCallback = (oldTransform: Mat33, newTransform: Mat33) => void;
|
12
12
|
export declare class Viewport {
|
13
|
-
private
|
13
|
+
private onTransformChangeCallback;
|
14
14
|
private static ViewportTransform;
|
15
15
|
private transform;
|
16
16
|
private inverseTransform;
|
17
17
|
private screenRect;
|
18
|
-
constructor(
|
18
|
+
constructor(onTransformChangeCallback: TransformChangeCallback);
|
19
19
|
updateScreenSize(screenSize: Vec2): void;
|
20
20
|
/** Get the screen's visible region transformed into canvas space. */
|
21
21
|
get visibleRect(): Rect2;
|
package/dist/src/Viewport.js
CHANGED
@@ -15,13 +15,12 @@ import Mat33 from './math/Mat33';
|
|
15
15
|
import Rect2 from './math/Rect2';
|
16
16
|
import { Vec2 } from './math/Vec2';
|
17
17
|
import Vec3 from './math/Vec3';
|
18
|
-
import { EditorEventType } from './types';
|
19
18
|
export class ViewportTransform extends Command {
|
20
19
|
}
|
21
20
|
export class Viewport {
|
22
21
|
// @internal
|
23
|
-
constructor(
|
24
|
-
this.
|
22
|
+
constructor(onTransformChangeCallback) {
|
23
|
+
this.onTransformChangeCallback = onTransformChangeCallback;
|
25
24
|
this.resetTransform(Mat33.identity);
|
26
25
|
this.screenRect = Rect2.empty;
|
27
26
|
}
|
@@ -50,14 +49,11 @@ export class Viewport {
|
|
50
49
|
* @param newTransform - should map from canvas coordinates to screen coordinates.
|
51
50
|
*/
|
52
51
|
resetTransform(newTransform = Mat33.identity) {
|
52
|
+
var _a;
|
53
53
|
const oldTransform = this.transform;
|
54
54
|
this.transform = newTransform;
|
55
55
|
this.inverseTransform = newTransform.inverse();
|
56
|
-
this.
|
57
|
-
kind: EditorEventType.ViewportChanged,
|
58
|
-
newTransform,
|
59
|
-
oldTransform,
|
60
|
-
});
|
56
|
+
(_a = this.onTransformChangeCallback) === null || _a === void 0 ? void 0 : _a.call(this, oldTransform, newTransform);
|
61
57
|
}
|
62
58
|
get screenToCanvasTransform() {
|
63
59
|
return this.inverseTransform;
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import SerializableCommand from '../commands/SerializableCommand';
|
2
|
+
import EditorImage from '../EditorImage';
|
2
3
|
import LineSegment2 from '../math/LineSegment2';
|
3
4
|
import Mat33 from '../math/Mat33';
|
4
5
|
import Rect2 from '../math/Rect2';
|
@@ -17,7 +18,7 @@ export default abstract class AbstractComponent {
|
|
17
18
|
private zIndex;
|
18
19
|
private id;
|
19
20
|
private static zIndexCounter;
|
20
|
-
protected constructor(componentKind: string);
|
21
|
+
protected constructor(componentKind: string, initialZIndex?: number);
|
21
22
|
getId(): string;
|
22
23
|
private static deserializationCallbacks;
|
23
24
|
static registerComponent(componentKind: string, deserialize: DeserializeCallback | null): void;
|
@@ -33,6 +34,9 @@ export default abstract class AbstractComponent {
|
|
33
34
|
getZIndex(): number;
|
34
35
|
/** @returns the bounding box of */
|
35
36
|
getBBox(): Rect2;
|
37
|
+
/** Called when this component is added to the given image. */
|
38
|
+
onAddToImage(_image: EditorImage): void;
|
39
|
+
onRemoveFromImage(): void;
|
36
40
|
abstract render(canvas: AbstractRenderer, visibleRect?: Rect2): void;
|
37
41
|
/** @return true if `lineSegment` intersects this component. */
|
38
42
|
abstract intersects(lineSegment: LineSegment2): boolean;
|
@@ -9,12 +9,17 @@ import UnresolvedSerializableCommand from '../commands/UnresolvedCommand';
|
|
9
9
|
export default class AbstractComponent {
|
10
10
|
constructor(
|
11
11
|
// A unique identifier for the type of component
|
12
|
-
componentKind) {
|
12
|
+
componentKind, initialZIndex) {
|
13
13
|
this.componentKind = componentKind;
|
14
14
|
// Stores data attached by a loader.
|
15
15
|
this.loadSaveData = {};
|
16
16
|
this.lastChangedTime = (new Date()).getTime();
|
17
|
-
|
17
|
+
if (initialZIndex !== undefined) {
|
18
|
+
this.zIndex = initialZIndex;
|
19
|
+
}
|
20
|
+
else {
|
21
|
+
this.zIndex = AbstractComponent.zIndexCounter++;
|
22
|
+
}
|
18
23
|
// Create a unique ID.
|
19
24
|
this.id = `${new Date().getTime()}-${Math.random()}`;
|
20
25
|
if (AbstractComponent.deserializationCallbacks[componentKind] === undefined) {
|
@@ -54,6 +59,9 @@ export default class AbstractComponent {
|
|
54
59
|
getBBox() {
|
55
60
|
return this.contentBBox;
|
56
61
|
}
|
62
|
+
/** Called when this component is added to the given image. */
|
63
|
+
onAddToImage(_image) { }
|
64
|
+
onRemoveFromImage() { }
|
57
65
|
/**
|
58
66
|
* @returns true if this component intersects `rect` -- it is entirely contained
|
59
67
|
* within the rectangle or one of the rectangle's edges intersects this component.
|
@@ -80,7 +88,7 @@ export default class AbstractComponent {
|
|
80
88
|
}
|
81
89
|
// Returns a command that updates this component's z-index.
|
82
90
|
setZIndex(newZIndex) {
|
83
|
-
return new AbstractComponent.TransformElementCommand(Mat33.identity, this.getId(), this, newZIndex);
|
91
|
+
return new AbstractComponent.TransformElementCommand(Mat33.identity, this.getId(), this, newZIndex, this.getZIndex());
|
84
92
|
}
|
85
93
|
// @returns true iff this component can be selected (e.g. by the selection tool.)
|
86
94
|
isSelectable() {
|
@@ -163,22 +171,26 @@ AbstractComponent.TransformElementCommand = (_a = class extends UnresolvedSerial
|
|
163
171
|
// Construct a new TransformElementCommand. `component`, while optional, should
|
164
172
|
// be provided if available. If not provided, it will be fetched from the editor's
|
165
173
|
// document when the command is applied.
|
166
|
-
constructor(affineTransfm, componentID, component, targetZIndex) {
|
174
|
+
constructor(affineTransfm, componentID, component, targetZIndex, origZIndex) {
|
167
175
|
super(AbstractComponent.transformElementCommandId, componentID, component);
|
168
176
|
this.affineTransfm = affineTransfm;
|
169
|
-
this.origZIndex =
|
177
|
+
this.origZIndex = origZIndex;
|
170
178
|
this.targetZIndex = targetZIndex !== null && targetZIndex !== void 0 ? targetZIndex : AbstractComponent.zIndexCounter++;
|
171
179
|
// Ensure that we keep drawing on top even after changing the z-index.
|
172
180
|
if (this.targetZIndex >= AbstractComponent.zIndexCounter) {
|
173
181
|
AbstractComponent.zIndexCounter = this.targetZIndex + 1;
|
174
182
|
}
|
183
|
+
if (component && origZIndex === undefined) {
|
184
|
+
this.origZIndex = component.getZIndex();
|
185
|
+
}
|
175
186
|
}
|
176
187
|
resolveComponent(image) {
|
188
|
+
var _a;
|
177
189
|
if (this.component) {
|
178
190
|
return;
|
179
191
|
}
|
180
192
|
super.resolveComponent(image);
|
181
|
-
this.origZIndex = this.component.getZIndex();
|
193
|
+
(_a = this.origZIndex) !== null && _a !== void 0 ? _a : (this.origZIndex = this.component.getZIndex());
|
182
194
|
}
|
183
195
|
updateTransform(editor, newTransfm) {
|
184
196
|
if (!this.component) {
|
@@ -218,16 +230,18 @@ AbstractComponent.TransformElementCommand = (_a = class extends UnresolvedSerial
|
|
218
230
|
id: this.componentID,
|
219
231
|
transfm: this.affineTransfm.toArray(),
|
220
232
|
targetZIndex: this.targetZIndex,
|
233
|
+
origZIndex: this.origZIndex,
|
221
234
|
};
|
222
235
|
}
|
223
236
|
},
|
224
237
|
(() => {
|
225
238
|
SerializableCommand.register(AbstractComponent.transformElementCommandId, (json, editor) => {
|
226
|
-
var _a;
|
239
|
+
var _a, _b;
|
227
240
|
const elem = (_a = editor.image.lookupElement(json.id)) !== null && _a !== void 0 ? _a : undefined;
|
228
241
|
const transform = new Mat33(...json.transfm);
|
229
242
|
const targetZIndex = json.targetZIndex;
|
230
|
-
|
243
|
+
const origZIndex = (_b = json.origZIndex) !== null && _b !== void 0 ? _b : undefined;
|
244
|
+
return new AbstractComponent.TransformElementCommand(transform, json.id, elem, targetZIndex, origZIndex);
|
231
245
|
});
|
232
246
|
})(),
|
233
247
|
_a);
|
@@ -0,0 +1,41 @@
|
|
1
|
+
import Color4 from '../Color4';
|
2
|
+
import Editor from '../Editor';
|
3
|
+
import EditorImage from '../EditorImage';
|
4
|
+
import SerializableCommand from '../commands/SerializableCommand';
|
5
|
+
import LineSegment2 from '../math/LineSegment2';
|
6
|
+
import Mat33 from '../math/Mat33';
|
7
|
+
import Rect2 from '../math/Rect2';
|
8
|
+
import AbstractRenderer from '../rendering/renderers/AbstractRenderer';
|
9
|
+
import AbstractComponent from './AbstractComponent';
|
10
|
+
import { ImageComponentLocalization } from './localization';
|
11
|
+
import RestyleableComponent, { ComponentStyle } from './RestylableComponent';
|
12
|
+
export declare enum BackgroundType {
|
13
|
+
SolidColor = 0,
|
14
|
+
None = 1
|
15
|
+
}
|
16
|
+
export declare const imageBackgroundCSSClassName = "js-draw-image-background";
|
17
|
+
export default class ImageBackground extends AbstractComponent implements RestyleableComponent {
|
18
|
+
private backgroundType;
|
19
|
+
private mainColor;
|
20
|
+
protected contentBBox: Rect2;
|
21
|
+
private viewportSizeChangeListener;
|
22
|
+
readonly isRestylableComponent: true;
|
23
|
+
constructor(backgroundType: BackgroundType, mainColor: Color4);
|
24
|
+
getStyle(): ComponentStyle;
|
25
|
+
updateStyle(style: ComponentStyle): SerializableCommand;
|
26
|
+
forceStyle(style: ComponentStyle, _editor: Editor | null): void;
|
27
|
+
onAddToImage(image: EditorImage): void;
|
28
|
+
onRemoveFromImage(): void;
|
29
|
+
private recomputeBBox;
|
30
|
+
render(canvas: AbstractRenderer, visibleRect?: Rect2): void;
|
31
|
+
intersects(lineSegment: LineSegment2): boolean;
|
32
|
+
isSelectable(): boolean;
|
33
|
+
protected serializeToJSON(): {
|
34
|
+
mainColor: string;
|
35
|
+
backgroundType: BackgroundType;
|
36
|
+
};
|
37
|
+
protected applyTransformation(_affineTransfm: Mat33): void;
|
38
|
+
description(localizationTable: ImageComponentLocalization): string;
|
39
|
+
protected createClone(): AbstractComponent;
|
40
|
+
static deserializeFromJSON(json: any): ImageBackground;
|
41
|
+
}
|