js-draw 0.1.11 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +1 -0
- package/.firebaserc +5 -0
- package/.github/workflows/firebase-hosting-merge.yml +25 -0
- package/.github/workflows/firebase-hosting-pull-request.yml +22 -0
- package/.github/workflows/github-pages.yml +52 -0
- package/CHANGELOG.md +13 -0
- package/README.md +11 -6
- package/dist/bundle.js +1 -1
- package/dist/src/Color4.d.ts +19 -0
- package/dist/src/Color4.js +24 -3
- package/dist/src/Editor.d.ts +133 -4
- package/dist/src/Editor.js +124 -27
- package/dist/src/EditorImage.d.ts +8 -3
- package/dist/src/EditorImage.js +42 -26
- package/dist/src/EventDispatcher.d.ts +18 -0
- package/dist/src/EventDispatcher.js +19 -4
- package/dist/src/Pointer.d.ts +1 -1
- package/dist/src/Pointer.js +4 -3
- package/dist/src/SVGLoader.d.ts +1 -1
- package/dist/src/SVGLoader.js +14 -6
- package/dist/src/UndoRedoHistory.js +15 -2
- package/dist/src/Viewport.d.ts +8 -25
- package/dist/src/Viewport.js +18 -10
- package/dist/src/bundle/bundled.d.ts +1 -2
- package/dist/src/bundle/bundled.js +1 -2
- package/dist/src/commands/Command.d.ts +2 -2
- package/dist/src/commands/Command.js +4 -4
- package/dist/src/commands/Duplicate.d.ts +2 -2
- package/dist/src/commands/Duplicate.js +4 -5
- package/dist/src/commands/Erase.d.ts +2 -2
- package/dist/src/commands/Erase.js +7 -6
- package/dist/src/commands/SerializableCommand.d.ts +4 -5
- package/dist/src/commands/SerializableCommand.js +12 -4
- package/dist/src/commands/invertCommand.d.ts +4 -0
- package/dist/src/commands/invertCommand.js +44 -0
- package/dist/src/commands/lib.d.ts +6 -0
- package/dist/src/commands/lib.js +6 -0
- package/dist/src/commands/localization.d.ts +2 -1
- package/dist/src/commands/localization.js +1 -0
- package/dist/src/components/AbstractComponent.d.ts +16 -11
- package/dist/src/components/AbstractComponent.js +28 -17
- package/dist/src/components/SVGGlobalAttributesObject.d.ts +4 -4
- package/dist/src/components/SVGGlobalAttributesObject.js +8 -2
- package/dist/src/components/Stroke.d.ts +16 -6
- package/dist/src/components/Stroke.js +12 -9
- package/dist/src/components/Text.d.ts +5 -5
- package/dist/src/components/Text.js +9 -9
- package/dist/src/components/UnknownSVGObject.d.ts +4 -4
- package/dist/src/components/UnknownSVGObject.js +7 -2
- package/dist/src/components/builders/ArrowBuilder.d.ts +1 -1
- package/dist/src/components/builders/ArrowBuilder.js +1 -1
- package/dist/src/components/builders/FreehandLineBuilder.d.ts +8 -3
- package/dist/src/components/builders/FreehandLineBuilder.js +142 -71
- package/dist/src/components/builders/LineBuilder.d.ts +1 -1
- package/dist/src/components/builders/LineBuilder.js +1 -1
- package/dist/src/components/builders/RectangleBuilder.d.ts +1 -1
- package/dist/src/components/builders/RectangleBuilder.js +3 -3
- package/dist/src/components/builders/types.d.ts +1 -1
- package/dist/src/components/lib.d.ts +4 -0
- package/dist/src/components/lib.js +4 -0
- package/dist/src/lib.d.ts +25 -0
- package/dist/src/lib.js +25 -0
- package/dist/src/localization.d.ts +1 -0
- package/dist/src/localization.js +5 -1
- package/dist/src/localizations/es.js +1 -1
- package/dist/src/{geometry → math}/LineSegment2.d.ts +0 -0
- package/dist/src/{geometry → math}/LineSegment2.js +0 -0
- package/dist/src/math/Mat33.d.ts +78 -0
- package/dist/src/{geometry → math}/Mat33.js +48 -20
- package/dist/src/{geometry → math}/Path.d.ts +2 -1
- package/dist/src/{geometry → math}/Path.js +59 -52
- package/dist/src/{geometry → math}/Rect2.d.ts +2 -2
- package/dist/src/{geometry → math}/Rect2.js +0 -0
- package/dist/src/{geometry → math}/Vec2.d.ts +0 -0
- package/dist/src/{geometry → math}/Vec2.js +0 -0
- package/dist/src/math/Vec3.d.ts +96 -0
- package/dist/src/{geometry → math}/Vec3.js +63 -15
- package/dist/src/math/lib.d.ts +7 -0
- package/dist/src/math/lib.js +7 -0
- package/dist/src/math/rounding.d.ts +3 -0
- package/dist/src/math/rounding.js +121 -0
- package/dist/src/rendering/Display.d.ts +47 -1
- package/dist/src/rendering/Display.js +60 -15
- package/dist/src/rendering/caching/CacheRecord.d.ts +3 -2
- package/dist/src/rendering/caching/CacheRecord.js +4 -1
- package/dist/src/rendering/caching/CacheRecordManager.d.ts +5 -4
- package/dist/src/rendering/caching/CacheRecordManager.js +16 -4
- package/dist/src/rendering/caching/RenderingCache.d.ts +2 -3
- package/dist/src/rendering/caching/RenderingCache.js +10 -11
- package/dist/src/rendering/caching/RenderingCacheNode.d.ts +2 -1
- package/dist/src/rendering/caching/RenderingCacheNode.js +18 -7
- package/dist/src/rendering/caching/testUtils.js +1 -1
- package/dist/src/rendering/caching/types.d.ts +2 -4
- package/dist/src/rendering/localization.d.ts +2 -0
- package/dist/src/rendering/localization.js +2 -0
- package/dist/src/rendering/renderers/AbstractRenderer.d.ts +4 -4
- package/dist/src/rendering/renderers/AbstractRenderer.js +2 -2
- package/dist/src/rendering/renderers/CanvasRenderer.d.ts +4 -4
- package/dist/src/rendering/renderers/CanvasRenderer.js +2 -2
- package/dist/src/rendering/renderers/DummyRenderer.d.ts +4 -4
- package/dist/src/rendering/renderers/DummyRenderer.js +1 -1
- package/dist/src/rendering/renderers/SVGRenderer.d.ts +3 -3
- package/dist/src/rendering/renderers/SVGRenderer.js +8 -2
- package/dist/src/rendering/renderers/TextOnlyRenderer.d.ts +5 -3
- package/dist/src/rendering/renderers/TextOnlyRenderer.js +13 -3
- package/dist/src/toolbar/HTMLToolbar.js +1 -0
- package/dist/src/toolbar/icons.d.ts +3 -0
- package/dist/src/toolbar/icons.js +142 -132
- package/dist/src/toolbar/localization.d.ts +2 -1
- package/dist/src/toolbar/localization.js +2 -1
- package/dist/src/toolbar/makeColorInput.js +3 -2
- package/dist/src/toolbar/widgets/ActionButtonWidget.d.ts +13 -0
- package/dist/src/toolbar/widgets/ActionButtonWidget.js +21 -0
- package/dist/src/toolbar/widgets/BaseWidget.js +2 -0
- package/dist/src/toolbar/widgets/HandToolWidget.js +3 -3
- package/dist/src/toolbar/widgets/PenWidget.js +1 -0
- package/dist/src/toolbar/widgets/SelectionWidget.d.ts +0 -1
- package/dist/src/toolbar/widgets/SelectionWidget.js +23 -30
- package/dist/src/tools/Eraser.js +1 -1
- package/dist/src/tools/PanZoom.d.ts +1 -1
- package/dist/src/tools/PanZoom.js +24 -14
- package/dist/src/tools/Pen.d.ts +1 -2
- package/dist/src/tools/Pen.js +8 -1
- package/dist/src/tools/PipetteTool.js +1 -0
- package/dist/src/tools/SelectionTool.d.ts +3 -3
- package/dist/src/tools/SelectionTool.js +51 -28
- package/dist/src/tools/TextTool.js +1 -1
- package/dist/src/types.d.ts +21 -10
- package/dist/src/types.js +7 -5
- package/firebase.json +16 -0
- package/package.json +118 -101
- package/src/Color4.ts +23 -2
- package/src/Editor.ts +181 -37
- package/src/EditorImage.test.ts +2 -4
- package/src/EditorImage.ts +46 -28
- package/src/EventDispatcher.ts +21 -6
- package/src/Pointer.ts +4 -3
- package/src/SVGLoader.ts +14 -6
- package/src/UndoRedoHistory.ts +18 -2
- package/src/Viewport.ts +23 -18
- package/src/bundle/bundled.ts +1 -2
- package/src/commands/Command.ts +5 -5
- package/src/commands/Duplicate.ts +4 -5
- package/src/commands/Erase.ts +7 -6
- package/src/commands/SerializableCommand.ts +17 -9
- package/src/commands/invertCommand.ts +51 -0
- package/src/commands/lib.ts +14 -0
- package/src/commands/localization.ts +3 -1
- package/src/components/AbstractComponent.ts +35 -24
- package/src/components/SVGGlobalAttributesObject.ts +11 -4
- package/src/components/Stroke.test.ts +4 -6
- package/src/components/Stroke.ts +15 -11
- package/src/components/Text.test.ts +2 -2
- package/src/components/Text.ts +9 -10
- package/src/components/UnknownSVGObject.ts +10 -4
- package/src/components/builders/ArrowBuilder.ts +2 -2
- package/src/components/builders/FreehandLineBuilder.ts +190 -80
- package/src/components/builders/LineBuilder.ts +2 -2
- package/src/components/builders/RectangleBuilder.ts +3 -3
- package/src/components/builders/types.ts +1 -1
- package/src/components/lib.ts +9 -0
- package/src/lib.ts +28 -0
- package/src/localization.ts +6 -0
- package/src/localizations/es.ts +2 -1
- package/src/{geometry → math}/LineSegment2.test.ts +0 -0
- package/src/{geometry → math}/LineSegment2.ts +0 -0
- package/src/{geometry → math}/Mat33.test.ts +0 -0
- package/src/{geometry → math}/Mat33.ts +48 -20
- package/src/{geometry → math}/Path.fromString.test.ts +0 -0
- package/src/{geometry → math}/Path.test.ts +0 -0
- package/src/{geometry → math}/Path.toString.test.ts +11 -2
- package/src/{geometry → math}/Path.ts +61 -58
- package/src/{geometry → math}/Rect2.test.ts +0 -0
- package/src/{geometry → math}/Rect2.ts +2 -2
- package/src/{geometry → math}/Vec2.test.ts +0 -0
- package/src/{geometry → math}/Vec2.ts +0 -0
- package/src/{geometry → math}/Vec3.test.ts +0 -0
- package/src/{geometry → math}/Vec3.ts +64 -16
- package/src/math/lib.ts +15 -0
- package/src/math/rounding.test.ts +40 -0
- package/src/math/rounding.ts +147 -0
- package/src/rendering/Display.ts +63 -15
- package/src/rendering/caching/CacheRecord.test.ts +3 -3
- package/src/rendering/caching/CacheRecord.ts +6 -2
- package/src/rendering/caching/CacheRecordManager.ts +34 -8
- package/src/rendering/caching/RenderingCache.test.ts +3 -3
- package/src/rendering/caching/RenderingCache.ts +11 -16
- package/src/rendering/caching/RenderingCacheNode.ts +23 -7
- package/src/rendering/caching/testUtils.ts +1 -1
- package/src/rendering/caching/types.ts +2 -7
- package/src/rendering/localization.ts +4 -0
- package/src/rendering/renderers/AbstractRenderer.ts +4 -4
- package/src/rendering/renderers/CanvasRenderer.ts +5 -5
- package/src/rendering/renderers/DummyRenderer.test.ts +2 -2
- package/src/rendering/renderers/DummyRenderer.ts +4 -4
- package/src/rendering/renderers/SVGRenderer.ts +10 -4
- package/src/rendering/renderers/TextOnlyRenderer.ts +17 -6
- package/src/toolbar/HTMLToolbar.ts +1 -0
- package/src/toolbar/icons.ts +157 -137
- package/src/toolbar/localization.ts +4 -2
- package/src/toolbar/makeColorInput.ts +3 -2
- package/src/toolbar/toolbar.css +1 -1
- package/src/toolbar/widgets/ActionButtonWidget.ts +31 -0
- package/src/toolbar/widgets/BaseWidget.ts +2 -0
- package/src/toolbar/widgets/HandToolWidget.ts +3 -3
- package/src/toolbar/widgets/PenWidget.ts +2 -0
- package/src/toolbar/widgets/SelectionWidget.ts +46 -41
- package/src/tools/Eraser.ts +2 -2
- package/src/tools/PanZoom.ts +28 -17
- package/src/tools/Pen.ts +11 -2
- package/src/tools/PipetteTool.ts +2 -0
- package/src/tools/SelectionTool.test.ts +2 -4
- package/src/tools/SelectionTool.ts +52 -24
- package/src/tools/TextTool.ts +2 -2
- package/src/tools/UndoRedoShortcut.test.ts +1 -1
- package/src/types.ts +23 -7
- package/tsconfig.json +4 -1
- package/typedoc.json +20 -0
- package/dist/src/geometry/Mat33.d.ts +0 -32
- package/dist/src/geometry/Vec3.d.ts +0 -34
package/dist/src/EditorImage.js
CHANGED
@@ -1,12 +1,14 @@
|
|
1
1
|
var _a;
|
2
2
|
import AbstractComponent from './components/AbstractComponent';
|
3
|
-
import Rect2 from './
|
3
|
+
import Rect2 from './math/Rect2';
|
4
4
|
import SerializableCommand from './commands/SerializableCommand';
|
5
|
+
// @internal
|
5
6
|
export const sortLeavesByZIndex = (leaves) => {
|
6
7
|
leaves.sort((a, b) => a.getContent().getZIndex() - b.getContent().getZIndex());
|
7
8
|
};
|
8
9
|
// Handles lookup/storage of elements in the image
|
9
10
|
export default class EditorImage {
|
11
|
+
// @internal
|
10
12
|
constructor() {
|
11
13
|
this.root = new ImageNode();
|
12
14
|
this.componentsById = {};
|
@@ -21,13 +23,15 @@ export default class EditorImage {
|
|
21
23
|
}
|
22
24
|
return null;
|
23
25
|
}
|
26
|
+
/** @internal */
|
24
27
|
renderWithCache(screenRenderer, cache, viewport) {
|
25
28
|
cache.render(screenRenderer, this.root, viewport);
|
26
29
|
}
|
30
|
+
/** @internal */
|
27
31
|
render(renderer, viewport) {
|
28
32
|
this.root.render(renderer, viewport.visibleRect);
|
29
33
|
}
|
30
|
-
|
34
|
+
/** Renders all nodes, even ones not within the viewport. @internal */
|
31
35
|
renderAll(renderer) {
|
32
36
|
const leaves = this.root.getLeaves();
|
33
37
|
sortLeavesByZIndex(leaves);
|
@@ -40,6 +44,7 @@ export default class EditorImage {
|
|
40
44
|
sortLeavesByZIndex(leaves);
|
41
45
|
return leaves.map(leaf => leaf.getContent());
|
42
46
|
}
|
47
|
+
/** @internal */
|
43
48
|
onDestroyElement(elem) {
|
44
49
|
delete this.componentsById[elem.getId()];
|
45
50
|
}
|
@@ -83,24 +88,25 @@ EditorImage.AddElementCommand = (_a = class extends SerializableCommand {
|
|
83
88
|
container === null || container === void 0 ? void 0 : container.remove();
|
84
89
|
editor.queueRerender();
|
85
90
|
}
|
86
|
-
description(localization) {
|
91
|
+
description(_editor, localization) {
|
87
92
|
return localization.addElementAction(this.element.description(localization));
|
88
93
|
}
|
89
|
-
|
90
|
-
return
|
94
|
+
serializeToJSON() {
|
95
|
+
return {
|
91
96
|
elemData: this.element.serialize(),
|
92
|
-
}
|
97
|
+
};
|
93
98
|
}
|
94
99
|
},
|
95
100
|
(() => {
|
96
|
-
SerializableCommand.register('add-element', (
|
97
|
-
const
|
98
|
-
const
|
101
|
+
SerializableCommand.register('add-element', (json, editor) => {
|
102
|
+
const id = json.elemData.id;
|
103
|
+
const foundElem = editor.image.lookupElement(id);
|
104
|
+
const elem = foundElem !== null && foundElem !== void 0 ? foundElem : AbstractComponent.deserialize(json.elemData);
|
99
105
|
return new EditorImage.AddElementCommand(elem);
|
100
106
|
});
|
101
107
|
})(),
|
102
108
|
_a);
|
103
|
-
|
109
|
+
/** Part of the Editor's image. @internal */
|
104
110
|
export class ImageNode {
|
105
111
|
constructor(parent = null) {
|
106
112
|
this.parent = parent;
|
@@ -136,16 +142,22 @@ export class ImageNode {
|
|
136
142
|
// Returns a list of `ImageNode`s with content (and thus no children).
|
137
143
|
getLeavesIntersectingRegion(region, isTooSmall) {
|
138
144
|
const result = [];
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
145
|
+
let current;
|
146
|
+
const workList = [];
|
147
|
+
workList.push(this);
|
148
|
+
const toNext = () => {
|
149
|
+
current = undefined;
|
150
|
+
const next = workList.pop();
|
151
|
+
if (next && !(isTooSmall === null || isTooSmall === void 0 ? void 0 : isTooSmall(next.bbox))) {
|
152
|
+
current = next;
|
153
|
+
if (current.content !== null && current.getBBox().intersection(region)) {
|
154
|
+
result.push(current);
|
155
|
+
}
|
156
|
+
workList.push(...current.getChildrenIntersectingRegion(region));
|
157
|
+
}
|
158
|
+
};
|
159
|
+
while (workList.length > 0) {
|
160
|
+
toNext();
|
149
161
|
}
|
150
162
|
return result;
|
151
163
|
}
|
@@ -180,13 +192,17 @@ export class ImageNode {
|
|
180
192
|
// share a parent.
|
181
193
|
const leafBBox = leaf.getBBox();
|
182
194
|
if (leafBBox.containsRect(this.getBBox())) {
|
183
|
-
// Create a node for this' children and for the new content..
|
184
195
|
const nodeForNewLeaf = new ImageNode(this);
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
196
|
+
if (this.children.length < this.targetChildCount) {
|
197
|
+
this.children.push(nodeForNewLeaf);
|
198
|
+
}
|
199
|
+
else {
|
200
|
+
const nodeForChildren = new ImageNode(this);
|
201
|
+
nodeForChildren.children = this.children;
|
202
|
+
this.children = [nodeForNewLeaf, nodeForChildren];
|
203
|
+
nodeForChildren.recomputeBBox(true);
|
204
|
+
nodeForChildren.updateParents();
|
205
|
+
}
|
190
206
|
return nodeForNewLeaf.addLeaf(leaf);
|
191
207
|
}
|
192
208
|
const containingNodes = this.children.filter(child => child.getBBox().containsRect(leafBBox));
|
@@ -1,3 +1,20 @@
|
|
1
|
+
/**
|
2
|
+
* Handles notifying listeners of events.
|
3
|
+
*
|
4
|
+
* `EventKeyType` is used to distinguish events (e.g. a `ClickEvent` vs a `TouchEvent`)
|
5
|
+
* while `EventMessageType` is the type of the data sent with an event (can be `void`).
|
6
|
+
*
|
7
|
+
* @example
|
8
|
+
* ```
|
9
|
+
* const dispatcher = new EventDispatcher<'event1'|'event2'|'event3', void>();
|
10
|
+
* dispatcher.on('event1', () => {
|
11
|
+
* console.log('Event 1 triggered.');
|
12
|
+
* });
|
13
|
+
* dispatcher.dispatch('event1');
|
14
|
+
* ```
|
15
|
+
*
|
16
|
+
* @packageDocumentation
|
17
|
+
*/
|
1
18
|
declare type CallbackHandler<EventType> = (data: EventType) => void;
|
2
19
|
export default class EventDispatcher<EventKeyType extends string | symbol | number, EventMessageType> {
|
3
20
|
private listeners;
|
@@ -6,6 +23,7 @@ export default class EventDispatcher<EventKeyType extends string | symbol | numb
|
|
6
23
|
on(eventName: EventKeyType, callback: CallbackHandler<EventMessageType>): {
|
7
24
|
remove: () => boolean;
|
8
25
|
};
|
26
|
+
/** Removes an event listener. This is equivalent to calling `.remove()` on the object returned by `.on`. */
|
9
27
|
off(eventName: EventKeyType, callback: CallbackHandler<EventMessageType>): void;
|
10
28
|
}
|
11
29
|
export {};
|
@@ -1,6 +1,21 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
/**
|
2
|
+
* Handles notifying listeners of events.
|
3
|
+
*
|
4
|
+
* `EventKeyType` is used to distinguish events (e.g. a `ClickEvent` vs a `TouchEvent`)
|
5
|
+
* while `EventMessageType` is the type of the data sent with an event (can be `void`).
|
6
|
+
*
|
7
|
+
* @example
|
8
|
+
* ```
|
9
|
+
* const dispatcher = new EventDispatcher<'event1'|'event2'|'event3', void>();
|
10
|
+
* dispatcher.on('event1', () => {
|
11
|
+
* console.log('Event 1 triggered.');
|
12
|
+
* });
|
13
|
+
* dispatcher.dispatch('event1');
|
14
|
+
* ```
|
15
|
+
*
|
16
|
+
* @packageDocumentation
|
17
|
+
*/
|
18
|
+
// { @inheritDoc EventDispatcher! }
|
4
19
|
export default class EventDispatcher {
|
5
20
|
constructor() {
|
6
21
|
this.listeners = {};
|
@@ -26,7 +41,7 @@ export default class EventDispatcher {
|
|
26
41
|
},
|
27
42
|
};
|
28
43
|
}
|
29
|
-
|
44
|
+
/** Removes an event listener. This is equivalent to calling `.remove()` on the object returned by `.on`. */
|
30
45
|
off(eventName, callback) {
|
31
46
|
const listeners = this.listeners[eventName];
|
32
47
|
if (!listeners)
|
package/dist/src/Pointer.d.ts
CHANGED
package/dist/src/Pointer.js
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
import { Vec2 } from './
|
1
|
+
import { Vec2 } from './math/Vec2';
|
2
2
|
export var PointerDevice;
|
3
3
|
(function (PointerDevice) {
|
4
4
|
PointerDevice[PointerDevice["Pen"] = 0] = "Pen";
|
@@ -9,7 +9,7 @@ export var PointerDevice;
|
|
9
9
|
PointerDevice[PointerDevice["Other"] = 5] = "Other";
|
10
10
|
})(PointerDevice || (PointerDevice = {}));
|
11
11
|
// Provides a snapshot containing information about a pointer. A Pointer
|
12
|
-
// object is immutable
|
12
|
+
// object is immutable — it will not be updated when the pointer's information changes.
|
13
13
|
export default class Pointer {
|
14
14
|
constructor(
|
15
15
|
// The (x, y) position of the pointer relative to the top-left corner
|
@@ -20,7 +20,7 @@ export default class Pointer {
|
|
20
20
|
canvasPos, pressure, isPrimary, down, device,
|
21
21
|
// Unique ID for the pointer
|
22
22
|
id,
|
23
|
-
// Numeric timestamp (milliseconds, as from (new Date).getTime())
|
23
|
+
// Numeric timestamp (milliseconds, as from `(new Date).getTime()`)
|
24
24
|
timeStamp) {
|
25
25
|
this.screenPos = screenPos;
|
26
26
|
this.canvasPos = canvasPos;
|
@@ -31,6 +31,7 @@ export default class Pointer {
|
|
31
31
|
this.id = id;
|
32
32
|
this.timeStamp = timeStamp;
|
33
33
|
}
|
34
|
+
// Creates a Pointer from a DOM event.
|
34
35
|
static ofEvent(evt, isDown, viewport) {
|
35
36
|
var _a, _b;
|
36
37
|
const screenPos = Vec2.of(evt.offsetX, evt.offsetY);
|
package/dist/src/SVGLoader.d.ts
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
import Rect2 from './
|
1
|
+
import Rect2 from './math/Rect2';
|
2
2
|
import { ComponentAddedListener, ImageLoader, OnDetermineExportRectListener, OnProgressListener } from './types';
|
3
3
|
export declare const defaultSVGViewRect: Rect2;
|
4
4
|
export declare const svgAttributesDataKey = "svgAttrs";
|
package/dist/src/SVGLoader.js
CHANGED
@@ -12,10 +12,10 @@ import Stroke from './components/Stroke';
|
|
12
12
|
import SVGGlobalAttributesObject from './components/SVGGlobalAttributesObject';
|
13
13
|
import Text from './components/Text';
|
14
14
|
import UnknownSVGObject from './components/UnknownSVGObject';
|
15
|
-
import Mat33 from './
|
16
|
-
import Path from './
|
17
|
-
import Rect2 from './
|
18
|
-
import { Vec2 } from './
|
15
|
+
import Mat33 from './math/Mat33';
|
16
|
+
import Path from './math/Path';
|
17
|
+
import Rect2 from './math/Rect2';
|
18
|
+
import { Vec2 } from './math/Vec2';
|
19
19
|
// Size of a loaded image if no size is specified.
|
20
20
|
export const defaultSVGViewRect = new Rect2(0, 0, 500, 500);
|
21
21
|
// Key to retrieve unrecognised attributes from an AbstractComponent
|
@@ -171,8 +171,16 @@ export default class SVGLoader {
|
|
171
171
|
if (transformProperty === '' || transformProperty === 'none') {
|
172
172
|
transformProperty = elem.style.transform || 'none';
|
173
173
|
}
|
174
|
-
// Compute transform matrix
|
175
|
-
|
174
|
+
// Compute transform matrix. Prefer the actual .style.transform
|
175
|
+
// to the computed stylesheet -- in some browsers, the computedStyles version
|
176
|
+
// can have lower precision.
|
177
|
+
let transform;
|
178
|
+
try {
|
179
|
+
transform = Mat33.fromCSSMatrix(elem.style.transform);
|
180
|
+
}
|
181
|
+
catch (_e) {
|
182
|
+
transform = Mat33.fromCSSMatrix(transformProperty);
|
183
|
+
}
|
176
184
|
const supportedAttrs = [];
|
177
185
|
const elemX = elem.getAttribute('x');
|
178
186
|
const elemY = elem.getAttribute('y');
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import { EditorEventType } from './types';
|
2
2
|
class UndoRedoHistory {
|
3
|
+
// @internal
|
3
4
|
constructor(editor, announceRedoCallback, announceUndoCallback) {
|
4
5
|
this.editor = editor;
|
5
6
|
this.announceRedoCallback = announceRedoCallback;
|
@@ -25,6 +26,10 @@ class UndoRedoHistory {
|
|
25
26
|
}
|
26
27
|
this.redoStack = [];
|
27
28
|
this.fireUpdateEvent();
|
29
|
+
this.editor.notifier.dispatch(EditorEventType.CommandDone, {
|
30
|
+
kind: EditorEventType.CommandDone,
|
31
|
+
command,
|
32
|
+
});
|
28
33
|
}
|
29
34
|
// Remove the last command from this' undo stack and apply it.
|
30
35
|
undo() {
|
@@ -33,8 +38,12 @@ class UndoRedoHistory {
|
|
33
38
|
this.redoStack.push(command);
|
34
39
|
command.unapply(this.editor);
|
35
40
|
this.announceUndoCallback(command);
|
41
|
+
this.fireUpdateEvent();
|
42
|
+
this.editor.notifier.dispatch(EditorEventType.CommandUndone, {
|
43
|
+
kind: EditorEventType.CommandUndone,
|
44
|
+
command,
|
45
|
+
});
|
36
46
|
}
|
37
|
-
this.fireUpdateEvent();
|
38
47
|
}
|
39
48
|
redo() {
|
40
49
|
const command = this.redoStack.pop();
|
@@ -42,8 +51,12 @@ class UndoRedoHistory {
|
|
42
51
|
this.undoStack.push(command);
|
43
52
|
command.apply(this.editor);
|
44
53
|
this.announceRedoCallback(command);
|
54
|
+
this.fireUpdateEvent();
|
55
|
+
this.editor.notifier.dispatch(EditorEventType.CommandDone, {
|
56
|
+
kind: EditorEventType.CommandDone,
|
57
|
+
command,
|
58
|
+
});
|
45
59
|
}
|
46
|
-
this.fireUpdateEvent();
|
47
60
|
}
|
48
61
|
get undoStackSize() {
|
49
62
|
return this.undoStack.length;
|
package/dist/src/Viewport.d.ts
CHANGED
@@ -1,31 +1,16 @@
|
|
1
1
|
import Command from './commands/Command';
|
2
|
-
import
|
3
|
-
import
|
4
|
-
import
|
5
|
-
import Rect2 from './geometry/Rect2';
|
6
|
-
import { Point2, Vec2 } from './geometry/Vec2';
|
2
|
+
import Mat33 from './math/Mat33';
|
3
|
+
import Rect2 from './math/Rect2';
|
4
|
+
import { Point2, Vec2 } from './math/Vec2';
|
7
5
|
import { StrokeDataPoint } from './types';
|
8
6
|
import { EditorNotifier } from './types';
|
9
7
|
declare type PointDataType<T extends Point2 | StrokeDataPoint | number> = T extends Point2 ? Point2 : number;
|
8
|
+
export declare abstract class ViewportTransform extends Command {
|
9
|
+
abstract readonly transform: Mat33;
|
10
|
+
}
|
10
11
|
export declare class Viewport {
|
11
12
|
private notifier;
|
12
|
-
static ViewportTransform
|
13
|
-
new (transform: Mat33): {
|
14
|
-
readonly "__#679@#inverseTransform": Mat33;
|
15
|
-
readonly transform: Mat33;
|
16
|
-
apply(editor: Editor): void;
|
17
|
-
unapply(editor: Editor): void;
|
18
|
-
description(localizationTable: CommandLocalization): string;
|
19
|
-
onDrop(_editor: Editor): void;
|
20
|
-
};
|
21
|
-
union(a: Command, b: Command): Command;
|
22
|
-
readonly empty: {
|
23
|
-
description(_localizationTable: import("./localization").EditorLocalization): string;
|
24
|
-
apply(_editor: Editor): void;
|
25
|
-
unapply(_editor: Editor): void;
|
26
|
-
onDrop(_editor: Editor): void;
|
27
|
-
};
|
28
|
-
};
|
13
|
+
private static ViewportTransform;
|
29
14
|
private transform;
|
30
15
|
private inverseTransform;
|
31
16
|
private screenRect;
|
@@ -34,6 +19,7 @@ export declare class Viewport {
|
|
34
19
|
get visibleRect(): Rect2;
|
35
20
|
screenToCanvas(screenPoint: Point2): Point2;
|
36
21
|
canvasToScreen(canvasPoint: Point2): Point2;
|
22
|
+
static transformBy(transform: Mat33): ViewportTransform;
|
37
23
|
resetTransform(newTransform?: Mat33): void;
|
38
24
|
get screenToCanvasTransform(): Mat33;
|
39
25
|
get canvasToScreenTransform(): Mat33;
|
@@ -45,7 +31,4 @@ export declare class Viewport {
|
|
45
31
|
roundPoint(point: Point2): Point2;
|
46
32
|
zoomTo(toMakeVisible: Rect2, allowZoomIn?: boolean, allowZoomOut?: boolean): Command;
|
47
33
|
}
|
48
|
-
export declare namespace Viewport {
|
49
|
-
type ViewportTransform = typeof Viewport.ViewportTransform.prototype;
|
50
|
-
}
|
51
34
|
export default Viewport;
|
package/dist/src/Viewport.js
CHANGED
@@ -11,17 +11,21 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
11
11
|
};
|
12
12
|
var _inverseTransform, _a;
|
13
13
|
import Command from './commands/Command';
|
14
|
-
import Mat33 from './
|
15
|
-
import Rect2 from './
|
16
|
-
import { Vec2 } from './
|
17
|
-
import Vec3 from './
|
14
|
+
import Mat33 from './math/Mat33';
|
15
|
+
import Rect2 from './math/Rect2';
|
16
|
+
import { Vec2 } from './math/Vec2';
|
17
|
+
import Vec3 from './math/Vec3';
|
18
18
|
import { EditorEventType } from './types';
|
19
|
+
export class ViewportTransform extends Command {
|
20
|
+
}
|
19
21
|
export class Viewport {
|
22
|
+
// @internal
|
20
23
|
constructor(notifier) {
|
21
24
|
this.notifier = notifier;
|
22
25
|
this.resetTransform(Mat33.identity);
|
23
26
|
this.screenRect = Rect2.empty;
|
24
27
|
}
|
28
|
+
// @internal
|
25
29
|
updateScreenSize(screenSize) {
|
26
30
|
this.screenRect = this.screenRect.resizedTo(screenSize);
|
27
31
|
}
|
@@ -35,7 +39,10 @@ export class Viewport {
|
|
35
39
|
canvasToScreen(canvasPoint) {
|
36
40
|
return this.transform.transformVec2(canvasPoint);
|
37
41
|
}
|
38
|
-
|
42
|
+
static transformBy(transform) {
|
43
|
+
return new Viewport.ViewportTransform(transform);
|
44
|
+
}
|
45
|
+
// Updates the transformation directly. Using `transformBy` is preferred.
|
39
46
|
// [newTransform] should map from canvas coordinates to screen coordinates.
|
40
47
|
resetTransform(newTransform = Mat33.identity) {
|
41
48
|
const oldTransform = this.transform;
|
@@ -61,6 +68,7 @@ export class Viewport {
|
|
61
68
|
// Use transformVec3 to avoid translating the vector
|
62
69
|
return this.transform.transformVec3(Vec3.unitX).magnitude();
|
63
70
|
}
|
71
|
+
// Returns the size of one screen pixel in canvas units.
|
64
72
|
getSizeOfPixelOnCanvas() {
|
65
73
|
return 1 / this.getScaleFactor();
|
66
74
|
}
|
@@ -132,7 +140,7 @@ export class Viewport {
|
|
132
140
|
}
|
133
141
|
}
|
134
142
|
// Command that translates/scales the viewport.
|
135
|
-
Viewport.ViewportTransform = (_a = class extends
|
143
|
+
Viewport.ViewportTransform = (_a = class extends ViewportTransform {
|
136
144
|
constructor(transform) {
|
137
145
|
super();
|
138
146
|
this.transform = transform;
|
@@ -149,13 +157,13 @@ Viewport.ViewportTransform = (_a = class extends Command {
|
|
149
157
|
viewport.resetTransform(viewport.transform.rightMul(__classPrivateFieldGet(this, _inverseTransform, "f")));
|
150
158
|
editor.queueRerender();
|
151
159
|
}
|
152
|
-
description(localizationTable) {
|
160
|
+
description(editor, localizationTable) {
|
153
161
|
const result = [];
|
154
162
|
// Describe the transformation's affect on the viewport (note that transformation transforms
|
155
163
|
// the **elements** within the viewport). Assumes the transformation only does rotation/scale/translation.
|
156
|
-
const origVec =
|
164
|
+
const origVec = editor.viewport.visibleRect.center;
|
157
165
|
const linearTransformedVec = this.transform.transformVec3(Vec2.unitX);
|
158
|
-
const affineTransformedVec = this.transform.transformVec2(
|
166
|
+
const affineTransformedVec = this.transform.transformVec2(origVec);
|
159
167
|
const scale = linearTransformedVec.magnitude();
|
160
168
|
const rotation = 180 / Math.PI * linearTransformedVec.angle();
|
161
169
|
const translation = affineTransformedVec.minus(origVec);
|
@@ -175,7 +183,7 @@ Viewport.ViewportTransform = (_a = class extends Command {
|
|
175
183
|
else if (translation.x < -minTranslation) {
|
176
184
|
result.push(localizationTable.movedRight);
|
177
185
|
}
|
178
|
-
if (translation.y < minTranslation) {
|
186
|
+
if (translation.y < -minTranslation) {
|
179
187
|
result.push(localizationTable.movedDown);
|
180
188
|
}
|
181
189
|
else if (translation.y > minTranslation) {
|
@@ -1,6 +1,5 @@
|
|
1
1
|
// Main entrypoint for Webpack when building a bundle for release.
|
2
2
|
import '../styles';
|
3
3
|
import Editor from '../Editor';
|
4
|
-
|
4
|
+
export * from '../lib';
|
5
5
|
export default Editor;
|
6
|
-
export { Editor, getLocalizationTable };
|
@@ -4,10 +4,10 @@ export declare abstract class Command {
|
|
4
4
|
abstract apply(editor: Editor): void;
|
5
5
|
abstract unapply(editor: Editor): void;
|
6
6
|
onDrop(_editor: Editor): void;
|
7
|
-
abstract description(localizationTable: EditorLocalization): string;
|
7
|
+
abstract description(editor: Editor, localizationTable: EditorLocalization): string;
|
8
8
|
static union(a: Command, b: Command): Command;
|
9
9
|
static readonly empty: {
|
10
|
-
description(_localizationTable: EditorLocalization): string;
|
10
|
+
description(_editor: Editor, _localizationTable: EditorLocalization): string;
|
11
11
|
apply(_editor: Editor): void;
|
12
12
|
unapply(_editor: Editor): void;
|
13
13
|
onDrop(_editor: Editor): void;
|
@@ -11,9 +11,9 @@ export class Command {
|
|
11
11
|
b.unapply(editor);
|
12
12
|
a.unapply(editor);
|
13
13
|
}
|
14
|
-
description(localizationTable) {
|
15
|
-
const aDescription = a.description(localizationTable);
|
16
|
-
const bDescription = b.description(localizationTable);
|
14
|
+
description(editor, localizationTable) {
|
15
|
+
const aDescription = a.description(editor, localizationTable);
|
16
|
+
const bDescription = b.description(editor, localizationTable);
|
17
17
|
if (aDescription === bDescription) {
|
18
18
|
return aDescription;
|
19
19
|
}
|
@@ -23,7 +23,7 @@ export class Command {
|
|
23
23
|
}
|
24
24
|
}
|
25
25
|
Command.empty = new class extends Command {
|
26
|
-
description(_localizationTable) { return ''; }
|
26
|
+
description(_editor, _localizationTable) { return ''; }
|
27
27
|
apply(_editor) { }
|
28
28
|
unapply(_editor) { }
|
29
29
|
};
|
@@ -9,6 +9,6 @@ export default class Duplicate extends SerializableCommand {
|
|
9
9
|
constructor(toDuplicate: AbstractComponent[]);
|
10
10
|
apply(editor: Editor): void;
|
11
11
|
unapply(editor: Editor): void;
|
12
|
-
description(localizationTable: EditorLocalization): string;
|
13
|
-
protected
|
12
|
+
description(_editor: Editor, localizationTable: EditorLocalization): string;
|
13
|
+
protected serializeToJSON(): string[];
|
14
14
|
}
|
@@ -14,20 +14,19 @@ export default class Duplicate extends SerializableCommand {
|
|
14
14
|
unapply(editor) {
|
15
15
|
this.reverse.apply(editor);
|
16
16
|
}
|
17
|
-
description(localizationTable) {
|
17
|
+
description(_editor, localizationTable) {
|
18
18
|
var _a;
|
19
19
|
if (this.duplicates.length === 0) {
|
20
20
|
return localizationTable.duplicatedNoElements;
|
21
21
|
}
|
22
22
|
return localizationTable.duplicateAction((_a = describeComponentList(localizationTable, this.duplicates)) !== null && _a !== void 0 ? _a : localizationTable.elements, this.duplicates.length);
|
23
23
|
}
|
24
|
-
|
25
|
-
return
|
24
|
+
serializeToJSON() {
|
25
|
+
return this.toDuplicate.map(elem => elem.getId());
|
26
26
|
}
|
27
27
|
}
|
28
28
|
(() => {
|
29
|
-
SerializableCommand.register('duplicate', (
|
30
|
-
const json = JSON.parse(data);
|
29
|
+
SerializableCommand.register('duplicate', (json, editor) => {
|
31
30
|
const elems = json.map((id) => editor.image.lookupElement(id));
|
32
31
|
return new Duplicate(elems);
|
33
32
|
});
|
@@ -9,6 +9,6 @@ export default class Erase extends SerializableCommand {
|
|
9
9
|
apply(editor: Editor): void;
|
10
10
|
unapply(editor: Editor): void;
|
11
11
|
onDrop(editor: Editor): void;
|
12
|
-
description(localizationTable: EditorLocalization): string;
|
13
|
-
protected
|
12
|
+
description(_editor: Editor, localizationTable: EditorLocalization): string;
|
13
|
+
protected serializeToJSON(): string[];
|
14
14
|
}
|
@@ -34,7 +34,7 @@ export default class Erase extends SerializableCommand {
|
|
34
34
|
}
|
35
35
|
}
|
36
36
|
}
|
37
|
-
description(localizationTable) {
|
37
|
+
description(_editor, localizationTable) {
|
38
38
|
var _a;
|
39
39
|
if (this.toRemove.length === 0) {
|
40
40
|
return localizationTable.erasedNoElements;
|
@@ -42,15 +42,16 @@ export default class Erase extends SerializableCommand {
|
|
42
42
|
const description = (_a = describeComponentList(localizationTable, this.toRemove)) !== null && _a !== void 0 ? _a : localizationTable.elements;
|
43
43
|
return localizationTable.eraseAction(description, this.toRemove.length);
|
44
44
|
}
|
45
|
-
|
45
|
+
serializeToJSON() {
|
46
46
|
const elemIds = this.toRemove.map(elem => elem.getId());
|
47
|
-
return
|
47
|
+
return elemIds;
|
48
48
|
}
|
49
49
|
}
|
50
50
|
(() => {
|
51
|
-
SerializableCommand.register('erase', (
|
52
|
-
const
|
53
|
-
|
51
|
+
SerializableCommand.register('erase', (json, editor) => {
|
52
|
+
const elems = json
|
53
|
+
.map((elemId) => editor.image.lookupElement(elemId))
|
54
|
+
.filter((elem) => elem !== null);
|
54
55
|
return new Erase(elems);
|
55
56
|
});
|
56
57
|
})();
|
@@ -1,13 +1,12 @@
|
|
1
1
|
import Editor from '../Editor';
|
2
2
|
import Command from './Command';
|
3
|
-
declare type DeserializationCallback = (data: string, editor: Editor) => SerializableCommand;
|
3
|
+
export declare type DeserializationCallback = (data: Record<string, any> | any[], editor: Editor) => SerializableCommand;
|
4
4
|
export default abstract class SerializableCommand extends Command {
|
5
5
|
private commandTypeId;
|
6
6
|
constructor(commandTypeId: string);
|
7
|
-
protected abstract
|
7
|
+
protected abstract serializeToJSON(): string | Record<string, any> | any[];
|
8
8
|
private static deserializationCallbacks;
|
9
|
-
serialize(): string
|
10
|
-
static deserialize(data: string, editor: Editor): SerializableCommand;
|
9
|
+
serialize(): Record<string | symbol, any>;
|
10
|
+
static deserialize(data: string | Record<string, any>, editor: Editor): SerializableCommand;
|
11
11
|
static register(commandTypeId: string, deserialize: DeserializationCallback): void;
|
12
12
|
}
|
13
|
-
export {};
|
@@ -7,20 +7,28 @@ export default class SerializableCommand extends Command {
|
|
7
7
|
throw new Error(`Command ${commandTypeId} must have a registered deserialization callback. To do this, call SerializableCommand.register.`);
|
8
8
|
}
|
9
9
|
}
|
10
|
+
// Convert this command to an object that can be passed to `JSON.stringify`.
|
11
|
+
//
|
12
|
+
// Do not rely on the stability of the optupt of this function — it can change
|
13
|
+
// form without a major version increase.
|
10
14
|
serialize() {
|
11
|
-
return
|
12
|
-
data: this.
|
15
|
+
return {
|
16
|
+
data: this.serializeToJSON(),
|
13
17
|
commandType: this.commandTypeId,
|
14
|
-
}
|
18
|
+
};
|
15
19
|
}
|
20
|
+
// Convert a `string` containing JSON data (or the output of `JSON.parse`) into a
|
21
|
+
// `Command`.
|
16
22
|
static deserialize(data, editor) {
|
17
|
-
const json = JSON.parse(data);
|
23
|
+
const json = typeof data === 'string' ? JSON.parse(data) : data;
|
18
24
|
const commandType = json.commandType;
|
19
25
|
if (!(commandType in SerializableCommand.deserializationCallbacks)) {
|
20
26
|
throw new Error(`Unrecognised command type ${commandType}!`);
|
21
27
|
}
|
22
28
|
return SerializableCommand.deserializationCallbacks[commandType](json.data, editor);
|
23
29
|
}
|
30
|
+
// Register a deserialization callback. This must be called at least once for every subclass of
|
31
|
+
// `SerializableCommand`.
|
24
32
|
static register(commandTypeId, deserialize) {
|
25
33
|
SerializableCommand.deserializationCallbacks[commandTypeId] = deserialize;
|
26
34
|
}
|