js-draw 0.1.11 → 0.2.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/.eslintrc.js +1 -0
- package/.firebaserc +5 -0
- package/.github/workflows/firebase-hosting-merge.yml +25 -0
- package/.github/workflows/firebase-hosting-pull-request.yml +22 -0
- package/.github/workflows/github-pages.yml +52 -0
- package/CHANGELOG.md +13 -0
- package/README.md +11 -6
- package/dist/bundle.js +1 -1
- package/dist/src/Color4.d.ts +19 -0
- package/dist/src/Color4.js +24 -3
- package/dist/src/Editor.d.ts +133 -4
- package/dist/src/Editor.js +124 -27
- package/dist/src/EditorImage.d.ts +8 -3
- package/dist/src/EditorImage.js +42 -26
- package/dist/src/EventDispatcher.d.ts +18 -0
- package/dist/src/EventDispatcher.js +19 -4
- package/dist/src/Pointer.d.ts +1 -1
- package/dist/src/Pointer.js +4 -3
- package/dist/src/SVGLoader.d.ts +1 -1
- package/dist/src/SVGLoader.js +14 -6
- package/dist/src/UndoRedoHistory.js +15 -2
- package/dist/src/Viewport.d.ts +8 -25
- package/dist/src/Viewport.js +18 -10
- package/dist/src/bundle/bundled.d.ts +1 -2
- package/dist/src/bundle/bundled.js +1 -2
- package/dist/src/commands/Command.d.ts +2 -2
- package/dist/src/commands/Command.js +4 -4
- package/dist/src/commands/Duplicate.d.ts +2 -2
- package/dist/src/commands/Duplicate.js +4 -5
- package/dist/src/commands/Erase.d.ts +2 -2
- package/dist/src/commands/Erase.js +7 -6
- package/dist/src/commands/SerializableCommand.d.ts +4 -5
- package/dist/src/commands/SerializableCommand.js +12 -4
- package/dist/src/commands/invertCommand.d.ts +4 -0
- package/dist/src/commands/invertCommand.js +44 -0
- package/dist/src/commands/lib.d.ts +6 -0
- package/dist/src/commands/lib.js +6 -0
- package/dist/src/commands/localization.d.ts +2 -1
- package/dist/src/commands/localization.js +1 -0
- package/dist/src/components/AbstractComponent.d.ts +16 -11
- package/dist/src/components/AbstractComponent.js +28 -17
- package/dist/src/components/SVGGlobalAttributesObject.d.ts +4 -4
- package/dist/src/components/SVGGlobalAttributesObject.js +8 -2
- package/dist/src/components/Stroke.d.ts +16 -6
- package/dist/src/components/Stroke.js +12 -9
- package/dist/src/components/Text.d.ts +5 -5
- package/dist/src/components/Text.js +9 -9
- package/dist/src/components/UnknownSVGObject.d.ts +4 -4
- package/dist/src/components/UnknownSVGObject.js +7 -2
- package/dist/src/components/builders/ArrowBuilder.d.ts +1 -1
- package/dist/src/components/builders/ArrowBuilder.js +1 -1
- package/dist/src/components/builders/FreehandLineBuilder.d.ts +8 -3
- package/dist/src/components/builders/FreehandLineBuilder.js +142 -71
- package/dist/src/components/builders/LineBuilder.d.ts +1 -1
- package/dist/src/components/builders/LineBuilder.js +1 -1
- package/dist/src/components/builders/RectangleBuilder.d.ts +1 -1
- package/dist/src/components/builders/RectangleBuilder.js +3 -3
- package/dist/src/components/builders/types.d.ts +1 -1
- package/dist/src/components/lib.d.ts +4 -0
- package/dist/src/components/lib.js +4 -0
- package/dist/src/lib.d.ts +25 -0
- package/dist/src/lib.js +25 -0
- package/dist/src/localization.d.ts +1 -0
- package/dist/src/localization.js +5 -1
- package/dist/src/localizations/es.js +1 -1
- package/dist/src/{geometry → math}/LineSegment2.d.ts +0 -0
- package/dist/src/{geometry → math}/LineSegment2.js +0 -0
- package/dist/src/math/Mat33.d.ts +78 -0
- package/dist/src/{geometry → math}/Mat33.js +48 -20
- package/dist/src/{geometry → math}/Path.d.ts +2 -1
- package/dist/src/{geometry → math}/Path.js +59 -52
- package/dist/src/{geometry → math}/Rect2.d.ts +2 -2
- package/dist/src/{geometry → math}/Rect2.js +0 -0
- package/dist/src/{geometry → math}/Vec2.d.ts +0 -0
- package/dist/src/{geometry → math}/Vec2.js +0 -0
- package/dist/src/math/Vec3.d.ts +96 -0
- package/dist/src/{geometry → math}/Vec3.js +63 -15
- package/dist/src/math/lib.d.ts +7 -0
- package/dist/src/math/lib.js +7 -0
- package/dist/src/math/rounding.d.ts +3 -0
- package/dist/src/math/rounding.js +121 -0
- package/dist/src/rendering/Display.d.ts +47 -1
- package/dist/src/rendering/Display.js +60 -15
- package/dist/src/rendering/caching/CacheRecord.d.ts +3 -2
- package/dist/src/rendering/caching/CacheRecord.js +4 -1
- package/dist/src/rendering/caching/CacheRecordManager.d.ts +5 -4
- package/dist/src/rendering/caching/CacheRecordManager.js +16 -4
- package/dist/src/rendering/caching/RenderingCache.d.ts +2 -3
- package/dist/src/rendering/caching/RenderingCache.js +10 -11
- package/dist/src/rendering/caching/RenderingCacheNode.d.ts +2 -1
- package/dist/src/rendering/caching/RenderingCacheNode.js +18 -7
- package/dist/src/rendering/caching/testUtils.js +1 -1
- package/dist/src/rendering/caching/types.d.ts +2 -4
- package/dist/src/rendering/localization.d.ts +2 -0
- package/dist/src/rendering/localization.js +2 -0
- package/dist/src/rendering/renderers/AbstractRenderer.d.ts +4 -4
- package/dist/src/rendering/renderers/AbstractRenderer.js +2 -2
- package/dist/src/rendering/renderers/CanvasRenderer.d.ts +4 -4
- package/dist/src/rendering/renderers/CanvasRenderer.js +2 -2
- package/dist/src/rendering/renderers/DummyRenderer.d.ts +4 -4
- package/dist/src/rendering/renderers/DummyRenderer.js +1 -1
- package/dist/src/rendering/renderers/SVGRenderer.d.ts +3 -3
- package/dist/src/rendering/renderers/SVGRenderer.js +8 -2
- package/dist/src/rendering/renderers/TextOnlyRenderer.d.ts +5 -3
- package/dist/src/rendering/renderers/TextOnlyRenderer.js +13 -3
- package/dist/src/toolbar/HTMLToolbar.js +1 -0
- package/dist/src/toolbar/icons.d.ts +3 -0
- package/dist/src/toolbar/icons.js +142 -132
- package/dist/src/toolbar/localization.d.ts +2 -1
- package/dist/src/toolbar/localization.js +2 -1
- package/dist/src/toolbar/makeColorInput.js +3 -2
- package/dist/src/toolbar/widgets/ActionButtonWidget.d.ts +13 -0
- package/dist/src/toolbar/widgets/ActionButtonWidget.js +21 -0
- package/dist/src/toolbar/widgets/BaseWidget.js +2 -0
- package/dist/src/toolbar/widgets/HandToolWidget.js +3 -3
- package/dist/src/toolbar/widgets/PenWidget.js +1 -0
- package/dist/src/toolbar/widgets/SelectionWidget.d.ts +0 -1
- package/dist/src/toolbar/widgets/SelectionWidget.js +23 -30
- package/dist/src/tools/Eraser.js +1 -1
- package/dist/src/tools/PanZoom.d.ts +1 -1
- package/dist/src/tools/PanZoom.js +24 -14
- package/dist/src/tools/Pen.d.ts +1 -2
- package/dist/src/tools/Pen.js +8 -1
- package/dist/src/tools/PipetteTool.js +1 -0
- package/dist/src/tools/SelectionTool.d.ts +3 -3
- package/dist/src/tools/SelectionTool.js +51 -28
- package/dist/src/tools/TextTool.js +1 -1
- package/dist/src/types.d.ts +21 -10
- package/dist/src/types.js +7 -5
- package/firebase.json +16 -0
- package/package.json +118 -101
- package/src/Color4.ts +23 -2
- package/src/Editor.ts +181 -37
- package/src/EditorImage.test.ts +2 -4
- package/src/EditorImage.ts +46 -28
- package/src/EventDispatcher.ts +21 -6
- package/src/Pointer.ts +4 -3
- package/src/SVGLoader.ts +14 -6
- package/src/UndoRedoHistory.ts +18 -2
- package/src/Viewport.ts +23 -18
- package/src/bundle/bundled.ts +1 -2
- package/src/commands/Command.ts +5 -5
- package/src/commands/Duplicate.ts +4 -5
- package/src/commands/Erase.ts +7 -6
- package/src/commands/SerializableCommand.ts +17 -9
- package/src/commands/invertCommand.ts +51 -0
- package/src/commands/lib.ts +14 -0
- package/src/commands/localization.ts +3 -1
- package/src/components/AbstractComponent.ts +35 -24
- package/src/components/SVGGlobalAttributesObject.ts +11 -4
- package/src/components/Stroke.test.ts +4 -6
- package/src/components/Stroke.ts +15 -11
- package/src/components/Text.test.ts +2 -2
- package/src/components/Text.ts +9 -10
- package/src/components/UnknownSVGObject.ts +10 -4
- package/src/components/builders/ArrowBuilder.ts +2 -2
- package/src/components/builders/FreehandLineBuilder.ts +190 -80
- package/src/components/builders/LineBuilder.ts +2 -2
- package/src/components/builders/RectangleBuilder.ts +3 -3
- package/src/components/builders/types.ts +1 -1
- package/src/components/lib.ts +9 -0
- package/src/lib.ts +28 -0
- package/src/localization.ts +6 -0
- package/src/localizations/es.ts +2 -1
- package/src/{geometry → math}/LineSegment2.test.ts +0 -0
- package/src/{geometry → math}/LineSegment2.ts +0 -0
- package/src/{geometry → math}/Mat33.test.ts +0 -0
- package/src/{geometry → math}/Mat33.ts +48 -20
- package/src/{geometry → math}/Path.fromString.test.ts +0 -0
- package/src/{geometry → math}/Path.test.ts +0 -0
- package/src/{geometry → math}/Path.toString.test.ts +11 -2
- package/src/{geometry → math}/Path.ts +61 -58
- package/src/{geometry → math}/Rect2.test.ts +0 -0
- package/src/{geometry → math}/Rect2.ts +2 -2
- package/src/{geometry → math}/Vec2.test.ts +0 -0
- package/src/{geometry → math}/Vec2.ts +0 -0
- package/src/{geometry → math}/Vec3.test.ts +0 -0
- package/src/{geometry → math}/Vec3.ts +64 -16
- package/src/math/lib.ts +15 -0
- package/src/math/rounding.test.ts +40 -0
- package/src/math/rounding.ts +147 -0
- package/src/rendering/Display.ts +63 -15
- package/src/rendering/caching/CacheRecord.test.ts +3 -3
- package/src/rendering/caching/CacheRecord.ts +6 -2
- package/src/rendering/caching/CacheRecordManager.ts +34 -8
- package/src/rendering/caching/RenderingCache.test.ts +3 -3
- package/src/rendering/caching/RenderingCache.ts +11 -16
- package/src/rendering/caching/RenderingCacheNode.ts +23 -7
- package/src/rendering/caching/testUtils.ts +1 -1
- package/src/rendering/caching/types.ts +2 -7
- package/src/rendering/localization.ts +4 -0
- package/src/rendering/renderers/AbstractRenderer.ts +4 -4
- package/src/rendering/renderers/CanvasRenderer.ts +5 -5
- package/src/rendering/renderers/DummyRenderer.test.ts +2 -2
- package/src/rendering/renderers/DummyRenderer.ts +4 -4
- package/src/rendering/renderers/SVGRenderer.ts +10 -4
- package/src/rendering/renderers/TextOnlyRenderer.ts +17 -6
- package/src/toolbar/HTMLToolbar.ts +1 -0
- package/src/toolbar/icons.ts +157 -137
- package/src/toolbar/localization.ts +4 -2
- package/src/toolbar/makeColorInput.ts +3 -2
- package/src/toolbar/toolbar.css +1 -1
- package/src/toolbar/widgets/ActionButtonWidget.ts +31 -0
- package/src/toolbar/widgets/BaseWidget.ts +2 -0
- package/src/toolbar/widgets/HandToolWidget.ts +3 -3
- package/src/toolbar/widgets/PenWidget.ts +2 -0
- package/src/toolbar/widgets/SelectionWidget.ts +46 -41
- package/src/tools/Eraser.ts +2 -2
- package/src/tools/PanZoom.ts +28 -17
- package/src/tools/Pen.ts +11 -2
- package/src/tools/PipetteTool.ts +2 -0
- package/src/tools/SelectionTool.test.ts +2 -4
- package/src/tools/SelectionTool.ts +52 -24
- package/src/tools/TextTool.ts +2 -2
- package/src/tools/UndoRedoShortcut.test.ts +1 -1
- package/src/types.ts +23 -7
- package/tsconfig.json +4 -1
- package/typedoc.json +20 -0
- package/dist/src/geometry/Mat33.d.ts +0 -32
- package/dist/src/geometry/Vec3.d.ts +0 -34
@@ -1,8 +1,8 @@
|
|
1
1
|
import { Bezier } from 'bezier-js';
|
2
|
-
import { Vec2 } from '../../
|
3
|
-
import Rect2 from '../../
|
4
|
-
import { PathCommandType } from '../../
|
5
|
-
import LineSegment2 from '../../
|
2
|
+
import { Vec2 } from '../../math/Vec2';
|
3
|
+
import Rect2 from '../../math/Rect2';
|
4
|
+
import { PathCommandType } from '../../math/Path';
|
5
|
+
import LineSegment2 from '../../math/LineSegment2';
|
6
6
|
import Stroke from '../Stroke';
|
7
7
|
import Viewport from '../../Viewport';
|
8
8
|
export const makeFreehandLineBuilder = (initialPoint, viewport) => {
|
@@ -24,9 +24,13 @@ export default class FreehandLineBuilder {
|
|
24
24
|
this.startPoint = startPoint;
|
25
25
|
this.minFitAllowed = minFitAllowed;
|
26
26
|
this.maxFitAllowed = maxFitAllowed;
|
27
|
+
this.isFirstSegment = true;
|
28
|
+
this.pathStartConnector = null;
|
29
|
+
this.mostRecentConnector = null;
|
27
30
|
this.currentCurve = null;
|
28
31
|
this.lastPoint = this.startPoint;
|
29
|
-
this.
|
32
|
+
this.upperSegments = [];
|
33
|
+
this.lowerSegments = [];
|
30
34
|
this.buffer = [this.startPoint.pos];
|
31
35
|
this.momentum = Vec2.zero;
|
32
36
|
this.currentCurve = null;
|
@@ -41,24 +45,81 @@ export default class FreehandLineBuilder {
|
|
41
45
|
fill: (_a = this.lastPoint.color) !== null && _a !== void 0 ? _a : null,
|
42
46
|
};
|
43
47
|
}
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
48
|
+
previewPath() {
|
49
|
+
var _a;
|
50
|
+
let upperPath;
|
51
|
+
let lowerPath;
|
52
|
+
let lowerToUpperCap;
|
53
|
+
let pathStartConnector;
|
54
|
+
if (this.currentCurve) {
|
55
|
+
const { upperCurve, lowerToUpperConnector, upperToLowerConnector, lowerCurve } = this.currentSegmentToPath();
|
56
|
+
upperPath = this.upperSegments.concat(upperCurve);
|
57
|
+
lowerPath = this.lowerSegments.concat(lowerCurve);
|
58
|
+
lowerToUpperCap = lowerToUpperConnector;
|
59
|
+
pathStartConnector = (_a = this.pathStartConnector) !== null && _a !== void 0 ? _a : upperToLowerConnector;
|
60
|
+
}
|
61
|
+
else {
|
62
|
+
if (this.mostRecentConnector === null || this.pathStartConnector === null) {
|
63
|
+
return null;
|
64
|
+
}
|
65
|
+
upperPath = this.upperSegments.slice();
|
66
|
+
lowerPath = this.lowerSegments.slice();
|
67
|
+
lowerToUpperCap = this.mostRecentConnector;
|
68
|
+
pathStartConnector = this.pathStartConnector;
|
69
|
+
}
|
70
|
+
const startPoint = lowerPath[lowerPath.length - 1].endPoint;
|
71
|
+
return {
|
72
|
+
// Start at the end of the lower curve:
|
73
|
+
// Start point
|
74
|
+
// ↓
|
75
|
+
// __/ __/ ← Most recent points on this end
|
76
|
+
// /___ /
|
77
|
+
// ↑
|
78
|
+
// Oldest points
|
79
|
+
startPoint,
|
80
|
+
commands: [
|
81
|
+
// Move to the most recent point on the upperPath:
|
82
|
+
// ----→•
|
83
|
+
// __/ __/
|
84
|
+
// /___ /
|
85
|
+
lowerToUpperCap,
|
86
|
+
// Move to the beginning of the upperPath:
|
87
|
+
// __/ __/
|
88
|
+
// /___ /
|
89
|
+
// • ←-
|
90
|
+
...upperPath.reverse(),
|
91
|
+
// Move to the beginning of the lowerPath:
|
92
|
+
// __/ __/
|
93
|
+
// /___ /
|
94
|
+
// •
|
95
|
+
pathStartConnector,
|
96
|
+
// Move back to the start point:
|
97
|
+
// •
|
98
|
+
// __/ __/
|
99
|
+
// /___ /
|
100
|
+
...lowerPath,
|
101
|
+
],
|
102
|
+
style: this.getRenderingStyle(),
|
103
|
+
};
|
104
|
+
}
|
105
|
+
previewStroke() {
|
106
|
+
const pathPreview = this.previewPath();
|
107
|
+
if (pathPreview) {
|
108
|
+
return new Stroke([pathPreview]);
|
49
109
|
}
|
50
|
-
return
|
110
|
+
return null;
|
51
111
|
}
|
52
112
|
preview(renderer) {
|
53
|
-
|
54
|
-
|
113
|
+
const path = this.previewPath();
|
114
|
+
if (path) {
|
115
|
+
renderer.drawPath(path);
|
55
116
|
}
|
56
117
|
}
|
57
118
|
build() {
|
58
119
|
if (this.lastPoint) {
|
59
120
|
this.finalizeCurrentCurve();
|
60
121
|
}
|
61
|
-
return
|
122
|
+
return this.previewStroke();
|
62
123
|
}
|
63
124
|
roundPoint(point) {
|
64
125
|
return Viewport.roundPoint(point, this.minFitAllowed);
|
@@ -67,53 +128,61 @@ export default class FreehandLineBuilder {
|
|
67
128
|
// Case where no points have been added
|
68
129
|
if (!this.currentCurve) {
|
69
130
|
// Don't create a circle around the initial point if the stroke has more than one point.
|
70
|
-
if (this.
|
131
|
+
if (!this.isFirstSegment) {
|
71
132
|
return;
|
72
133
|
}
|
73
|
-
const width = Viewport.roundPoint(this.startPoint.width / 3, this.minFitAllowed);
|
134
|
+
const width = Viewport.roundPoint(this.startPoint.width / 3.5, this.minFitAllowed);
|
74
135
|
const center = this.roundPoint(this.startPoint.pos);
|
136
|
+
// Start on the right, cycle clockwise:
|
137
|
+
// |
|
138
|
+
// ----- ←
|
139
|
+
// |
|
140
|
+
const startPoint = this.startPoint.pos.plus(Vec2.of(width, 0));
|
75
141
|
// Draw a circle-ish shape around the start point
|
76
|
-
this.
|
77
|
-
|
142
|
+
this.lowerSegments.push({
|
143
|
+
kind: PathCommandType.QuadraticBezierTo,
|
144
|
+
controlPoint: center.plus(Vec2.of(width, width)),
|
145
|
+
// Bottom of the circle
|
78
146
|
// |
|
79
|
-
// -----
|
147
|
+
// -----
|
80
148
|
// |
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
controlPoint: center.plus(Vec2.of(-width, width)),
|
96
|
-
endPoint: center.plus(Vec2.of(-width, 0)),
|
97
|
-
},
|
98
|
-
{
|
99
|
-
kind: PathCommandType.QuadraticBezierTo,
|
100
|
-
controlPoint: center.plus(Vec2.of(-width, -width)),
|
101
|
-
endPoint: center.plus(Vec2.of(0, -width)),
|
102
|
-
},
|
103
|
-
{
|
104
|
-
kind: PathCommandType.QuadraticBezierTo,
|
105
|
-
controlPoint: center.plus(Vec2.of(width, -width)),
|
106
|
-
endPoint: center.plus(Vec2.of(width, 0)),
|
107
|
-
},
|
108
|
-
],
|
109
|
-
style: this.getRenderingStyle(),
|
149
|
+
// ↑
|
150
|
+
endPoint: center.plus(Vec2.of(0, width)),
|
151
|
+
}, {
|
152
|
+
kind: PathCommandType.QuadraticBezierTo,
|
153
|
+
controlPoint: center.plus(Vec2.of(-width, width)),
|
154
|
+
endPoint: center.plus(Vec2.of(-width, 0)),
|
155
|
+
}, {
|
156
|
+
kind: PathCommandType.QuadraticBezierTo,
|
157
|
+
controlPoint: center.plus(Vec2.of(-width, -width)),
|
158
|
+
endPoint: center.plus(Vec2.of(0, -width)),
|
159
|
+
}, {
|
160
|
+
kind: PathCommandType.QuadraticBezierTo,
|
161
|
+
controlPoint: center.plus(Vec2.of(width, -width)),
|
162
|
+
endPoint: center.plus(Vec2.of(width, 0)),
|
110
163
|
});
|
164
|
+
this.pathStartConnector = {
|
165
|
+
kind: PathCommandType.LineTo,
|
166
|
+
point: startPoint,
|
167
|
+
};
|
168
|
+
this.mostRecentConnector = this.pathStartConnector;
|
111
169
|
return;
|
112
170
|
}
|
113
|
-
this.
|
171
|
+
const { upperCurve, lowerToUpperConnector, upperToLowerConnector, lowerCurve } = this.currentSegmentToPath();
|
172
|
+
if (this.isFirstSegment) {
|
173
|
+
// We draw the upper path (reversed), then the lower path, so we need the
|
174
|
+
// upperToLowerConnector to join the two paths.
|
175
|
+
this.pathStartConnector = upperToLowerConnector;
|
176
|
+
this.isFirstSegment = false;
|
177
|
+
}
|
178
|
+
// With the most recent connector, we're joining the end of the lowerPath to the most recent
|
179
|
+
// upperPath:
|
180
|
+
this.mostRecentConnector = lowerToUpperConnector;
|
181
|
+
this.upperSegments.push(upperCurve);
|
182
|
+
this.lowerSegments.push(lowerCurve);
|
114
183
|
const lastPoint = this.buffer[this.buffer.length - 1];
|
115
184
|
this.lastExitingVec = Vec2.ofXY(this.currentCurve.points[2]).minus(Vec2.ofXY(this.currentCurve.points[1]));
|
116
|
-
console.assert(this.lastExitingVec.magnitude() !== 0);
|
185
|
+
console.assert(this.lastExitingVec.magnitude() !== 0, 'lastExitingVec has zero length!');
|
117
186
|
// Use the last two points to start a new curve (the last point isn't used
|
118
187
|
// in the current curve and we want connected curves to share end points)
|
119
188
|
this.buffer = [
|
@@ -121,6 +190,7 @@ export default class FreehandLineBuilder {
|
|
121
190
|
];
|
122
191
|
this.currentCurve = null;
|
123
192
|
}
|
193
|
+
// Returns [upper curve, connector, lower curve]
|
124
194
|
currentSegmentToPath() {
|
125
195
|
if (this.currentCurve == null) {
|
126
196
|
throw new Error('Invalid State: currentCurve is null!');
|
@@ -163,27 +233,28 @@ export default class FreehandLineBuilder {
|
|
163
233
|
if (upperBoundary.intersects(lowerBoundary).length > 0) {
|
164
234
|
halfVec = halfVec.times(2);
|
165
235
|
}
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
236
|
+
// Each starts at startPt ± startVec
|
237
|
+
const lowerCurve = {
|
238
|
+
kind: PathCommandType.QuadraticBezierTo,
|
239
|
+
controlPoint: this.roundPoint(controlPoint.plus(halfVec)),
|
240
|
+
endPoint: this.roundPoint(endPt.plus(endVec)),
|
241
|
+
};
|
242
|
+
// From the end of the upperCurve to the start of the lowerCurve:
|
243
|
+
const upperToLowerConnector = {
|
244
|
+
kind: PathCommandType.LineTo,
|
245
|
+
point: this.roundPoint(startPt.plus(startVec)),
|
246
|
+
};
|
247
|
+
// From the end of lowerCurve to the start of upperCurve:
|
248
|
+
const lowerToUpperConnector = {
|
249
|
+
kind: PathCommandType.LineTo,
|
250
|
+
point: this.roundPoint(endPt.minus(endVec))
|
251
|
+
};
|
252
|
+
const upperCurve = {
|
253
|
+
kind: PathCommandType.QuadraticBezierTo,
|
254
|
+
controlPoint: this.roundPoint(controlPoint.minus(halfVec)),
|
255
|
+
endPoint: this.roundPoint(startPt.minus(startVec)),
|
186
256
|
};
|
257
|
+
return { upperCurve, upperToLowerConnector, lowerToUpperConnector, lowerCurve };
|
187
258
|
}
|
188
259
|
// Compute the direction of the velocity at the end of this.buffer
|
189
260
|
computeExitingVec() {
|
@@ -205,7 +276,7 @@ export default class FreehandLineBuilder {
|
|
205
276
|
}
|
206
277
|
const threshold = Math.min(this.lastPoint.width, newPoint.width) / 4;
|
207
278
|
const shouldSnapToInitial = this.startPoint.pos.minus(newPoint.pos).magnitude() < threshold
|
208
|
-
&& this.
|
279
|
+
&& this.isFirstSegment;
|
209
280
|
// Snap to the starting point if the stroke is contained within a small ball centered
|
210
281
|
// at the starting point.
|
211
282
|
// This allows us to create a circle/dot at the start of the stroke.
|
@@ -1,6 +1,6 @@
|
|
1
|
-
import Mat33 from '../../
|
2
|
-
import Path from '../../
|
3
|
-
import Rect2 from '../../
|
1
|
+
import Mat33 from '../../math/Mat33';
|
2
|
+
import Path from '../../math/Path';
|
3
|
+
import Rect2 from '../../math/Rect2';
|
4
4
|
import Stroke from '../Stroke';
|
5
5
|
export const makeFilledRectangleBuilder = (initialPoint, viewport) => {
|
6
6
|
return new RectangleBuilder(initialPoint, true, viewport);
|
@@ -0,0 +1,25 @@
|
|
1
|
+
/**
|
2
|
+
* The main entrypoint for the NPM package. Everything exported by this file
|
3
|
+
* is available through the `js-draw` package.
|
4
|
+
*
|
5
|
+
* @example
|
6
|
+
* ```
|
7
|
+
* import { Editor, Vec3, Mat33 } from 'js-draw';
|
8
|
+
* ```
|
9
|
+
*
|
10
|
+
* @see
|
11
|
+
* {@link Editor!}
|
12
|
+
*
|
13
|
+
* @packageDocumentation
|
14
|
+
*/
|
15
|
+
import Editor from './Editor';
|
16
|
+
export { EditorEventType } from './types';
|
17
|
+
export { default as getLocalizationTable } from './localizations/getLocalizationTable';
|
18
|
+
export * from './localization';
|
19
|
+
export { default as Color4 } from './Color4';
|
20
|
+
export * from './math/lib';
|
21
|
+
export * from './components/lib';
|
22
|
+
export * from './commands/lib';
|
23
|
+
export { default as HTMLToolbar } from './toolbar/HTMLToolbar';
|
24
|
+
export { Editor };
|
25
|
+
export default Editor;
|
package/dist/src/lib.js
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
/**
|
2
|
+
* The main entrypoint for the NPM package. Everything exported by this file
|
3
|
+
* is available through the `js-draw` package.
|
4
|
+
*
|
5
|
+
* @example
|
6
|
+
* ```
|
7
|
+
* import { Editor, Vec3, Mat33 } from 'js-draw';
|
8
|
+
* ```
|
9
|
+
*
|
10
|
+
* @see
|
11
|
+
* {@link Editor!}
|
12
|
+
*
|
13
|
+
* @packageDocumentation
|
14
|
+
*/
|
15
|
+
import Editor from './Editor';
|
16
|
+
export { EditorEventType } from './types';
|
17
|
+
export { default as getLocalizationTable } from './localizations/getLocalizationTable';
|
18
|
+
export * from './localization';
|
19
|
+
export { default as Color4 } from './Color4';
|
20
|
+
export * from './math/lib';
|
21
|
+
export * from './components/lib';
|
22
|
+
export * from './commands/lib';
|
23
|
+
export { default as HTMLToolbar } from './toolbar/HTMLToolbar';
|
24
|
+
export { Editor };
|
25
|
+
export default Editor;
|
@@ -4,6 +4,7 @@ import { TextRendererLocalization } from './rendering/localization';
|
|
4
4
|
import { ToolbarLocalization } from './toolbar/localization';
|
5
5
|
import { ToolLocalization } from './tools/localization';
|
6
6
|
export interface EditorLocalization extends ToolbarLocalization, ToolLocalization, CommandLocalization, ImageComponentLocalization, TextRendererLocalization {
|
7
|
+
accessibilityInputInstructions: string;
|
7
8
|
undoAnnouncement: (actionDescription: string) => string;
|
8
9
|
redoAnnouncement: (actionDescription: string) => string;
|
9
10
|
doneLoading: string;
|
package/dist/src/localization.js
CHANGED
@@ -3,4 +3,8 @@ import { defaultComponentLocalization } from './components/localization';
|
|
3
3
|
import { defaultTextRendererLocalization } from './rendering/localization';
|
4
4
|
import { defaultToolbarLocalization } from './toolbar/localization';
|
5
5
|
import { defaultToolLocalization } from './tools/localization';
|
6
|
-
export const defaultEditorLocalization = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, defaultToolbarLocalization), defaultToolLocalization), defaultCommandLocalization), defaultComponentLocalization), defaultTextRendererLocalization), {
|
6
|
+
export const defaultEditorLocalization = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, defaultToolbarLocalization), defaultToolLocalization), defaultCommandLocalization), defaultComponentLocalization), defaultTextRendererLocalization), { accessibilityInputInstructions: [
|
7
|
+
'Press "t" to read the contents of the viewport as text.',
|
8
|
+
'Use the arrow keys to move the viewport, click and drag to draw strokes.',
|
9
|
+
'Press "w" to zoom in and "s" to zoom out.',
|
10
|
+
].join(' '), loading: (percentage) => `Loading ${percentage}%...`, imageEditor: 'Image Editor', doneLoading: 'Done loading', undoAnnouncement: (commandDescription) => `Undid ${commandDescription}`, redoAnnouncement: (commandDescription) => `Redid ${commandDescription}` });
|
@@ -6,7 +6,7 @@ const localization = Object.assign(Object.assign({}, defaultEditorLocalization),
|
|
6
6
|
loading: (percentage) => `Cargando: ${percentage}%...`, imageEditor: 'Editor de dibujos', undoAnnouncement: (commandDescription) => `${commandDescription} fue deshecho`, redoAnnouncement: (commandDescription) => `${commandDescription} fue rehecho`, undo: 'Deshace', redo: 'Rehace',
|
7
7
|
// Strings for the toolbar
|
8
8
|
// (see src/toolbar/localization.ts)
|
9
|
-
pen: 'Lapiz', eraser: 'Borrador', select: 'Selecciona', thicknessLabel: 'Tamaño: ', colorLabel: 'Color: ', doneLoading: 'El cargado terminó', fontLabel: 'Fuente: ', anyDevicePanning: 'Mover la pantalla con todo dispotivo', touchPanning: 'Mover la pantalla con un dedo', touchPanTool: 'Instrumento de mover la pantalla con un dedo', outlinedRectanglePen: 'Rectángulo con nada más que un borde', filledRectanglePen: 'Rectángulo sin borde', linePen: 'Línea', arrowPen: 'Flecha', freehandPen: 'Dibuja sin restricción de forma', selectObjectType: 'Forma de dibuja:', handTool: 'Mover', zoom: 'Zoom', resetView: 'Reiniciar vista', resizeImageToSelection: 'Redimensionar la imagen a lo que está seleccionado', deleteSelection: 'Borra la selección', duplicateSelection: 'Duplica la selección',
|
9
|
+
pen: 'Lapiz', eraser: 'Borrador', select: 'Selecciona', thicknessLabel: 'Tamaño: ', colorLabel: 'Color: ', doneLoading: 'El cargado terminó', fontLabel: 'Fuente: ', anyDevicePanning: 'Mover la pantalla con todo dispotivo', touchPanning: 'Mover la pantalla con un dedo', touchPanTool: 'Instrumento de mover la pantalla con un dedo', outlinedRectanglePen: 'Rectángulo con nada más que un borde', filledRectanglePen: 'Rectángulo sin borde', linePen: 'Línea', arrowPen: 'Flecha', freehandPen: 'Dibuja sin restricción de forma', selectObjectType: 'Forma de dibuja:', handTool: 'Mover', zoom: 'Zoom', resetView: 'Reiniciar vista', resizeImageToSelection: 'Redimensionar la imagen a lo que está seleccionado', deleteSelection: 'Borra la selección', duplicateSelection: 'Duplica la selección', pickColorFromScreen: 'Selecciona un color de la pantalla', clickToPickColorAnnouncement: 'Haga un clic en la pantalla para seleccionar un color', dropdownShown(toolName) {
|
10
10
|
return `Menú por ${toolName} es visible`;
|
11
11
|
}, dropdownHidden: function (toolName) {
|
12
12
|
return `Menú por ${toolName} fue ocultado`;
|
File without changes
|
File without changes
|
@@ -0,0 +1,78 @@
|
|
1
|
+
import { Point2, Vec2 } from './Vec2';
|
2
|
+
import Vec3 from './Vec3';
|
3
|
+
/**
|
4
|
+
* Represents a three dimensional linear transformation or
|
5
|
+
* a two-dimensional affine transformation. (An affine transformation scales/rotates/shears
|
6
|
+
* **and** translates while a linear transformation just scales/rotates/shears).
|
7
|
+
*/
|
8
|
+
export default class Mat33 {
|
9
|
+
readonly a1: number;
|
10
|
+
readonly a2: number;
|
11
|
+
readonly a3: number;
|
12
|
+
readonly b1: number;
|
13
|
+
readonly b2: number;
|
14
|
+
readonly b3: number;
|
15
|
+
readonly c1: number;
|
16
|
+
readonly c2: number;
|
17
|
+
readonly c3: number;
|
18
|
+
private readonly rows;
|
19
|
+
/**
|
20
|
+
* Creates a matrix from inputs in the form,
|
21
|
+
* ```
|
22
|
+
* ⎡ a1 a2 a3 ⎤
|
23
|
+
* ⎢ b1 b2 b3 ⎥
|
24
|
+
* ⎣ c1 c2 c3 ⎦
|
25
|
+
* ```
|
26
|
+
*/
|
27
|
+
constructor(a1: number, a2: number, a3: number, b1: number, b2: number, b3: number, c1: number, c2: number, c3: number);
|
28
|
+
/**
|
29
|
+
* Creates a matrix from the given rows:
|
30
|
+
* ```
|
31
|
+
* ⎡ r1.x r1.y r1.z ⎤
|
32
|
+
* ⎢ r2.x r2.y r2.z ⎥
|
33
|
+
* ⎣ r3.x r3.y r3.z ⎦
|
34
|
+
* ```
|
35
|
+
*/
|
36
|
+
static ofRows(r1: Vec3, r2: Vec3, r3: Vec3): Mat33;
|
37
|
+
static identity: Mat33;
|
38
|
+
/**
|
39
|
+
* Either returns the inverse of this, or, if this matrix is singular/uninvertable,
|
40
|
+
* returns Mat33.identity.
|
41
|
+
*
|
42
|
+
* This may cache the computed inverse and return the cached version instead of recomputing
|
43
|
+
* it.
|
44
|
+
*/
|
45
|
+
inverse(): Mat33;
|
46
|
+
invertable(): boolean;
|
47
|
+
private cachedInverse;
|
48
|
+
private computeInverse;
|
49
|
+
transposed(): Mat33;
|
50
|
+
rightMul(other: Mat33): Mat33;
|
51
|
+
/**
|
52
|
+
* Applies this as an affine transformation to the given vector.
|
53
|
+
* Returns a transformed version of `other`.
|
54
|
+
*/
|
55
|
+
transformVec2(other: Vec2): Vec2;
|
56
|
+
/**
|
57
|
+
* Applies this as a linear transformation to the given vector (doesn't translate).
|
58
|
+
* This is the standard way of transforming vectors in ℝ³.
|
59
|
+
*/
|
60
|
+
transformVec3(other: Vec3): Vec3;
|
61
|
+
/** Returns true iff this = other ± fuzz */
|
62
|
+
eq(other: Mat33, fuzz?: number): boolean;
|
63
|
+
toString(): string;
|
64
|
+
/**
|
65
|
+
* ```
|
66
|
+
* result[0] = top left element
|
67
|
+
* result[1] = element at row zero, column 1
|
68
|
+
* ...
|
69
|
+
* ```
|
70
|
+
*/
|
71
|
+
toArray(): number[];
|
72
|
+
/** Constructs a 3x3 translation matrix (for translating `Vec2`s) */
|
73
|
+
static translation(amount: Vec2): Mat33;
|
74
|
+
static zRotation(radians: number, center?: Point2): Mat33;
|
75
|
+
static scaling2D(amount: number | Vec2, center?: Point2): Mat33;
|
76
|
+
/** Converts a CSS-form `matrix(a, b, c, d, e, f)` to a Mat33. */
|
77
|
+
static fromCSSMatrix(cssString: string): Mat33;
|
78
|
+
}
|
@@ -1,12 +1,19 @@
|
|
1
1
|
import { Vec2 } from './Vec2';
|
2
2
|
import Vec3 from './Vec3';
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
/**
|
4
|
+
* Represents a three dimensional linear transformation or
|
5
|
+
* a two-dimensional affine transformation. (An affine transformation scales/rotates/shears
|
6
|
+
* **and** translates while a linear transformation just scales/rotates/shears).
|
7
|
+
*/
|
6
8
|
export default class Mat33 {
|
7
|
-
|
8
|
-
|
9
|
-
|
9
|
+
/**
|
10
|
+
* Creates a matrix from inputs in the form,
|
11
|
+
* ```
|
12
|
+
* ⎡ a1 a2 a3 ⎤
|
13
|
+
* ⎢ b1 b2 b3 ⎥
|
14
|
+
* ⎣ c1 c2 c3 ⎦
|
15
|
+
* ```
|
16
|
+
*/
|
10
17
|
constructor(a1, a2, a3, b1, b2, b3, c1, c2, c3) {
|
11
18
|
this.a1 = a1;
|
12
19
|
this.a2 = a2;
|
@@ -24,11 +31,24 @@ export default class Mat33 {
|
|
24
31
|
Vec3.of(c1, c2, c3),
|
25
32
|
];
|
26
33
|
}
|
34
|
+
/**
|
35
|
+
* Creates a matrix from the given rows:
|
36
|
+
* ```
|
37
|
+
* ⎡ r1.x r1.y r1.z ⎤
|
38
|
+
* ⎢ r2.x r2.y r2.z ⎥
|
39
|
+
* ⎣ r3.x r3.y r3.z ⎦
|
40
|
+
* ```
|
41
|
+
*/
|
27
42
|
static ofRows(r1, r2, r3) {
|
28
43
|
return new Mat33(r1.x, r1.y, r1.z, r2.x, r2.y, r2.z, r3.x, r3.y, r3.z);
|
29
44
|
}
|
30
|
-
|
31
|
-
|
45
|
+
/**
|
46
|
+
* Either returns the inverse of this, or, if this matrix is singular/uninvertable,
|
47
|
+
* returns Mat33.identity.
|
48
|
+
*
|
49
|
+
* This may cache the computed inverse and return the cached version instead of recomputing
|
50
|
+
* it.
|
51
|
+
*/
|
32
52
|
inverse() {
|
33
53
|
var _a;
|
34
54
|
return (_a = this.computeInverse()) !== null && _a !== void 0 ? _a : Mat33.identity;
|
@@ -109,8 +129,10 @@ export default class Mat33 {
|
|
109
129
|
};
|
110
130
|
return new Mat33(at(0, 0), at(0, 1), at(0, 2), at(1, 0), at(1, 1), at(1, 2), at(2, 0), at(2, 1), at(2, 2));
|
111
131
|
}
|
112
|
-
|
113
|
-
|
132
|
+
/**
|
133
|
+
* Applies this as an affine transformation to the given vector.
|
134
|
+
* Returns a transformed version of `other`.
|
135
|
+
*/
|
114
136
|
transformVec2(other) {
|
115
137
|
// When transforming a Vec2, we want to use the z transformation
|
116
138
|
// components of this for translation:
|
@@ -124,12 +146,14 @@ export default class Mat33 {
|
|
124
146
|
// Drop the z=1 to allow magnitude to work as expected
|
125
147
|
return Vec2.of(intermediate.x, intermediate.y);
|
126
148
|
}
|
127
|
-
|
128
|
-
|
149
|
+
/**
|
150
|
+
* Applies this as a linear transformation to the given vector (doesn't translate).
|
151
|
+
* This is the standard way of transforming vectors in ℝ³.
|
152
|
+
*/
|
129
153
|
transformVec3(other) {
|
130
154
|
return Vec3.of(this.rows[0].dot(other), this.rows[1].dot(other), this.rows[2].dot(other));
|
131
155
|
}
|
132
|
-
|
156
|
+
/** Returns true iff this = other ± fuzz */
|
133
157
|
eq(other, fuzz = 0) {
|
134
158
|
for (let i = 0; i < 3; i++) {
|
135
159
|
if (!this.rows[i].eq(other.rows[i], fuzz)) {
|
@@ -143,11 +167,15 @@ export default class Mat33 {
|
|
143
167
|
⎡ ${this.a1},\t ${this.a2},\t ${this.a3}\t ⎤
|
144
168
|
⎢ ${this.b1},\t ${this.b2},\t ${this.b3}\t ⎥
|
145
169
|
⎣ ${this.c1},\t ${this.c2},\t ${this.c3}\t ⎦
|
146
|
-
`.
|
147
|
-
}
|
148
|
-
|
149
|
-
|
150
|
-
|
170
|
+
`.trimEnd().trimStart();
|
171
|
+
}
|
172
|
+
/**
|
173
|
+
* ```
|
174
|
+
* result[0] = top left element
|
175
|
+
* result[1] = element at row zero, column 1
|
176
|
+
* ...
|
177
|
+
* ```
|
178
|
+
*/
|
151
179
|
toArray() {
|
152
180
|
return [
|
153
181
|
this.a1, this.a2, this.a3,
|
@@ -155,7 +183,7 @@ export default class Mat33 {
|
|
155
183
|
this.c1, this.c2, this.c3,
|
156
184
|
];
|
157
185
|
}
|
158
|
-
|
186
|
+
/** Constructs a 3x3 translation matrix (for translating `Vec2`s) */
|
159
187
|
static translation(amount) {
|
160
188
|
// When transforming Vec2s by a 3x3 matrix, we give the input
|
161
189
|
// Vec2s z = 1. As such,
|
@@ -186,7 +214,7 @@ export default class Mat33 {
|
|
186
214
|
// Translate such that [center] goes to (0, 0)
|
187
215
|
return result.rightMul(Mat33.translation(center.times(-1)));
|
188
216
|
}
|
189
|
-
|
217
|
+
/** Converts a CSS-form `matrix(a, b, c, d, e, f)` to a Mat33. */
|
190
218
|
static fromCSSMatrix(cssString) {
|
191
219
|
if (cssString === '' || cssString === 'none') {
|
192
220
|
return Mat33.identity;
|
@@ -45,6 +45,7 @@ export default class Path {
|
|
45
45
|
get geometry(): Array<LineSegment2 | Bezier>;
|
46
46
|
static computeBBoxForSegment(startPoint: Point2, part: PathCommand): Rect2;
|
47
47
|
intersection(line: LineSegment2): IntersectionResult[];
|
48
|
+
mapPoints(mapping: (point: Point2) => Point2): Path;
|
48
49
|
transformedBy(affineTransfm: Mat33): Path;
|
49
50
|
union(other: Path | null): Path;
|
50
51
|
static fromRect(rect: Rect2, lineWidth?: number | null): Path;
|
@@ -52,7 +53,7 @@ export default class Path {
|
|
52
53
|
toRenderable(fill: RenderingStyle): RenderablePathSpec;
|
53
54
|
toString(): string;
|
54
55
|
serialize(): string;
|
55
|
-
static toString(startPoint: Point2, parts: PathCommand[]): string;
|
56
|
+
static toString(startPoint: Point2, parts: PathCommand[], onlyAbsCommands?: boolean): string;
|
56
57
|
static fromString(pathString: string): Path;
|
57
58
|
static empty: Path;
|
58
59
|
}
|