js-draw 0.2.2 → 0.3.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 +7 -0
- package/README.md +2 -2
- package/dist/bundle.js +1 -1
- package/dist/src/EditorImage.js +0 -1
- package/dist/src/components/builders/FreehandLineBuilder.js +18 -9
- package/dist/src/components/lib.d.ts +2 -0
- package/dist/src/components/lib.js +2 -0
- package/dist/src/lib.d.ts +5 -1
- package/dist/src/lib.js +5 -1
- package/dist/src/rendering/Display.js +2 -2
- package/dist/src/rendering/caching/RenderingCacheNode.js +2 -1
- package/dist/src/rendering/renderers/CanvasRenderer.js +6 -6
- package/dist/src/toolbar/HTMLToolbar.d.ts +4 -1
- package/dist/src/toolbar/HTMLToolbar.js +29 -31
- package/dist/src/toolbar/icons.d.ts +1 -1
- package/dist/src/toolbar/icons.js +4 -0
- package/dist/src/toolbar/lib.d.ts +3 -0
- package/dist/src/toolbar/lib.js +4 -0
- package/dist/src/toolbar/makeColorInput.js +2 -2
- package/dist/src/toolbar/types.d.ts +0 -4
- package/dist/src/toolbar/types.js +1 -5
- package/dist/src/toolbar/widgets/{EraserWidget.d.ts → EraserToolWidget.d.ts} +1 -1
- package/dist/src/toolbar/widgets/{EraserWidget.js → EraserToolWidget.js} +1 -1
- package/dist/src/toolbar/widgets/{PenWidget.d.ts → PenToolWidget.d.ts} +2 -3
- package/dist/src/toolbar/widgets/{PenWidget.js → PenToolWidget.js} +6 -7
- package/dist/src/toolbar/widgets/{SelectionWidget.d.ts → SelectionToolWidget.d.ts} +1 -1
- package/dist/src/toolbar/widgets/{SelectionWidget.js → SelectionToolWidget.js} +1 -1
- package/dist/src/toolbar/widgets/lib.d.ts +8 -0
- package/dist/src/toolbar/widgets/lib.js +8 -0
- package/dist/src/tools/BaseTool.d.ts +0 -2
- package/dist/src/tools/Eraser.d.ts +0 -2
- package/dist/src/tools/Eraser.js +0 -2
- package/dist/src/tools/PanZoom.d.ts +0 -2
- package/dist/src/tools/PanZoom.js +0 -2
- package/dist/src/tools/Pen.d.ts +8 -9
- package/dist/src/tools/Pen.js +15 -9
- package/dist/src/tools/PipetteTool.d.ts +0 -2
- package/dist/src/tools/PipetteTool.js +0 -2
- package/dist/src/tools/SelectionTool.d.ts +0 -2
- package/dist/src/tools/SelectionTool.js +4 -3
- package/dist/src/tools/TextTool.d.ts +0 -2
- package/dist/src/tools/TextTool.js +0 -2
- package/dist/src/tools/ToolController.d.ts +7 -11
- package/dist/src/tools/ToolController.js +28 -16
- package/dist/src/tools/ToolEnabledGroup.js +1 -1
- package/dist/src/tools/UndoRedoShortcut.d.ts +0 -2
- package/dist/src/tools/UndoRedoShortcut.js +3 -2
- package/dist/src/tools/lib.d.ts +12 -0
- package/dist/src/tools/lib.js +12 -0
- package/package.json +1 -1
- package/src/EditorImage.ts +0 -1
- package/src/components/builders/FreehandLineBuilder.ts +27 -17
- package/src/components/lib.ts +3 -0
- package/src/lib.ts +5 -1
- package/src/rendering/Display.ts +2 -2
- package/src/rendering/caching/RenderingCacheNode.ts +3 -1
- package/src/rendering/renderers/CanvasRenderer.ts +6 -6
- package/src/toolbar/HTMLToolbar.ts +34 -37
- package/src/toolbar/icons.ts +5 -1
- package/src/toolbar/lib.ts +4 -0
- package/src/toolbar/makeColorInput.ts +1 -2
- package/src/toolbar/types.ts +0 -4
- package/src/toolbar/widgets/{EraserWidget.ts → EraserToolWidget.ts} +1 -1
- package/src/toolbar/widgets/{PenWidget.ts → PenToolWidget.ts} +10 -9
- package/src/toolbar/widgets/{SelectionWidget.ts → SelectionToolWidget.ts} +1 -1
- package/src/toolbar/widgets/lib.ts +10 -0
- package/src/tools/BaseTool.ts +0 -3
- package/src/tools/Eraser.ts +0 -2
- package/src/tools/PanZoom.ts +0 -2
- package/src/tools/Pen.ts +21 -15
- package/src/tools/PipetteTool.ts +0 -3
- package/src/tools/SelectionTool.test.ts +1 -2
- package/src/tools/SelectionTool.ts +5 -3
- package/src/tools/TextTool.ts +0 -2
- package/src/tools/ToolController.ts +34 -17
- package/src/tools/ToolEnabledGroup.ts +1 -1
- package/src/tools/UndoRedoShortcut.ts +4 -4
- package/src/tools/lib.ts +17 -0
package/dist/src/tools/Pen.js
CHANGED
@@ -3,7 +3,6 @@ import { PointerDevice } from '../Pointer';
|
|
3
3
|
import { makeFreehandLineBuilder } from '../components/builders/FreehandLineBuilder';
|
4
4
|
import { EditorEventType } from '../types';
|
5
5
|
import BaseTool from './BaseTool';
|
6
|
-
import { ToolType } from './ToolController';
|
7
6
|
export default class Pen extends BaseTool {
|
8
7
|
constructor(editor, description, style) {
|
9
8
|
super(editor.notifier, description);
|
@@ -12,12 +11,12 @@ export default class Pen extends BaseTool {
|
|
12
11
|
this.builder = null;
|
13
12
|
this.builderFactory = makeFreehandLineBuilder;
|
14
13
|
this.lastPoint = null;
|
15
|
-
this.kind = ToolType.Pen;
|
16
14
|
}
|
17
15
|
getPressureMultiplier() {
|
18
16
|
return 1 / this.editor.viewport.getScaleFactor() * this.style.thickness;
|
19
17
|
}
|
20
|
-
|
18
|
+
// Converts a `pointer` to a `StrokeDataPoint`.
|
19
|
+
toStrokePoint(pointer) {
|
21
20
|
var _a;
|
22
21
|
const minPressure = 0.3;
|
23
22
|
let pressure = Math.max((_a = pointer.pressure) !== null && _a !== void 0 ? _a : 1.0, minPressure);
|
@@ -35,11 +34,13 @@ export default class Pen extends BaseTool {
|
|
35
34
|
time: pointer.timeStamp,
|
36
35
|
};
|
37
36
|
}
|
37
|
+
// Displays the stroke that is currently being built with the display's `wetInkRenderer`.
|
38
38
|
previewStroke() {
|
39
39
|
var _a;
|
40
40
|
this.editor.clearWetInk();
|
41
41
|
(_a = this.builder) === null || _a === void 0 ? void 0 : _a.preview(this.editor.display.getWetInkRenderer());
|
42
42
|
}
|
43
|
+
// Throws if no stroke builder exists.
|
43
44
|
addPointToStroke(point) {
|
44
45
|
if (!this.builder) {
|
45
46
|
throw new Error('No stroke is currently being generated.');
|
@@ -49,17 +50,22 @@ export default class Pen extends BaseTool {
|
|
49
50
|
this.previewStroke();
|
50
51
|
}
|
51
52
|
onPointerDown({ current, allPointers }) {
|
52
|
-
|
53
|
-
|
53
|
+
const isEraser = current.device === PointerDevice.Eraser;
|
54
|
+
let anyDeviceIsStylus = false;
|
55
|
+
for (const pointer of allPointers) {
|
56
|
+
if (pointer.device === PointerDevice.Pen) {
|
57
|
+
anyDeviceIsStylus = true;
|
58
|
+
break;
|
59
|
+
}
|
54
60
|
}
|
55
|
-
if (allPointers.length === 1
|
56
|
-
this.builder = this.builderFactory(this.
|
61
|
+
if ((allPointers.length === 1 && !isEraser) || anyDeviceIsStylus) {
|
62
|
+
this.builder = this.builderFactory(this.toStrokePoint(current), this.editor.viewport);
|
57
63
|
return true;
|
58
64
|
}
|
59
65
|
return false;
|
60
66
|
}
|
61
67
|
onPointerMove({ current }) {
|
62
|
-
this.addPointToStroke(this.
|
68
|
+
this.addPointToStroke(this.toStrokePoint(current));
|
63
69
|
}
|
64
70
|
onPointerUp({ current }) {
|
65
71
|
var _a, _b;
|
@@ -67,7 +73,7 @@ export default class Pen extends BaseTool {
|
|
67
73
|
return;
|
68
74
|
}
|
69
75
|
// onPointerUp events can have zero pressure. Use the last pressure instead.
|
70
|
-
const currentPoint = this.
|
76
|
+
const currentPoint = this.toStrokePoint(current);
|
71
77
|
const strokePoint = Object.assign(Object.assign({}, currentPoint), { width: (_b = (_a = this.lastPoint) === null || _a === void 0 ? void 0 : _a.width) !== null && _b !== void 0 ? _b : currentPoint.width });
|
72
78
|
this.addPointToStroke(strokePoint);
|
73
79
|
if (this.builder && current.isPrimary) {
|
@@ -2,11 +2,9 @@ import Color4 from '../Color4';
|
|
2
2
|
import Editor from '../Editor';
|
3
3
|
import { PointerEvt } from '../types';
|
4
4
|
import BaseTool from './BaseTool';
|
5
|
-
import { ToolType } from './ToolController';
|
6
5
|
declare type ColorListener = (color: Color4 | null) => void;
|
7
6
|
export default class PipetteTool extends BaseTool {
|
8
7
|
private editor;
|
9
|
-
kind: ToolType;
|
10
8
|
private colorPreviewListener;
|
11
9
|
private colorSelectListener;
|
12
10
|
constructor(editor: Editor, description: string);
|
@@ -1,11 +1,9 @@
|
|
1
1
|
// @internal @packageDocumentation
|
2
2
|
import BaseTool from './BaseTool';
|
3
|
-
import { ToolType } from './ToolController';
|
4
3
|
export default class PipetteTool extends BaseTool {
|
5
4
|
constructor(editor, description) {
|
6
5
|
super(editor.notifier, description);
|
7
6
|
this.editor = editor;
|
8
|
-
this.kind = ToolType.Pipette;
|
9
7
|
this.colorPreviewListener = null;
|
10
8
|
this.colorSelectListener = null;
|
11
9
|
}
|
@@ -5,7 +5,6 @@ import Rect2 from '../math/Rect2';
|
|
5
5
|
import { Point2, Vec2 } from '../math/Vec2';
|
6
6
|
import { KeyPressEvent, KeyUpEvent, PointerEvt } from '../types';
|
7
7
|
import BaseTool from './BaseTool';
|
8
|
-
import { ToolType } from './ToolController';
|
9
8
|
declare class Selection {
|
10
9
|
startPoint: Point2;
|
11
10
|
private editor;
|
@@ -43,7 +42,6 @@ export default class SelectionTool extends BaseTool {
|
|
43
42
|
private handleOverlay;
|
44
43
|
private prevSelectionBox;
|
45
44
|
private selectionBox;
|
46
|
-
readonly kind: ToolType;
|
47
45
|
constructor(editor: Editor, description: string);
|
48
46
|
onPointerDown(event: PointerEvt): boolean;
|
49
47
|
onPointerMove(event: PointerEvt): void;
|
@@ -1,3 +1,6 @@
|
|
1
|
+
// Allows users to select/transform portions of the `EditorImage`.
|
2
|
+
// With respect to `extend`ing, `SelectionTool` is not stable.
|
3
|
+
// @packageDocumentation
|
1
4
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
2
5
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
3
6
|
return new (P || (P = Promise))(function (resolve, reject) {
|
@@ -11,13 +14,11 @@ var _a;
|
|
11
14
|
import Duplicate from '../commands/Duplicate';
|
12
15
|
import Erase from '../commands/Erase';
|
13
16
|
import Mat33 from '../math/Mat33';
|
14
|
-
// import Mat33 from "../geometry/Mat33";
|
15
17
|
import Rect2 from '../math/Rect2';
|
16
18
|
import { Vec2 } from '../math/Vec2';
|
17
19
|
import { EditorEventType } from '../types';
|
18
20
|
import Viewport from '../Viewport';
|
19
21
|
import BaseTool from './BaseTool';
|
20
|
-
import { ToolType } from './ToolController';
|
21
22
|
import SerializableCommand from '../commands/SerializableCommand';
|
22
23
|
const handleScreenSize = 30;
|
23
24
|
const styles = `
|
@@ -409,11 +410,11 @@ Selection.ApplyTransformationCommand = class extends SerializableCommand {
|
|
409
410
|
return localizationTable.transformedElements(this.currentTransfmCommands.length);
|
410
411
|
}
|
411
412
|
};
|
413
|
+
// {@inheritDoc SelectionTool!}
|
412
414
|
export default class SelectionTool extends BaseTool {
|
413
415
|
constructor(editor, description) {
|
414
416
|
super(editor.notifier, description);
|
415
417
|
this.editor = editor;
|
416
|
-
this.kind = ToolType.Selection;
|
417
418
|
this.handleOverlay = document.createElement('div');
|
418
419
|
editor.createHTMLOverlay(this.handleOverlay);
|
419
420
|
editor.addStyleSheet(styles);
|
@@ -4,11 +4,9 @@ import Editor from '../Editor';
|
|
4
4
|
import { PointerEvt } from '../types';
|
5
5
|
import BaseTool from './BaseTool';
|
6
6
|
import { ToolLocalization } from './localization';
|
7
|
-
import { ToolType } from './ToolController';
|
8
7
|
export default class TextTool extends BaseTool {
|
9
8
|
private editor;
|
10
9
|
private localizationTable;
|
11
|
-
kind: ToolType;
|
12
10
|
private textStyle;
|
13
11
|
private textEditOverlay;
|
14
12
|
private textInputElem;
|
@@ -5,14 +5,12 @@ import Mat33 from '../math/Mat33';
|
|
5
5
|
import { PointerDevice } from '../Pointer';
|
6
6
|
import { EditorEventType } from '../types';
|
7
7
|
import BaseTool from './BaseTool';
|
8
|
-
import { ToolType } from './ToolController';
|
9
8
|
const overlayCssClass = 'textEditorOverlay';
|
10
9
|
export default class TextTool extends BaseTool {
|
11
10
|
constructor(editor, description, localizationTable) {
|
12
11
|
super(editor.notifier, description);
|
13
12
|
this.editor = editor;
|
14
13
|
this.localizationTable = localizationTable;
|
15
|
-
this.kind = ToolType.Text;
|
16
14
|
this.textInputElem = null;
|
17
15
|
this.textTargetPosition = null;
|
18
16
|
this.textMeasuringCtx = null;
|
@@ -1,21 +1,17 @@
|
|
1
1
|
import { InputEvt } from '../types';
|
2
2
|
import Editor from '../Editor';
|
3
3
|
import BaseTool from './BaseTool';
|
4
|
+
import ToolEnabledGroup from './ToolEnabledGroup';
|
4
5
|
import { ToolLocalization } from './localization';
|
5
|
-
export declare enum ToolType {
|
6
|
-
Pen = 0,
|
7
|
-
Selection = 1,
|
8
|
-
Eraser = 2,
|
9
|
-
PanZoom = 3,
|
10
|
-
Text = 4,
|
11
|
-
UndoRedoShortcut = 5,
|
12
|
-
Pipette = 6,
|
13
|
-
Other = 7
|
14
|
-
}
|
15
6
|
export default class ToolController {
|
16
7
|
private tools;
|
17
8
|
private activeTool;
|
9
|
+
private primaryToolGroup;
|
10
|
+
/** @internal */
|
18
11
|
constructor(editor: Editor, localization: ToolLocalization);
|
12
|
+
setTools(tools: BaseTool[], primaryToolGroup?: ToolEnabledGroup): void;
|
13
|
+
addPrimaryTool(tool: BaseTool): void;
|
14
|
+
addTool(tool: BaseTool): void;
|
19
15
|
dispatchInputEvent(event: InputEvt): boolean;
|
20
|
-
getMatchingTools(
|
16
|
+
getMatchingTools<Type extends BaseTool>(type: new (...args: any[]) => Type): Type[];
|
21
17
|
}
|
@@ -8,20 +8,12 @@ import Color4 from '../Color4';
|
|
8
8
|
import UndoRedoShortcut from './UndoRedoShortcut';
|
9
9
|
import TextTool from './TextTool';
|
10
10
|
import PipetteTool from './PipetteTool';
|
11
|
-
export var ToolType;
|
12
|
-
(function (ToolType) {
|
13
|
-
ToolType[ToolType["Pen"] = 0] = "Pen";
|
14
|
-
ToolType[ToolType["Selection"] = 1] = "Selection";
|
15
|
-
ToolType[ToolType["Eraser"] = 2] = "Eraser";
|
16
|
-
ToolType[ToolType["PanZoom"] = 3] = "PanZoom";
|
17
|
-
ToolType[ToolType["Text"] = 4] = "Text";
|
18
|
-
ToolType[ToolType["UndoRedoShortcut"] = 5] = "UndoRedoShortcut";
|
19
|
-
ToolType[ToolType["Pipette"] = 6] = "Pipette";
|
20
|
-
ToolType[ToolType["Other"] = 7] = "Other";
|
21
|
-
})(ToolType || (ToolType = {}));
|
22
11
|
export default class ToolController {
|
12
|
+
/** @internal */
|
23
13
|
constructor(editor, localization) {
|
24
|
-
|
14
|
+
this.activeTool = null;
|
15
|
+
const primaryToolGroup = new ToolEnabledGroup();
|
16
|
+
this.primaryToolGroup = primaryToolGroup;
|
25
17
|
const panZoomTool = new PanZoom(editor, PanZoomMode.TwoFingerTouchGestures | PanZoomMode.RightClickDrags, localization.touchPanTool);
|
26
18
|
const keyboardPanZoomTool = new PanZoom(editor, PanZoomMode.Keyboard, localization.keyboardPanZoom);
|
27
19
|
const primaryPenTool = new Pen(editor, localization.penTool(1), { color: Color4.purple, thickness: 16 });
|
@@ -30,7 +22,7 @@ export default class ToolController {
|
|
30
22
|
new Eraser(editor, localization.eraserTool),
|
31
23
|
// Three pens
|
32
24
|
primaryPenTool,
|
33
|
-
new Pen(editor, localization.penTool(2), { color: Color4.clay, thickness:
|
25
|
+
new Pen(editor, localization.penTool(2), { color: Color4.clay, thickness: 4 }),
|
34
26
|
// Highlighter-like pen with width=64
|
35
27
|
new Pen(editor, localization.penTool(3), { color: Color4.ofRGBA(1, 1, 0, 0.5), thickness: 64 }),
|
36
28
|
new TextTool(editor, localization.textTool, localization),
|
@@ -42,7 +34,7 @@ export default class ToolController {
|
|
42
34
|
keyboardPanZoomTool,
|
43
35
|
new UndoRedoShortcut(editor),
|
44
36
|
];
|
45
|
-
primaryTools.forEach(tool => tool.setToolGroup(
|
37
|
+
primaryTools.forEach(tool => tool.setToolGroup(primaryToolGroup));
|
46
38
|
panZoomTool.setEnabled(true);
|
47
39
|
primaryPenTool.setEnabled(true);
|
48
40
|
editor.notifier.on(EditorEventType.ToolEnabled, event => {
|
@@ -57,6 +49,26 @@ export default class ToolController {
|
|
57
49
|
});
|
58
50
|
this.activeTool = null;
|
59
51
|
}
|
52
|
+
// Replaces the current set of tools with `tools`. This should only be done before
|
53
|
+
// the creation of the app's toolbar (if using `HTMLToolbar`).
|
54
|
+
setTools(tools, primaryToolGroup) {
|
55
|
+
this.tools = tools;
|
56
|
+
this.primaryToolGroup = primaryToolGroup !== null && primaryToolGroup !== void 0 ? primaryToolGroup : new ToolEnabledGroup();
|
57
|
+
}
|
58
|
+
// Add a tool that acts like one of the primary tools (only one primary tool can be enabled at a time).
|
59
|
+
// This should be called before creating the app's toolbar.
|
60
|
+
addPrimaryTool(tool) {
|
61
|
+
tool.setToolGroup(this.primaryToolGroup);
|
62
|
+
if (tool.isEnabled()) {
|
63
|
+
this.primaryToolGroup.notifyEnabled(tool);
|
64
|
+
}
|
65
|
+
this.addTool(tool);
|
66
|
+
}
|
67
|
+
// Add a tool to the end of this' tool list (the added tool receives events after tools already added to this).
|
68
|
+
// This should be called before creating the app's toolbar.
|
69
|
+
addTool(tool) {
|
70
|
+
this.tools.push(tool);
|
71
|
+
}
|
60
72
|
// Returns true if the event was handled
|
61
73
|
dispatchInputEvent(event) {
|
62
74
|
var _a, _b;
|
@@ -116,7 +128,7 @@ export default class ToolController {
|
|
116
128
|
}
|
117
129
|
return handled;
|
118
130
|
}
|
119
|
-
getMatchingTools(
|
120
|
-
return this.tools.filter(tool => tool
|
131
|
+
getMatchingTools(type) {
|
132
|
+
return this.tools.filter(tool => tool instanceof type);
|
121
133
|
}
|
122
134
|
}
|
@@ -1,10 +1,8 @@
|
|
1
1
|
import Editor from '../Editor';
|
2
2
|
import { KeyPressEvent } from '../types';
|
3
3
|
import BaseTool from './BaseTool';
|
4
|
-
import { ToolType } from './ToolController';
|
5
4
|
export default class UndoRedoShortcut extends BaseTool {
|
6
5
|
private editor;
|
7
|
-
kind: ToolType.UndoRedoShortcut;
|
8
6
|
constructor(editor: Editor);
|
9
7
|
onKeyPress({ key, ctrlKey }: KeyPressEvent): boolean;
|
10
8
|
}
|
@@ -1,10 +1,11 @@
|
|
1
|
+
// Handles ctrl+Z, ctrl+Shift+Z keyboard shortcuts.
|
2
|
+
// @packageDocumentation
|
1
3
|
import BaseTool from './BaseTool';
|
2
|
-
|
4
|
+
// {@inheritDoc UndoRedoShortcut!}
|
3
5
|
export default class UndoRedoShortcut extends BaseTool {
|
4
6
|
constructor(editor) {
|
5
7
|
super(editor.notifier, editor.localization.undoRedoTool);
|
6
8
|
this.editor = editor;
|
7
|
-
this.kind = ToolType.UndoRedoShortcut;
|
8
9
|
}
|
9
10
|
// Activate undo/redo
|
10
11
|
onKeyPress({ key, ctrlKey }) {
|
@@ -0,0 +1,12 @@
|
|
1
|
+
/**
|
2
|
+
* @packageDocumentation
|
3
|
+
*/
|
4
|
+
export { default as BaseTool } from './BaseTool';
|
5
|
+
export { default as ToolController } from './ToolController';
|
6
|
+
export { default as ToolEnabledGroup } from './ToolEnabledGroup';
|
7
|
+
export { default as UndoRedoShortcut } from './UndoRedoShortcut';
|
8
|
+
export { default as PanZoomTool, PanZoomMode } from './PanZoom';
|
9
|
+
export { default as PenTool, PenStyle } from './Pen';
|
10
|
+
export { default as TextTool } from './TextTool';
|
11
|
+
export { default as SelectionTool } from './SelectionTool';
|
12
|
+
export { default as EraserTool } from './Eraser';
|
@@ -0,0 +1,12 @@
|
|
1
|
+
/**
|
2
|
+
* @packageDocumentation
|
3
|
+
*/
|
4
|
+
export { default as BaseTool } from './BaseTool';
|
5
|
+
export { default as ToolController } from './ToolController';
|
6
|
+
export { default as ToolEnabledGroup } from './ToolEnabledGroup';
|
7
|
+
export { default as UndoRedoShortcut } from './UndoRedoShortcut';
|
8
|
+
export { default as PanZoomTool, PanZoomMode } from './PanZoom';
|
9
|
+
export { default as PenTool } from './Pen';
|
10
|
+
export { default as TextTool } from './TextTool';
|
11
|
+
export { default as SelectionTool } from './SelectionTool';
|
12
|
+
export { default as EraserTool } from './Eraser';
|
package/package.json
CHANGED
package/src/EditorImage.ts
CHANGED
@@ -388,7 +388,6 @@ export class ImageNode {
|
|
388
388
|
}
|
389
389
|
|
390
390
|
public render(renderer: AbstractRenderer, visibleRect: Rect2) {
|
391
|
-
// Don't render components that are < 0.1% of the viewport.
|
392
391
|
const leaves = this.getLeavesIntersectingRegion(visibleRect, rect => renderer.isTooSmallToRender(rect));
|
393
392
|
sortLeavesByZIndex(leaves);
|
394
393
|
|
@@ -2,7 +2,7 @@ import { Bezier } from 'bezier-js';
|
|
2
2
|
import AbstractRenderer, { RenderablePathSpec } from '../../rendering/renderers/AbstractRenderer';
|
3
3
|
import { Point2, Vec2 } from '../../math/Vec2';
|
4
4
|
import Rect2 from '../../math/Rect2';
|
5
|
-
import { LinePathCommand, PathCommandType, QuadraticBezierPathCommand } from '../../math/Path';
|
5
|
+
import { LinePathCommand, PathCommand, PathCommandType, QuadraticBezierPathCommand } from '../../math/Path';
|
6
6
|
import LineSegment2 from '../../math/LineSegment2';
|
7
7
|
import Stroke from '../Stroke';
|
8
8
|
import Viewport from '../../Viewport';
|
@@ -13,9 +13,8 @@ import RenderingStyle from '../../rendering/RenderingStyle';
|
|
13
13
|
export const makeFreehandLineBuilder: ComponentBuilderFactory = (initialPoint: StrokeDataPoint, viewport: Viewport) => {
|
14
14
|
// Don't smooth if input is more than ± 7 pixels from the true curve, do smooth if
|
15
15
|
// less than ± 2 px from the curve.
|
16
|
-
const
|
17
|
-
const
|
18
|
-
const minSmoothingDist = canvasTransform.transformVec3(Vec2.unitX).magnitude() * 2;
|
16
|
+
const maxSmoothingDist = viewport.getSizeOfPixelOnCanvas() * 7;
|
17
|
+
const minSmoothingDist = viewport.getSizeOfPixelOnCanvas() * 2;
|
19
18
|
|
20
19
|
return new FreehandLineBuilder(
|
21
20
|
initialPoint, minSmoothingDist, maxSmoothingDist
|
@@ -24,16 +23,16 @@ export const makeFreehandLineBuilder: ComponentBuilderFactory = (initialPoint: S
|
|
24
23
|
|
25
24
|
type CurrentSegmentToPathResult = {
|
26
25
|
upperCurve: QuadraticBezierPathCommand,
|
27
|
-
lowerToUpperConnector:
|
28
|
-
upperToLowerConnector:
|
26
|
+
lowerToUpperConnector: PathCommand,
|
27
|
+
upperToLowerConnector: PathCommand,
|
29
28
|
lowerCurve: QuadraticBezierPathCommand,
|
30
29
|
};
|
31
30
|
|
32
31
|
// Handles stroke smoothing and creates Strokes from user/stylus input.
|
33
32
|
export default class FreehandLineBuilder implements ComponentBuilder {
|
34
33
|
private isFirstSegment: boolean = true;
|
35
|
-
private pathStartConnector:
|
36
|
-
private mostRecentConnector:
|
34
|
+
private pathStartConnector: PathCommand|null = null;
|
35
|
+
private mostRecentConnector: PathCommand|null = null;
|
37
36
|
|
38
37
|
// Beginning of the list of lower parts
|
39
38
|
// ↓
|
@@ -53,7 +52,7 @@ export default class FreehandLineBuilder implements ComponentBuilder {
|
|
53
52
|
|
54
53
|
private buffer: Point2[];
|
55
54
|
private lastPoint: StrokeDataPoint;
|
56
|
-
private lastExitingVec: Vec2;
|
55
|
+
private lastExitingVec: Vec2|null = null;
|
57
56
|
private currentCurve: Bezier|null = null;
|
58
57
|
private curveStartWidth: number;
|
59
58
|
private curveEndWidth: number;
|
@@ -79,6 +78,7 @@ export default class FreehandLineBuilder implements ComponentBuilder {
|
|
79
78
|
this.buffer = [this.startPoint.pos];
|
80
79
|
this.momentum = Vec2.zero;
|
81
80
|
this.currentCurve = null;
|
81
|
+
this.curveStartWidth = startPoint.width;
|
82
82
|
|
83
83
|
this.bbox = new Rect2(this.startPoint.pos.x, this.startPoint.pos.y, 0, 0);
|
84
84
|
}
|
@@ -96,8 +96,8 @@ export default class FreehandLineBuilder implements ComponentBuilder {
|
|
96
96
|
private previewPath(): RenderablePathSpec|null {
|
97
97
|
let upperPath: QuadraticBezierPathCommand[];
|
98
98
|
let lowerPath: QuadraticBezierPathCommand[];
|
99
|
-
let lowerToUpperCap:
|
100
|
-
let pathStartConnector:
|
99
|
+
let lowerToUpperCap: PathCommand;
|
100
|
+
let pathStartConnector: PathCommand;
|
101
101
|
if (this.currentCurve) {
|
102
102
|
const { upperCurve, lowerToUpperConnector, upperToLowerConnector, lowerCurve } = this.currentSegmentToPath();
|
103
103
|
upperPath = this.upperSegments.concat(upperCurve);
|
@@ -180,7 +180,13 @@ export default class FreehandLineBuilder implements ComponentBuilder {
|
|
180
180
|
}
|
181
181
|
|
182
182
|
private roundPoint(point: Point2): Point2 {
|
183
|
-
|
183
|
+
let minFit = Math.min(this.minFitAllowed, this.curveStartWidth / 2);
|
184
|
+
|
185
|
+
if (minFit < 1e-10) {
|
186
|
+
minFit = this.minFitAllowed;
|
187
|
+
}
|
188
|
+
|
189
|
+
return Viewport.roundPoint(point, minFit);
|
184
190
|
}
|
185
191
|
|
186
192
|
private finalizeCurrentCurve() {
|
@@ -317,11 +323,14 @@ export default class FreehandLineBuilder implements ComponentBuilder {
|
|
317
323
|
);
|
318
324
|
};
|
319
325
|
|
320
|
-
const
|
321
|
-
|
326
|
+
const boundariesIntersect = () => {
|
327
|
+
const upperBoundary = computeBoundaryCurve(1, halfVec);
|
328
|
+
const lowerBoundary = computeBoundaryCurve(-1, halfVec);
|
329
|
+
return upperBoundary.intersects(lowerBoundary).length > 0;
|
330
|
+
};
|
322
331
|
|
323
332
|
// If the boundaries have two intersections, increasing the half vector's length could fix this.
|
324
|
-
if (
|
333
|
+
if (boundariesIntersect()) {
|
325
334
|
halfVec = halfVec.times(2);
|
326
335
|
}
|
327
336
|
|
@@ -372,7 +381,7 @@ export default class FreehandLineBuilder implements ComponentBuilder {
|
|
372
381
|
return;
|
373
382
|
}
|
374
383
|
|
375
|
-
const threshold = Math.min(this.lastPoint.width, newPoint.width) /
|
384
|
+
const threshold = Math.min(this.lastPoint.width, newPoint.width) / 3;
|
376
385
|
const shouldSnapToInitial = this.startPoint.pos.minus(newPoint.pos).magnitude() < threshold
|
377
386
|
&& this.isFirstSegment;
|
378
387
|
|
@@ -493,7 +502,8 @@ export default class FreehandLineBuilder implements ComponentBuilder {
|
|
493
502
|
return true;
|
494
503
|
};
|
495
504
|
|
496
|
-
|
505
|
+
const approxCurveLen = controlPoint.minus(segmentStart).magnitude() + segmentEnd.minus(controlPoint).magnitude();
|
506
|
+
if (this.buffer.length > 3 && approxCurveLen > this.curveEndWidth / 2) {
|
497
507
|
if (!curveMatchesPoints(this.currentCurve)) {
|
498
508
|
// Use a curve that better fits the points
|
499
509
|
this.currentCurve = prevCurve;
|
package/src/components/lib.ts
CHANGED
package/src/lib.ts
CHANGED
@@ -14,7 +14,8 @@
|
|
14
14
|
*/
|
15
15
|
|
16
16
|
import Editor from './Editor';
|
17
|
-
export {
|
17
|
+
export { default as EditorImage } from './EditorImage';
|
18
|
+
export * from './types';
|
18
19
|
export { default as getLocalizationTable } from './localizations/getLocalizationTable';
|
19
20
|
export * from './localization';
|
20
21
|
|
@@ -22,6 +23,9 @@ export { default as Color4 } from './Color4';
|
|
22
23
|
export * from './math/lib';
|
23
24
|
export * from './components/lib';
|
24
25
|
export * from './commands/lib';
|
26
|
+
export * from './tools/lib';
|
27
|
+
export * from './toolbar/lib';
|
28
|
+
export { default as Pointer, PointerDevice } from './Pointer';
|
25
29
|
export { default as HTMLToolbar } from './toolbar/HTMLToolbar';
|
26
30
|
|
27
31
|
export { Editor };
|
package/src/rendering/Display.ts
CHANGED
@@ -76,8 +76,8 @@ export default class Display {
|
|
76
76
|
return this.dryInkRenderer.canRenderFromWithoutDataLoss(renderer);
|
77
77
|
},
|
78
78
|
blockResolution: cacheBlockResolution,
|
79
|
-
cacheSize:
|
80
|
-
maxScale: 1.
|
79
|
+
cacheSize: 600 * 600 * 4 * 120,
|
80
|
+
maxScale: 1.4,
|
81
81
|
minComponentsPerCache: 45,
|
82
82
|
minComponentsToUseCache: 105,
|
83
83
|
});
|
@@ -221,11 +221,13 @@ export default class RenderingCacheNode {
|
|
221
221
|
}
|
222
222
|
} else {
|
223
223
|
// Determine whether we already have rendered the items
|
224
|
+
const tooSmallToRender = (rect: Rect2) => rect.w / this.region.w < 1 / this.cacheState.props.blockResolution.x;
|
225
|
+
|
224
226
|
const leaves = [];
|
225
227
|
for (const item of items) {
|
226
228
|
leaves.push(
|
227
229
|
...item.getLeavesIntersectingRegion(
|
228
|
-
this.region,
|
230
|
+
this.region, tooSmallToRender,
|
229
231
|
)
|
230
232
|
);
|
231
233
|
}
|
@@ -59,13 +59,13 @@ export default class CanvasRenderer extends AbstractRenderer {
|
|
59
59
|
// Set parameters for lower/higher quality rendering
|
60
60
|
public setDraftMode(draftMode: boolean) {
|
61
61
|
if (draftMode) {
|
62
|
-
this.minSquareCurveApproxDist =
|
63
|
-
this.minRenderSizeBothDimens =
|
64
|
-
this.minRenderSizeAnyDimen =
|
62
|
+
this.minSquareCurveApproxDist = 9;
|
63
|
+
this.minRenderSizeBothDimens = 2;
|
64
|
+
this.minRenderSizeAnyDimen = 0.5;
|
65
65
|
} else {
|
66
|
-
this.minSquareCurveApproxDist =
|
67
|
-
this.minRenderSizeBothDimens = 0.
|
68
|
-
this.minRenderSizeAnyDimen =
|
66
|
+
this.minSquareCurveApproxDist = 0.5;
|
67
|
+
this.minRenderSizeBothDimens = 0.3;
|
68
|
+
this.minRenderSizeAnyDimen = 1e-5;
|
69
69
|
}
|
70
70
|
}
|
71
71
|
|