js-draw 1.18.0 → 1.19.1
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/Editor.css +35 -3
- package/dist/bundle.js +2 -2
- package/dist/bundledStyles.js +1 -1
- package/dist/cjs/Editor.d.ts +20 -1
- package/dist/cjs/Editor.js +6 -0
- package/dist/cjs/{SVGLoader.d.ts → SVGLoader/index.d.ts} +1 -1
- package/dist/cjs/{SVGLoader.js → SVGLoader/index.js} +12 -29
- package/dist/cjs/SVGLoader/utils/determineFontSize.d.ts +3 -0
- package/dist/cjs/SVGLoader/utils/determineFontSize.js +27 -0
- package/dist/cjs/Viewport.d.ts +33 -1
- package/dist/cjs/components/TextComponent.js +3 -1
- package/dist/cjs/rendering/caching/RenderingCacheNode.js +20 -15
- package/dist/cjs/testing/findNodeWithText.d.ts +3 -0
- package/dist/cjs/testing/findNodeWithText.js +16 -0
- package/dist/cjs/testing/firstElementAncestorOfNode.d.ts +3 -0
- package/dist/cjs/testing/firstElementAncestorOfNode.js +13 -0
- package/dist/cjs/testing/sendKeyPressRelease.d.ts +3 -0
- package/dist/cjs/testing/sendKeyPressRelease.js +8 -0
- package/dist/cjs/testing/sendPenEvent.d.ts +2 -2
- package/dist/cjs/testing/sendPenEvent.js +26 -3
- package/dist/cjs/toolbar/localization.d.ts +2 -0
- package/dist/cjs/toolbar/localization.js +2 -0
- package/dist/cjs/toolbar/widgets/BaseWidget.d.ts +1 -0
- package/dist/cjs/toolbar/widgets/BaseWidget.js +1 -0
- package/dist/cjs/toolbar/widgets/InsertImageWidget/ImageWrapper.d.ts +22 -0
- package/dist/cjs/toolbar/widgets/InsertImageWidget/ImageWrapper.js +58 -0
- package/dist/cjs/toolbar/widgets/InsertImageWidget/fileToImages.d.ts +3 -0
- package/dist/cjs/toolbar/widgets/InsertImageWidget/fileToImages.js +21 -0
- package/dist/cjs/toolbar/widgets/InsertImageWidget/index.d.ts +37 -0
- package/dist/cjs/toolbar/widgets/InsertImageWidget/index.js +281 -0
- package/dist/cjs/toolbar/widgets/TextToolWidget.js +5 -3
- package/dist/cjs/toolbar/widgets/TextToolWidget.test.d.ts +1 -0
- package/dist/cjs/toolbar/widgets/components/makeFileInput.d.ts +12 -2
- package/dist/cjs/toolbar/widgets/components/makeFileInput.js +102 -45
- package/dist/cjs/toolbar/widgets/components/makeFileInput.test.d.ts +1 -0
- package/dist/cjs/toolbar/widgets/components/makeSnappedList.d.ts +15 -0
- package/dist/cjs/toolbar/widgets/components/makeSnappedList.js +103 -0
- package/dist/cjs/tools/Eraser.d.ts +7 -2
- package/dist/cjs/tools/Eraser.js +54 -1
- package/dist/cjs/tools/SelectionTool/Selection.d.ts +2 -2
- package/dist/cjs/tools/SelectionTool/Selection.js +20 -20
- package/dist/cjs/tools/SelectionTool/SelectionHandle.d.ts +8 -2
- package/dist/cjs/tools/SelectionTool/SelectionHandle.js +6 -0
- package/dist/cjs/tools/SelectionTool/SelectionTool.js +1 -1
- package/dist/cjs/tools/SelectionTool/types.d.ts +19 -0
- package/dist/cjs/tools/TextTool.js +2 -1
- package/dist/cjs/tools/TextTool.test.d.ts +1 -0
- package/dist/cjs/tools/ToolController.d.ts +2 -0
- package/dist/cjs/tools/ToolController.js +10 -1
- package/dist/cjs/util/ReactiveValue.d.ts +2 -0
- package/dist/cjs/util/ReactiveValue.js +11 -0
- package/dist/cjs/util/bytesToSizeString.d.ts +8 -0
- package/dist/cjs/util/bytesToSizeString.js +26 -0
- package/dist/cjs/util/bytesToSizeString.test.d.ts +1 -0
- package/dist/cjs/util/stopPropagationOfScrollingWheelEvents.js +10 -6
- package/dist/cjs/util/waitForAll.d.ts +2 -0
- package/dist/cjs/util/waitForAll.js +2 -0
- package/dist/cjs/util/waitForImageLoaded.js +3 -0
- package/dist/cjs/util/waitForTimeout.d.ts +1 -0
- package/dist/cjs/util/waitForTimeout.js +1 -1
- package/dist/cjs/version.js +1 -1
- package/dist/mjs/Editor.d.ts +20 -1
- package/dist/mjs/Editor.mjs +6 -0
- package/dist/mjs/{SVGLoader.d.ts → SVGLoader/index.d.ts} +1 -1
- package/dist/mjs/{SVGLoader.mjs → SVGLoader/index.mjs} +12 -29
- package/dist/mjs/SVGLoader/index.test.d.ts +1 -0
- package/dist/mjs/SVGLoader/utils/determineFontSize.d.ts +3 -0
- package/dist/mjs/SVGLoader/utils/determineFontSize.mjs +25 -0
- package/dist/mjs/Viewport.d.ts +33 -1
- package/dist/mjs/components/TextComponent.mjs +3 -1
- package/dist/mjs/rendering/caching/RenderingCacheNode.mjs +20 -15
- package/dist/mjs/testing/findNodeWithText.d.ts +3 -0
- package/dist/mjs/testing/findNodeWithText.mjs +14 -0
- package/dist/mjs/testing/firstElementAncestorOfNode.d.ts +3 -0
- package/dist/mjs/testing/firstElementAncestorOfNode.mjs +11 -0
- package/dist/mjs/testing/sendKeyPressRelease.d.ts +3 -0
- package/dist/mjs/testing/sendKeyPressRelease.mjs +6 -0
- package/dist/mjs/testing/sendPenEvent.d.ts +2 -2
- package/dist/mjs/testing/sendPenEvent.mjs +3 -3
- package/dist/mjs/toolbar/localization.d.ts +2 -0
- package/dist/mjs/toolbar/localization.mjs +2 -0
- package/dist/mjs/toolbar/widgets/BaseWidget.d.ts +1 -0
- package/dist/mjs/toolbar/widgets/BaseWidget.mjs +1 -0
- package/dist/mjs/toolbar/widgets/InsertImageWidget/ImageWrapper.d.ts +22 -0
- package/dist/mjs/toolbar/widgets/InsertImageWidget/ImageWrapper.mjs +54 -0
- package/dist/mjs/toolbar/widgets/InsertImageWidget/fileToImages.d.ts +3 -0
- package/dist/mjs/toolbar/widgets/InsertImageWidget/fileToImages.mjs +16 -0
- package/dist/mjs/toolbar/widgets/InsertImageWidget/index.d.ts +37 -0
- package/dist/mjs/toolbar/widgets/InsertImageWidget/index.mjs +276 -0
- package/dist/mjs/toolbar/widgets/InsertImageWidget/index.test.d.ts +1 -0
- package/dist/mjs/toolbar/widgets/TextToolWidget.mjs +5 -3
- package/dist/mjs/toolbar/widgets/TextToolWidget.test.d.ts +1 -0
- package/dist/mjs/toolbar/widgets/components/makeFileInput.d.ts +12 -2
- package/dist/mjs/toolbar/widgets/components/makeFileInput.mjs +102 -45
- package/dist/mjs/toolbar/widgets/components/makeFileInput.test.d.ts +1 -0
- package/dist/mjs/toolbar/widgets/components/makeSnappedList.d.ts +15 -0
- package/dist/mjs/toolbar/widgets/components/makeSnappedList.mjs +98 -0
- package/dist/mjs/tools/Eraser.d.ts +7 -2
- package/dist/mjs/tools/Eraser.mjs +54 -1
- package/dist/mjs/tools/SelectionTool/Selection.d.ts +2 -2
- package/dist/mjs/tools/SelectionTool/Selection.mjs +20 -20
- package/dist/mjs/tools/SelectionTool/SelectionHandle.d.ts +8 -2
- package/dist/mjs/tools/SelectionTool/SelectionHandle.mjs +6 -0
- package/dist/mjs/tools/SelectionTool/SelectionTool.mjs +1 -1
- package/dist/mjs/tools/SelectionTool/types.d.ts +19 -0
- package/dist/mjs/tools/TextTool.mjs +2 -1
- package/dist/mjs/tools/TextTool.test.d.ts +1 -0
- package/dist/mjs/tools/ToolController.d.ts +2 -0
- package/dist/mjs/tools/ToolController.mjs +10 -1
- package/dist/mjs/util/ReactiveValue.d.ts +2 -0
- package/dist/mjs/util/ReactiveValue.mjs +11 -0
- package/dist/mjs/util/bytesToSizeString.d.ts +8 -0
- package/dist/mjs/util/bytesToSizeString.mjs +24 -0
- package/dist/mjs/util/bytesToSizeString.test.d.ts +1 -0
- package/dist/mjs/util/stopPropagationOfScrollingWheelEvents.mjs +10 -6
- package/dist/mjs/util/waitForAll.d.ts +2 -0
- package/dist/mjs/util/waitForAll.mjs +2 -0
- package/dist/mjs/util/waitForImageLoaded.mjs +3 -0
- package/dist/mjs/util/waitForTimeout.d.ts +1 -0
- package/dist/mjs/util/waitForTimeout.mjs +1 -1
- package/dist/mjs/version.mjs +1 -1
- package/package.json +4 -4
- package/src/toolbar/toolbar.scss +1 -7
- package/src/toolbar/widgets/{InsertImageWidget.scss → InsertImageWidget/index.scss} +3 -2
- package/src/toolbar/widgets/components/components.scss +2 -1
- package/src/toolbar/widgets/components/makeFileInput.scss +14 -1
- package/src/toolbar/widgets/components/makeSnappedList.scss +28 -0
- package/src/toolbar/widgets/widgets.scss +7 -0
- package/dist/cjs/toolbar/widgets/InsertImageWidget.d.ts +0 -22
- package/dist/cjs/toolbar/widgets/InsertImageWidget.js +0 -269
- package/dist/mjs/toolbar/widgets/InsertImageWidget.d.ts +0 -22
- package/dist/mjs/toolbar/widgets/InsertImageWidget.mjs +0 -264
- /package/dist/cjs/{SVGLoader.test.d.ts → SVGLoader/index.test.d.ts} +0 -0
- /package/dist/{mjs/SVGLoader.test.d.ts → cjs/toolbar/widgets/InsertImageWidget/index.test.d.ts} +0 -0
@@ -62,6 +62,7 @@ class ToolController {
|
|
62
62
|
const secondaryPenTool = new Pen_1.default(editor, localization.penTool(2), { color: math_1.Color4.clay, thickness: 4 });
|
63
63
|
// Stabilize the secondary pen tool.
|
64
64
|
secondaryPenTool.setInputMapper(new InputStabilizer_1.default(editor.viewport));
|
65
|
+
const eraser = new Eraser_1.default(editor, localization.eraserTool);
|
65
66
|
const primaryTools = [
|
66
67
|
// Three pens
|
67
68
|
primaryPenTool,
|
@@ -72,7 +73,7 @@ class ToolController {
|
|
72
73
|
thickness: 40,
|
73
74
|
factory: PressureSensitiveFreehandLineBuilder_1.makePressureSensitiveFreehandLineBuilder
|
74
75
|
}),
|
75
|
-
|
76
|
+
eraser,
|
76
77
|
new SelectionTool_1.default(editor, localization.selectionTool),
|
77
78
|
new TextTool_1.default(editor, localization.textTool, localization),
|
78
79
|
new PanZoom_1.default(editor, PanZoom_1.PanZoomMode.SinglePointerGestures, localization.anyDevicePanning),
|
@@ -90,6 +91,7 @@ class ToolController {
|
|
90
91
|
new UndoRedoShortcut_1.default(editor),
|
91
92
|
new ToolbarShortcutHandler_1.default(editor),
|
92
93
|
new ToolSwitcherShortcut_1.default(editor),
|
94
|
+
eraser.makeEraserSwitcherTool(),
|
93
95
|
new FindTool_1.default(editor),
|
94
96
|
new PasteHandler_1.default(editor),
|
95
97
|
new SelectAllShortcutHandler_1.default(editor),
|
@@ -208,6 +210,13 @@ class ToolController {
|
|
208
210
|
insertToolsBefore(insertBefore, toolsToInsert) {
|
209
211
|
this.insertTools(insertBefore, toolsToInsert, 'before');
|
210
212
|
}
|
213
|
+
/** @internal */
|
214
|
+
changeActiveToolTo(tool) {
|
215
|
+
if (!tool.isEnabled()) {
|
216
|
+
tool.setEnabled(true);
|
217
|
+
}
|
218
|
+
this.activeTool = tool;
|
219
|
+
}
|
211
220
|
// @internal use `dispatchEvent` rather than calling `onEvent` directly.
|
212
221
|
onEventInternal(event) {
|
213
222
|
const isEditorReadOnly = this.isEditorReadOnly.get();
|
@@ -33,6 +33,8 @@ export declare abstract class ReactiveValue<T> {
|
|
33
33
|
* @see {@link onUpdate}.
|
34
34
|
*/
|
35
35
|
abstract onUpdateAndNow(callback: UpdateCallback<T>): ListenerResult;
|
36
|
+
/** Returns a promise that resolves when this value is next changed. */
|
37
|
+
waitForNextUpdate(): Promise<T>;
|
36
38
|
/** Creates a `ReactiveValue` with an initial value, `initialValue`. */
|
37
39
|
static fromInitialValue<T>(initialValue: T): MutableReactiveValue<T>;
|
38
40
|
/** Returns a `ReactiveValue` that is **known** will never change. */
|
@@ -38,6 +38,15 @@ const noOpSetUpdateListener = () => {
|
|
38
38
|
* Avoid extending this class from an external library, as that may not be stable.
|
39
39
|
*/
|
40
40
|
class ReactiveValue {
|
41
|
+
/** Returns a promise that resolves when this value is next changed. */
|
42
|
+
waitForNextUpdate() {
|
43
|
+
return new Promise(resolve => {
|
44
|
+
const listener = this.onUpdate(value => {
|
45
|
+
listener.remove();
|
46
|
+
resolve(value);
|
47
|
+
});
|
48
|
+
});
|
49
|
+
}
|
41
50
|
/** Creates a `ReactiveValue` with an initial value, `initialValue`. */
|
42
51
|
static fromInitialValue(initialValue) {
|
43
52
|
return new ReactiveValueImpl(initialValue);
|
@@ -51,6 +60,8 @@ class ReactiveValue {
|
|
51
60
|
callback(value);
|
52
61
|
return noOpUpdateListenerResult;
|
53
62
|
},
|
63
|
+
// Never resolves -- immutable.
|
64
|
+
waitForNextUpdate: () => new Promise(() => { }),
|
54
65
|
};
|
55
66
|
}
|
56
67
|
/**
|
@@ -0,0 +1,26 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
/**
|
4
|
+
* Returns a size in bytes, KiB, or MiB with units suffix.
|
5
|
+
*/
|
6
|
+
const bytesToSizeString = (sizeBytes) => {
|
7
|
+
const sizeInKiB = sizeBytes / 1024;
|
8
|
+
const sizeInMiB = sizeInKiB / 1024;
|
9
|
+
const sizeInGiB = sizeInMiB / 1024;
|
10
|
+
let units = 'B';
|
11
|
+
let size = sizeBytes;
|
12
|
+
if (sizeInGiB >= 1) {
|
13
|
+
size = sizeInGiB;
|
14
|
+
units = 'GiB';
|
15
|
+
}
|
16
|
+
else if (sizeInMiB >= 1) {
|
17
|
+
size = sizeInMiB;
|
18
|
+
units = 'MiB';
|
19
|
+
}
|
20
|
+
else if (sizeInKiB >= 1) {
|
21
|
+
size = sizeInKiB;
|
22
|
+
units = 'KiB';
|
23
|
+
}
|
24
|
+
return { size, units };
|
25
|
+
};
|
26
|
+
exports.default = bytesToSizeString;
|
@@ -0,0 +1 @@
|
|
1
|
+
export {};
|
@@ -1,15 +1,19 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
3
|
const stopPropagationOfScrollingWheelEvents = (scrollingContainer) => {
|
4
|
+
const scrollsAxis = (delta, clientSize, scrollOffset, scrollSize) => {
|
5
|
+
const hasScroll = clientSize !== scrollSize && delta !== 0;
|
6
|
+
const eventScrollsPastStart = scrollOffset + delta <= 0;
|
7
|
+
const scrollEnd = scrollOffset + clientSize;
|
8
|
+
const eventScrollsPastEnd = scrollEnd + delta > scrollSize;
|
9
|
+
return hasScroll && !eventScrollsPastStart && !eventScrollsPastEnd;
|
10
|
+
};
|
4
11
|
scrollingContainer.onwheel = (event) => {
|
5
|
-
const
|
6
|
-
|
7
|
-
const eventScrollsPastLeft = scrollingContainer.scrollLeft + event.deltaX <= 0;
|
8
|
-
const scrollRight = scrollingContainer.scrollLeft + scrollingContainer.clientWidth;
|
9
|
-
const eventScrollsPastRight = scrollRight + event.deltaX > scrollingContainer.scrollWidth;
|
12
|
+
const scrollsX = scrollsAxis(event.deltaX, scrollingContainer.clientWidth, scrollingContainer.scrollLeft, scrollingContainer.scrollWidth);
|
13
|
+
const scrollsY = scrollsAxis(event.deltaY, scrollingContainer.clientHeight, scrollingContainer.scrollTop, scrollingContainer.scrollHeight);
|
10
14
|
// Stop the editor from receiving the event if it will scroll the pen type selector
|
11
15
|
// instead.
|
12
|
-
if (
|
16
|
+
if (scrollsX || scrollsY) {
|
13
17
|
event.stopPropagation();
|
14
18
|
}
|
15
19
|
};
|
@@ -1,6 +1,8 @@
|
|
1
1
|
/**
|
2
2
|
* Resolves when all given promises have resolved. If no promises are given,
|
3
3
|
* does not return a Promise.
|
4
|
+
*
|
5
|
+
* If all elements of `results` are known to be `Promise`s, use `Promise.all`.
|
4
6
|
*/
|
5
7
|
declare const waitForAll: (results: (Promise<void> | void)[]) => Promise<void> | void;
|
6
8
|
export default waitForAll;
|
@@ -3,6 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
/**
|
4
4
|
* Resolves when all given promises have resolved. If no promises are given,
|
5
5
|
* does not return a Promise.
|
6
|
+
*
|
7
|
+
* If all elements of `results` are known to be `Promise`s, use `Promise.all`.
|
6
8
|
*/
|
7
9
|
const waitForAll = (results) => {
|
8
10
|
// If any are Promises...
|
@@ -4,7 +4,10 @@ const waitForImageLoad = async (image) => {
|
|
4
4
|
if (!image.complete) {
|
5
5
|
await new Promise((resolve, reject) => {
|
6
6
|
image.onload = event => resolve(event);
|
7
|
+
// TODO(v2): Return a `new Error(event.message)`
|
8
|
+
// eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors -- Forwarding an error-like object.
|
7
9
|
image.onerror = event => reject(event);
|
10
|
+
// eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors -- Forwarding an error-like object.
|
8
11
|
image.onabort = event => reject(event);
|
9
12
|
});
|
10
13
|
}
|
@@ -1,6 +1,6 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
|
3
|
+
/** Returns a promise that resolves after `timeout` milliseconds. */
|
4
4
|
const waitForTimeout = (timeout) => {
|
5
5
|
return new Promise(resolve => {
|
6
6
|
setTimeout(() => resolve(), timeout);
|
package/dist/cjs/version.js
CHANGED
package/dist/mjs/Editor.d.ts
CHANGED
@@ -19,6 +19,7 @@ import RenderablePathSpec from './rendering/RenderablePathSpec';
|
|
19
19
|
import { AboutDialogEntry } from './dialogs/makeAboutDialog';
|
20
20
|
import ReactiveValue, { MutableReactiveValue } from './util/ReactiveValue';
|
21
21
|
import { PenTypeRecord } from './toolbar/widgets/PenToolWidget';
|
22
|
+
import { ShowCustomFilePickerCallback } from './toolbar/widgets/components/makeFileInput';
|
22
23
|
/**
|
23
24
|
* Provides settings to an instance of an editor. See the Editor {@link Editor.constructor}.
|
24
25
|
*
|
@@ -76,7 +77,7 @@ export interface EditorSettings {
|
|
76
77
|
version?: string;
|
77
78
|
} | null;
|
78
79
|
/**
|
79
|
-
* Configures the default
|
80
|
+
* Configures the default {@link PenTool} tools.
|
80
81
|
*
|
81
82
|
* **Example**:
|
82
83
|
* [[include:doc-pages/inline-examples/editor-settings-polyline-pen.md]]
|
@@ -102,6 +103,24 @@ export interface EditorSettings {
|
|
102
103
|
*/
|
103
104
|
filterPenTypes?: (penType: PenTypeRecord) => boolean;
|
104
105
|
} | null;
|
106
|
+
/** Configures the default {@link TextTool} control and text tool. */
|
107
|
+
text: {
|
108
|
+
/** Fonts to show in the text UI. */
|
109
|
+
fonts?: string[];
|
110
|
+
} | null;
|
111
|
+
/** Configures the default {@link InsertImageWidget} control. */
|
112
|
+
image: {
|
113
|
+
/**
|
114
|
+
* A custom callback to show an image picker. If given, this should return
|
115
|
+
* a list of `File`s representing the images selected by the picker.
|
116
|
+
*
|
117
|
+
* If not given, the default file picker shown by a [file input](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file)
|
118
|
+
* is shown.
|
119
|
+
*
|
120
|
+
* @beta -- API may change between minor releases.
|
121
|
+
*/
|
122
|
+
showImagePicker?: ShowCustomFilePickerCallback;
|
123
|
+
} | null;
|
105
124
|
}
|
106
125
|
/**
|
107
126
|
* The main entrypoint for the full editor.
|
package/dist/mjs/Editor.mjs
CHANGED
@@ -113,6 +113,12 @@ export class Editor {
|
|
113
113
|
additionalPenTypes: settings.pens?.additionalPenTypes ?? [],
|
114
114
|
filterPenTypes: settings.pens?.filterPenTypes ?? (() => true)
|
115
115
|
},
|
116
|
+
text: {
|
117
|
+
fonts: settings.text?.fonts ?? ['sans-serif', 'serif', 'monospace'],
|
118
|
+
},
|
119
|
+
image: {
|
120
|
+
showImagePicker: settings.image?.showImagePicker ?? undefined,
|
121
|
+
},
|
116
122
|
};
|
117
123
|
// Validate settings
|
118
124
|
if (this.settings.minZoom > this.settings.maxZoom) {
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import { Rect2 } from '@js-draw/math';
|
2
|
-
import { ComponentAddedListener, ImageLoader, OnDetermineExportRectListener, OnProgressListener } from '
|
2
|
+
import { ComponentAddedListener, ImageLoader, OnDetermineExportRectListener, OnProgressListener } from '../types';
|
3
3
|
export declare const defaultSVGViewRect: Rect2;
|
4
4
|
export declare const svgAttributesDataKey = "svgAttrs";
|
5
5
|
export declare const svgStyleAttributesDataKey = "svgStyleAttrs";
|
@@ -1,12 +1,13 @@
|
|
1
1
|
import { Color4, Mat33, Path, Rect2, Vec2 } from '@js-draw/math';
|
2
|
-
import BackgroundComponent, { BackgroundType, backgroundTypeToClassNameMap, imageBackgroundCSSClassName, imageBackgroundGridSizeCSSPrefix, imageBackgroundNonAutomaticSecondaryColorCSSClassName } from '
|
3
|
-
import ImageComponent from '
|
4
|
-
import Stroke from '
|
5
|
-
import SVGGlobalAttributesObject from '
|
6
|
-
import TextComponent, { TextTransformMode } from '
|
7
|
-
import UnknownSVGObject from '
|
8
|
-
import { pathToRenderable } from '
|
9
|
-
import { renderedStylesheetId } from '
|
2
|
+
import BackgroundComponent, { BackgroundType, backgroundTypeToClassNameMap, imageBackgroundCSSClassName, imageBackgroundGridSizeCSSPrefix, imageBackgroundNonAutomaticSecondaryColorCSSClassName } from '../components/BackgroundComponent.mjs';
|
3
|
+
import ImageComponent from '../components/ImageComponent.mjs';
|
4
|
+
import Stroke from '../components/Stroke.mjs';
|
5
|
+
import SVGGlobalAttributesObject from '../components/SVGGlobalAttributesObject.mjs';
|
6
|
+
import TextComponent, { TextTransformMode } from '../components/TextComponent.mjs';
|
7
|
+
import UnknownSVGObject from '../components/UnknownSVGObject.mjs';
|
8
|
+
import { pathToRenderable } from '../rendering/RenderablePathSpec.mjs';
|
9
|
+
import { renderedStylesheetId } from '../rendering/renderers/SVGRenderer.mjs';
|
10
|
+
import determineFontSize from './utils/determineFontSize.mjs';
|
10
11
|
// Size of a loaded image if no size is specified.
|
11
12
|
export const defaultSVGViewRect = new Rect2(0, 0, 500, 500);
|
12
13
|
// Key to retrieve unrecognised attributes from an AbstractComponent
|
@@ -296,31 +297,13 @@ export default class SVGLoader {
|
|
296
297
|
}
|
297
298
|
// Compute styles.
|
298
299
|
const computedStyles = this.getComputedStyle(elem);
|
299
|
-
const
|
300
|
-
// In some environments, computedStyles.fontSize can be increased by the system.
|
301
|
-
// Thus, to prevent text from growing on load/save, prefer .style.fontSize.
|
302
|
-
let fontSizeMatch = fontSizeExp.exec(elem.style?.fontSize ?? '');
|
303
|
-
if (!fontSizeMatch && elem.tagName.toLowerCase() === 'tspan' && elem.parentElement) {
|
304
|
-
// Try to inherit the font size of the parent text element.
|
305
|
-
fontSizeMatch = fontSizeExp.exec(elem.parentElement.style?.fontSize ?? '');
|
306
|
-
}
|
307
|
-
// If we still couldn't find a font size, try to use computedStyles (which can be
|
308
|
-
// wrong).
|
309
|
-
if (!fontSizeMatch && computedStyles) {
|
310
|
-
fontSizeMatch = fontSizeExp.exec(computedStyles.fontSize);
|
311
|
-
}
|
312
|
-
const supportedStyleAttrs = [
|
300
|
+
const supportedStyleAttrs = new Set([
|
313
301
|
'fontFamily',
|
314
302
|
'transform',
|
315
303
|
...supportedStrokeFillStyleAttrs,
|
316
|
-
];
|
317
|
-
let fontSize = 12;
|
318
|
-
if (fontSizeMatch) {
|
319
|
-
supportedStyleAttrs.push('fontSize');
|
320
|
-
fontSize = parseFloat(fontSizeMatch[1]);
|
321
|
-
}
|
304
|
+
]);
|
322
305
|
const style = {
|
323
|
-
size:
|
306
|
+
size: determineFontSize(elem, computedStyles, supportedStyleAttrs),
|
324
307
|
fontFamily: computedStyles?.fontFamily || elem.style?.fontFamily || 'sans-serif',
|
325
308
|
fontWeight: computedStyles?.fontWeight || elem.style?.fontWeight || undefined,
|
326
309
|
fontStyle: computedStyles?.fontStyle || elem.style?.fontStyle || undefined,
|
@@ -0,0 +1 @@
|
|
1
|
+
export {};
|
@@ -0,0 +1,3 @@
|
|
1
|
+
/** Computes the font size of a text element, based on style information. */
|
2
|
+
declare const determineFontSize: (elem: SVGTextElement | SVGTSpanElement, computedStyles: CSSStyleDeclaration | undefined, supportedStyleAttrs: Set<string>) => number;
|
3
|
+
export default determineFontSize;
|
@@ -0,0 +1,25 @@
|
|
1
|
+
/** Computes the font size of a text element, based on style information. */
|
2
|
+
const determineFontSize = (elem, computedStyles,
|
3
|
+
// output: Written to to update supported style attributes
|
4
|
+
supportedStyleAttrs) => {
|
5
|
+
const fontSizeExp = /^([-0-9.e]+)px/i;
|
6
|
+
// In some environments, computedStyles.fontSize can be increased by the system.
|
7
|
+
// Thus, to prevent text from growing on load/save, prefer .style.fontSize.
|
8
|
+
let fontSizeMatch = fontSizeExp.exec(elem.style?.fontSize ?? '');
|
9
|
+
if (!fontSizeMatch && elem.tagName.toLowerCase() === 'tspan' && elem.parentElement) {
|
10
|
+
// Try to inherit the font size of the parent text element.
|
11
|
+
fontSizeMatch = fontSizeExp.exec(elem.parentElement.style?.fontSize ?? '');
|
12
|
+
}
|
13
|
+
// If we still couldn't find a font size, try to use computedStyles (which can be
|
14
|
+
// wrong).
|
15
|
+
if (!fontSizeMatch && computedStyles) {
|
16
|
+
fontSizeMatch = fontSizeExp.exec(computedStyles.fontSize);
|
17
|
+
}
|
18
|
+
let fontSize = 12;
|
19
|
+
if (fontSizeMatch) {
|
20
|
+
supportedStyleAttrs.add('fontSize');
|
21
|
+
fontSize = parseFloat(fontSizeMatch[1]);
|
22
|
+
}
|
23
|
+
return fontSize;
|
24
|
+
};
|
25
|
+
export default determineFontSize;
|
package/dist/mjs/Viewport.d.ts
CHANGED
@@ -55,7 +55,39 @@ export declare class Viewport {
|
|
55
55
|
*
|
56
56
|
* @see {@link getGridSize} and {@link getScaleFactorToNearestPowerOf}.
|
57
57
|
*/
|
58
|
-
snapToGrid(canvasPos: Point2):
|
58
|
+
snapToGrid(canvasPos: Point2): {
|
59
|
+
readonly x: number;
|
60
|
+
readonly y: number;
|
61
|
+
readonly z: number;
|
62
|
+
readonly xy: {
|
63
|
+
x: number;
|
64
|
+
y: number;
|
65
|
+
};
|
66
|
+
at(idx: number): number;
|
67
|
+
length(): number;
|
68
|
+
magnitude(): number;
|
69
|
+
magnitudeSquared(): number;
|
70
|
+
squareDistanceTo(p: Vec3): number;
|
71
|
+
distanceTo(p: Vec3): number;
|
72
|
+
maximumEntryMagnitude(): number;
|
73
|
+
angle(): number;
|
74
|
+
normalized(): Vec3;
|
75
|
+
normalizedOrZero(): Vec3;
|
76
|
+
times(c: number): Vec3;
|
77
|
+
plus(v: Vec3): Vec3;
|
78
|
+
minus(v: Vec3): Vec3;
|
79
|
+
dot(other: Vec3): number;
|
80
|
+
cross(other: Vec3): Vec3;
|
81
|
+
scale(other: number | Vec3): Vec3;
|
82
|
+
orthog(): Vec3;
|
83
|
+
extend(distance: number, direction: Vec3): Vec3;
|
84
|
+
lerp(target: Vec3, fractionTo: number): Vec3;
|
85
|
+
zip(other: Vec3, zip: (componentInThis: number, componentInOther: number) => number): Vec3;
|
86
|
+
map(fn: (component: number, index: number) => number): Vec3;
|
87
|
+
asArray(): [number, number, number];
|
88
|
+
eq(other: Vec3, fuzz?: number | undefined): boolean;
|
89
|
+
toString(): string;
|
90
|
+
};
|
59
91
|
/** Returns the size of one screen pixel in canvas units. */
|
60
92
|
getSizeOfPixelOnCanvas(): number;
|
61
93
|
/**
|
@@ -83,7 +83,9 @@ class TextComponent extends AbstractComponent {
|
|
83
83
|
}
|
84
84
|
static applyTextStyles(ctx, style) {
|
85
85
|
// Quote the font family if necessary.
|
86
|
-
const
|
86
|
+
const hasSpaces = style.fontFamily.match(/\s/);
|
87
|
+
const isQuoted = style.fontFamily.match(/^".*"$/);
|
88
|
+
const fontFamily = hasSpaces && !isQuoted ? `"${style.fontFamily.replace(/["]/g, '\\"')}"` : style.fontFamily;
|
87
89
|
ctx.font = [
|
88
90
|
style.fontStyle ?? '',
|
89
91
|
style.fontWeight ?? '',
|
@@ -139,24 +139,29 @@ export default class RenderingCacheNode {
|
|
139
139
|
|| items.length === 0) {
|
140
140
|
return;
|
141
141
|
}
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
const
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
142
|
+
// Divide [items] until nodes are smaller than this, or are leaves.
|
143
|
+
const divideUntilSmallerThanThis = (itemsToDivide) => {
|
144
|
+
const newItems = [];
|
145
|
+
for (const item of itemsToDivide) {
|
146
|
+
const bbox = item.getBBox();
|
147
|
+
if (!bbox.intersects(this.region)) {
|
148
|
+
continue;
|
149
|
+
}
|
150
|
+
if (bbox.maxDimension >= this.region.maxDimension) {
|
151
|
+
newItems.push(...item.getChildrenOrSelfIntersectingRegion(this.region));
|
152
|
+
}
|
153
|
+
else {
|
154
|
+
newItems.push(item);
|
155
|
+
}
|
154
156
|
}
|
155
|
-
|
156
|
-
|
157
|
+
return newItems;
|
158
|
+
};
|
159
|
+
items = divideUntilSmallerThanThis(items);
|
157
160
|
// Can we cache at all?
|
158
161
|
if (!this.cacheState.props.isOfCorrectType(screenRenderer)) {
|
159
|
-
|
162
|
+
for (const item of items) {
|
163
|
+
item.render(screenRenderer, viewport.visibleRect);
|
164
|
+
}
|
160
165
|
return;
|
161
166
|
}
|
162
167
|
if (this.cacheState.debugMode) {
|
@@ -0,0 +1,14 @@
|
|
1
|
+
/** Returns the first node or element with `textContent` matching `expectedText`. */
|
2
|
+
const findNodeWithText = (expectedText, parent) => {
|
3
|
+
if (parent.textContent === expectedText) {
|
4
|
+
return parent;
|
5
|
+
}
|
6
|
+
for (const child of parent.childNodes) {
|
7
|
+
const results = findNodeWithText(expectedText, child);
|
8
|
+
if (results) {
|
9
|
+
return results;
|
10
|
+
}
|
11
|
+
}
|
12
|
+
return null;
|
13
|
+
};
|
14
|
+
export default findNodeWithText;
|
@@ -0,0 +1,11 @@
|
|
1
|
+
/** Returns the first ancestor of the given node that is an HTMLElement */
|
2
|
+
const firstElementAncestorOfNode = (node) => {
|
3
|
+
if (node instanceof HTMLElement) {
|
4
|
+
return node;
|
5
|
+
}
|
6
|
+
else if (node?.parentNode) {
|
7
|
+
return firstElementAncestorOfNode(node.parentNode);
|
8
|
+
}
|
9
|
+
return null;
|
10
|
+
};
|
11
|
+
export default firstElementAncestorOfNode;
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import Editor from '../Editor';
|
2
2
|
import { Point2 } from '@js-draw/math';
|
3
|
-
import Pointer from '../Pointer';
|
3
|
+
import Pointer, { PointerDevice } from '../Pointer';
|
4
4
|
import { InputEvtType } from '../inputEvents';
|
5
5
|
/**
|
6
6
|
* Dispatch a pen event to the currently selected tool.
|
@@ -8,5 +8,5 @@ import { InputEvtType } from '../inputEvents';
|
|
8
8
|
*
|
9
9
|
* @see {@link sendTouchEvent}
|
10
10
|
*/
|
11
|
-
declare const sendPenEvent: (editor: Editor, eventType: InputEvtType.PointerDownEvt | InputEvtType.PointerMoveEvt | InputEvtType.PointerUpEvt, point: Point2, allPointers?: Pointer[]) => Pointer;
|
11
|
+
declare const sendPenEvent: (editor: Editor, eventType: InputEvtType.PointerDownEvt | InputEvtType.PointerMoveEvt | InputEvtType.PointerUpEvt, point: Point2, allPointers?: Pointer[], deviceType?: PointerDevice) => Pointer;
|
12
12
|
export default sendPenEvent;
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import Pointer from '../Pointer.mjs';
|
1
|
+
import Pointer, { PointerDevice } from '../Pointer.mjs';
|
2
2
|
import { InputEvtType } from '../inputEvents.mjs';
|
3
3
|
import getUniquePointerId from './getUniquePointerId.mjs';
|
4
4
|
/**
|
@@ -7,9 +7,9 @@ import getUniquePointerId from './getUniquePointerId.mjs';
|
|
7
7
|
*
|
8
8
|
* @see {@link sendTouchEvent}
|
9
9
|
*/
|
10
|
-
const sendPenEvent = (editor, eventType, point, allPointers) => {
|
10
|
+
const sendPenEvent = (editor, eventType, point, allPointers, deviceType = PointerDevice.Pen) => {
|
11
11
|
const id = getUniquePointerId(allPointers ?? []);
|
12
|
-
const mainPointer = Pointer.ofCanvasPoint(point, eventType !== InputEvtType.PointerUpEvt, editor.viewport, id);
|
12
|
+
const mainPointer = Pointer.ofCanvasPoint(point, eventType !== InputEvtType.PointerUpEvt, editor.viewport, id, deviceType);
|
13
13
|
editor.toolController.dispatchInputEvent({
|
14
14
|
kind: eventType,
|
15
15
|
allPointers: allPointers ?? [
|
@@ -17,6 +17,7 @@ export interface ToolbarLocalization extends ToolbarUtilsLocalization {
|
|
17
17
|
dragAndDropHereOrBrowse: string;
|
18
18
|
cancel: string;
|
19
19
|
submit: string;
|
20
|
+
addAll: string;
|
20
21
|
roundedTipPen: string;
|
21
22
|
roundedTipPen2: string;
|
22
23
|
flatTipPen: string;
|
@@ -56,6 +57,7 @@ export interface ToolbarLocalization extends ToolbarUtilsLocalization {
|
|
56
57
|
strokeAutocorrect: string;
|
57
58
|
errorImageHasZeroSize: string;
|
58
59
|
describeTheImage: string;
|
60
|
+
fileInput__loading: string;
|
59
61
|
penDropdown__baseHelpText: string;
|
60
62
|
penDropdown__colorHelpText: string;
|
61
63
|
penDropdown__thicknessHelpText: string;
|
@@ -14,6 +14,7 @@ export const defaultToolbarLocalization = {
|
|
14
14
|
chooseFile: 'Choose file',
|
15
15
|
dragAndDropHereOrBrowse: 'Drag and drop here\nor\n{{browse}}',
|
16
16
|
submit: 'Submit',
|
17
|
+
addAll: 'Add all',
|
17
18
|
cancel: 'Cancel',
|
18
19
|
resetView: 'Reset view',
|
19
20
|
thicknessLabel: 'Thickness',
|
@@ -57,6 +58,7 @@ export const defaultToolbarLocalization = {
|
|
57
58
|
paste: 'Paste',
|
58
59
|
errorImageHasZeroSize: 'Error: Image has zero size',
|
59
60
|
describeTheImage: 'Image description',
|
61
|
+
fileInput__loading: 'Loading...',
|
60
62
|
// Help text
|
61
63
|
penDropdown__baseHelpText: 'This tool draws shapes or freehand lines.',
|
62
64
|
penDropdown__colorHelpText: 'Changes the pen\'s color',
|
@@ -126,6 +126,7 @@ export default abstract class BaseWidget {
|
|
126
126
|
setHidden(hidden: boolean): void;
|
127
127
|
/** Set whether the widget is contained within another. @internal */
|
128
128
|
setIsToplevel(toplevel: boolean): void;
|
129
|
+
/** Returns true if the menu for this widget is open. */
|
129
130
|
protected isDropdownVisible(): boolean;
|
130
131
|
protected isSelected(): boolean;
|
131
132
|
private createDropdownIcon;
|
@@ -0,0 +1,22 @@
|
|
1
|
+
import { RenderableImage } from 'js-draw/src/rendering/renderers/AbstractRenderer';
|
2
|
+
/** Handles filtering and other operations on an image. */
|
3
|
+
export declare class ImageWrapper {
|
4
|
+
private imageBase64Url;
|
5
|
+
private preview;
|
6
|
+
private onUrlUpdate;
|
7
|
+
private readonly originalSrc;
|
8
|
+
private altText;
|
9
|
+
private constructor();
|
10
|
+
private updateImageData;
|
11
|
+
decreaseSize(resizeFactor?: number): void;
|
12
|
+
reset(): void;
|
13
|
+
isChanged(): boolean;
|
14
|
+
getBase64Url(): string;
|
15
|
+
getAltText(): string;
|
16
|
+
setAltText(text: string): void;
|
17
|
+
static fromSrcAndPreview(initialBase64Src: string, preview: HTMLImageElement, onUrlUpdate: () => void): ImageWrapper;
|
18
|
+
static fromRenderable(renderable: RenderableImage, onUrlUpdate: () => void): {
|
19
|
+
wrapper: ImageWrapper;
|
20
|
+
preview: HTMLImageElement;
|
21
|
+
};
|
22
|
+
}
|