js-draw 0.1.12 → 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 +6 -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 +129 -2
- package/dist/src/Editor.js +94 -17
- package/dist/src/EditorImage.d.ts +7 -2
- package/dist/src/EditorImage.js +41 -25
- package/dist/src/EventDispatcher.d.ts +18 -0
- package/dist/src/EventDispatcher.js +19 -4
- package/dist/src/Pointer.js +3 -2
- package/dist/src/UndoRedoHistory.js +15 -2
- package/dist/src/Viewport.js +4 -1
- package/dist/src/bundle/bundled.d.ts +1 -2
- package/dist/src/bundle/bundled.js +1 -2
- package/dist/src/commands/Duplicate.d.ts +1 -1
- package/dist/src/commands/Duplicate.js +3 -4
- package/dist/src/commands/Erase.d.ts +1 -1
- package/dist/src/commands/Erase.js +6 -5
- 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 +1 -0
- package/dist/src/commands/localization.js +1 -0
- package/dist/src/components/AbstractComponent.d.ts +13 -8
- package/dist/src/components/AbstractComponent.js +26 -15
- package/dist/src/components/SVGGlobalAttributesObject.d.ts +1 -1
- package/dist/src/components/SVGGlobalAttributesObject.js +7 -1
- package/dist/src/components/Stroke.d.ts +12 -2
- package/dist/src/components/Stroke.js +10 -7
- package/dist/src/components/Text.d.ts +2 -2
- package/dist/src/components/Text.js +6 -6
- package/dist/src/components/UnknownSVGObject.d.ts +1 -1
- package/dist/src/components/UnknownSVGObject.js +6 -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/math/Mat33.d.ts +47 -1
- package/dist/src/math/Mat33.js +48 -20
- package/dist/src/math/Path.js +3 -3
- package/dist/src/math/Rect2.d.ts +2 -2
- package/dist/src/math/Vec3.d.ts +62 -0
- package/dist/src/math/Vec3.js +62 -14
- package/dist/src/math/lib.d.ts +7 -0
- package/dist/src/math/lib.js +7 -0
- package/dist/src/math/rounding.js +1 -0
- package/dist/src/rendering/Display.d.ts +44 -0
- package/dist/src/rendering/Display.js +45 -6
- package/dist/src/rendering/caching/CacheRecord.d.ts +1 -0
- package/dist/src/rendering/caching/CacheRecord.js +3 -0
- package/dist/src/rendering/caching/CacheRecordManager.d.ts +4 -3
- 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 +9 -10
- package/dist/src/rendering/caching/types.d.ts +1 -3
- package/dist/src/rendering/renderers/CanvasRenderer.js +1 -1
- package/dist/src/toolbar/HTMLToolbar.js +1 -0
- package/dist/src/toolbar/makeColorInput.js +1 -1
- package/dist/src/toolbar/widgets/PenWidget.js +1 -0
- 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.js +45 -22
- package/dist/src/types.d.ts +17 -6
- 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 +147 -25
- package/src/EditorImage.ts +45 -27
- package/src/EventDispatcher.ts +21 -6
- package/src/Pointer.ts +3 -2
- package/src/UndoRedoHistory.ts +18 -2
- package/src/Viewport.ts +5 -2
- package/src/bundle/bundled.ts +1 -2
- package/src/commands/Duplicate.ts +3 -4
- package/src/commands/Erase.ts +6 -5
- 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 +2 -0
- package/src/components/AbstractComponent.ts +31 -20
- package/src/components/SVGGlobalAttributesObject.ts +8 -1
- package/src/components/Stroke.test.ts +1 -1
- package/src/components/Stroke.ts +11 -7
- package/src/components/Text.ts +6 -7
- package/src/components/UnknownSVGObject.ts +7 -1
- package/src/components/lib.ts +9 -0
- package/src/lib.ts +28 -0
- package/src/math/Mat33.ts +48 -20
- package/src/math/Path.ts +3 -3
- package/src/math/Rect2.ts +2 -2
- package/src/math/Vec3.ts +62 -14
- package/src/math/lib.ts +15 -0
- package/src/math/rounding.ts +2 -0
- package/src/rendering/Display.ts +46 -6
- package/src/rendering/caching/CacheRecord.test.ts +1 -1
- package/src/rendering/caching/CacheRecord.ts +4 -0
- package/src/rendering/caching/CacheRecordManager.ts +33 -7
- package/src/rendering/caching/RenderingCache.ts +10 -15
- package/src/rendering/caching/types.ts +1 -6
- package/src/rendering/renderers/CanvasRenderer.ts +1 -1
- package/src/toolbar/HTMLToolbar.ts +1 -0
- package/src/toolbar/makeColorInput.ts +1 -1
- package/src/toolbar/widgets/PenWidget.ts +2 -0
- package/src/tools/PanZoom.ts +0 -1
- package/src/tools/Pen.ts +11 -2
- package/src/tools/PipetteTool.ts +2 -0
- package/src/tools/SelectionTool.ts +46 -18
- package/src/types.ts +19 -3
- package/tsconfig.json +4 -1
- package/typedoc.json +20 -0
package/src/components/Stroke.ts
CHANGED
@@ -111,19 +111,23 @@ export default class Stroke extends AbstractComponent {
|
|
111
111
|
return new Stroke(this.parts);
|
112
112
|
}
|
113
113
|
|
114
|
-
protected
|
115
|
-
return
|
114
|
+
protected serializeToJSON() {
|
115
|
+
return this.parts.map(part => {
|
116
116
|
return {
|
117
117
|
style: styleToJSON(part.style),
|
118
118
|
path: part.path.serialize(),
|
119
119
|
};
|
120
|
-
})
|
120
|
+
});
|
121
121
|
}
|
122
122
|
|
123
|
-
|
124
|
-
|
123
|
+
/** @internal */
|
124
|
+
public static deserializeFromJSON(json: any): Stroke {
|
125
|
+
if (typeof json === 'string') {
|
126
|
+
json = JSON.parse(json);
|
127
|
+
}
|
128
|
+
|
125
129
|
if (typeof json !== 'object' || typeof json.length !== 'number') {
|
126
|
-
throw new Error(`${
|
130
|
+
throw new Error(`${json} is missing required field, parts, or parts is of the wrong type.`);
|
127
131
|
}
|
128
132
|
|
129
133
|
const pathSpec: RenderablePathSpec[] = json.map((part: any) => {
|
@@ -134,4 +138,4 @@ export default class Stroke extends AbstractComponent {
|
|
134
138
|
}
|
135
139
|
}
|
136
140
|
|
137
|
-
AbstractComponent.registerComponent('stroke', Stroke.
|
141
|
+
AbstractComponent.registerComponent('stroke', Stroke.deserializeFromJSON);
|
package/src/components/Text.ts
CHANGED
@@ -26,6 +26,7 @@ export default class Text extends AbstractComponent {
|
|
26
26
|
private readonly style: TextStyle,
|
27
27
|
|
28
28
|
// If not given, an HtmlCanvasElement is used to determine text boundaries.
|
29
|
+
// @internal
|
29
30
|
private readonly getTextDimens: GetTextDimensCallback = Text.getTextDimens,
|
30
31
|
) {
|
31
32
|
super(componentTypeId);
|
@@ -152,7 +153,7 @@ export default class Text extends AbstractComponent {
|
|
152
153
|
return localizationTable.text(this.getText());
|
153
154
|
}
|
154
155
|
|
155
|
-
protected
|
156
|
+
protected serializeToJSON(): Record<string, any> {
|
156
157
|
const serializableStyle = {
|
157
158
|
...this.style,
|
158
159
|
renderingStyle: styleToJSON(this.style.renderingStyle),
|
@@ -165,21 +166,19 @@ export default class Text extends AbstractComponent {
|
|
165
166
|
};
|
166
167
|
} else {
|
167
168
|
return {
|
168
|
-
json: text.
|
169
|
+
json: text.serializeToJSON(),
|
169
170
|
};
|
170
171
|
}
|
171
172
|
});
|
172
173
|
|
173
|
-
return
|
174
|
+
return {
|
174
175
|
textObjects,
|
175
176
|
transform: this.transform.toArray(),
|
176
177
|
style: serializableStyle,
|
177
|
-
}
|
178
|
+
};
|
178
179
|
}
|
179
180
|
|
180
|
-
public static deserializeFromString(
|
181
|
-
const json = JSON.parse(data);
|
182
|
-
|
181
|
+
public static deserializeFromString(json: any, getTextDimens: GetTextDimensCallback = Text.getTextDimens): Text {
|
183
182
|
const style: TextStyle = {
|
184
183
|
renderingStyle: styleFromJSON(json.style.renderingStyle),
|
185
184
|
size: json.style.size,
|
@@ -1,3 +1,9 @@
|
|
1
|
+
//
|
2
|
+
// Stores objects loaded from an SVG that aren't recognised by the editor.
|
3
|
+
// @internal
|
4
|
+
// @packageDocumentation
|
5
|
+
//
|
6
|
+
|
1
7
|
import LineSegment2 from '../math/LineSegment2';
|
2
8
|
import Mat33 from '../math/Mat33';
|
3
9
|
import Rect2 from '../math/Rect2';
|
@@ -39,7 +45,7 @@ export default class UnknownSVGObject extends AbstractComponent {
|
|
39
45
|
return localization.svgObject;
|
40
46
|
}
|
41
47
|
|
42
|
-
protected
|
48
|
+
protected serializeToJSON(): string | null {
|
43
49
|
return JSON.stringify({
|
44
50
|
html: this.svgObject.outerHTML,
|
45
51
|
});
|
package/src/lib.ts
ADDED
@@ -0,0 +1,28 @@
|
|
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
|
+
|
16
|
+
import Editor from './Editor';
|
17
|
+
export { EditorEventType } from './types';
|
18
|
+
export { default as getLocalizationTable } from './localizations/getLocalizationTable';
|
19
|
+
export * from './localization';
|
20
|
+
|
21
|
+
export { default as Color4 } from './Color4';
|
22
|
+
export * from './math/lib';
|
23
|
+
export * from './components/lib';
|
24
|
+
export * from './commands/lib';
|
25
|
+
export { default as HTMLToolbar } from './toolbar/HTMLToolbar';
|
26
|
+
|
27
|
+
export { Editor };
|
28
|
+
export default Editor;
|
package/src/math/Mat33.ts
CHANGED
@@ -1,15 +1,22 @@
|
|
1
1
|
import { Point2, Vec2 } from './Vec2';
|
2
2
|
import Vec3 from './Vec3';
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
/**
|
5
|
+
* Represents a three dimensional linear transformation or
|
6
|
+
* a two-dimensional affine transformation. (An affine transformation scales/rotates/shears
|
7
|
+
* **and** translates while a linear transformation just scales/rotates/shears).
|
8
|
+
*/
|
7
9
|
export default class Mat33 {
|
8
10
|
private readonly rows: Vec3[];
|
9
11
|
|
10
|
-
|
11
|
-
|
12
|
-
|
12
|
+
/**
|
13
|
+
* Creates a matrix from inputs in the form,
|
14
|
+
* ```
|
15
|
+
* ⎡ a1 a2 a3 ⎤
|
16
|
+
* ⎢ b1 b2 b3 ⎥
|
17
|
+
* ⎣ c1 c2 c3 ⎦
|
18
|
+
* ```
|
19
|
+
*/
|
13
20
|
public constructor(
|
14
21
|
public readonly a1: number,
|
15
22
|
public readonly a2: number,
|
@@ -30,6 +37,14 @@ export default class Mat33 {
|
|
30
37
|
];
|
31
38
|
}
|
32
39
|
|
40
|
+
/**
|
41
|
+
* Creates a matrix from the given rows:
|
42
|
+
* ```
|
43
|
+
* ⎡ r1.x r1.y r1.z ⎤
|
44
|
+
* ⎢ r2.x r2.y r2.z ⎥
|
45
|
+
* ⎣ r3.x r3.y r3.z ⎦
|
46
|
+
* ```
|
47
|
+
*/
|
33
48
|
public static ofRows(r1: Vec3, r2: Vec3, r3: Vec3): Mat33 {
|
34
49
|
return new Mat33(
|
35
50
|
r1.x, r1.y, r1.z,
|
@@ -44,8 +59,13 @@ export default class Mat33 {
|
|
44
59
|
0, 0, 1
|
45
60
|
);
|
46
61
|
|
47
|
-
|
48
|
-
|
62
|
+
/**
|
63
|
+
* Either returns the inverse of this, or, if this matrix is singular/uninvertable,
|
64
|
+
* returns Mat33.identity.
|
65
|
+
*
|
66
|
+
* This may cache the computed inverse and return the cached version instead of recomputing
|
67
|
+
* it.
|
68
|
+
*/
|
49
69
|
public inverse(): Mat33 {
|
50
70
|
return this.computeInverse() ?? Mat33.identity;
|
51
71
|
}
|
@@ -162,9 +182,11 @@ export default class Mat33 {
|
|
162
182
|
);
|
163
183
|
}
|
164
184
|
|
165
|
-
|
166
|
-
|
167
|
-
|
185
|
+
/**
|
186
|
+
* Applies this as an affine transformation to the given vector.
|
187
|
+
* Returns a transformed version of `other`.
|
188
|
+
*/
|
189
|
+
public transformVec2(other: Vec2): Vec2 {
|
168
190
|
// When transforming a Vec2, we want to use the z transformation
|
169
191
|
// components of this for translation:
|
170
192
|
// ⎡ . . tX ⎤
|
@@ -179,8 +201,10 @@ export default class Mat33 {
|
|
179
201
|
return Vec2.of(intermediate.x, intermediate.y);
|
180
202
|
}
|
181
203
|
|
182
|
-
|
183
|
-
|
204
|
+
/**
|
205
|
+
* Applies this as a linear transformation to the given vector (doesn't translate).
|
206
|
+
* This is the standard way of transforming vectors in ℝ³.
|
207
|
+
*/
|
184
208
|
public transformVec3(other: Vec3): Vec3 {
|
185
209
|
return Vec3.of(
|
186
210
|
this.rows[0].dot(other),
|
@@ -189,7 +213,7 @@ export default class Mat33 {
|
|
189
213
|
);
|
190
214
|
}
|
191
215
|
|
192
|
-
|
216
|
+
/** Returns true iff this = other ± fuzz */
|
193
217
|
public eq(other: Mat33, fuzz: number = 0): boolean {
|
194
218
|
for (let i = 0; i < 3; i++) {
|
195
219
|
if (!this.rows[i].eq(other.rows[i], fuzz)) {
|
@@ -205,12 +229,16 @@ export default class Mat33 {
|
|
205
229
|
⎡ ${this.a1},\t ${this.a2},\t ${this.a3}\t ⎤
|
206
230
|
⎢ ${this.b1},\t ${this.b2},\t ${this.b3}\t ⎥
|
207
231
|
⎣ ${this.c1},\t ${this.c2},\t ${this.c3}\t ⎦
|
208
|
-
`.
|
232
|
+
`.trimEnd().trimStart();
|
209
233
|
}
|
210
234
|
|
211
|
-
|
212
|
-
|
213
|
-
|
235
|
+
/**
|
236
|
+
* ```
|
237
|
+
* result[0] = top left element
|
238
|
+
* result[1] = element at row zero, column 1
|
239
|
+
* ...
|
240
|
+
* ```
|
241
|
+
*/
|
214
242
|
public toArray(): number[] {
|
215
243
|
return [
|
216
244
|
this.a1, this.a2, this.a3,
|
@@ -219,7 +247,7 @@ export default class Mat33 {
|
|
219
247
|
];
|
220
248
|
}
|
221
249
|
|
222
|
-
|
250
|
+
/** Constructs a 3x3 translation matrix (for translating `Vec2`s) */
|
223
251
|
public static translation(amount: Vec2): Mat33 {
|
224
252
|
// When transforming Vec2s by a 3x3 matrix, we give the input
|
225
253
|
// Vec2s z = 1. As such,
|
@@ -269,7 +297,7 @@ export default class Mat33 {
|
|
269
297
|
return result.rightMul(Mat33.translation(center.times(-1)));
|
270
298
|
}
|
271
299
|
|
272
|
-
|
300
|
+
/** Converts a CSS-form `matrix(a, b, c, d, e, f)` to a Mat33. */
|
273
301
|
public static fromCSSMatrix(cssString: string): Mat33 {
|
274
302
|
if (cssString === '' || cssString === 'none') {
|
275
303
|
return Mat33.identity;
|
package/src/math/Path.ts
CHANGED
@@ -299,8 +299,8 @@ export default class Path {
|
|
299
299
|
return this.toString();
|
300
300
|
}
|
301
301
|
|
302
|
-
//
|
303
|
-
//
|
302
|
+
// @param onlyAbsCommands - True if we should avoid converting absolute coordinates to relative offsets -- such
|
303
|
+
// conversions can lead to smaller output strings, but also take time.
|
304
304
|
public static toString(startPoint: Point2, parts: PathCommand[], onlyAbsCommands: boolean = true): string {
|
305
305
|
const result: string[] = [];
|
306
306
|
|
@@ -377,7 +377,7 @@ export default class Path {
|
|
377
377
|
|
378
378
|
// Create a Path from a SVG path specification.
|
379
379
|
// TODO: Support a larger subset of SVG paths.
|
380
|
-
// TODO: Support s
|
380
|
+
// TODO: Support `s`,`t` commands shorthands.
|
381
381
|
public static fromString(pathString: string): Path {
|
382
382
|
// See the MDN reference:
|
383
383
|
// https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/d
|
package/src/math/Rect2.ts
CHANGED
@@ -2,8 +2,8 @@ import LineSegment2 from './LineSegment2';
|
|
2
2
|
import Mat33 from './Mat33';
|
3
3
|
import { Point2, Vec2 } from './Vec2';
|
4
4
|
|
5
|
-
|
6
|
-
interface RectTemplate {
|
5
|
+
/** An object that can be converted to a Rect2. */
|
6
|
+
export interface RectTemplate {
|
7
7
|
x: number;
|
8
8
|
y: number;
|
9
9
|
w?: number;
|
package/src/math/Vec3.ts
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
|
2
2
|
|
3
|
-
|
3
|
+
/**
|
4
|
+
* A vector with three components. Can also be used to represent a two-component vector.
|
5
|
+
*
|
6
|
+
* A `Vec3` is immutable.
|
7
|
+
*/
|
4
8
|
export default class Vec3 {
|
5
9
|
private constructor(
|
6
10
|
public readonly x: number,
|
@@ -9,7 +13,7 @@ export default class Vec3 {
|
|
9
13
|
) {
|
10
14
|
}
|
11
15
|
|
12
|
-
|
16
|
+
/** Returns the x, y components of this. */
|
13
17
|
public get xy(): { x: number; y: number } {
|
14
18
|
// Useful for APIs that behave differently if .z is present.
|
15
19
|
return {
|
@@ -22,7 +26,7 @@ export default class Vec3 {
|
|
22
26
|
return new Vec3(x, y, z);
|
23
27
|
}
|
24
28
|
|
25
|
-
|
29
|
+
/** Returns this' `idx`th component. For example, `Vec3.of(1, 2, 3).at(1) → 2`. */
|
26
30
|
public at(idx: number): number {
|
27
31
|
if (idx === 0) return this.x;
|
28
32
|
if (idx === 1) return this.y;
|
@@ -31,7 +35,7 @@ export default class Vec3 {
|
|
31
35
|
throw new Error(`${idx} out of bounds!`);
|
32
36
|
}
|
33
37
|
|
34
|
-
|
38
|
+
/** Alias for this.magnitude. */
|
35
39
|
public length(): number {
|
36
40
|
return this.magnitude();
|
37
41
|
}
|
@@ -44,16 +48,26 @@ export default class Vec3 {
|
|
44
48
|
return this.dot(this);
|
45
49
|
}
|
46
50
|
|
47
|
-
|
51
|
+
/**
|
52
|
+
* Return this' angle in the XY plane (treats this as a Vec2).
|
53
|
+
*
|
54
|
+
* This is equivalent to `Math.atan2(vec.y, vec.x)`.
|
55
|
+
*/
|
48
56
|
public angle(): number {
|
49
57
|
return Math.atan2(this.y, this.x);
|
50
58
|
}
|
51
59
|
|
60
|
+
/**
|
61
|
+
* Returns a unit vector in the same direction as this.
|
62
|
+
*
|
63
|
+
* If `this` has zero length, the resultant vector has `NaN` components.
|
64
|
+
*/
|
52
65
|
public normalized(): Vec3 {
|
53
66
|
const norm = this.magnitude();
|
54
67
|
return Vec3.of(this.x / norm, this.y / norm, this.z / norm);
|
55
68
|
}
|
56
69
|
|
70
|
+
/** @returns A copy of `this` multiplied by a scalar. */
|
57
71
|
public times(c: number): Vec3 {
|
58
72
|
return Vec3.of(this.x * c, this.y * c, this.z * c);
|
59
73
|
}
|
@@ -81,8 +95,10 @@ export default class Vec3 {
|
|
81
95
|
);
|
82
96
|
}
|
83
97
|
|
84
|
-
|
85
|
-
|
98
|
+
/**
|
99
|
+
* Returns a vector orthogonal to this. If this is a Vec2, returns `this` rotated
|
100
|
+
* 90 degrees counter-clockwise.
|
101
|
+
*/
|
86
102
|
public orthog(): Vec3 {
|
87
103
|
// If parallel to the z-axis
|
88
104
|
if (this.dot(Vec3.unitX) === 0 && this.dot(Vec3.unitY) === 0) {
|
@@ -92,18 +108,32 @@ export default class Vec3 {
|
|
92
108
|
return this.cross(Vec3.unitZ.times(-1)).normalized();
|
93
109
|
}
|
94
110
|
|
95
|
-
|
111
|
+
/** Returns this plus a vector of length `distance` in `direction`. */
|
96
112
|
public extend(distance: number, direction: Vec3): Vec3 {
|
97
113
|
return this.plus(direction.normalized().times(distance));
|
98
114
|
}
|
99
115
|
|
100
|
-
|
116
|
+
/** Returns a vector `fractionTo` of the way to target from this. */
|
101
117
|
public lerp(target: Vec3, fractionTo: number): Vec3 {
|
102
118
|
return this.times(1 - fractionTo).plus(target.times(fractionTo));
|
103
119
|
}
|
104
120
|
|
105
|
-
|
106
|
-
|
121
|
+
/**
|
122
|
+
* `zip` Maps a component of this and a corresponding component of
|
123
|
+
* `other` to a component of the output vector.
|
124
|
+
*
|
125
|
+
* @example
|
126
|
+
* ```
|
127
|
+
* const a = Vec3.of(1, 2, 3);
|
128
|
+
* const b = Vec3.of(0.5, 2.1, 2.9);
|
129
|
+
*
|
130
|
+
* const zipped = a.zip(b, (aComponent, bComponent) => {
|
131
|
+
* return Math.min(aComponent, bComponent);
|
132
|
+
* });
|
133
|
+
*
|
134
|
+
* console.log(zipped.toString()); // → Vec(0.5, 2, 2.9)
|
135
|
+
* ```
|
136
|
+
*/
|
107
137
|
public zip(
|
108
138
|
other: Vec3, zip: (componentInThis: number, componentInOther: number)=> number
|
109
139
|
): Vec3 {
|
@@ -114,7 +144,14 @@ export default class Vec3 {
|
|
114
144
|
);
|
115
145
|
}
|
116
146
|
|
117
|
-
|
147
|
+
/**
|
148
|
+
* Returns a vector with each component acted on by `fn`.
|
149
|
+
*
|
150
|
+
* @example
|
151
|
+
* ```
|
152
|
+
* console.log(Vec3.of(1, 2, 3).map(val => val + 1)); // → Vec(2, 3, 4)
|
153
|
+
* ```
|
154
|
+
*/
|
118
155
|
public map(fn: (component: number, index: number)=> number): Vec3 {
|
119
156
|
return Vec3.of(
|
120
157
|
fn(this.x, 0), fn(this.y, 1), fn(this.z, 2)
|
@@ -125,8 +162,19 @@ export default class Vec3 {
|
|
125
162
|
return [this.x, this.y, this.z];
|
126
163
|
}
|
127
164
|
|
128
|
-
|
129
|
-
|
165
|
+
/**
|
166
|
+
* [fuzz] The maximum difference between two components for this and [other]
|
167
|
+
* to be considered equal.
|
168
|
+
*
|
169
|
+
* @example
|
170
|
+
* ```
|
171
|
+
* Vec3.of(1, 2, 3).eq(Vec3.of(4, 5, 6), 100); // → true
|
172
|
+
* Vec3.of(1, 2, 3).eq(Vec3.of(4, 5, 6), 0.1); // → false
|
173
|
+
* Vec3.of(1, 2, 3).eq(Vec3.of(4, 5, 6), 3); // → true
|
174
|
+
* Vec3.of(1, 2, 3).eq(Vec3.of(4, 5, 6), 3.01); // → true
|
175
|
+
* Vec3.of(1, 2, 3).eq(Vec3.of(4, 5, 6), 2.99); // → false
|
176
|
+
* ```
|
177
|
+
*/
|
130
178
|
public eq(other: Vec3, fuzz: number): boolean {
|
131
179
|
for (let i = 0; i < 3; i++) {
|
132
180
|
if (Math.abs(other.at(i) - this.at(i)) > fuzz) {
|
package/src/math/lib.ts
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
import LineSegment2 from './LineSegment2';
|
2
|
+
import Mat33 from './Mat33';
|
3
|
+
import Path from './Path';
|
4
|
+
import Rect2 from './Rect2';
|
5
|
+
import { Vec2 } from './Vec2';
|
6
|
+
import Vec3 from './Vec3';
|
7
|
+
|
8
|
+
export {
|
9
|
+
LineSegment2,
|
10
|
+
Mat33,
|
11
|
+
Path,
|
12
|
+
Rect2,
|
13
|
+
Vec3,
|
14
|
+
Vec2,
|
15
|
+
};
|
package/src/math/rounding.ts
CHANGED
package/src/rendering/Display.ts
CHANGED
@@ -1,3 +1,18 @@
|
|
1
|
+
/**
|
2
|
+
* Handles `HTMLCanvasElement`s (or other drawing surfaces if being used) used to display the editor's contents.
|
3
|
+
*
|
4
|
+
* @example
|
5
|
+
* ```
|
6
|
+
* const editor = new Editor(document.body);
|
7
|
+
* const w = editor.display.width;
|
8
|
+
* const h = editor.display.height;
|
9
|
+
* const center = Vec2.of(w / 2, h / 2);
|
10
|
+
* const colorAtCenter = editor.display.getColorAt(center);
|
11
|
+
* ```
|
12
|
+
*
|
13
|
+
* @packageDocumentation
|
14
|
+
*/
|
15
|
+
|
1
16
|
import AbstractRenderer from './renderers/AbstractRenderer';
|
2
17
|
import CanvasRenderer from './renderers/CanvasRenderer';
|
3
18
|
import { Editor } from '../Editor';
|
@@ -23,6 +38,7 @@ export default class Display {
|
|
23
38
|
private resizeSurfacesCallback?: ()=> void;
|
24
39
|
private flattenCallback?: ()=> void;
|
25
40
|
|
41
|
+
/** @internal */
|
26
42
|
public constructor(
|
27
43
|
private editor: Editor, mode: RenderingMode, private parent: HTMLElement|null
|
28
44
|
) {
|
@@ -60,7 +76,7 @@ export default class Display {
|
|
60
76
|
return this.dryInkRenderer.canRenderFromWithoutDataLoss(renderer);
|
61
77
|
},
|
62
78
|
blockResolution: cacheBlockResolution,
|
63
|
-
cacheSize: 500 * 500 * 4 *
|
79
|
+
cacheSize: 500 * 500 * 4 * 150,
|
64
80
|
maxScale: 1.5,
|
65
81
|
minComponentsPerCache: 45,
|
66
82
|
minComponentsToUseCache: 105,
|
@@ -75,9 +91,11 @@ export default class Display {
|
|
75
91
|
});
|
76
92
|
}
|
77
93
|
|
78
|
-
|
79
|
-
|
80
|
-
|
94
|
+
/**
|
95
|
+
* @returns the visible width of the display (e.g. how much
|
96
|
+
* space the display's element takes up in the x direction
|
97
|
+
* in the DOM).
|
98
|
+
*/
|
81
99
|
public get width(): number {
|
82
100
|
return this.dryInkRenderer.displaySize().x;
|
83
101
|
}
|
@@ -86,10 +104,15 @@ export default class Display {
|
|
86
104
|
return this.dryInkRenderer.displaySize().y;
|
87
105
|
}
|
88
106
|
|
107
|
+
/** @internal */
|
89
108
|
public getCache() {
|
90
109
|
return this.cache;
|
91
110
|
}
|
92
111
|
|
112
|
+
/**
|
113
|
+
* @returns the color at the given point on the dry ink renderer, or `null` if `screenPos`
|
114
|
+
* is not on the display.
|
115
|
+
*/
|
93
116
|
public getColorAt = (_screenPos: Point2): Color4|null => {
|
94
117
|
return null;
|
95
118
|
};
|
@@ -170,6 +193,10 @@ export default class Display {
|
|
170
193
|
this.editor.createHTMLOverlay(textRendererOutputContainer);
|
171
194
|
}
|
172
195
|
|
196
|
+
/**
|
197
|
+
* Rerenders the text-based display.
|
198
|
+
* The text-based display is intended for screen readers and can be navigated to by pressing `tab`.
|
199
|
+
*/
|
173
200
|
public rerenderAsText() {
|
174
201
|
this.textRenderer.clear();
|
175
202
|
this.editor.image.render(this.textRenderer, this.editor.viewport);
|
@@ -179,7 +206,11 @@ export default class Display {
|
|
179
206
|
}
|
180
207
|
}
|
181
208
|
|
182
|
-
|
209
|
+
/**
|
210
|
+
* Clears the drawing surfaces and otherwise prepares for a rerender.
|
211
|
+
*
|
212
|
+
* @returns the dry ink renderer.
|
213
|
+
*/
|
183
214
|
public startRerender(): AbstractRenderer {
|
184
215
|
this.resizeSurfacesCallback?.();
|
185
216
|
this.wetInkRenderer.clear();
|
@@ -188,19 +219,28 @@ export default class Display {
|
|
188
219
|
return this.dryInkRenderer;
|
189
220
|
}
|
190
221
|
|
222
|
+
/**
|
223
|
+
* If `draftMode`, the dry ink renderer is configured to render
|
224
|
+
* low-quality output.
|
225
|
+
*/
|
191
226
|
public setDraftMode(draftMode: boolean) {
|
192
227
|
this.dryInkRenderer.setDraftMode(draftMode);
|
193
228
|
}
|
194
229
|
|
230
|
+
/** @internal */
|
195
231
|
public getDryInkRenderer(): AbstractRenderer {
|
196
232
|
return this.dryInkRenderer;
|
197
233
|
}
|
198
234
|
|
235
|
+
/**
|
236
|
+
* @returns The renderer used for showing action previews (e.g. an unfinished stroke).
|
237
|
+
* The `wetInkRenderer`'s surface is stacked above the `dryInkRenderer`'s.
|
238
|
+
*/
|
199
239
|
public getWetInkRenderer(): AbstractRenderer {
|
200
240
|
return this.wetInkRenderer;
|
201
241
|
}
|
202
242
|
|
203
|
-
|
243
|
+
/** Re-renders the contents of the wetInkRenderer onto the dryInkRenderer. */
|
204
244
|
public flatten() {
|
205
245
|
this.flattenCallback?.();
|
206
246
|
}
|
@@ -11,6 +11,9 @@ export default class CacheRecord {
|
|
11
11
|
private lastUsedCycle: number;
|
12
12
|
private allocd: boolean = false;
|
13
13
|
|
14
|
+
// For debugging
|
15
|
+
public allocCount: number = 0;
|
16
|
+
|
14
17
|
public constructor(
|
15
18
|
private onBeforeDeallocCallback: BeforeDeallocCallback|null,
|
16
19
|
private cacheState: CacheState,
|
@@ -46,6 +49,7 @@ export default class CacheRecord {
|
|
46
49
|
this.allocd = true;
|
47
50
|
this.onBeforeDeallocCallback = newDeallocCallback;
|
48
51
|
this.lastUsedCycle = this.cacheState.currentRenderingCycle;
|
52
|
+
this.allocCount ++;
|
49
53
|
}
|
50
54
|
|
51
55
|
public getLastUsedCycle(): number {
|