js-draw 1.3.1 → 1.4.1
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 +2 -2
- package/dist/Editor.css +55 -13
- package/dist/bundle.js +2 -2
- package/dist/bundledStyles.js +1 -1
- package/dist/cjs/Editor.d.ts +36 -3
- package/dist/cjs/Editor.js +63 -26
- package/dist/cjs/commands/Erase.js +1 -1
- package/dist/cjs/commands/UnresolvedCommand.d.ts +1 -1
- package/dist/cjs/components/AbstractComponent.d.ts +1 -1
- package/dist/cjs/components/AbstractComponent.js +1 -1
- package/dist/cjs/components/BackgroundComponent.d.ts +1 -1
- package/dist/cjs/components/BackgroundComponent.js +13 -7
- package/dist/cjs/components/SVGGlobalAttributesObject.d.ts +2 -2
- package/dist/cjs/components/SVGGlobalAttributesObject.js +10 -14
- package/dist/cjs/{EditorImage.d.ts → image/EditorImage.d.ts} +30 -8
- package/dist/cjs/{EditorImage.js → image/EditorImage.js} +51 -7
- package/dist/cjs/image/export/adjustExportedSVGSize.d.ts +6 -0
- package/dist/cjs/image/export/adjustExportedSVGSize.js +22 -0
- package/dist/cjs/image/export/editorImageToSVG.d.ts +8 -0
- package/dist/cjs/image/export/editorImageToSVG.js +63 -0
- package/dist/cjs/image/lib.d.ts +1 -0
- package/dist/cjs/image/lib.js +8 -0
- package/dist/cjs/lib.d.ts +1 -1
- package/dist/cjs/lib.js +2 -3
- package/dist/cjs/localizations/comments.d.ts +6 -0
- package/dist/cjs/localizations/comments.js +10 -0
- package/dist/cjs/localizations/es.js +68 -48
- package/dist/cjs/rendering/caching/RenderingCache.d.ts +1 -1
- package/dist/cjs/rendering/caching/RenderingCacheNode.d.ts +1 -1
- package/dist/cjs/rendering/caching/RenderingCacheNode.js +4 -3
- package/dist/cjs/rendering/renderers/AbstractRenderer.d.ts +1 -0
- package/dist/cjs/rendering/renderers/AbstractRenderer.js +8 -0
- package/dist/cjs/rendering/renderers/SVGRenderer.d.ts +28 -1
- package/dist/cjs/rendering/renderers/SVGRenderer.js +58 -7
- package/dist/cjs/toolbar/AbstractToolbar.d.ts +11 -3
- package/dist/cjs/toolbar/AbstractToolbar.js +20 -6
- package/dist/cjs/toolbar/EdgeToolbar.js +5 -6
- package/dist/cjs/toolbar/IconProvider.d.ts +1 -0
- package/dist/cjs/toolbar/IconProvider.js +43 -0
- package/dist/cjs/toolbar/widgets/ActionButtonWidget.d.ts +3 -1
- package/dist/cjs/toolbar/widgets/ActionButtonWidget.js +19 -1
- package/dist/cjs/toolbar/widgets/BaseToolWidget.d.ts +1 -0
- package/dist/cjs/toolbar/widgets/BaseToolWidget.js +3 -0
- package/dist/cjs/toolbar/widgets/BaseWidget.d.ts +5 -0
- package/dist/cjs/toolbar/widgets/BaseWidget.js +30 -2
- package/dist/cjs/toolbar/widgets/DocumentPropertiesWidget.js +1 -1
- package/dist/cjs/toolbar/widgets/HandToolWidget.d.ts +1 -0
- package/dist/cjs/toolbar/widgets/HandToolWidget.js +6 -0
- package/dist/cjs/toolbar/widgets/InsertImageWidget.js +1 -1
- package/dist/cjs/toolbar/widgets/OverflowWidget.d.ts +1 -0
- package/dist/cjs/toolbar/widgets/OverflowWidget.js +3 -0
- package/dist/cjs/toolbar/widgets/SaveActionWidget.d.ts +1 -0
- package/dist/cjs/toolbar/widgets/SaveActionWidget.js +3 -0
- package/dist/cjs/tools/BaseTool.d.ts +3 -0
- package/dist/cjs/tools/BaseTool.js +13 -2
- package/dist/cjs/tools/FindTool.d.ts +1 -0
- package/dist/cjs/tools/FindTool.js +4 -1
- package/dist/cjs/tools/PanZoom.d.ts +1 -0
- package/dist/cjs/tools/PanZoom.js +4 -0
- package/dist/cjs/tools/Pen.d.ts +0 -1
- package/dist/cjs/tools/Pen.js +1 -4
- package/dist/cjs/tools/PipetteTool.d.ts +1 -0
- package/dist/cjs/tools/PipetteTool.js +3 -0
- package/dist/cjs/tools/SelectionTool/SelectAllShortcutHandler.d.ts +1 -0
- package/dist/cjs/tools/SelectionTool/SelectAllShortcutHandler.js +3 -0
- package/dist/cjs/tools/SelectionTool/Selection.d.ts +2 -0
- package/dist/cjs/tools/SelectionTool/Selection.js +44 -8
- package/dist/cjs/tools/SelectionTool/SelectionHandle.d.ts +14 -6
- package/dist/cjs/tools/SelectionTool/SelectionHandle.js +26 -8
- package/dist/cjs/tools/SelectionTool/SelectionTool.js +5 -0
- package/dist/cjs/tools/SoundUITool.d.ts +1 -0
- package/dist/cjs/tools/SoundUITool.js +4 -1
- package/dist/cjs/tools/TextTool.js +2 -2
- package/dist/cjs/tools/ToolController.d.ts +2 -0
- package/dist/cjs/tools/ToolController.js +13 -2
- package/dist/cjs/tools/ToolSwitcherShortcut.d.ts +1 -0
- package/dist/cjs/tools/ToolSwitcherShortcut.js +3 -0
- package/dist/cjs/types.d.ts +9 -4
- package/dist/cjs/types.js +4 -3
- package/dist/cjs/util/ReactiveValue.d.ts +1 -1
- package/dist/cjs/util/ReactiveValue.js +2 -2
- package/dist/cjs/version.js +1 -1
- package/dist/mjs/Editor.d.ts +36 -3
- package/dist/mjs/Editor.mjs +64 -27
- package/dist/mjs/Editor.toSVGAsync.test.d.ts +1 -0
- package/dist/mjs/commands/Erase.mjs +1 -1
- package/dist/mjs/commands/UnresolvedCommand.d.ts +1 -1
- package/dist/mjs/components/AbstractComponent.d.ts +1 -1
- package/dist/mjs/components/AbstractComponent.mjs +1 -1
- package/dist/mjs/components/BackgroundComponent.d.ts +1 -1
- package/dist/mjs/components/BackgroundComponent.mjs +13 -7
- package/dist/mjs/components/SVGGlobalAttributesObject.d.ts +2 -2
- package/dist/mjs/components/SVGGlobalAttributesObject.mjs +10 -14
- package/dist/mjs/{EditorImage.d.ts → image/EditorImage.d.ts} +30 -8
- package/dist/mjs/{EditorImage.mjs → image/EditorImage.mjs} +51 -7
- package/dist/mjs/image/EditorImage.test.d.ts +1 -0
- package/dist/mjs/image/export/adjustExportedSVGSize.d.ts +6 -0
- package/dist/mjs/image/export/adjustExportedSVGSize.mjs +20 -0
- package/dist/mjs/image/export/editorImageToSVG.d.ts +8 -0
- package/dist/mjs/image/export/editorImageToSVG.mjs +55 -0
- package/dist/mjs/image/lib.d.ts +1 -0
- package/dist/mjs/image/lib.mjs +1 -0
- package/dist/mjs/lib.d.ts +1 -1
- package/dist/mjs/lib.mjs +1 -1
- package/dist/mjs/localizations/comments.d.ts +6 -0
- package/dist/mjs/localizations/comments.mjs +8 -0
- package/dist/mjs/localizations/es.mjs +68 -48
- package/dist/mjs/rendering/caching/RenderingCache.d.ts +1 -1
- package/dist/mjs/rendering/caching/RenderingCacheNode.d.ts +1 -1
- package/dist/mjs/rendering/caching/RenderingCacheNode.mjs +4 -3
- package/dist/mjs/rendering/renderers/AbstractRenderer.d.ts +1 -0
- package/dist/mjs/rendering/renderers/AbstractRenderer.mjs +8 -0
- package/dist/mjs/rendering/renderers/SVGRenderer.d.ts +28 -1
- package/dist/mjs/rendering/renderers/SVGRenderer.mjs +58 -7
- package/dist/mjs/toolbar/AbstractToolbar.d.ts +11 -3
- package/dist/mjs/toolbar/AbstractToolbar.mjs +20 -6
- package/dist/mjs/toolbar/EdgeToolbar.mjs +5 -6
- package/dist/mjs/toolbar/IconProvider.d.ts +1 -0
- package/dist/mjs/toolbar/IconProvider.mjs +43 -0
- package/dist/mjs/toolbar/widgets/ActionButtonWidget.d.ts +3 -1
- package/dist/mjs/toolbar/widgets/ActionButtonWidget.mjs +21 -2
- package/dist/mjs/toolbar/widgets/BaseToolWidget.d.ts +1 -0
- package/dist/mjs/toolbar/widgets/BaseToolWidget.mjs +3 -0
- package/dist/mjs/toolbar/widgets/BaseWidget.d.ts +5 -0
- package/dist/mjs/toolbar/widgets/BaseWidget.mjs +30 -2
- package/dist/mjs/toolbar/widgets/DocumentPropertiesWidget.mjs +1 -1
- package/dist/mjs/toolbar/widgets/HandToolWidget.d.ts +1 -0
- package/dist/mjs/toolbar/widgets/HandToolWidget.mjs +6 -0
- package/dist/mjs/toolbar/widgets/InsertImageWidget.mjs +1 -1
- package/dist/mjs/toolbar/widgets/OverflowWidget.d.ts +1 -0
- package/dist/mjs/toolbar/widgets/OverflowWidget.mjs +3 -0
- package/dist/mjs/toolbar/widgets/SaveActionWidget.d.ts +1 -0
- package/dist/mjs/toolbar/widgets/SaveActionWidget.mjs +3 -0
- package/dist/mjs/tools/BaseTool.d.ts +3 -0
- package/dist/mjs/tools/BaseTool.mjs +13 -2
- package/dist/mjs/tools/FindTool.d.ts +1 -0
- package/dist/mjs/tools/FindTool.mjs +4 -1
- package/dist/mjs/tools/PanZoom.d.ts +1 -0
- package/dist/mjs/tools/PanZoom.mjs +4 -0
- package/dist/mjs/tools/Pen.d.ts +0 -1
- package/dist/mjs/tools/Pen.mjs +1 -4
- package/dist/mjs/tools/PipetteTool.d.ts +1 -0
- package/dist/mjs/tools/PipetteTool.mjs +3 -0
- package/dist/mjs/tools/SelectionTool/SelectAllShortcutHandler.d.ts +1 -0
- package/dist/mjs/tools/SelectionTool/SelectAllShortcutHandler.mjs +3 -0
- package/dist/mjs/tools/SelectionTool/Selection.d.ts +2 -0
- package/dist/mjs/tools/SelectionTool/Selection.mjs +45 -9
- package/dist/mjs/tools/SelectionTool/SelectionHandle.d.ts +14 -6
- package/dist/mjs/tools/SelectionTool/SelectionHandle.mjs +25 -7
- package/dist/mjs/tools/SelectionTool/SelectionTool.mjs +5 -0
- package/dist/mjs/tools/SoundUITool.d.ts +1 -0
- package/dist/mjs/tools/SoundUITool.mjs +4 -1
- package/dist/mjs/tools/TextTool.mjs +2 -2
- package/dist/mjs/tools/ToolController.d.ts +2 -0
- package/dist/mjs/tools/ToolController.mjs +13 -2
- package/dist/mjs/tools/ToolSwitcherShortcut.d.ts +1 -0
- package/dist/mjs/tools/ToolSwitcherShortcut.mjs +3 -0
- package/dist/mjs/types.d.ts +9 -4
- package/dist/mjs/types.mjs +4 -3
- package/dist/mjs/util/ReactiveValue.d.ts +1 -1
- package/dist/mjs/util/ReactiveValue.mjs +2 -2
- package/dist/mjs/version.mjs +1 -1
- package/package.json +5 -5
- package/src/Editor.scss +6 -0
- package/src/toolbar/EdgeToolbar.scss +19 -2
- package/src/tools/SelectionTool/SelectionTool.scss +74 -0
- package/src/tools/tools.scss +1 -1
- package/src/tools/SelectionTool/SelectionTool.css +0 -35
- /package/dist/cjs/{EditorImage.test.d.ts → Editor.toSVGAsync.test.d.ts} +0 -0
- /package/dist/{mjs → cjs/image}/EditorImage.test.d.ts +0 -0
package/dist/mjs/Editor.mjs
CHANGED
@@ -1,14 +1,13 @@
|
|
1
|
-
import EditorImage from './EditorImage.mjs';
|
1
|
+
import EditorImage from './image/EditorImage.mjs';
|
2
2
|
import ToolController from './tools/ToolController.mjs';
|
3
3
|
import { EditorEventType } from './types.mjs';
|
4
4
|
import { InputEvtType, keyUpEventFromHTMLEvent, keyPressEventFromHTMLEvent } from './inputEvents.mjs';
|
5
5
|
import UndoRedoHistory from './UndoRedoHistory.mjs';
|
6
6
|
import Viewport from './Viewport.mjs';
|
7
7
|
import EventDispatcher from './EventDispatcher.mjs';
|
8
|
-
import { Vec2, Vec3, Color4, Mat33
|
8
|
+
import { Vec2, Vec3, Color4, Mat33 } from '@js-draw/math';
|
9
9
|
import Display, { RenderingMode } from './rendering/Display.mjs';
|
10
|
-
import
|
11
|
-
import SVGLoader, { svgLoaderAutoresizeClassName } from './SVGLoader.mjs';
|
10
|
+
import SVGLoader from './SVGLoader.mjs';
|
12
11
|
import Pointer from './Pointer.mjs';
|
13
12
|
import getLocalizationTable from './localizations/getLocalizationTable.mjs';
|
14
13
|
import IconProvider from './toolbar/IconProvider.mjs';
|
@@ -26,6 +25,8 @@ import StrokeKeyboardControl from './tools/InputFilter/StrokeKeyboardControl.m
|
|
26
25
|
import guessKeyCodeFromKey from './util/guessKeyCodeFromKey.mjs';
|
27
26
|
import makeAboutDialog from './dialogs/makeAboutDialog.mjs';
|
28
27
|
import version from './version.mjs';
|
28
|
+
import { editorImageToSVGSync, editorImageToSVGAsync } from './image/export/editorImageToSVG.mjs';
|
29
|
+
import { MutableReactiveValue } from './util/ReactiveValue.mjs';
|
29
30
|
/**
|
30
31
|
* The main entrypoint for the full editor.
|
31
32
|
*
|
@@ -110,6 +111,7 @@ export class Editor {
|
|
110
111
|
if (this.settings.minZoom > this.settings.maxZoom) {
|
111
112
|
throw new Error('Minimum zoom must be lesser than maximum zoom!');
|
112
113
|
}
|
114
|
+
this.readOnly = MutableReactiveValue.fromInitialValue(false);
|
113
115
|
this.icons = this.settings.iconProvider;
|
114
116
|
this.shortcuts = new KeyboardShortcutManager(this.settings.keyboardShortcutOverrides);
|
115
117
|
this.container = document.createElement('div');
|
@@ -660,6 +662,26 @@ export class Editor {
|
|
660
662
|
};
|
661
663
|
this.eventListenerTargets.push(elem);
|
662
664
|
}
|
665
|
+
/**
|
666
|
+
* Attempts to prevent **user-triggered** events from modifying
|
667
|
+
* the content of the image.
|
668
|
+
*/
|
669
|
+
setReadOnly(readOnly) {
|
670
|
+
if (readOnly !== this.readOnly.get()) {
|
671
|
+
this.readOnly.set(readOnly);
|
672
|
+
this.notifier.dispatch(EditorEventType.ReadOnlyModeToggled, {
|
673
|
+
kind: EditorEventType.ReadOnlyModeToggled,
|
674
|
+
editorIsReadOnly: readOnly,
|
675
|
+
});
|
676
|
+
}
|
677
|
+
}
|
678
|
+
// @internal
|
679
|
+
isReadOnlyReactiveValue() {
|
680
|
+
return this.readOnly;
|
681
|
+
}
|
682
|
+
isReadOnly() {
|
683
|
+
return this.readOnly;
|
684
|
+
}
|
663
685
|
/** `apply` a command. `command` will be announced for accessibility. */
|
664
686
|
dispatch(command, addToHistory = true) {
|
665
687
|
const dispatchResult = this.dispatchNoAnnounce(command, addToHistory);
|
@@ -938,31 +960,42 @@ export class Editor {
|
|
938
960
|
/**
|
939
961
|
* Converts the editor's content into an SVG image.
|
940
962
|
*
|
963
|
+
* If the output SVG has width or height less than `options.minDimension`, its size
|
964
|
+
* will be increased.
|
965
|
+
*
|
941
966
|
* @see
|
942
967
|
* {@link SVGRenderer}
|
943
968
|
*/
|
944
|
-
toSVG() {
|
945
|
-
|
946
|
-
|
947
|
-
|
948
|
-
|
949
|
-
|
950
|
-
|
951
|
-
|
952
|
-
|
953
|
-
|
954
|
-
|
955
|
-
|
956
|
-
|
957
|
-
|
958
|
-
|
959
|
-
|
960
|
-
|
961
|
-
|
962
|
-
|
963
|
-
|
964
|
-
|
965
|
-
|
969
|
+
toSVG(options) {
|
970
|
+
return editorImageToSVGSync(this.image, options ?? {});
|
971
|
+
}
|
972
|
+
/**
|
973
|
+
* Converts the editor's content into an SVG image in an asynchronous,
|
974
|
+
* but **potentially lossy** way.
|
975
|
+
*
|
976
|
+
* **Warning**: If the image is being edited during an async rendering, edited components
|
977
|
+
* may not be rendered.
|
978
|
+
*
|
979
|
+
* Like {@link toSVG}, but can be configured to briefly pause after processing every
|
980
|
+
* `pauseAfterCount` items. This can prevent the editor from becoming unresponsive
|
981
|
+
* when saving very large images.
|
982
|
+
*/
|
983
|
+
async toSVGAsync(options = {}) {
|
984
|
+
const pauseAfterCount = options.pauseAfterCount ?? 100;
|
985
|
+
return await editorImageToSVGAsync(this.image, async (_component, processedCount, totalComponents) => {
|
986
|
+
if (options.onProgress) {
|
987
|
+
const shouldContinue = await options.onProgress(processedCount, totalComponents);
|
988
|
+
if (shouldContinue === false) {
|
989
|
+
return false;
|
990
|
+
}
|
991
|
+
}
|
992
|
+
if (processedCount % pauseAfterCount === 0) {
|
993
|
+
await untilNextAnimationFrame();
|
994
|
+
}
|
995
|
+
return true;
|
996
|
+
}, {
|
997
|
+
minDimension: options.minDimension,
|
998
|
+
});
|
966
999
|
}
|
967
1000
|
/**
|
968
1001
|
* Load editor data from an `ImageLoader` (e.g. an {@link SVGLoader}).
|
@@ -1114,10 +1147,14 @@ export class Editor {
|
|
1114
1147
|
this.closeAboutDialog?.();
|
1115
1148
|
this.closeAboutDialog = makeAboutDialog(this, notices).close;
|
1116
1149
|
}
|
1117
|
-
/**
|
1150
|
+
/**
|
1151
|
+
* Removes and **destroys** the editor. The editor cannot be added to a parent
|
1152
|
+
* again after calling this method.
|
1153
|
+
*/
|
1118
1154
|
remove() {
|
1119
1155
|
this.container.remove();
|
1120
1156
|
// TODO: Is additional cleanup necessary here?
|
1157
|
+
this.toolController.onEditorDestroyed();
|
1121
1158
|
}
|
1122
1159
|
}
|
1123
1160
|
export default Editor;
|
@@ -0,0 +1 @@
|
|
1
|
+
export {};
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import describeComponentList from '../components/util/describeComponentList.mjs';
|
2
|
-
import EditorImage from '../EditorImage.mjs';
|
2
|
+
import EditorImage from '../image/EditorImage.mjs';
|
3
3
|
import SerializableCommand from './SerializableCommand.mjs';
|
4
4
|
/**
|
5
5
|
* Removes the given {@link AbstractComponent}s from the image.
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import EditorImage from '../EditorImage';
|
1
|
+
import EditorImage from '../image/EditorImage';
|
2
2
|
import AbstractComponent from '../components/AbstractComponent';
|
3
3
|
import SerializableCommand from './SerializableCommand';
|
4
4
|
export type ResolveFromComponentCallback = () => SerializableCommand;
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import SerializableCommand from '../commands/SerializableCommand';
|
2
|
-
import EditorImage from '../EditorImage';
|
2
|
+
import EditorImage from '../image/EditorImage';
|
3
3
|
import { LineSegment2, Mat33, Rect2 } from '@js-draw/math';
|
4
4
|
import AbstractRenderer from '../rendering/renderers/AbstractRenderer';
|
5
5
|
import { ImageComponentLocalization } from './localization';
|
@@ -4,7 +4,7 @@ var __setFunctionName = (this && this.__setFunctionName) || function (f, name, p
|
|
4
4
|
};
|
5
5
|
var _a;
|
6
6
|
import SerializableCommand from '../commands/SerializableCommand.mjs';
|
7
|
-
import EditorImage from '../EditorImage.mjs';
|
7
|
+
import EditorImage from '../image/EditorImage.mjs';
|
8
8
|
import { Mat33 } from '@js-draw/math';
|
9
9
|
import UnresolvedSerializableCommand from '../commands/UnresolvedCommand.mjs';
|
10
10
|
export var ComponentSizingMode;
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import Editor from '../Editor';
|
2
|
-
import EditorImage from '../EditorImage';
|
2
|
+
import EditorImage from '../image/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';
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import { EditorImageEventType } from '../EditorImage.mjs';
|
1
|
+
import { EditorImageEventType } from '../image/EditorImage.mjs';
|
2
2
|
import { Rect2, Color4, toRoundedString, Path, PathCommandType, Vec2 } from '@js-draw/math';
|
3
3
|
import AbstractComponent, { ComponentSizingMode } from './AbstractComponent.mjs';
|
4
4
|
import { createRestyleComponentCommand } from './RestylableComponent.mjs';
|
@@ -190,6 +190,14 @@ export default class BackgroundComponent extends AbstractComponent {
|
|
190
190
|
if (this.backgroundType === BackgroundType.None) {
|
191
191
|
return;
|
192
192
|
}
|
193
|
+
// If visibleRect is null, components should render everything.
|
194
|
+
// In that case, a full render is being done.
|
195
|
+
const mustRender = !visibleRect;
|
196
|
+
// If this.fillsScreen, the visibleRect needs to be known.
|
197
|
+
// Use the screen rect.
|
198
|
+
if (this.fillsScreen) {
|
199
|
+
visibleRect ??= canvas.getVisibleRect();
|
200
|
+
}
|
193
201
|
const clip = this.backgroundType === BackgroundType.Grid;
|
194
202
|
const contentBBox = this.getFullBoundingBox(visibleRect);
|
195
203
|
canvas.startObject(contentBBox, clip);
|
@@ -197,13 +205,11 @@ export default class BackgroundComponent extends AbstractComponent {
|
|
197
205
|
// If the rectangle for this region contains the visible rect,
|
198
206
|
// we can fill the entire visible rectangle (which may be more efficient than
|
199
207
|
// filling the entire region for this.)
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
canvas.fillRect(intersection, this.mainColor);
|
204
|
-
}
|
208
|
+
const intersection = visibleRect?.intersection(contentBBox);
|
209
|
+
if (intersection) {
|
210
|
+
canvas.fillRect(intersection, this.mainColor);
|
205
211
|
}
|
206
|
-
else {
|
212
|
+
else if (mustRender) {
|
207
213
|
canvas.fillRect(contentBBox, this.mainColor);
|
208
214
|
}
|
209
215
|
}
|
@@ -4,8 +4,8 @@ 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 {
|
7
|
-
private readonly attrs;
|
8
7
|
protected contentBBox: Rect2;
|
8
|
+
private readonly attrs;
|
9
9
|
constructor(attrs: GlobalAttrsList);
|
10
10
|
render(canvas: AbstractRenderer, _visibleRect?: Rect2): void;
|
11
11
|
intersects(_lineSegment: LineSegment2): boolean;
|
@@ -15,6 +15,6 @@ export default class SVGGlobalAttributesObject extends AbstractComponent {
|
|
15
15
|
protected createClone(): SVGGlobalAttributesObject;
|
16
16
|
description(localization: ImageComponentLocalization): string;
|
17
17
|
protected serializeToJSON(): string | null;
|
18
|
-
static deserializeFromString(
|
18
|
+
static deserializeFromString(_data: string): AbstractComponent;
|
19
19
|
}
|
20
20
|
export {};
|
@@ -10,10 +10,16 @@ import AbstractComponent, { ComponentSizingMode } from './AbstractComponent.mj
|
|
10
10
|
const componentKind = 'svg-global-attributes';
|
11
11
|
// Stores global SVG attributes (e.g. namespace identifiers.)
|
12
12
|
export default class SVGGlobalAttributesObject extends AbstractComponent {
|
13
|
+
// Does not modify `attrs`
|
13
14
|
constructor(attrs) {
|
14
15
|
super(componentKind);
|
15
|
-
this.attrs = attrs;
|
16
16
|
this.contentBBox = Rect2.empty;
|
17
|
+
// Already stored/managed in `editor.image`.
|
18
|
+
const attrsManagedByRenderer = ['viewBox', 'width', 'height'];
|
19
|
+
// Only store attributes that aren't managed by other parts of the app.
|
20
|
+
this.attrs = attrs.filter(([attr, _value]) => {
|
21
|
+
return !attrsManagedByRenderer.includes(attr);
|
22
|
+
});
|
17
23
|
}
|
18
24
|
render(canvas, _visibleRect) {
|
19
25
|
if (!(canvas instanceof SVGRenderer)) {
|
@@ -47,19 +53,9 @@ export default class SVGGlobalAttributesObject extends AbstractComponent {
|
|
47
53
|
serializeToJSON() {
|
48
54
|
return JSON.stringify(this.attrs);
|
49
55
|
}
|
50
|
-
static deserializeFromString(
|
51
|
-
|
52
|
-
|
53
|
-
const numericAndSpaceContentExp = /^[ \t\n0-9.-eE]+$/;
|
54
|
-
// Don't deserialize all attributes, just those that should be safe.
|
55
|
-
for (const [key, val] of json) {
|
56
|
-
if (key === 'viewBox' || key === 'width' || key === 'height') {
|
57
|
-
if (val && numericAndSpaceContentExp.exec(val)) {
|
58
|
-
attrs.push([key, val]);
|
59
|
-
}
|
60
|
-
}
|
61
|
-
}
|
62
|
-
return new SVGGlobalAttributesObject(attrs);
|
56
|
+
static deserializeFromString(_data) {
|
57
|
+
// To be safe, don't deserialize any attributes
|
58
|
+
return new SVGGlobalAttributesObject([]);
|
63
59
|
}
|
64
60
|
}
|
65
61
|
AbstractComponent.registerComponent(componentKind, SVGGlobalAttributesObject.deserializeFromString);
|
@@ -1,11 +1,11 @@
|
|
1
|
-
import AbstractRenderer from '
|
2
|
-
import Viewport from '
|
3
|
-
import AbstractComponent from '
|
1
|
+
import AbstractRenderer from '../rendering/renderers/AbstractRenderer';
|
2
|
+
import Viewport from '../Viewport';
|
3
|
+
import AbstractComponent from '../components/AbstractComponent';
|
4
4
|
import { Rect2 } from '@js-draw/math';
|
5
|
-
import RenderingCache from '
|
6
|
-
import SerializableCommand from '
|
7
|
-
import EventDispatcher from '
|
8
|
-
import Command from '
|
5
|
+
import RenderingCache from '../rendering/caching/RenderingCache';
|
6
|
+
import SerializableCommand from '../commands/SerializableCommand';
|
7
|
+
import EventDispatcher from '../EventDispatcher';
|
8
|
+
import Command from '../commands/Command';
|
9
9
|
export declare const sortLeavesByZIndex: (leaves: Array<ImageNode>) => void;
|
10
10
|
export declare enum EditorImageEventType {
|
11
11
|
ExportViewportChanged = 0,
|
@@ -14,6 +14,13 @@ export declare enum EditorImageEventType {
|
|
14
14
|
export type EditorImageNotifier = EventDispatcher<EditorImageEventType, {
|
15
15
|
image: EditorImage;
|
16
16
|
}>;
|
17
|
+
/**
|
18
|
+
* A callback used to
|
19
|
+
* 1. pause the render process
|
20
|
+
* 2. observe progress through `componentsProcessed` and `totalComponents`
|
21
|
+
* 3. stop the render process early by returning `false`.
|
22
|
+
*/
|
23
|
+
export type PreRenderComponentCallback = (component: AbstractComponent, componentsProcessed: number, totalComponents: number) => Promise<boolean>;
|
17
24
|
export default class EditorImage {
|
18
25
|
private root;
|
19
26
|
private background;
|
@@ -36,7 +43,21 @@ export default class EditorImage {
|
|
36
43
|
* the viewport used by the `renderer` (if any).
|
37
44
|
*/
|
38
45
|
render(renderer: AbstractRenderer, viewport: Viewport | null): void;
|
39
|
-
/**
|
46
|
+
/**
|
47
|
+
* Like {@link renderAll}, but can be stopped early and paused.
|
48
|
+
*
|
49
|
+
* **Note**: If the image is being edited during an async rendering, there is no
|
50
|
+
* guarantee that all nodes will be rendered correctly (some may be missing).
|
51
|
+
*
|
52
|
+
* @internal
|
53
|
+
*/
|
54
|
+
renderAllAsync(renderer: AbstractRenderer, preRenderComponent: PreRenderComponentCallback): Promise<boolean>;
|
55
|
+
/**
|
56
|
+
* Renders all nodes, even ones not within the viewport.
|
57
|
+
*
|
58
|
+
* This can be slow for large images
|
59
|
+
* @internal
|
60
|
+
*/
|
40
61
|
renderAll(renderer: AbstractRenderer): void;
|
41
62
|
/**
|
42
63
|
* @returns all elements in the image, sorted by z-index. This can be slow for large images.
|
@@ -136,6 +157,7 @@ export declare class ImageNode {
|
|
136
157
|
private rebalance;
|
137
158
|
protected removeChild(child: ImageNode): void;
|
138
159
|
remove(): void;
|
160
|
+
renderAllAsync(renderer: AbstractRenderer, preRenderComponent: PreRenderComponentCallback): Promise<boolean>;
|
139
161
|
render(renderer: AbstractRenderer, visibleRect?: Rect2): void;
|
140
162
|
renderDebugBoundingBoxes(renderer: AbstractRenderer, visibleRect: Rect2, depth?: number): void;
|
141
163
|
}
|
@@ -3,13 +3,13 @@ var __setFunctionName = (this && this.__setFunctionName) || function (f, name, p
|
|
3
3
|
return Object.defineProperty(f, "name", { configurable: true, value: prefix ? "".concat(prefix, " ", name) : name });
|
4
4
|
};
|
5
5
|
var _a, _b, _c;
|
6
|
-
import Viewport from '
|
7
|
-
import AbstractComponent, { ComponentSizingMode } from '
|
6
|
+
import Viewport from '../Viewport.mjs';
|
7
|
+
import AbstractComponent, { ComponentSizingMode } from '../components/AbstractComponent.mjs';
|
8
8
|
import { Rect2, Vec2, Mat33, Color4 } from '@js-draw/math';
|
9
|
-
import SerializableCommand from '
|
10
|
-
import EventDispatcher from '
|
11
|
-
import { assertIsBoolean, assertIsNumber, assertIsNumberArray } from '
|
12
|
-
import Command from '
|
9
|
+
import SerializableCommand from '../commands/SerializableCommand.mjs';
|
10
|
+
import EventDispatcher from '../EventDispatcher.mjs';
|
11
|
+
import { assertIsBoolean, assertIsNumber, assertIsNumberArray } from '../util/assertions.mjs';
|
12
|
+
import Command from '../commands/Command.mjs';
|
13
13
|
// @internal Sort by z-index, low to high
|
14
14
|
export const sortLeavesByZIndex = (leaves) => {
|
15
15
|
leaves.sort((a, b) => a.getContent().getZIndex() - b.getContent().getZIndex());
|
@@ -87,7 +87,27 @@ class EditorImage {
|
|
87
87
|
this.background.render(renderer, viewport?.visibleRect);
|
88
88
|
this.root.render(renderer, viewport?.visibleRect);
|
89
89
|
}
|
90
|
-
/**
|
90
|
+
/**
|
91
|
+
* Like {@link renderAll}, but can be stopped early and paused.
|
92
|
+
*
|
93
|
+
* **Note**: If the image is being edited during an async rendering, there is no
|
94
|
+
* guarantee that all nodes will be rendered correctly (some may be missing).
|
95
|
+
*
|
96
|
+
* @internal
|
97
|
+
*/
|
98
|
+
async renderAllAsync(renderer, preRenderComponent) {
|
99
|
+
const stoppedEarly = !(await this.background.renderAllAsync(renderer, preRenderComponent));
|
100
|
+
if (!stoppedEarly) {
|
101
|
+
return await this.root.renderAllAsync(renderer, preRenderComponent);
|
102
|
+
}
|
103
|
+
return false;
|
104
|
+
}
|
105
|
+
/**
|
106
|
+
* Renders all nodes, even ones not within the viewport.
|
107
|
+
*
|
108
|
+
* This can be slow for large images
|
109
|
+
* @internal
|
110
|
+
*/
|
91
111
|
renderAll(renderer) {
|
92
112
|
this.render(renderer, null);
|
93
113
|
}
|
@@ -610,6 +630,30 @@ export class ImageNode {
|
|
610
630
|
this.content = null;
|
611
631
|
this.children = [];
|
612
632
|
}
|
633
|
+
// Creates a (potentially incomplete) async rendering of this image.
|
634
|
+
// Returns false if stopped early
|
635
|
+
async renderAllAsync(renderer,
|
636
|
+
// Used to pause/stop the renderer process
|
637
|
+
preRenderComponent) {
|
638
|
+
const leaves = this.getLeaves();
|
639
|
+
sortLeavesByZIndex(leaves);
|
640
|
+
const totalLeaves = leaves.length;
|
641
|
+
for (let leafIndex = 0; leafIndex < totalLeaves; leafIndex++) {
|
642
|
+
const leaf = leaves[leafIndex];
|
643
|
+
const component = leaf.getContent();
|
644
|
+
// Even though leaf was originally a leaf, it might not be any longer --
|
645
|
+
// rendering is async and the tree can change during that time.
|
646
|
+
if (!component) {
|
647
|
+
continue;
|
648
|
+
}
|
649
|
+
const shouldContinue = await preRenderComponent(component, leafIndex, totalLeaves);
|
650
|
+
if (!shouldContinue) {
|
651
|
+
return false;
|
652
|
+
}
|
653
|
+
component.render(renderer, undefined);
|
654
|
+
}
|
655
|
+
return true;
|
656
|
+
}
|
613
657
|
render(renderer, visibleRect) {
|
614
658
|
let leaves;
|
615
659
|
if (visibleRect) {
|
@@ -0,0 +1 @@
|
|
1
|
+
export {};
|
@@ -0,0 +1,20 @@
|
|
1
|
+
import { toRoundedString } from '@js-draw/math';
|
2
|
+
// @internal
|
3
|
+
const adjustExportedSVGSize = (svg, exportRect, options) => {
|
4
|
+
// Adjust the width/height as necessary
|
5
|
+
let width = exportRect.w;
|
6
|
+
let height = exportRect.h;
|
7
|
+
if (options?.minDimension && width < options.minDimension) {
|
8
|
+
const newWidth = options.minDimension;
|
9
|
+
height *= newWidth / (width || 1);
|
10
|
+
width = newWidth;
|
11
|
+
}
|
12
|
+
if (options?.minDimension && height < options.minDimension) {
|
13
|
+
const newHeight = options.minDimension;
|
14
|
+
width *= newHeight / (height || 1);
|
15
|
+
height = newHeight;
|
16
|
+
}
|
17
|
+
svg.setAttribute('width', toRoundedString(width));
|
18
|
+
svg.setAttribute('height', toRoundedString(height));
|
19
|
+
};
|
20
|
+
export default adjustExportedSVGSize;
|
@@ -0,0 +1,8 @@
|
|
1
|
+
import EditorImage, { PreRenderComponentCallback } from '../EditorImage';
|
2
|
+
import { SVGSizingOptions } from './adjustExportedSVGSize';
|
3
|
+
export interface SVGExportOptions extends SVGSizingOptions {
|
4
|
+
sanitize?: boolean;
|
5
|
+
minDimension?: number;
|
6
|
+
}
|
7
|
+
export declare const editorImageToSVGSync: (image: EditorImage, options: SVGExportOptions) => SVGSVGElement;
|
8
|
+
export declare const editorImageToSVGAsync: (image: EditorImage, preRenderComponent: PreRenderComponentCallback, options: SVGExportOptions) => Promise<SVGElement>;
|
@@ -0,0 +1,55 @@
|
|
1
|
+
import { Rect2 } from '@js-draw/math';
|
2
|
+
import SVGRenderer from '../../rendering/renderers/SVGRenderer.mjs';
|
3
|
+
import { svgLoaderAutoresizeClassName } from '../../SVGLoader.mjs';
|
4
|
+
import adjustExportedSVGSize from './adjustExportedSVGSize.mjs';
|
5
|
+
const toSVGInternal = (image, renderFunction, options) => {
|
6
|
+
const importExportViewport = image.getImportExportViewport().getTemporaryClone();
|
7
|
+
// If the rectangle has zero width or height, its size can't be increased
|
8
|
+
// -- set its size to the minimum.
|
9
|
+
if (options?.minDimension) {
|
10
|
+
const originalRect = importExportViewport.visibleRect;
|
11
|
+
let rect = originalRect;
|
12
|
+
if (rect.w <= 0) {
|
13
|
+
rect = new Rect2(rect.x, rect.y, options.minDimension, rect.h);
|
14
|
+
}
|
15
|
+
if (rect.h <= 0) {
|
16
|
+
rect = new Rect2(rect.x, rect.y, rect.w, options.minDimension);
|
17
|
+
}
|
18
|
+
if (!rect.eq(originalRect)) {
|
19
|
+
importExportViewport.updateScreenSize(rect.size);
|
20
|
+
}
|
21
|
+
}
|
22
|
+
const { element: result, renderer } = SVGRenderer.fromViewport(importExportViewport, {
|
23
|
+
sanitize: options.sanitize ?? false,
|
24
|
+
useViewBoxForPositioning: true,
|
25
|
+
});
|
26
|
+
// Use a callback rather than async/await to allow this function to create
|
27
|
+
// both sync and async render functions
|
28
|
+
renderFunction(renderer, () => {
|
29
|
+
if (image.getAutoresizeEnabled()) {
|
30
|
+
result.classList.add(svgLoaderAutoresizeClassName);
|
31
|
+
}
|
32
|
+
else {
|
33
|
+
result.classList.remove(svgLoaderAutoresizeClassName);
|
34
|
+
}
|
35
|
+
const exportRect = importExportViewport.visibleRect;
|
36
|
+
adjustExportedSVGSize(result, exportRect, options);
|
37
|
+
return result;
|
38
|
+
});
|
39
|
+
return result;
|
40
|
+
};
|
41
|
+
export const editorImageToSVGSync = (image, options) => {
|
42
|
+
return toSVGInternal(image, (renderer, onComplete) => {
|
43
|
+
image.renderAll(renderer);
|
44
|
+
onComplete();
|
45
|
+
}, options);
|
46
|
+
};
|
47
|
+
export const editorImageToSVGAsync = (image, preRenderComponent, options) => {
|
48
|
+
return new Promise(resolve => {
|
49
|
+
toSVGInternal(image, async (renderer, onComplete) => {
|
50
|
+
await image.renderAllAsync(renderer, preRenderComponent);
|
51
|
+
const result = onComplete();
|
52
|
+
resolve(result);
|
53
|
+
}, options);
|
54
|
+
});
|
55
|
+
};
|
@@ -0,0 +1 @@
|
|
1
|
+
export { default as EditorImage } from './EditorImage';
|
@@ -0,0 +1 @@
|
|
1
|
+
export { default as EditorImage } from './EditorImage.mjs';
|
package/dist/mjs/lib.d.ts
CHANGED
@@ -15,7 +15,7 @@
|
|
15
15
|
* @packageDocumentation
|
16
16
|
*/
|
17
17
|
import Editor, { EditorSettings } from './Editor';
|
18
|
-
export
|
18
|
+
export * from './image/lib';
|
19
19
|
export * from './types';
|
20
20
|
export * from './inputEvents';
|
21
21
|
export { default as getLocalizationTable, matchingLocalizationTable } from './localizations/getLocalizationTable';
|
package/dist/mjs/lib.mjs
CHANGED
@@ -15,7 +15,7 @@
|
|
15
15
|
* @packageDocumentation
|
16
16
|
*/
|
17
17
|
import Editor from './Editor.mjs';
|
18
|
-
export
|
18
|
+
export * from './image/lib.mjs';
|
19
19
|
export * from './types.mjs';
|
20
20
|
export * from './inputEvents.mjs';
|
21
21
|
export { default as getLocalizationTable, matchingLocalizationTable } from './localizations/getLocalizationTable.mjs';
|