js-draw 1.3.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- 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/SVGLoader.js +37 -22
- 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 +3 -2
- 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/editorImageToSVG.d.ts +8 -0
- package/dist/cjs/image/export/editorImageToSVG.js +49 -0
- package/dist/cjs/image/export/setExportedSVGSize.d.ts +6 -0
- package/dist/cjs/image/export/setExportedSVGSize.js +25 -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/SVGRenderer.js +8 -19
- package/dist/cjs/rendering/renderers/SVGRenderer.test.d.ts +1 -0
- 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/SVGLoader.mjs +37 -22
- 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 +3 -2
- 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/editorImageToSVG.d.ts +8 -0
- package/dist/mjs/image/export/editorImageToSVG.mjs +41 -0
- package/dist/mjs/image/export/setExportedSVGSize.d.ts +6 -0
- package/dist/mjs/image/export/setExportedSVGSize.mjs +23 -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/SVGRenderer.mjs +8 -19
- package/dist/mjs/rendering/renderers/SVGRenderer.test.d.ts +1 -0
- 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
@@ -4,6 +4,7 @@ import { ToolbarLocalization } from '../localization';
|
|
4
4
|
import ActionButtonWidget from './ActionButtonWidget';
|
5
5
|
declare class SaveActionWidget extends ActionButtonWidget {
|
6
6
|
constructor(editor: Editor, localization: ToolbarLocalization, saveCallback: () => void);
|
7
|
+
protected shouldAutoDisableInReadOnlyEditor(): boolean;
|
7
8
|
protected onKeyPress(event: KeyPressEvent): boolean;
|
8
9
|
mustBeInToplevelMenu(): boolean;
|
9
10
|
}
|
@@ -6,6 +6,9 @@ class SaveActionWidget extends ActionButtonWidget {
|
|
6
6
|
super(editor, 'save-button', editor.icons.makeSaveIcon, localization.save, saveCallback);
|
7
7
|
this.setTags([ToolbarWidgetTag.Save]);
|
8
8
|
}
|
9
|
+
shouldAutoDisableInReadOnlyEditor() {
|
10
|
+
return false;
|
11
|
+
}
|
9
12
|
onKeyPress(event) {
|
10
13
|
if (this.editor.shortcuts.matchesShortcut(saveKeyboardShortcut, event)) {
|
11
14
|
this.clickAction();
|
@@ -8,6 +8,8 @@ export default abstract class BaseTool implements InputEventListener {
|
|
8
8
|
private notifier;
|
9
9
|
readonly description: string;
|
10
10
|
protected constructor(notifier: EditorNotifier, description: string);
|
11
|
+
/** Override this to allow this tool to be enabled in a read-only editor */
|
12
|
+
canReceiveInputInReadOnlyEditor(): boolean;
|
11
13
|
setInputMapper(mapper: InputMapper | null): void;
|
12
14
|
getInputMapper(): InputMapper | null;
|
13
15
|
private dispatchEventToCallback;
|
@@ -54,4 +56,5 @@ export default abstract class BaseTool implements InputEventListener {
|
|
54
56
|
enabledValue(): ReactiveValue<boolean>;
|
55
57
|
setToolGroup(group: ToolEnabledGroup): void;
|
56
58
|
getToolGroup(): ToolEnabledGroup | null;
|
59
|
+
onDestroy(): void;
|
57
60
|
}
|
@@ -9,7 +9,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
9
9
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
10
10
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
11
11
|
};
|
12
|
-
var _BaseTool_enabled, _BaseTool_group, _BaseTool_inputMapper;
|
12
|
+
var _BaseTool_enabled, _BaseTool_group, _BaseTool_inputMapper, _BaseTool_readOnlyEditorChangeListener;
|
13
13
|
import { EditorEventType } from '../types.mjs';
|
14
14
|
import { InputEvtType } from '../inputEvents.mjs';
|
15
15
|
import { ReactiveValue } from '../util/ReactiveValue.mjs';
|
@@ -20,6 +20,7 @@ class BaseTool {
|
|
20
20
|
_BaseTool_enabled.set(this, void 0);
|
21
21
|
_BaseTool_group.set(this, null);
|
22
22
|
_BaseTool_inputMapper.set(this, null);
|
23
|
+
_BaseTool_readOnlyEditorChangeListener.set(this, null);
|
23
24
|
__classPrivateFieldSet(this, _BaseTool_enabled, ReactiveValue.fromInitialValue(true), "f");
|
24
25
|
__classPrivateFieldGet(this, _BaseTool_enabled, "f").onUpdate(enabled => {
|
25
26
|
// Ensure that at most one tool in the group is enabled.
|
@@ -38,6 +39,10 @@ class BaseTool {
|
|
38
39
|
}
|
39
40
|
});
|
40
41
|
}
|
42
|
+
/** Override this to allow this tool to be enabled in a read-only editor */
|
43
|
+
canReceiveInputInReadOnlyEditor() {
|
44
|
+
return false;
|
45
|
+
}
|
41
46
|
setInputMapper(mapper) {
|
42
47
|
__classPrivateFieldSet(this, _BaseTool_inputMapper, mapper, "f");
|
43
48
|
if (mapper) {
|
@@ -155,6 +160,12 @@ class BaseTool {
|
|
155
160
|
}
|
156
161
|
return null;
|
157
162
|
}
|
163
|
+
// Called when the tool is removed/when the editor is destroyed.
|
164
|
+
// Subclasses that override this method **must call super.onDestroy()**.
|
165
|
+
onDestroy() {
|
166
|
+
__classPrivateFieldGet(this, _BaseTool_readOnlyEditorChangeListener, "f")?.remove();
|
167
|
+
__classPrivateFieldSet(this, _BaseTool_readOnlyEditorChangeListener, null, "f");
|
168
|
+
}
|
158
169
|
}
|
159
|
-
_BaseTool_enabled = new WeakMap(), _BaseTool_group = new WeakMap(), _BaseTool_inputMapper = new WeakMap();
|
170
|
+
_BaseTool_enabled = new WeakMap(), _BaseTool_group = new WeakMap(), _BaseTool_inputMapper = new WeakMap(), _BaseTool_readOnlyEditorChangeListener = new WeakMap();
|
160
171
|
export default BaseTool;
|
@@ -16,6 +16,9 @@ export default class FindTool extends BaseTool {
|
|
16
16
|
this.overlay.style.display = 'none';
|
17
17
|
this.overlay.classList.add(`${cssPrefix}-overlay`);
|
18
18
|
}
|
19
|
+
canReceiveInputInReadOnlyEditor() {
|
20
|
+
return true;
|
21
|
+
}
|
19
22
|
getMatches(searchFor) {
|
20
23
|
searchFor = searchFor.toLocaleLowerCase();
|
21
24
|
const allTextComponents = this.editor.image.getAllElements()
|
@@ -108,7 +111,7 @@ export default class FindTool extends BaseTool {
|
|
108
111
|
}
|
109
112
|
setEnabled(enabled) {
|
110
113
|
super.setEnabled(enabled);
|
111
|
-
if (
|
114
|
+
if (this.isEnabled()) {
|
112
115
|
this.setVisible(false);
|
113
116
|
}
|
114
117
|
}
|
@@ -32,6 +32,7 @@ export default class PanZoom extends BaseTool {
|
|
32
32
|
private inertialScroller;
|
33
33
|
private velocity;
|
34
34
|
constructor(editor: Editor, mode: PanZoomMode, description: string);
|
35
|
+
canReceiveInputInReadOnlyEditor(): boolean;
|
35
36
|
computePinchData(p1: Pointer, p2: Pointer): PinchData;
|
36
37
|
private allPointersAreOfType;
|
37
38
|
onPointerDown({ allPointers: pointers, current: currentPointer }: PointerEvt): boolean;
|
@@ -74,6 +74,10 @@ export default class PanZoom extends BaseTool {
|
|
74
74
|
this.inertialScroller = null;
|
75
75
|
this.velocity = null;
|
76
76
|
}
|
77
|
+
// The pan/zoom tool can be used in a read-only editor.
|
78
|
+
canReceiveInputInReadOnlyEditor() {
|
79
|
+
return true;
|
80
|
+
}
|
77
81
|
// Returns information about the pointers in a gesture
|
78
82
|
computePinchData(p1, p2) {
|
79
83
|
// Swap the pointers to ensure consistent ordering.
|
package/dist/mjs/tools/Pen.d.ts
CHANGED
package/dist/mjs/tools/Pen.mjs
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
import { Color4 } from '@js-draw/math';
|
2
|
-
import EditorImage from '../EditorImage.mjs';
|
2
|
+
import EditorImage from '../image/EditorImage.mjs';
|
3
3
|
import { PointerDevice } from '../Pointer.mjs';
|
4
4
|
import { makeFreehandLineBuilder } from '../components/builders/FreehandLineBuilder.mjs';
|
5
5
|
import { EditorEventType } from '../types.mjs';
|
@@ -200,9 +200,6 @@ export default class Pen extends BaseTool {
|
|
200
200
|
getColor() { return this.style.color; }
|
201
201
|
getStrokeFactory() { return this.style.factory; }
|
202
202
|
getStyleValue() { return this.styleValue; }
|
203
|
-
setEnabled(enabled) {
|
204
|
-
super.setEnabled(enabled);
|
205
|
-
}
|
206
203
|
onKeyPress(event) {
|
207
204
|
const shortcuts = this.editor.shortcuts;
|
208
205
|
// Ctrl+Z: End the stroke so that it can be undone/redone.
|
@@ -16,6 +16,7 @@ export default class PipetteTool extends BaseTool {
|
|
16
16
|
private colorPreviewListener;
|
17
17
|
private colorSelectListener;
|
18
18
|
constructor(editor: Editor, description: string);
|
19
|
+
canReceiveInputInReadOnlyEditor(): boolean;
|
19
20
|
private updateSelectingStatus;
|
20
21
|
setColorListener(colorPreviewListener: ColorListener, colorSelectListener: ColorListener): void;
|
21
22
|
clearColorListener(): void;
|
@@ -18,6 +18,9 @@ export default class PipetteTool extends BaseTool {
|
|
18
18
|
this.updateSelectingStatus();
|
19
19
|
});
|
20
20
|
}
|
21
|
+
canReceiveInputInReadOnlyEditor() {
|
22
|
+
return true;
|
23
|
+
}
|
21
24
|
// Ensures that the root editor element correctly reflects whether color selection
|
22
25
|
// is in progress.
|
23
26
|
updateSelectingStatus() {
|
@@ -7,6 +7,9 @@ export default class SelectAllShortcutHandler extends BaseTool {
|
|
7
7
|
super(editor.notifier, editor.localization.selectAllTool);
|
8
8
|
this.editor = editor;
|
9
9
|
}
|
10
|
+
canReceiveInputInReadOnlyEditor() {
|
11
|
+
return true;
|
12
|
+
}
|
10
13
|
// @internal
|
11
14
|
onKeyPress(event) {
|
12
15
|
if (this.editor.shortcuts.matchesShortcut(selectAllKeyboardShortcut, event)) {
|
@@ -11,6 +11,7 @@ export default class Selection {
|
|
11
11
|
private editor;
|
12
12
|
private handles;
|
13
13
|
private originalRegion;
|
14
|
+
private selectionTightBoundingBox;
|
14
15
|
private transformers;
|
15
16
|
private transform;
|
16
17
|
private selectedElems;
|
@@ -39,6 +40,7 @@ export default class Selection {
|
|
39
40
|
private previewTransformCmds;
|
40
41
|
resolveToObjects(): boolean;
|
41
42
|
recomputeRegion(): boolean;
|
43
|
+
padRegion(): void;
|
42
44
|
getMinCanvasSize(): number;
|
43
45
|
getSelectedItemCount(): number;
|
44
46
|
updateUI(): void;
|
@@ -5,20 +5,23 @@
|
|
5
5
|
var _a;
|
6
6
|
import SerializableCommand from '../../commands/SerializableCommand.mjs';
|
7
7
|
import { Mat33, Rect2, Vec2 } from '@js-draw/math';
|
8
|
-
import SelectionHandle, {
|
8
|
+
import SelectionHandle, { HandleAction, handleSize } from './SelectionHandle.mjs';
|
9
9
|
import { cssPrefix } from './SelectionTool.mjs';
|
10
10
|
import Viewport from '../../Viewport.mjs';
|
11
11
|
import Erase from '../../commands/Erase.mjs';
|
12
12
|
import Duplicate from '../../commands/Duplicate.mjs';
|
13
13
|
import { DragTransformer, ResizeTransformer, RotateTransformer } from './TransformMode.mjs';
|
14
14
|
import { ResizeMode } from './types.mjs';
|
15
|
-
import EditorImage from '../../EditorImage.mjs';
|
15
|
+
import EditorImage from '../../image/EditorImage.mjs';
|
16
16
|
const updateChunkSize = 100;
|
17
17
|
const maxPreviewElemCount = 500;
|
18
18
|
// @internal
|
19
19
|
class Selection {
|
20
20
|
constructor(startPoint, editor) {
|
21
21
|
this.editor = editor;
|
22
|
+
// The last-computed bounding box of selected content
|
23
|
+
// @see getTightBoundingBox
|
24
|
+
this.selectionTightBoundingBox = null;
|
22
25
|
this.transform = Mat33.identity;
|
23
26
|
this.selectedElems = [];
|
24
27
|
this.hasParent = true;
|
@@ -37,10 +40,23 @@ class Selection {
|
|
37
40
|
this.backgroundElem = document.createElement('div');
|
38
41
|
this.backgroundElem.classList.add(`${cssPrefix}selection-background`);
|
39
42
|
this.container.appendChild(this.backgroundElem);
|
40
|
-
const resizeHorizontalHandle = new SelectionHandle(
|
41
|
-
|
42
|
-
|
43
|
-
|
43
|
+
const resizeHorizontalHandle = new SelectionHandle({
|
44
|
+
action: HandleAction.ResizeX,
|
45
|
+
side: Vec2.of(1, 0.5),
|
46
|
+
}, this, this.editor.viewport, (startPoint) => this.transformers.resize.onDragStart(startPoint, ResizeMode.HorizontalOnly), (currentPoint) => this.transformers.resize.onDragUpdate(currentPoint), () => this.transformers.resize.onDragEnd());
|
47
|
+
const resizeVerticalHandle = new SelectionHandle({
|
48
|
+
action: HandleAction.ResizeY,
|
49
|
+
side: Vec2.of(0.5, 1),
|
50
|
+
}, this, this.editor.viewport, (startPoint) => this.transformers.resize.onDragStart(startPoint, ResizeMode.VerticalOnly), (currentPoint) => this.transformers.resize.onDragUpdate(currentPoint), () => this.transformers.resize.onDragEnd());
|
51
|
+
const resizeBothHandle = new SelectionHandle({
|
52
|
+
action: HandleAction.ResizeXY,
|
53
|
+
side: Vec2.of(1, 1),
|
54
|
+
}, this, this.editor.viewport, (startPoint) => this.transformers.resize.onDragStart(startPoint, ResizeMode.Both), (currentPoint) => this.transformers.resize.onDragUpdate(currentPoint), () => this.transformers.resize.onDragEnd());
|
55
|
+
const rotationHandle = new SelectionHandle({
|
56
|
+
action: HandleAction.Rotate,
|
57
|
+
side: Vec2.of(0.5, 0),
|
58
|
+
icon: this.editor.icons.makeRotateIcon(),
|
59
|
+
}, this, this.editor.viewport, (startPoint) => this.transformers.rotate.onDragStart(startPoint), (currentPoint) => this.transformers.rotate.onDragUpdate(currentPoint), () => this.transformers.rotate.onDragEnd());
|
44
60
|
this.handles = [
|
45
61
|
resizeBothHandle,
|
46
62
|
resizeHorizontalHandle,
|
@@ -167,18 +183,26 @@ class Selection {
|
|
167
183
|
// Returns false if the selection is empty.
|
168
184
|
recomputeRegion() {
|
169
185
|
const newRegion = this.computeTightBoundingBox();
|
186
|
+
this.selectionTightBoundingBox = newRegion;
|
170
187
|
if (!newRegion) {
|
171
188
|
this.cancelSelection();
|
172
189
|
return false;
|
173
190
|
}
|
174
191
|
this.originalRegion = newRegion;
|
192
|
+
this.padRegion();
|
193
|
+
return true;
|
194
|
+
}
|
195
|
+
// Applies padding to the current region if it is too small.
|
196
|
+
// @internal
|
197
|
+
padRegion() {
|
198
|
+
const sourceRegion = this.selectionTightBoundingBox ?? this.originalRegion;
|
175
199
|
const minSize = this.getMinCanvasSize();
|
176
|
-
if (
|
200
|
+
if (sourceRegion.w < minSize || sourceRegion.h < minSize) {
|
177
201
|
// Add padding
|
178
202
|
const padding = minSize / 2;
|
179
|
-
this.originalRegion = Rect2.bboxOf(
|
203
|
+
this.originalRegion = Rect2.bboxOf(sourceRegion.corners, padding);
|
204
|
+
this.updateUI();
|
180
205
|
}
|
181
|
-
return true;
|
182
206
|
}
|
183
207
|
getMinCanvasSize() {
|
184
208
|
const canvasHandleSize = handleSize / this.editor.viewport.getScaleFactor();
|
@@ -202,6 +226,14 @@ class Selection {
|
|
202
226
|
const rotationDeg = this.screenRegionRotation * 180 / Math.PI;
|
203
227
|
this.backgroundElem.style.transform = `rotate(${rotationDeg}deg)`;
|
204
228
|
this.backgroundElem.style.transformOrigin = 'center';
|
229
|
+
// If closer to perpendicular, apply different CSS
|
230
|
+
const perpendicularClassName = `${cssPrefix}rotated-near-perpendicular`;
|
231
|
+
if (Math.abs(Math.sin(this.screenRegionRotation)) > 0.5) {
|
232
|
+
this.container.classList.add(perpendicularClassName);
|
233
|
+
}
|
234
|
+
else {
|
235
|
+
this.container.classList.remove(perpendicularClassName);
|
236
|
+
}
|
205
237
|
for (const handle of this.handles) {
|
206
238
|
handle.updatePosition();
|
207
239
|
}
|
@@ -373,6 +405,7 @@ class Selection {
|
|
373
405
|
}
|
374
406
|
setToPoint(point) {
|
375
407
|
this.originalRegion = this.originalRegion.grownToPoint(point);
|
408
|
+
this.selectionTightBoundingBox = null;
|
376
409
|
this.updateUI();
|
377
410
|
}
|
378
411
|
cancelSelection() {
|
@@ -380,12 +413,15 @@ class Selection {
|
|
380
413
|
this.container.remove();
|
381
414
|
}
|
382
415
|
this.originalRegion = Rect2.empty;
|
416
|
+
this.selectionTightBoundingBox = null;
|
383
417
|
this.hasParent = false;
|
384
418
|
}
|
385
419
|
setSelectedObjects(objects, bbox) {
|
386
420
|
this.addRemoveSelectionFromImage(true);
|
387
421
|
this.originalRegion = bbox;
|
422
|
+
this.selectionTightBoundingBox = bbox;
|
388
423
|
this.selectedElems = objects.filter(object => object.isSelectable());
|
424
|
+
this.padRegion();
|
389
425
|
this.updateUI();
|
390
426
|
}
|
391
427
|
getSelectedObjects() {
|
@@ -2,17 +2,23 @@ import { Point2, Vec2 } from '@js-draw/math';
|
|
2
2
|
import Selection from './Selection';
|
3
3
|
import Pointer from '../../Pointer';
|
4
4
|
import Viewport from '../../Viewport';
|
5
|
-
export declare enum
|
6
|
-
|
7
|
-
|
5
|
+
export declare enum HandleAction {
|
6
|
+
ResizeXY = "resize-xy",
|
7
|
+
Rotate = "rotate",
|
8
|
+
ResizeX = "resize-x",
|
9
|
+
ResizeY = "resize-y"
|
10
|
+
}
|
11
|
+
export interface HandlePresentation {
|
12
|
+
side: Vec2;
|
13
|
+
icon?: Element;
|
14
|
+
action: HandleAction;
|
8
15
|
}
|
9
16
|
export declare const handleSize = 30;
|
10
17
|
export type DragStartCallback = (startPoint: Point2) => void;
|
11
18
|
export type DragUpdateCallback = (canvasPoint: Point2) => void;
|
12
19
|
export type DragEndCallback = () => void;
|
13
20
|
export default class SelectionHandle {
|
14
|
-
readonly
|
15
|
-
private readonly parentSide;
|
21
|
+
readonly presentation: HandlePresentation;
|
16
22
|
private readonly parent;
|
17
23
|
private readonly viewport;
|
18
24
|
private readonly onDragStart;
|
@@ -20,7 +26,9 @@ export default class SelectionHandle {
|
|
20
26
|
private readonly onDragEnd;
|
21
27
|
private element;
|
22
28
|
private snapToGrid;
|
23
|
-
|
29
|
+
private shape;
|
30
|
+
private parentSide;
|
31
|
+
constructor(presentation: HandlePresentation, parent: Selection, viewport: Viewport, onDragStart: DragStartCallback, onDragUpdate: DragUpdateCallback, onDragEnd: DragEndCallback);
|
24
32
|
/**
|
25
33
|
* Adds this to `container`, where `conatiner` should be the background/selection
|
26
34
|
* element visible on the screen.
|
@@ -1,16 +1,22 @@
|
|
1
1
|
import { assertUnreachable } from '../../util/assertions.mjs';
|
2
2
|
import { Rect2, Vec2 } from '@js-draw/math';
|
3
3
|
import { cssPrefix } from './SelectionTool.mjs';
|
4
|
-
|
4
|
+
var HandleShape;
|
5
5
|
(function (HandleShape) {
|
6
6
|
HandleShape[HandleShape["Circle"] = 0] = "Circle";
|
7
7
|
HandleShape[HandleShape["Square"] = 1] = "Square";
|
8
8
|
})(HandleShape || (HandleShape = {}));
|
9
|
+
export var HandleAction;
|
10
|
+
(function (HandleAction) {
|
11
|
+
HandleAction["ResizeXY"] = "resize-xy";
|
12
|
+
HandleAction["Rotate"] = "rotate";
|
13
|
+
HandleAction["ResizeX"] = "resize-x";
|
14
|
+
HandleAction["ResizeY"] = "resize-y";
|
15
|
+
})(HandleAction || (HandleAction = {}));
|
9
16
|
export const handleSize = 30;
|
10
17
|
export default class SelectionHandle {
|
11
|
-
constructor(
|
12
|
-
this.
|
13
|
-
this.parentSide = parentSide;
|
18
|
+
constructor(presentation, parent, viewport, onDragStart, onDragUpdate, onDragEnd) {
|
19
|
+
this.presentation = presentation;
|
14
20
|
this.parent = parent;
|
15
21
|
this.viewport = viewport;
|
16
22
|
this.onDragStart = onDragStart;
|
@@ -18,8 +24,20 @@ export default class SelectionHandle {
|
|
18
24
|
this.onDragEnd = onDragEnd;
|
19
25
|
this.dragLastPos = null;
|
20
26
|
this.element = document.createElement('div');
|
21
|
-
this.element.classList.add(`${cssPrefix}handle`);
|
22
|
-
|
27
|
+
this.element.classList.add(`${cssPrefix}handle`, `${cssPrefix}${presentation.action}`);
|
28
|
+
this.parentSide = presentation.side;
|
29
|
+
const icon = presentation.icon;
|
30
|
+
if (icon) {
|
31
|
+
this.element.appendChild(icon);
|
32
|
+
icon.classList.add('icon');
|
33
|
+
}
|
34
|
+
if (presentation.action === HandleAction.Rotate) {
|
35
|
+
this.shape = HandleShape.Circle;
|
36
|
+
}
|
37
|
+
else {
|
38
|
+
this.shape = HandleShape.Square;
|
39
|
+
}
|
40
|
+
switch (this.shape) {
|
23
41
|
case HandleShape.Circle:
|
24
42
|
this.element.classList.add(`${cssPrefix}circle`);
|
25
43
|
break;
|
@@ -27,7 +45,7 @@ export default class SelectionHandle {
|
|
27
45
|
this.element.classList.add(`${cssPrefix}square`);
|
28
46
|
break;
|
29
47
|
default:
|
30
|
-
assertUnreachable(shape);
|
48
|
+
assertUnreachable(this.shape);
|
31
49
|
}
|
32
50
|
this.updatePosition();
|
33
51
|
}
|
@@ -27,6 +27,11 @@ class SelectionTool extends BaseTool {
|
|
27
27
|
// The selection box could be using the wet ink display if its transformation
|
28
28
|
// hasn't been finalized yet. Clear before updating the UI.
|
29
29
|
this.editor.clearWetInk();
|
30
|
+
// If not currently selecting, ensure that the selection box
|
31
|
+
// is large enough.
|
32
|
+
if (!this.expandingSelectionBox) {
|
33
|
+
this.selectionBox?.padRegion();
|
34
|
+
}
|
30
35
|
this.selectionBox?.updateUI();
|
31
36
|
});
|
32
37
|
this.editor.handleKeyEventsFrom(this.handleOverlay);
|
@@ -14,6 +14,7 @@ export default class SoundUITool extends BaseTool {
|
|
14
14
|
private toggleButton;
|
15
15
|
private toggleButtonContainer;
|
16
16
|
constructor(editor: Editor, description: string);
|
17
|
+
canReceiveInputInReadOnlyEditor(): boolean;
|
17
18
|
private updateToggleButtonText;
|
18
19
|
setEnabled(enabled: boolean): void;
|
19
20
|
onKeyPress(event: KeyPressEvent): boolean;
|
@@ -100,6 +100,9 @@ export default class SoundUITool extends BaseTool {
|
|
100
100
|
this.updateToggleButtonText();
|
101
101
|
editor.createHTMLOverlay(this.toggleButtonContainer);
|
102
102
|
}
|
103
|
+
canReceiveInputInReadOnlyEditor() {
|
104
|
+
return true;
|
105
|
+
}
|
103
106
|
updateToggleButtonText() {
|
104
107
|
const containerEnabledClass = 'sound-ui-tool-enabled';
|
105
108
|
if (this.isEnabled()) {
|
@@ -113,7 +116,7 @@ export default class SoundUITool extends BaseTool {
|
|
113
116
|
}
|
114
117
|
setEnabled(enabled) {
|
115
118
|
super.setEnabled(enabled);
|
116
|
-
if (!
|
119
|
+
if (!this.isEnabled()) {
|
117
120
|
this.soundFeedback?.close();
|
118
121
|
this.soundFeedback = null;
|
119
122
|
}
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import TextComponent from '../components/TextComponent.mjs';
|
2
|
-
import EditorImage from '../EditorImage.mjs';
|
2
|
+
import EditorImage from '../image/EditorImage.mjs';
|
3
3
|
import { Rect2, Mat33, Vec2, Color4 } from '@js-draw/math';
|
4
4
|
import { PointerDevice } from '../Pointer.mjs';
|
5
5
|
import { EditorEventType } from '../types.mjs';
|
@@ -188,7 +188,7 @@ export default class TextTool extends BaseTool {
|
|
188
188
|
}
|
189
189
|
setEnabled(enabled) {
|
190
190
|
super.setEnabled(enabled);
|
191
|
-
if (!
|
191
|
+
if (!this.isEnabled()) {
|
192
192
|
this.flushInput();
|
193
193
|
}
|
194
194
|
this.textEditOverlay.style.display = enabled ? 'block' : 'none';
|
@@ -9,6 +9,7 @@ export default class ToolController implements InputEventListener {
|
|
9
9
|
private activeTool;
|
10
10
|
private primaryToolGroup;
|
11
11
|
private inputPipeline;
|
12
|
+
private isEditorReadOnly;
|
12
13
|
/** @internal */
|
13
14
|
constructor(editor: Editor, localization: ToolLocalization);
|
14
15
|
setTools(tools: BaseTool[], primaryToolGroup?: ToolEnabledGroup): void;
|
@@ -29,4 +30,5 @@ export default class ToolController implements InputEventListener {
|
|
29
30
|
*/
|
30
31
|
addInputMapper(mapper: InputMapper): void;
|
31
32
|
getMatchingTools<Type extends BaseTool>(type: new (...args: any[]) => Type): Type[];
|
33
|
+
onEditorDestroyed(): void;
|
32
34
|
}
|
@@ -23,6 +23,7 @@ export default class ToolController {
|
|
23
23
|
/** @internal */
|
24
24
|
constructor(editor, localization) {
|
25
25
|
this.activeTool = null;
|
26
|
+
this.isEditorReadOnly = editor.isReadOnlyReactiveValue();
|
26
27
|
this.inputPipeline = new InputPipeline();
|
27
28
|
this.inputPipeline.setEmitListener(event => this.onEventInternal(event));
|
28
29
|
const primaryToolGroup = new ToolEnabledGroup();
|
@@ -107,6 +108,10 @@ export default class ToolController {
|
|
107
108
|
}
|
108
109
|
// @internal use `dispatchEvent` rather than calling `onEvent` directly.
|
109
110
|
onEventInternal(event) {
|
111
|
+
const isEditorReadOnly = this.isEditorReadOnly.get();
|
112
|
+
const canToolReceiveInput = (tool) => {
|
113
|
+
return tool.isEnabled() && (!isEditorReadOnly || tool.canReceiveInputInReadOnlyEditor());
|
114
|
+
};
|
110
115
|
let handled = false;
|
111
116
|
if (event.kind === InputEvtType.PointerDownEvt) {
|
112
117
|
let canOnlySendToActiveTool = false;
|
@@ -117,7 +122,7 @@ export default class ToolController {
|
|
117
122
|
if (canOnlySendToActiveTool && tool !== this.activeTool) {
|
118
123
|
continue;
|
119
124
|
}
|
120
|
-
if (tool
|
125
|
+
if (canToolReceiveInput(tool) && tool.onEvent(event)) {
|
121
126
|
if (this.activeTool !== tool) {
|
122
127
|
this.activeTool?.onEvent({ kind: InputEvtType.GestureCancelEvt });
|
123
128
|
}
|
@@ -151,7 +156,7 @@ export default class ToolController {
|
|
151
156
|
}
|
152
157
|
else {
|
153
158
|
for (const tool of this.tools) {
|
154
|
-
if (!tool
|
159
|
+
if (!canToolReceiveInput(tool)) {
|
155
160
|
continue;
|
156
161
|
}
|
157
162
|
handled = tool.onEvent(event);
|
@@ -185,4 +190,10 @@ export default class ToolController {
|
|
185
190
|
getMatchingTools(type) {
|
186
191
|
return this.tools.filter(tool => tool instanceof type);
|
187
192
|
}
|
193
|
+
// @internal
|
194
|
+
onEditorDestroyed() {
|
195
|
+
for (const tool of this.tools) {
|
196
|
+
tool.onDestroy();
|
197
|
+
}
|
198
|
+
}
|
188
199
|
}
|
@@ -12,6 +12,9 @@ export default class ToolSwitcherShortcut extends BaseTool {
|
|
12
12
|
super(editor.notifier, editor.localization.changeTool);
|
13
13
|
this.editor = editor;
|
14
14
|
}
|
15
|
+
canReceiveInputInReadOnlyEditor() {
|
16
|
+
return true;
|
17
|
+
}
|
15
18
|
// @internal
|
16
19
|
onKeyPress({ key }) {
|
17
20
|
const toolController = this.editor.toolController;
|
package/dist/mjs/types.d.ts
CHANGED
@@ -16,12 +16,13 @@ export declare enum EditorEventType {
|
|
16
16
|
ViewportChanged = 7,
|
17
17
|
DisplayResized = 8,
|
18
18
|
SelectionUpdated = 9,
|
19
|
+
ReadOnlyModeToggled = 10,
|
19
20
|
/** @internal */
|
20
|
-
ColorPickerToggled =
|
21
|
+
ColorPickerToggled = 11,
|
21
22
|
/** @internal */
|
22
|
-
ColorPickerColorSelected =
|
23
|
+
ColorPickerColorSelected = 12,
|
23
24
|
/** @deprecated @internal */
|
24
|
-
ToolbarDropdownShown =
|
25
|
+
ToolbarDropdownShown = 13
|
25
26
|
}
|
26
27
|
export declare enum UndoEventType {
|
27
28
|
CommandDone = 0,
|
@@ -66,6 +67,10 @@ export interface SelectionUpdated {
|
|
66
67
|
readonly selectedComponents: AbstractComponent[];
|
67
68
|
readonly tool: BaseTool;
|
68
69
|
}
|
70
|
+
export interface ReadOnlyToggled {
|
71
|
+
readonly kind: EditorEventType.ReadOnlyModeToggled;
|
72
|
+
readonly editorIsReadOnly: boolean;
|
73
|
+
}
|
69
74
|
export interface ColorPickerToggled {
|
70
75
|
readonly kind: EditorEventType.ColorPickerToggled;
|
71
76
|
readonly open: boolean;
|
@@ -79,7 +84,7 @@ export interface ToolbarDropdownShownEvent {
|
|
79
84
|
readonly fromToplevelDropdown: boolean;
|
80
85
|
readonly layoutManager: WidgetContentLayoutManager;
|
81
86
|
}
|
82
|
-
export type EditorEventDataType = EditorToolEvent | EditorObjectEvent | EditorViewportChangedEvent | DisplayResizedEvent | EditorUndoStackUpdated | CommandDoneEvent | CommandUndoneEvent | SelectionUpdated | ColorPickerToggled | ColorPickerColorSelected | ToolbarDropdownShownEvent;
|
87
|
+
export type EditorEventDataType = EditorToolEvent | EditorObjectEvent | EditorViewportChangedEvent | DisplayResizedEvent | EditorUndoStackUpdated | CommandDoneEvent | CommandUndoneEvent | SelectionUpdated | ReadOnlyToggled | ColorPickerToggled | ColorPickerColorSelected | ToolbarDropdownShownEvent;
|
83
88
|
export type OnProgressListener = (amountProcessed: number, totalToProcess: number) => Promise<void> | null | void;
|
84
89
|
export type ComponentAddedListener = (component: AbstractComponent) => Promise<void> | void;
|
85
90
|
export type OnDetermineExportRectListener = (exportRect: Rect2, options?: {
|
package/dist/mjs/types.mjs
CHANGED
@@ -11,12 +11,13 @@ export var EditorEventType;
|
|
11
11
|
EditorEventType[EditorEventType["ViewportChanged"] = 7] = "ViewportChanged";
|
12
12
|
EditorEventType[EditorEventType["DisplayResized"] = 8] = "DisplayResized";
|
13
13
|
EditorEventType[EditorEventType["SelectionUpdated"] = 9] = "SelectionUpdated";
|
14
|
+
EditorEventType[EditorEventType["ReadOnlyModeToggled"] = 10] = "ReadOnlyModeToggled";
|
14
15
|
/** @internal */
|
15
|
-
EditorEventType[EditorEventType["ColorPickerToggled"] =
|
16
|
+
EditorEventType[EditorEventType["ColorPickerToggled"] = 11] = "ColorPickerToggled";
|
16
17
|
/** @internal */
|
17
|
-
EditorEventType[EditorEventType["ColorPickerColorSelected"] =
|
18
|
+
EditorEventType[EditorEventType["ColorPickerColorSelected"] = 12] = "ColorPickerColorSelected";
|
18
19
|
/** @deprecated @internal */
|
19
|
-
EditorEventType[EditorEventType["ToolbarDropdownShown"] =
|
20
|
+
EditorEventType[EditorEventType["ToolbarDropdownShown"] = 13] = "ToolbarDropdownShown";
|
20
21
|
})(EditorEventType || (EditorEventType = {}));
|
21
22
|
// Types of `EditorUndoStackUpdated` events.
|
22
23
|
export var UndoEventType;
|
@@ -55,7 +55,7 @@ export declare abstract class ReactiveValue<T> {
|
|
55
55
|
}
|
56
56
|
export declare abstract class MutableReactiveValue<T> extends ReactiveValue<T> {
|
57
57
|
/**
|
58
|
-
* Changes the value of this and fires all update listeners.
|
58
|
+
* Changes the value of this and, if different, fires all update listeners.
|
59
59
|
*
|
60
60
|
* @see {@link onUpdate}
|
61
61
|
*/
|