js-draw 1.27.1 → 1.28.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/build-config.json +2 -1
- package/dist/Editor.css +1 -1
- package/dist/bundle.js +28 -28
- package/dist/bundledStyles.js +1 -1
- package/dist/cjs/Editor.d.ts +7 -2
- package/dist/cjs/Editor.js +11 -5
- package/dist/cjs/SVGLoader/SVGLoader.d.ts +21 -0
- package/dist/cjs/SVGLoader/SVGLoader.js +74 -47
- package/dist/cjs/SVGLoader/SVGLoader.plugins.test.d.ts +1 -0
- package/dist/cjs/Viewport.js +2 -32
- package/dist/cjs/commands/Duplicate.d.ts +7 -4
- package/dist/cjs/commands/Duplicate.js +48 -7
- package/dist/cjs/commands/Duplicate.test.d.ts +1 -0
- package/dist/cjs/commands/Erase.d.ts +1 -1
- package/dist/cjs/commands/Erase.js +2 -2
- package/dist/cjs/commands/localization.d.ts +2 -2
- package/dist/cjs/commands/localization.js +2 -2
- package/dist/cjs/components/AbstractComponent.d.ts +7 -0
- package/dist/cjs/components/AbstractComponent.js +16 -2
- package/dist/cjs/components/Stroke.d.ts +21 -1
- package/dist/cjs/components/Stroke.js +29 -0
- package/dist/cjs/components/TextComponent.d.ts +2 -2
- package/dist/cjs/components/TextComponent.js +2 -2
- package/dist/cjs/components/builders/PolylineBuilder.js +1 -1
- package/dist/cjs/image/EditorImage.d.ts +17 -9
- package/dist/cjs/image/EditorImage.js +33 -17
- package/dist/cjs/lib.d.ts +1 -1
- package/dist/cjs/localizations/de.js +2 -2
- package/dist/cjs/rendering/RenderingStyle.d.ts +7 -6
- package/dist/cjs/rendering/lib.d.ts +1 -1
- package/dist/cjs/rendering/renderers/AbstractRenderer.js +4 -0
- package/dist/cjs/rendering/renderers/CanvasRenderer.d.ts +9 -0
- package/dist/cjs/rendering/renderers/CanvasRenderer.js +14 -0
- package/dist/cjs/rendering/renderers/SVGRenderer.d.ts +18 -0
- package/dist/cjs/rendering/renderers/SVGRenderer.js +21 -1
- package/dist/cjs/toolbar/AbstractToolbar.d.ts +2 -2
- package/dist/cjs/toolbar/AbstractToolbar.js +2 -3
- package/dist/cjs/toolbar/DropdownToolbar.d.ts +1 -1
- package/dist/cjs/toolbar/DropdownToolbar.js +2 -3
- package/dist/cjs/toolbar/DropdownToolbar.test.d.ts +1 -0
- package/dist/cjs/toolbar/utils/HelpDisplay.js +6 -4
- package/dist/cjs/toolbar/utils/localization.d.ts +1 -0
- package/dist/cjs/toolbar/utils/localization.js +1 -0
- package/dist/cjs/toolbar/widgets/DocumentPropertiesWidget.js +1 -1
- package/dist/cjs/toolbar/widgets/InsertImageWidget/InsertImageWidget.js +1 -1
- package/dist/cjs/toolbar/widgets/components/makeGridSelector.js +1 -1
- package/dist/cjs/tools/Eraser.js +3 -3
- package/dist/cjs/tools/FindTool.js +1 -1
- package/dist/cjs/tools/PasteHandler.js +4 -1
- package/dist/cjs/tools/Pen.js +1 -1
- package/dist/cjs/tools/SelectionTool/SelectAllShortcutHandler.js +1 -1
- package/dist/cjs/tools/SelectionTool/Selection.js +23 -10
- package/dist/cjs/tools/SelectionTool/SelectionBuilders/LassoSelectionBuilder.js +1 -1
- package/dist/cjs/tools/SelectionTool/SelectionBuilders/RectSelectionBuilder.js +1 -1
- package/dist/cjs/tools/SelectionTool/SelectionBuilders/SelectionBuilder.js +1 -1
- package/dist/cjs/tools/SelectionTool/SelectionTool.js +3 -2
- package/dist/cjs/tools/SoundUITool.js +1 -1
- package/dist/cjs/tools/TextTool.js +2 -2
- package/dist/cjs/util/assertions.d.ts +6 -0
- package/dist/cjs/util/assertions.js +18 -0
- package/dist/cjs/util/describeTransformation.d.ts +12 -0
- package/dist/cjs/util/describeTransformation.js +44 -0
- package/dist/cjs/version.js +2 -1
- package/dist/mjs/Editor.d.ts +7 -2
- package/dist/mjs/Editor.mjs +11 -5
- package/dist/mjs/SVGLoader/SVGLoader.d.ts +21 -0
- package/dist/mjs/SVGLoader/SVGLoader.mjs +74 -47
- package/dist/mjs/SVGLoader/SVGLoader.plugins.test.d.ts +1 -0
- package/dist/mjs/Viewport.mjs +2 -32
- package/dist/mjs/commands/Duplicate.d.ts +7 -4
- package/dist/mjs/commands/Duplicate.mjs +48 -7
- package/dist/mjs/commands/Duplicate.test.d.ts +1 -0
- package/dist/mjs/commands/Erase.d.ts +1 -1
- package/dist/mjs/commands/Erase.mjs +2 -2
- package/dist/mjs/commands/localization.d.ts +2 -2
- package/dist/mjs/commands/localization.mjs +2 -2
- package/dist/mjs/components/AbstractComponent.d.ts +7 -0
- package/dist/mjs/components/AbstractComponent.mjs +17 -3
- package/dist/mjs/components/Stroke.d.ts +21 -1
- package/dist/mjs/components/Stroke.mjs +31 -2
- package/dist/mjs/components/TextComponent.d.ts +2 -2
- package/dist/mjs/components/TextComponent.mjs +2 -2
- package/dist/mjs/components/builders/PolylineBuilder.mjs +1 -1
- package/dist/mjs/image/EditorImage.d.ts +17 -9
- package/dist/mjs/image/EditorImage.mjs +33 -17
- package/dist/mjs/lib.d.ts +1 -1
- package/dist/mjs/localizations/de.mjs +2 -2
- package/dist/mjs/rendering/RenderingStyle.d.ts +7 -6
- package/dist/mjs/rendering/lib.d.ts +1 -1
- package/dist/mjs/rendering/renderers/AbstractRenderer.mjs +4 -0
- package/dist/mjs/rendering/renderers/CanvasRenderer.d.ts +9 -0
- package/dist/mjs/rendering/renderers/CanvasRenderer.mjs +14 -0
- package/dist/mjs/rendering/renderers/SVGRenderer.d.ts +18 -0
- package/dist/mjs/rendering/renderers/SVGRenderer.mjs +21 -1
- package/dist/mjs/toolbar/AbstractToolbar.d.ts +2 -2
- package/dist/mjs/toolbar/AbstractToolbar.mjs +2 -3
- package/dist/mjs/toolbar/DropdownToolbar.d.ts +1 -1
- package/dist/mjs/toolbar/DropdownToolbar.mjs +2 -3
- package/dist/mjs/toolbar/DropdownToolbar.test.d.ts +1 -0
- package/dist/mjs/toolbar/utils/HelpDisplay.mjs +6 -4
- package/dist/mjs/toolbar/utils/localization.d.ts +1 -0
- package/dist/mjs/toolbar/utils/localization.mjs +1 -0
- package/dist/mjs/toolbar/widgets/DocumentPropertiesWidget.mjs +1 -1
- package/dist/mjs/toolbar/widgets/InsertImageWidget/InsertImageWidget.mjs +1 -1
- package/dist/mjs/toolbar/widgets/components/makeGridSelector.mjs +1 -1
- package/dist/mjs/tools/Eraser.mjs +3 -3
- package/dist/mjs/tools/FindTool.mjs +1 -1
- package/dist/mjs/tools/PasteHandler.mjs +4 -1
- package/dist/mjs/tools/Pen.mjs +1 -1
- package/dist/mjs/tools/SelectionTool/SelectAllShortcutHandler.mjs +1 -1
- package/dist/mjs/tools/SelectionTool/Selection.mjs +23 -10
- package/dist/mjs/tools/SelectionTool/SelectionBuilders/LassoSelectionBuilder.mjs +1 -1
- package/dist/mjs/tools/SelectionTool/SelectionBuilders/RectSelectionBuilder.mjs +1 -1
- package/dist/mjs/tools/SelectionTool/SelectionBuilders/SelectionBuilder.mjs +1 -1
- package/dist/mjs/tools/SelectionTool/SelectionTool.mjs +3 -2
- package/dist/mjs/tools/SoundUITool.mjs +1 -1
- package/dist/mjs/tools/TextTool.mjs +2 -2
- package/dist/mjs/util/assertions.d.ts +6 -0
- package/dist/mjs/util/assertions.mjs +16 -0
- package/dist/mjs/util/describeTransformation.d.ts +12 -0
- package/dist/mjs/util/describeTransformation.mjs +42 -0
- package/dist/mjs/version.mjs +2 -1
- package/package.json +4 -4
- package/src/toolbar/utils/HelpDisplay.scss +7 -1
@@ -139,7 +139,7 @@ export default class Eraser extends BaseTool {
|
|
139
139
|
const line = new LineSegment2(this.lastPoint, currentPoint);
|
140
140
|
const region = Rect2.union(line.bbox, eraserRect);
|
141
141
|
const intersectingElems = this.editor.image
|
142
|
-
.
|
142
|
+
.getComponentsIntersecting(region)
|
143
143
|
.filter((component) => {
|
144
144
|
return component.intersects(line) || component.intersectsRect(eraserRect);
|
145
145
|
});
|
@@ -178,7 +178,7 @@ export default class Eraser extends BaseTool {
|
|
178
178
|
toAdd.push(...targetElem.withRegionErased(erasePath, this.editor.viewport));
|
179
179
|
}
|
180
180
|
const eraseCommand = new Erase(toErase);
|
181
|
-
const newAddCommands = toAdd.map((elem) => EditorImage.
|
181
|
+
const newAddCommands = toAdd.map((elem) => EditorImage.addComponent(elem));
|
182
182
|
eraseCommand.apply(this.editor);
|
183
183
|
newAddCommands.forEach((command) => command.apply(this.editor));
|
184
184
|
const finalToErase = [];
|
@@ -234,7 +234,7 @@ export default class Eraser extends BaseTool {
|
|
234
234
|
this.toRemove = this.toRemove.filter((other) => other !== item);
|
235
235
|
}
|
236
236
|
}
|
237
|
-
commands.push(...[...this.toAdd].map((a) => EditorImage.
|
237
|
+
commands.push(...[...this.toAdd].map((a) => EditorImage.addComponent(a)));
|
238
238
|
this.addCommands = [];
|
239
239
|
}
|
240
240
|
if (this.eraseCommands.length > 0) {
|
@@ -22,7 +22,7 @@ export default class FindTool extends BaseTool {
|
|
22
22
|
}
|
23
23
|
getMatches(searchFor) {
|
24
24
|
const lowerSearchFor = searchFor.toLocaleLowerCase();
|
25
|
-
const matchingComponents = this.editor.image.
|
25
|
+
const matchingComponents = this.editor.image.getAllComponents().filter((component) => {
|
26
26
|
let text = '';
|
27
27
|
if (component instanceof TextComponent) {
|
28
28
|
text = component.getText();
|
@@ -71,7 +71,10 @@ export default class PasteHandler extends BaseTool {
|
|
71
71
|
async doSVGPaste(data) {
|
72
72
|
this.editor.showLoadingWarning(0);
|
73
73
|
try {
|
74
|
-
const loader = SVGLoader.fromString(data,
|
74
|
+
const loader = SVGLoader.fromString(data, {
|
75
|
+
sanitize: true,
|
76
|
+
plugins: this.editor.getCurrentSettings().svg?.loaderPlugins ?? [],
|
77
|
+
});
|
75
78
|
const components = [];
|
76
79
|
await loader.start((component) => {
|
77
80
|
components.push(component);
|
package/dist/mjs/tools/Pen.mjs
CHANGED
@@ -213,7 +213,7 @@ export default class Pen extends BaseTool {
|
|
213
213
|
this.editor.announceForAccessibility(this.editor.localization.autocorrectedTo(stroke.description(this.editor.localization)));
|
214
214
|
}
|
215
215
|
const canFlatten = true;
|
216
|
-
const action = EditorImage.
|
216
|
+
const action = EditorImage.addComponent(stroke, canFlatten);
|
217
217
|
this.editor.dispatch(action);
|
218
218
|
}
|
219
219
|
else {
|
@@ -17,7 +17,7 @@ export default class SelectAllShortcutHandler extends BaseTool {
|
|
17
17
|
if (selectionTools.length > 0) {
|
18
18
|
const selectionTool = selectionTools[0];
|
19
19
|
selectionTool.setEnabled(true);
|
20
|
-
selectionTool.setSelection(this.editor.image.
|
20
|
+
selectionTool.setSelection(this.editor.image.getAllComponents());
|
21
21
|
return true;
|
22
22
|
}
|
23
23
|
}
|
@@ -15,6 +15,8 @@ import { ResizeMode } from './types.mjs';
|
|
15
15
|
import EditorImage from '../../image/EditorImage.mjs';
|
16
16
|
import uniteCommands from '../../commands/uniteCommands.mjs';
|
17
17
|
import SelectionMenuShortcut from './SelectionMenuShortcut.mjs';
|
18
|
+
import { assertIsNumberArray, assertIsStringArray } from '../../util/assertions.mjs';
|
19
|
+
import describeTransformation from '../../util/describeTransformation.mjs';
|
18
20
|
const updateChunkSize = 100;
|
19
21
|
const maxPreviewElemCount = 500;
|
20
22
|
// @internal
|
@@ -148,7 +150,7 @@ class Selection {
|
|
148
150
|
return 0;
|
149
151
|
}
|
150
152
|
const selectedBottommostZIndex = this.selectedElems[0].getZIndex();
|
151
|
-
const visibleObjects = this.editor.image.
|
153
|
+
const visibleObjects = this.editor.image.getComponentsIntersecting(this.region);
|
152
154
|
const topMostVisibleZIndex = visibleObjects[visibleObjects.length - 1]?.getZIndex() ?? selectedBottommostZIndex;
|
153
155
|
const deltaZIndex = topMostVisibleZIndex + 1 - selectedBottommostZIndex;
|
154
156
|
return deltaZIndex;
|
@@ -167,13 +169,13 @@ class Selection {
|
|
167
169
|
// z-index of the just-transformed commands.
|
168
170
|
if (this.selectedElems.length > 0) {
|
169
171
|
const deltaZIndex = this.getDeltaZIndexToMoveSelectionToTop();
|
170
|
-
transformPromise = this.editor.dispatch(new _a.ApplyTransformationCommand(this, selectedElems, fullTransform, deltaZIndex));
|
172
|
+
transformPromise = this.editor.dispatch(new _a.ApplyTransformationCommand(this, selectedElems, this.originalRegion.center, fullTransform, deltaZIndex));
|
171
173
|
}
|
172
174
|
return transformPromise;
|
173
175
|
}
|
174
176
|
/** Sends all selected elements to the bottom of the visible image. */
|
175
177
|
sendToBack() {
|
176
|
-
const visibleObjects = this.editor.image.
|
178
|
+
const visibleObjects = this.editor.image.getComponentsIntersecting(this.editor.viewport.visibleRect);
|
177
179
|
// VisibleObjects and selectedElems should both be sorted by z-index
|
178
180
|
const lowestVisibleZIndex = visibleObjects[0]?.getZIndex() ?? 0;
|
179
181
|
const highestSelectedZIndex = this.selectedElems[this.selectedElems.length - 1]?.getZIndex() ?? 0;
|
@@ -300,7 +302,7 @@ class Selection {
|
|
300
302
|
// If we're making things visible and the selected object wasn't previously
|
301
303
|
// visible,
|
302
304
|
else if (!parent && this.removedFromImage[elem.getId()]) {
|
303
|
-
EditorImage.
|
305
|
+
EditorImage.addComponent(elem).apply(this.editor);
|
304
306
|
this.removedFromImage[elem.getId()] = false;
|
305
307
|
delete this.removedFromImage[elem.getId()];
|
306
308
|
}
|
@@ -438,14 +440,14 @@ class Selection {
|
|
438
440
|
// Don't update the selection's focus when redoing/undoing
|
439
441
|
const selectionToUpdate = null;
|
440
442
|
const deltaZIndex = this.getDeltaZIndexToMoveSelectionToTop();
|
441
|
-
tmpApplyCommand = new _a.ApplyTransformationCommand(selectionToUpdate, this.selectedElems, this.transform, deltaZIndex);
|
443
|
+
tmpApplyCommand = new _a.ApplyTransformationCommand(selectionToUpdate, this.selectedElems, this.region.center, this.transform, deltaZIndex);
|
442
444
|
// Transform to ensure that the duplicates are in the correct location
|
443
445
|
await tmpApplyCommand.apply(this.editor);
|
444
446
|
// Show items again
|
445
447
|
this.addRemoveSelectionFromImage(true);
|
446
448
|
// With the transformation applied, create the duplicates
|
447
449
|
command = uniteCommands(this.selectedElems.map((elem) => {
|
448
|
-
return EditorImage.
|
450
|
+
return EditorImage.addComponent(elem.clone());
|
449
451
|
}));
|
450
452
|
// Move the selected objects back to the correct location.
|
451
453
|
await tmpApplyCommand?.unapply(this.editor);
|
@@ -503,21 +505,31 @@ class Selection {
|
|
503
505
|
_a = Selection;
|
504
506
|
(() => {
|
505
507
|
SerializableCommand.register('selection-tool-transform', (json, _editor) => {
|
508
|
+
const rawTransformArray = json.transform;
|
509
|
+
const rawCenterArray = json.selectionCenter ?? [0, 0];
|
510
|
+
const rawElementIds = json.elems ?? [];
|
511
|
+
assertIsNumberArray(rawTransformArray);
|
512
|
+
assertIsNumberArray(rawCenterArray);
|
513
|
+
assertIsStringArray(rawElementIds);
|
506
514
|
// The selection box is lost when serializing/deserializing. No need to store box rotation
|
507
|
-
const fullTransform = new Mat33(...
|
508
|
-
const elemIds =
|
515
|
+
const fullTransform = new Mat33(...rawTransformArray);
|
516
|
+
const elemIds = rawElementIds;
|
509
517
|
const deltaZIndex = parseInt(json.deltaZIndex ?? 0);
|
510
|
-
|
518
|
+
const center = Vec2.of(rawCenterArray[0] ?? 0, rawCenterArray[1] ?? 0);
|
519
|
+
return new _a.ApplyTransformationCommand(null, elemIds, center, fullTransform, deltaZIndex);
|
511
520
|
});
|
512
521
|
})();
|
513
522
|
Selection.ApplyTransformationCommand = class extends SerializableCommand {
|
514
523
|
constructor(selection,
|
515
524
|
// If a `string[]`, selectedElems is a list of element IDs.
|
516
525
|
selectedElems,
|
526
|
+
// Information used to describe the transformation
|
527
|
+
selectionCenter,
|
517
528
|
// Full transformation used to transform elements.
|
518
529
|
fullTransform, deltaZIndex) {
|
519
530
|
super('selection-tool-transform');
|
520
531
|
this.selection = selection;
|
532
|
+
this.selectionCenter = selectionCenter;
|
521
533
|
this.fullTransform = fullTransform;
|
522
534
|
this.deltaZIndex = deltaZIndex;
|
523
535
|
const isIDList = (arr) => {
|
@@ -585,10 +597,11 @@ Selection.ApplyTransformationCommand = class extends SerializableCommand {
|
|
585
597
|
elems: this.selectedElemIds,
|
586
598
|
transform: this.fullTransform.toArray(),
|
587
599
|
deltaZIndex: this.deltaZIndex,
|
600
|
+
selectionCenter: this.selectionCenter.asArray(),
|
588
601
|
};
|
589
602
|
}
|
590
603
|
description(_editor, localizationTable) {
|
591
|
-
return localizationTable.transformedElements(this.selectedElemIds.length);
|
604
|
+
return localizationTable.transformedElements(this.selectedElemIds.length, describeTransformation(this.selectionCenter, this.fullTransform, false, localizationTable));
|
592
605
|
}
|
593
606
|
};
|
594
607
|
export default Selection;
|
@@ -33,7 +33,7 @@ export default class LassoSelectionBuilder extends SelectionBuilder {
|
|
33
33
|
resolveInternal(image) {
|
34
34
|
const path = this.previewPath();
|
35
35
|
const lines = path.polylineApproximation();
|
36
|
-
const candidates = image.
|
36
|
+
const candidates = image.getComponentsIntersecting(path.bbox);
|
37
37
|
const componentIsInSelection = (component) => {
|
38
38
|
if (path.closedContainsRect(component.getExactBBox())) {
|
39
39
|
return true;
|
@@ -15,7 +15,7 @@ export default class RectSelectionBuilder extends SelectionBuilder {
|
|
15
15
|
return Path.fromRect(this.rect);
|
16
16
|
}
|
17
17
|
resolveInternal(image) {
|
18
|
-
return image.
|
18
|
+
return image.getComponentsIntersecting(this.rect).filter((element) => {
|
19
19
|
// Filter out the case where the selection rectangle is completely contained
|
20
20
|
// within the element (and does not intersect it).
|
21
21
|
// This is useful, for example, if a very large stroke is used as the background
|
@@ -20,7 +20,7 @@ export default class SelectionBuilder {
|
|
20
20
|
if (isClick) {
|
21
21
|
const searchRegionSize = viewport.visibleRect.maxDimension / 200;
|
22
22
|
const minSizeBox = path.bbox.grownBy(searchRegionSize);
|
23
|
-
components = image.
|
23
|
+
components = image.getComponentsIntersecting(minSizeBox).filter((component) => {
|
24
24
|
return minSizeBox.containsRect(component.getBBox()) || component.intersectsRect(minSizeBox);
|
25
25
|
});
|
26
26
|
components = filterComponents(components);
|
@@ -253,7 +253,7 @@ export default class SelectionTool extends BaseTool {
|
|
253
253
|
return true;
|
254
254
|
}
|
255
255
|
else if (shortcucts.matchesShortcut(selectAllKeyboardShortcut, event)) {
|
256
|
-
this.setSelection(this.editor.image.
|
256
|
+
this.setSelection(this.editor.image.getAllComponents());
|
257
257
|
return true;
|
258
258
|
}
|
259
259
|
else if (event.ctrlKey) {
|
@@ -456,7 +456,8 @@ export default class SelectionTool extends BaseTool {
|
|
456
456
|
this.handleOverlay.style.display = enabled ? 'block' : 'none';
|
457
457
|
if (enabled) {
|
458
458
|
this.handleOverlay.tabIndex = 0;
|
459
|
-
this.handleOverlay.
|
459
|
+
this.handleOverlay.role = 'group';
|
460
|
+
this.handleOverlay.ariaLabel = this.editor.localization.selectionToolKeyboardShortcuts;
|
460
461
|
}
|
461
462
|
else {
|
462
463
|
this.handleOverlay.tabIndex = -1;
|
@@ -151,7 +151,7 @@ export default class SoundUITool extends BaseTool {
|
|
151
151
|
this.soundFeedback?.setColor(this.editor.display.getColorAt(current.screenPos) ?? Color4.black);
|
152
152
|
const pointerMotionLine = new LineSegment2(this.lastPointerPos, current.canvasPos);
|
153
153
|
const collisions = this.editor.image
|
154
|
-
.
|
154
|
+
.getComponentsIntersecting(pointerMotionLine.bbox)
|
155
155
|
.filter((component) => component.intersects(pointerMotionLine));
|
156
156
|
this.lastPointerPos = current.canvasPos;
|
157
157
|
if (collisions.length > 0) {
|
@@ -98,7 +98,7 @@ export default class TextTool extends BaseTool {
|
|
98
98
|
const scrollCorrectionCanvas = this.editor.viewport.screenToCanvasTransform.transformVec3(scrollCorrectionScreen);
|
99
99
|
const scrollTransform = Mat33.translation(scrollCorrectionCanvas);
|
100
100
|
const textComponent = TextComponent.fromLines(content.split('\n'), scrollTransform.rightMul(this.contentTransform.get()), this.textStyle);
|
101
|
-
const action = EditorImage.
|
101
|
+
const action = EditorImage.addComponent(textComponent);
|
102
102
|
if (this.removeExistingCommand) {
|
103
103
|
// Unapply so that `removeExistingCommand` can be added to the undo stack.
|
104
104
|
this.removeExistingCommand.unapply(this.editor);
|
@@ -208,7 +208,7 @@ export default class TextTool extends BaseTool {
|
|
208
208
|
const canvasPos = current.canvasPos;
|
209
209
|
const halfTestRegionSize = Vec2.of(4, 4).times(this.editor.viewport.getSizeOfPixelOnCanvas());
|
210
210
|
const testRegion = Rect2.fromCorners(canvasPos.minus(halfTestRegionSize), canvasPos.plus(halfTestRegionSize));
|
211
|
-
const targetNodes = this.editor.image.
|
211
|
+
const targetNodes = this.editor.image.getComponentsIntersecting(testRegion);
|
212
212
|
let targetTextNodes = targetNodes.filter((node) => node instanceof TextComponent);
|
213
213
|
// Don't try to edit text nodes that contain the viewport (this allows us
|
214
214
|
// to zoom in on text nodes and add text on top of them.)
|
@@ -15,11 +15,17 @@ export declare function assertUnreachable(key: never): never;
|
|
15
15
|
* ```
|
16
16
|
*/
|
17
17
|
export declare function assertIsNumber(value: unknown, allowNaN?: boolean): asserts value is number;
|
18
|
+
/** Throws an `Error` if the given `value` is not a `string`. */
|
19
|
+
export declare function assertIsString(value: unknown): asserts value is string;
|
18
20
|
export declare function assertIsArray(values: unknown): asserts values is unknown[];
|
19
21
|
/**
|
20
22
|
* Throws if any of `values` is not of type number.
|
21
23
|
*/
|
22
24
|
export declare function assertIsNumberArray(values: unknown, allowNaN?: boolean): asserts values is number[];
|
25
|
+
/**
|
26
|
+
* Throws if any of `values` is not of type `string`.
|
27
|
+
*/
|
28
|
+
export declare function assertIsStringArray(values: unknown): asserts values is string[];
|
23
29
|
/**
|
24
30
|
* Throws an exception if `typeof value` is not a boolean.
|
25
31
|
*/
|
@@ -24,6 +24,12 @@ export function assertIsNumber(value, allowNaN = false) {
|
|
24
24
|
throw new Error('Given value is not a number');
|
25
25
|
}
|
26
26
|
}
|
27
|
+
/** Throws an `Error` if the given `value` is not a `string`. */
|
28
|
+
export function assertIsString(value) {
|
29
|
+
if (typeof value !== 'string') {
|
30
|
+
throw new Error('Given value is not a string');
|
31
|
+
}
|
32
|
+
}
|
27
33
|
export function assertIsArray(values) {
|
28
34
|
if (!Array.isArray(values)) {
|
29
35
|
throw new Error('Asserting isArray: Given entity is not an array');
|
@@ -39,6 +45,16 @@ export function assertIsNumberArray(values, allowNaN = false) {
|
|
39
45
|
assertIsNumber(value, allowNaN);
|
40
46
|
}
|
41
47
|
}
|
48
|
+
/**
|
49
|
+
* Throws if any of `values` is not of type `string`.
|
50
|
+
*/
|
51
|
+
export function assertIsStringArray(values) {
|
52
|
+
assertIsArray(values);
|
53
|
+
assertIsNumber(values.length);
|
54
|
+
for (const value of values) {
|
55
|
+
assertIsString(value);
|
56
|
+
}
|
57
|
+
}
|
42
58
|
/**
|
43
59
|
* Throws an exception if `typeof value` is not a boolean.
|
44
60
|
*/
|
@@ -0,0 +1,12 @@
|
|
1
|
+
import { Mat33, Vec2 } from '@js-draw/math';
|
2
|
+
interface Descriptions {
|
3
|
+
zoomedIn: string;
|
4
|
+
zoomedOut: string;
|
5
|
+
movedLeft: string;
|
6
|
+
movedRight: string;
|
7
|
+
movedUp: string;
|
8
|
+
movedDown: string;
|
9
|
+
rotatedBy: (deg: number) => string;
|
10
|
+
}
|
11
|
+
declare const describeTransformation: (origin: Vec2, transform: Mat33, invertDirections: boolean, localizationTable: Descriptions) => string;
|
12
|
+
export default describeTransformation;
|
@@ -0,0 +1,42 @@
|
|
1
|
+
import { Vec2 } from '@js-draw/math';
|
2
|
+
const describeTransformation = (
|
3
|
+
// The location of the object before being transformed
|
4
|
+
origin,
|
5
|
+
// The transformation
|
6
|
+
transform,
|
7
|
+
// If true, moving the object right, for example, reads as "moved left"
|
8
|
+
invertDirections, localizationTable) => {
|
9
|
+
// Describe the transformation's affect on the viewport (note that transformation transforms
|
10
|
+
// the **elements** within the viewport). Assumes the transformation only does rotation/scale/translation.
|
11
|
+
const linearTransformedVec = transform.transformVec3(Vec2.unitX);
|
12
|
+
const affineTransformedVec = transform.transformVec2(origin);
|
13
|
+
const scale = linearTransformedVec.magnitude();
|
14
|
+
const clockwiseRotation = -(180 / Math.PI) * linearTransformedVec.angle();
|
15
|
+
const translation = affineTransformedVec.minus(origin);
|
16
|
+
const result = [];
|
17
|
+
if (scale > 1.2) {
|
18
|
+
result.push(localizationTable.zoomedIn);
|
19
|
+
}
|
20
|
+
else if (scale < 0.8) {
|
21
|
+
result.push(localizationTable.zoomedOut);
|
22
|
+
}
|
23
|
+
if (Math.floor(Math.abs(clockwiseRotation)) > 0) {
|
24
|
+
const roundedRotation = Math.round(invertDirections ? -clockwiseRotation : clockwiseRotation);
|
25
|
+
result.push(localizationTable.rotatedBy(roundedRotation));
|
26
|
+
}
|
27
|
+
const minTranslation = 1e-4;
|
28
|
+
if (translation.x > minTranslation) {
|
29
|
+
result.push(invertDirections ? localizationTable.movedLeft : localizationTable.movedRight);
|
30
|
+
}
|
31
|
+
else if (translation.x < -minTranslation) {
|
32
|
+
result.push(invertDirections ? localizationTable.movedRight : localizationTable.movedLeft);
|
33
|
+
}
|
34
|
+
if (translation.y < -minTranslation) {
|
35
|
+
result.push(invertDirections ? localizationTable.movedDown : localizationTable.movedUp);
|
36
|
+
}
|
37
|
+
else if (translation.y > minTranslation) {
|
38
|
+
result.push(invertDirections ? localizationTable.movedUp : localizationTable.movedDown);
|
39
|
+
}
|
40
|
+
return result.join('; ');
|
41
|
+
};
|
42
|
+
export default describeTransformation;
|
package/dist/mjs/version.mjs
CHANGED
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "js-draw",
|
3
|
-
"version": "1.
|
3
|
+
"version": "1.28.0",
|
4
4
|
"description": "Draw pictures using a pen, touchscreen, or mouse! JS-draw is a drawing library for JavaScript and TypeScript. ",
|
5
5
|
"types": "./dist/mjs/lib.d.ts",
|
6
6
|
"main": "./dist/cjs/lib.js",
|
@@ -64,11 +64,11 @@
|
|
64
64
|
"postpack": "ts-node tools/copyREADME.ts revert"
|
65
65
|
},
|
66
66
|
"dependencies": {
|
67
|
-
"@js-draw/math": "^1.
|
67
|
+
"@js-draw/math": "^1.28.0",
|
68
68
|
"@melloware/coloris": "0.22.0"
|
69
69
|
},
|
70
70
|
"devDependencies": {
|
71
|
-
"@js-draw/build-tool": "^1.
|
71
|
+
"@js-draw/build-tool": "^1.28.0",
|
72
72
|
"@types/jest": "29.5.5",
|
73
73
|
"@types/jsdom": "21.1.3"
|
74
74
|
},
|
@@ -86,5 +86,5 @@
|
|
86
86
|
"freehand",
|
87
87
|
"svg"
|
88
88
|
],
|
89
|
-
"gitHead": "
|
89
|
+
"gitHead": "03242acbf2250f5a41aa86a84146bb08583cf955"
|
90
90
|
}
|
@@ -291,9 +291,15 @@
|
|
291
291
|
&.-highlight-next > .next,
|
292
292
|
&.-highlight-previous > .previous {
|
293
293
|
font-weight: bold;
|
294
|
-
background-color: rgba(200, 200, 200, 0.1);
|
295
294
|
font-size: 1.4em;
|
296
295
|
}
|
296
|
+
|
297
|
+
&.-highlight-next > .next,
|
298
|
+
&.-highlight-previous > .previous,
|
299
|
+
.next:hover,
|
300
|
+
.previous:hover {
|
301
|
+
background-color: rgba(200, 200, 200, 0.1);
|
302
|
+
}
|
297
303
|
}
|
298
304
|
|
299
305
|
.navigation-help {
|