js-draw 0.4.1 → 0.6.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/CHANGELOG.md +19 -0
- package/dist/bundle.js +1 -1
- package/dist/src/Editor.d.ts +9 -6
- package/dist/src/Editor.js +9 -3
- package/dist/src/EditorImage.d.ts +3 -0
- package/dist/src/EditorImage.js +7 -0
- package/dist/src/SVGLoader.js +5 -6
- package/dist/src/components/AbstractComponent.d.ts +1 -0
- package/dist/src/components/AbstractComponent.js +4 -0
- package/dist/src/components/SVGGlobalAttributesObject.d.ts +1 -0
- package/dist/src/components/SVGGlobalAttributesObject.js +3 -0
- package/dist/src/components/Text.d.ts +3 -5
- package/dist/src/components/Text.js +19 -10
- package/dist/src/components/UnknownSVGObject.d.ts +1 -0
- package/dist/src/components/UnknownSVGObject.js +3 -0
- package/dist/src/components/builders/FreehandLineBuilder.js +3 -3
- package/dist/src/rendering/renderers/SVGRenderer.js +1 -1
- package/dist/src/testing/beforeEachFile.js +4 -0
- package/dist/src/toolbar/HTMLToolbar.js +2 -3
- package/dist/src/toolbar/IconProvider.d.ts +24 -0
- package/dist/src/toolbar/IconProvider.js +415 -0
- package/dist/src/toolbar/lib.d.ts +1 -1
- package/dist/src/toolbar/lib.js +1 -2
- package/dist/src/toolbar/localization.d.ts +0 -1
- package/dist/src/toolbar/localization.js +0 -1
- package/dist/src/toolbar/makeColorInput.js +1 -2
- package/dist/src/toolbar/widgets/BaseWidget.d.ts +2 -0
- package/dist/src/toolbar/widgets/BaseWidget.js +16 -2
- package/dist/src/toolbar/widgets/EraserToolWidget.js +1 -2
- package/dist/src/toolbar/widgets/HandToolWidget.d.ts +5 -3
- package/dist/src/toolbar/widgets/HandToolWidget.js +35 -12
- package/dist/src/toolbar/widgets/PenToolWidget.d.ts +2 -0
- package/dist/src/toolbar/widgets/PenToolWidget.js +16 -3
- package/dist/src/toolbar/widgets/SelectionToolWidget.d.ts +3 -0
- package/dist/src/toolbar/widgets/SelectionToolWidget.js +20 -7
- package/dist/src/toolbar/widgets/TextToolWidget.js +1 -2
- package/dist/src/tools/PanZoom.d.ts +1 -1
- package/dist/src/tools/PanZoom.js +4 -1
- package/dist/src/tools/SelectionTool/SelectionTool.d.ts +3 -0
- package/dist/src/tools/SelectionTool/SelectionTool.js +66 -3
- package/dist/src/tools/ToolController.js +3 -0
- package/dist/src/tools/ToolbarShortcutHandler.d.ts +12 -0
- package/dist/src/tools/ToolbarShortcutHandler.js +23 -0
- package/dist/src/tools/lib.d.ts +1 -0
- package/dist/src/tools/lib.js +1 -0
- package/dist/src/tools/localization.d.ts +1 -0
- package/dist/src/tools/localization.js +1 -0
- package/dist/src/types.d.ts +4 -2
- package/package.json +1 -1
- package/src/Editor.ts +17 -7
- package/src/EditorImage.ts +9 -0
- package/src/SVGLoader.test.ts +37 -0
- package/src/SVGLoader.ts +5 -6
- package/src/components/AbstractComponent.ts +5 -0
- package/src/components/SVGGlobalAttributesObject.ts +4 -0
- package/src/components/Text.test.ts +1 -16
- package/src/components/Text.ts +21 -11
- package/src/components/UnknownSVGObject.ts +4 -0
- package/src/components/builders/FreehandLineBuilder.ts +3 -3
- package/src/rendering/renderers/SVGRenderer.ts +1 -1
- package/src/testing/beforeEachFile.ts +6 -1
- package/src/toolbar/HTMLToolbar.ts +2 -3
- package/src/toolbar/IconProvider.ts +476 -0
- package/src/toolbar/lib.ts +1 -1
- package/src/toolbar/localization.ts +0 -2
- package/src/toolbar/makeColorInput.ts +1 -2
- package/src/toolbar/widgets/BaseWidget.ts +20 -3
- package/src/toolbar/widgets/EraserToolWidget.ts +1 -2
- package/src/toolbar/widgets/HandToolWidget.ts +42 -20
- package/src/toolbar/widgets/PenToolWidget.ts +20 -4
- package/src/toolbar/widgets/SelectionToolWidget.ts +24 -8
- package/src/toolbar/widgets/TextToolWidget.ts +1 -2
- package/src/tools/PanZoom.ts +4 -1
- package/src/tools/SelectionTool/SelectionTool.css +2 -1
- package/src/tools/SelectionTool/SelectionTool.test.ts +40 -0
- package/src/tools/SelectionTool/SelectionTool.ts +73 -4
- package/src/tools/ToolController.ts +3 -0
- package/src/tools/ToolbarShortcutHandler.ts +34 -0
- package/src/tools/UndoRedoShortcut.test.ts +3 -0
- package/src/tools/lib.ts +1 -0
- package/src/tools/localization.ts +4 -0
- package/src/types.ts +13 -8
- package/typedoc.json +5 -1
- package/dist/src/toolbar/icons.d.ts +0 -20
- package/dist/src/toolbar/icons.js +0 -385
- package/src/toolbar/icons.ts +0 -443
package/dist/src/Editor.d.ts
CHANGED
@@ -28,6 +28,7 @@ import Display, { RenderingMode } from './rendering/Display';
|
|
28
28
|
import Pointer from './Pointer';
|
29
29
|
import Rect2 from './math/Rect2';
|
30
30
|
import { EditorLocalization } from './localization';
|
31
|
+
import IconProvider from './toolbar/IconProvider';
|
31
32
|
declare type HTMLPointerEventType = 'pointerdown' | 'pointermove' | 'pointerup' | 'pointercancel';
|
32
33
|
declare type HTMLPointerEventFilter = (eventName: HTMLPointerEventType, event: PointerEvent) => boolean;
|
33
34
|
export interface EditorSettings {
|
@@ -44,6 +45,7 @@ export interface EditorSettings {
|
|
44
45
|
/** Minimum zoom fraction (e.g. 0.5 → 50% zoom). */
|
45
46
|
minZoom: number;
|
46
47
|
maxZoom: number;
|
48
|
+
iconProvider: IconProvider;
|
47
49
|
}
|
48
50
|
export declare class Editor {
|
49
51
|
private container;
|
@@ -81,18 +83,19 @@ export declare class Editor {
|
|
81
83
|
* editor.dispatch(addElementCommand);
|
82
84
|
* ```
|
83
85
|
*/
|
84
|
-
image: EditorImage;
|
86
|
+
readonly image: EditorImage;
|
85
87
|
/** Viewport for the exported/imported image. */
|
86
88
|
private importExportViewport;
|
87
89
|
/** @internal */
|
88
|
-
localization: EditorLocalization;
|
89
|
-
|
90
|
-
|
90
|
+
readonly localization: EditorLocalization;
|
91
|
+
readonly icons: IconProvider;
|
92
|
+
readonly viewport: Viewport;
|
93
|
+
readonly toolController: ToolController;
|
91
94
|
/**
|
92
95
|
* Global event dispatcher/subscriber.
|
93
96
|
* @see {@link types.EditorEventType}
|
94
97
|
*/
|
95
|
-
notifier: EditorNotifier;
|
98
|
+
readonly notifier: EditorNotifier;
|
96
99
|
private loadingWarning;
|
97
100
|
private accessibilityAnnounceArea;
|
98
101
|
private accessibilityControlArea;
|
@@ -193,7 +196,7 @@ export declare class Editor {
|
|
193
196
|
remove: () => void;
|
194
197
|
};
|
195
198
|
addStyleSheet(content: string): HTMLStyleElement;
|
196
|
-
sendKeyboardEvent(eventType: InputEvtType.KeyPressEvent | InputEvtType.KeyUpEvent, key: string, ctrlKey?: boolean): void;
|
199
|
+
sendKeyboardEvent(eventType: InputEvtType.KeyPressEvent | InputEvtType.KeyUpEvent, key: string, ctrlKey?: boolean, altKey?: boolean): void;
|
197
200
|
sendPenEvent(eventType: InputEvtType.PointerDownEvt | InputEvtType.PointerMoveEvt | InputEvtType.PointerUpEvt, point: Point2, allPointers?: Pointer[]): void;
|
198
201
|
toSVG(): SVGElement;
|
199
202
|
loadFrom(loader: ImageLoader): Promise<void>;
|
package/dist/src/Editor.js
CHANGED
@@ -41,6 +41,7 @@ import SVGLoader from './SVGLoader';
|
|
41
41
|
import Pointer from './Pointer';
|
42
42
|
import Mat33 from './math/Mat33';
|
43
43
|
import getLocalizationTable from './localizations/getLocalizationTable';
|
44
|
+
import IconProvider from './toolbar/IconProvider';
|
44
45
|
// { @inheritDoc Editor! }
|
45
46
|
export class Editor {
|
46
47
|
/**
|
@@ -67,7 +68,7 @@ export class Editor {
|
|
67
68
|
* ```
|
68
69
|
*/
|
69
70
|
constructor(parent, settings = {}) {
|
70
|
-
var _a, _b, _c, _d;
|
71
|
+
var _a, _b, _c, _d, _e;
|
71
72
|
this.eventListenerTargets = [];
|
72
73
|
this.previousAccessibilityAnnouncement = '';
|
73
74
|
this.pointers = {};
|
@@ -86,7 +87,9 @@ export class Editor {
|
|
86
87
|
localization: this.localization,
|
87
88
|
minZoom: (_c = settings.minZoom) !== null && _c !== void 0 ? _c : 2e-10,
|
88
89
|
maxZoom: (_d = settings.maxZoom) !== null && _d !== void 0 ? _d : 1e12,
|
90
|
+
iconProvider: (_e = settings.iconProvider) !== null && _e !== void 0 ? _e : new IconProvider(),
|
89
91
|
};
|
92
|
+
this.icons = this.settings.iconProvider;
|
90
93
|
this.container = document.createElement('div');
|
91
94
|
this.renderingRegion = document.createElement('div');
|
92
95
|
this.container.appendChild(this.renderingRegion);
|
@@ -441,6 +444,7 @@ export class Editor {
|
|
441
444
|
kind: InputEvtType.KeyPressEvent,
|
442
445
|
key: evt.key,
|
443
446
|
ctrlKey: evt.ctrlKey,
|
447
|
+
altKey: evt.altKey,
|
444
448
|
})) {
|
445
449
|
evt.preventDefault();
|
446
450
|
}
|
@@ -453,6 +457,7 @@ export class Editor {
|
|
453
457
|
kind: InputEvtType.KeyUpEvent,
|
454
458
|
key: evt.key,
|
455
459
|
ctrlKey: evt.ctrlKey,
|
460
|
+
altKey: evt.altKey,
|
456
461
|
})) {
|
457
462
|
evt.preventDefault();
|
458
463
|
}
|
@@ -598,11 +603,12 @@ export class Editor {
|
|
598
603
|
}
|
599
604
|
// Dispatch a keyboard event to the currently selected tool.
|
600
605
|
// Intended for unit testing
|
601
|
-
sendKeyboardEvent(eventType, key, ctrlKey = false) {
|
606
|
+
sendKeyboardEvent(eventType, key, ctrlKey = false, altKey = false) {
|
602
607
|
this.toolController.dispatchInputEvent({
|
603
608
|
kind: eventType,
|
604
609
|
key,
|
605
|
-
ctrlKey
|
610
|
+
ctrlKey,
|
611
|
+
altKey,
|
606
612
|
});
|
607
613
|
}
|
608
614
|
// Dispatch a pen event to the currently selected tool.
|
@@ -16,6 +16,9 @@ export default class EditorImage {
|
|
16
16
|
render(renderer: AbstractRenderer, viewport: Viewport): void;
|
17
17
|
/** Renders all nodes, even ones not within the viewport. @internal */
|
18
18
|
renderAll(renderer: AbstractRenderer): void;
|
19
|
+
/** @returns all elements in the image, sorted by z-index. This can be slow for large images. */
|
20
|
+
getAllElements(): AbstractComponent[];
|
21
|
+
/** @returns a list of `AbstractComponent`s intersecting `region`, sorted by z-index. */
|
19
22
|
getElementsIntersectingRegion(region: Rect2): AbstractComponent[];
|
20
23
|
/** @internal */
|
21
24
|
onDestroyElement(elem: AbstractComponent): void;
|
package/dist/src/EditorImage.js
CHANGED
@@ -39,6 +39,13 @@ export default class EditorImage {
|
|
39
39
|
leaf.getContent().render(renderer, leaf.getBBox());
|
40
40
|
}
|
41
41
|
}
|
42
|
+
/** @returns all elements in the image, sorted by z-index. This can be slow for large images. */
|
43
|
+
getAllElements() {
|
44
|
+
const leaves = this.root.getLeaves();
|
45
|
+
sortLeavesByZIndex(leaves);
|
46
|
+
return leaves.map(leaf => leaf.getContent());
|
47
|
+
}
|
48
|
+
/** @returns a list of `AbstractComponent`s intersecting `region`, sorted by z-index. */
|
42
49
|
getElementsIntersectingRegion(region) {
|
43
50
|
const leaves = this.root.getLeavesIntersectingRegion(region);
|
44
51
|
sortLeavesByZIndex(leaves);
|
package/dist/src/SVGLoader.js
CHANGED
@@ -99,7 +99,7 @@ export default class SVGLoader {
|
|
99
99
|
}
|
100
100
|
elem.attachLoadSaveData(svgAttributesDataKey, [attr, node.getAttribute(attr)]);
|
101
101
|
}
|
102
|
-
if (supportedStyleAttrs) {
|
102
|
+
if (supportedStyleAttrs && node.style) {
|
103
103
|
for (const attr of node.style) {
|
104
104
|
if (attr === '' || !attr) {
|
105
105
|
continue;
|
@@ -157,9 +157,9 @@ export default class SVGLoader {
|
|
157
157
|
}
|
158
158
|
const elemX = elem.getAttribute('x');
|
159
159
|
const elemY = elem.getAttribute('y');
|
160
|
-
if (elemX
|
161
|
-
const x = parseFloat(elemX);
|
162
|
-
const y = parseFloat(elemY);
|
160
|
+
if (elemX || elemY) {
|
161
|
+
const x = parseFloat(elemX !== null && elemX !== void 0 ? elemX : '0');
|
162
|
+
const y = parseFloat(elemY !== null && elemY !== void 0 ? elemY : '0');
|
163
163
|
if (!isNaN(x) && !isNaN(y)) {
|
164
164
|
supportedAttrs === null || supportedAttrs === void 0 ? void 0 : supportedAttrs.push('x', 'y');
|
165
165
|
transform = transform.rightMul(Mat33.translation(Vec2.of(x, y)));
|
@@ -204,7 +204,7 @@ export default class SVGLoader {
|
|
204
204
|
size: fontSize,
|
205
205
|
fontFamily: computedStyles.fontFamily || elem.style.fontFamily || 'sans-serif',
|
206
206
|
renderingStyle: {
|
207
|
-
fill: Color4.fromString(computedStyles.fill)
|
207
|
+
fill: Color4.fromString(computedStyles.fill || elem.style.fill || '#000')
|
208
208
|
},
|
209
209
|
};
|
210
210
|
const supportedAttrs = [];
|
@@ -339,7 +339,6 @@ export default class SVGLoader {
|
|
339
339
|
(_b = this.onFinish) === null || _b === void 0 ? void 0 : _b.call(this);
|
340
340
|
});
|
341
341
|
}
|
342
|
-
// TODO: Handling unsafe data! Tripple-check that this is secure!
|
343
342
|
// @param sanitize - if `true`, don't store unknown attributes.
|
344
343
|
static fromString(text, sanitize = false) {
|
345
344
|
var _a, _b;
|
@@ -28,6 +28,7 @@ export default abstract class AbstractComponent {
|
|
28
28
|
protected abstract serializeToJSON(): any[] | Record<string, any> | number | string | null;
|
29
29
|
protected abstract applyTransformation(affineTransfm: Mat33): void;
|
30
30
|
transformBy(affineTransfm: Mat33): SerializableCommand;
|
31
|
+
isSelectable(): boolean;
|
31
32
|
private static transformElementCommandId;
|
32
33
|
private static UnresolvedTransformElementCommand;
|
33
34
|
private static TransformElementCommand;
|
@@ -48,6 +48,10 @@ export default class AbstractComponent {
|
|
48
48
|
transformBy(affineTransfm) {
|
49
49
|
return new AbstractComponent.TransformElementCommand(affineTransfm, this);
|
50
50
|
}
|
51
|
+
// @returns true iff this component can be selected (e.g. by the selection tool.)
|
52
|
+
isSelectable() {
|
53
|
+
return true;
|
54
|
+
}
|
51
55
|
// Returns a copy of this component.
|
52
56
|
clone() {
|
53
57
|
const clone = this.createClone();
|
@@ -12,6 +12,7 @@ export default class SVGGlobalAttributesObject extends AbstractComponent {
|
|
12
12
|
render(canvas: AbstractRenderer, _visibleRect?: Rect2): void;
|
13
13
|
intersects(_lineSegment: LineSegment2): boolean;
|
14
14
|
protected applyTransformation(_affineTransfm: Mat33): void;
|
15
|
+
isSelectable(): boolean;
|
15
16
|
protected createClone(): SVGGlobalAttributesObject;
|
16
17
|
description(localization: ImageComponentLocalization): string;
|
17
18
|
protected serializeToJSON(): string | null;
|
@@ -12,16 +12,15 @@ export interface TextStyle {
|
|
12
12
|
fontVariant?: string;
|
13
13
|
renderingStyle: RenderingStyle;
|
14
14
|
}
|
15
|
-
declare type GetTextDimensCallback = (text: string, style: TextStyle) => Rect2;
|
16
15
|
export default class Text extends AbstractComponent {
|
17
16
|
protected readonly textObjects: Array<string | Text>;
|
18
17
|
private transform;
|
19
18
|
private readonly style;
|
20
|
-
private readonly getTextDimens;
|
21
19
|
protected contentBBox: Rect2;
|
22
|
-
constructor(textObjects: Array<string | Text>, transform: Mat33, style: TextStyle
|
20
|
+
constructor(textObjects: Array<string | Text>, transform: Mat33, style: TextStyle);
|
23
21
|
static applyTextStyles(ctx: CanvasRenderingContext2D, style: TextStyle): void;
|
24
22
|
private static textMeasuringCtx;
|
23
|
+
private static estimateTextDimens;
|
25
24
|
private static getTextDimens;
|
26
25
|
private computeBBoxOfPart;
|
27
26
|
private recomputeBBox;
|
@@ -32,6 +31,5 @@ export default class Text extends AbstractComponent {
|
|
32
31
|
getText(): string;
|
33
32
|
description(localizationTable: ImageComponentLocalization): string;
|
34
33
|
protected serializeToJSON(): Record<string, any>;
|
35
|
-
static deserializeFromString(json: any
|
34
|
+
static deserializeFromString(json: any): Text;
|
36
35
|
}
|
37
|
-
export {};
|
@@ -5,15 +5,11 @@ import { styleFromJSON, styleToJSON } from '../rendering/RenderingStyle';
|
|
5
5
|
import AbstractComponent from './AbstractComponent';
|
6
6
|
const componentTypeId = 'text';
|
7
7
|
export default class Text extends AbstractComponent {
|
8
|
-
constructor(textObjects, transform, style
|
9
|
-
// If not given, an HtmlCanvasElement is used to determine text boundaries.
|
10
|
-
// @internal
|
11
|
-
getTextDimens = Text.getTextDimens) {
|
8
|
+
constructor(textObjects, transform, style) {
|
12
9
|
super(componentTypeId);
|
13
10
|
this.textObjects = textObjects;
|
14
11
|
this.transform = transform;
|
15
12
|
this.style = style;
|
16
|
-
this.getTextDimens = getTextDimens;
|
17
13
|
this.recomputeBBox();
|
18
14
|
}
|
19
15
|
static applyTextStyles(ctx, style) {
|
@@ -28,9 +24,21 @@ export default class Text extends AbstractComponent {
|
|
28
24
|
].join(' ');
|
29
25
|
ctx.textAlign = 'left';
|
30
26
|
}
|
27
|
+
// Roughly estimate the bounding box of `text`. Use if no CanvasRenderingContext2D is available.
|
28
|
+
static estimateTextDimens(text, style) {
|
29
|
+
const widthEst = text.length * style.size;
|
30
|
+
const heightEst = style.size;
|
31
|
+
// Text is drawn with (0, 0) as its baseline. As such, the majority of the text's height should
|
32
|
+
// be above (0, 0).
|
33
|
+
return new Rect2(0, -heightEst * 2 / 3, widthEst, heightEst);
|
34
|
+
}
|
35
|
+
// Returns the bounding box of `text`. This is approximate if no Canvas is available.
|
31
36
|
static getTextDimens(text, style) {
|
32
|
-
var _a;
|
33
|
-
(_a = Text.textMeasuringCtx) !== null && _a !== void 0 ? _a : (Text.textMeasuringCtx = document.createElement('canvas').getContext('2d'));
|
37
|
+
var _a, _b;
|
38
|
+
(_a = Text.textMeasuringCtx) !== null && _a !== void 0 ? _a : (Text.textMeasuringCtx = (_b = document.createElement('canvas').getContext('2d')) !== null && _b !== void 0 ? _b : null);
|
39
|
+
if (!Text.textMeasuringCtx) {
|
40
|
+
return this.estimateTextDimens(text, style);
|
41
|
+
}
|
34
42
|
const ctx = Text.textMeasuringCtx;
|
35
43
|
Text.applyTextStyles(ctx, style);
|
36
44
|
const measure = ctx.measureText(text);
|
@@ -41,7 +49,7 @@ export default class Text extends AbstractComponent {
|
|
41
49
|
}
|
42
50
|
computeBBoxOfPart(part) {
|
43
51
|
if (typeof part === 'string') {
|
44
|
-
const textBBox =
|
52
|
+
const textBBox = Text.getTextDimens(part, this.style);
|
45
53
|
return textBBox.transformedBoundingBox(this.transform);
|
46
54
|
}
|
47
55
|
else {
|
@@ -138,7 +146,7 @@ export default class Text extends AbstractComponent {
|
|
138
146
|
style: serializableStyle,
|
139
147
|
};
|
140
148
|
}
|
141
|
-
static deserializeFromString(json
|
149
|
+
static deserializeFromString(json) {
|
142
150
|
const style = {
|
143
151
|
renderingStyle: styleFromJSON(json.style.renderingStyle),
|
144
152
|
size: json.style.size,
|
@@ -159,7 +167,8 @@ export default class Text extends AbstractComponent {
|
|
159
167
|
}
|
160
168
|
const transformData = json.transform;
|
161
169
|
const transform = new Mat33(...transformData);
|
162
|
-
return new Text(textObjects, transform, style
|
170
|
+
return new Text(textObjects, transform, style);
|
163
171
|
}
|
164
172
|
}
|
173
|
+
Text.textMeasuringCtx = null;
|
165
174
|
AbstractComponent.registerComponent(componentTypeId, (data) => Text.deserializeFromString(data));
|
@@ -11,6 +11,7 @@ export default class UnknownSVGObject extends AbstractComponent {
|
|
11
11
|
render(canvas: AbstractRenderer, _visibleRect?: Rect2): void;
|
12
12
|
intersects(lineSegment: LineSegment2): boolean;
|
13
13
|
protected applyTransformation(_affineTransfm: Mat33): void;
|
14
|
+
isSelectable(): boolean;
|
14
15
|
protected createClone(): AbstractComponent;
|
15
16
|
description(localization: ImageComponentLocalization): string;
|
16
17
|
protected serializeToJSON(): string | null;
|
@@ -312,15 +312,15 @@ export default class FreehandLineBuilder {
|
|
312
312
|
}
|
313
313
|
let enteringVec = this.lastExitingVec;
|
314
314
|
if (!enteringVec) {
|
315
|
-
let sampleIdx = Math.ceil(this.buffer.length /
|
316
|
-
if (sampleIdx === 0) {
|
315
|
+
let sampleIdx = Math.ceil(this.buffer.length / 2);
|
316
|
+
if (sampleIdx === 0 || sampleIdx >= this.buffer.length) {
|
317
317
|
sampleIdx = this.buffer.length - 1;
|
318
318
|
}
|
319
319
|
enteringVec = this.buffer[sampleIdx].minus(this.buffer[0]);
|
320
320
|
}
|
321
321
|
let exitingVec = this.computeExitingVec();
|
322
322
|
// Find the intersection between the entering vector and the exiting vector
|
323
|
-
const maxRelativeLength =
|
323
|
+
const maxRelativeLength = 2;
|
324
324
|
const segmentStart = this.buffer[0];
|
325
325
|
const segmentEnd = newPoint.pos;
|
326
326
|
const startEndDist = segmentEnd.minus(segmentStart).magnitude();
|
@@ -72,7 +72,7 @@ export default class SVGRenderer extends AbstractRenderer {
|
|
72
72
|
drawPath(pathSpec) {
|
73
73
|
var _a;
|
74
74
|
const style = pathSpec.style;
|
75
|
-
const path = Path.fromRenderable(pathSpec);
|
75
|
+
const path = Path.fromRenderable(pathSpec).transformedBy(this.getCanvasToScreenTransform());
|
76
76
|
// Try to extend the previous path, if possible
|
77
77
|
if (!style.fill.eq((_a = this.lastPathStyle) === null || _a === void 0 ? void 0 : _a.fill) || this.lastPathString.length === 0) {
|
78
78
|
this.addPathToSVG();
|
@@ -1,3 +1,7 @@
|
|
1
1
|
import loadExpectExtensions from './loadExpectExtensions';
|
2
2
|
loadExpectExtensions();
|
3
3
|
jest.useFakeTimers();
|
4
|
+
// jsdom doesn't support HTMLCanvasElement#getContext — it logs an error
|
5
|
+
// to the console. Make it return null so we can handle a non-existent Canvas
|
6
|
+
// at runtime (e.g. use something else, if available).
|
7
|
+
HTMLCanvasElement.prototype.getContext = () => null;
|
@@ -2,7 +2,6 @@ import { EditorEventType } from '../types';
|
|
2
2
|
import { coloris, init as colorisInit } from '@melloware/coloris';
|
3
3
|
import Color4 from '../Color4';
|
4
4
|
import { defaultToolbarLocalization } from './localization';
|
5
|
-
import { makeRedoIcon, makeUndoIcon } from './icons';
|
6
5
|
import SelectionTool from '../tools/SelectionTool/SelectionTool';
|
7
6
|
import PanZoomTool from '../tools/PanZoom';
|
8
7
|
import TextTool from '../tools/TextTool';
|
@@ -123,13 +122,13 @@ export default class HTMLToolbar {
|
|
123
122
|
undoRedoGroup.classList.add(`${toolbarCSSPrefix}buttonGroup`);
|
124
123
|
const undoButton = this.addActionButton({
|
125
124
|
label: this.localizationTable.undo,
|
126
|
-
icon: makeUndoIcon()
|
125
|
+
icon: this.editor.icons.makeUndoIcon()
|
127
126
|
}, () => {
|
128
127
|
this.editor.history.undo();
|
129
128
|
}, undoRedoGroup);
|
130
129
|
const redoButton = this.addActionButton({
|
131
130
|
label: this.localizationTable.redo,
|
132
|
-
icon: makeRedoIcon(),
|
131
|
+
icon: this.editor.icons.makeRedoIcon(),
|
133
132
|
}, () => {
|
134
133
|
this.editor.history.redo();
|
135
134
|
}, undoRedoGroup);
|
@@ -0,0 +1,24 @@
|
|
1
|
+
import Color4 from '../Color4';
|
2
|
+
import { ComponentBuilderFactory } from '../components/builders/types';
|
3
|
+
import { TextStyle } from '../components/Text';
|
4
|
+
import Pen from '../tools/Pen';
|
5
|
+
export default class IconProvider {
|
6
|
+
makeUndoIcon(): SVGSVGElement;
|
7
|
+
makeRedoIcon(mirror?: boolean): SVGSVGElement;
|
8
|
+
makeDropdownIcon(): SVGSVGElement;
|
9
|
+
makeEraserIcon(): SVGSVGElement;
|
10
|
+
makeSelectionIcon(): SVGSVGElement;
|
11
|
+
protected makeIconFromPath(pathData: string, fill?: string, strokeColor?: string, strokeWidth?: string): SVGSVGElement;
|
12
|
+
makeHandToolIcon(): SVGSVGElement;
|
13
|
+
makeTouchPanningIcon(): SVGSVGElement;
|
14
|
+
makeAllDevicePanningIcon(): SVGSVGElement;
|
15
|
+
makeZoomIcon: () => SVGSVGElement;
|
16
|
+
makeTextIcon(textStyle: TextStyle): SVGSVGElement;
|
17
|
+
makePenIcon(tipThickness: number, color: string | Color4): SVGSVGElement;
|
18
|
+
makeIconFromFactory(pen: Pen, factory: ComponentBuilderFactory): SVGSVGElement;
|
19
|
+
makePipetteIcon(color?: Color4): SVGSVGElement;
|
20
|
+
makeResizeViewportIcon(): SVGSVGElement;
|
21
|
+
makeDuplicateSelectionIcon(): SVGSVGElement;
|
22
|
+
makeDeleteSelectionIcon(): SVGSVGElement;
|
23
|
+
makeSaveIcon(): SVGSVGElement;
|
24
|
+
}
|