js-draw 0.1.12 → 0.2.1
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/ISSUE_TEMPLATE/bug_report.md +34 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- package/.github/ISSUE_TEMPLATE/translation.md +96 -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 +9 -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/localizations/de.d.ts +3 -0
- package/dist/src/localizations/de.js +4 -0
- package/dist/src/localizations/getLocalizationTable.js +2 -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/localizations/de.ts +98 -0
- package/src/localizations/getLocalizationTable.ts +2 -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/styles.js +4 -0
- package/src/toolbar/HTMLToolbar.ts +1 -0
- package/src/toolbar/makeColorInput.ts +1 -1
- package/src/toolbar/toolbar.css +8 -2
- 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;
|
@@ -0,0 +1,98 @@
|
|
1
|
+
import { defaultEditorLocalization, EditorLocalization } from '../localization';
|
2
|
+
|
3
|
+
// German localization
|
4
|
+
const localization: EditorLocalization = {
|
5
|
+
...defaultEditorLocalization,
|
6
|
+
|
7
|
+
pen: 'Stift',
|
8
|
+
eraser: 'Radierer',
|
9
|
+
select: 'Auswahl',
|
10
|
+
handTool: 'Verschieben',
|
11
|
+
|
12
|
+
zoom: 'Vergrößerung',
|
13
|
+
resetView: 'Ansicht zurücksetzen',
|
14
|
+
|
15
|
+
thicknessLabel: 'Dicke: ',
|
16
|
+
colorLabel: 'Farbe: ',
|
17
|
+
fontLabel: 'Schriftart: ',
|
18
|
+
|
19
|
+
resizeImageToSelection: 'Bildgröße an Auswahl anpassen',
|
20
|
+
deleteSelection: 'Auswahl löschen',
|
21
|
+
duplicateSelection: 'Auswahl duplizieren',
|
22
|
+
|
23
|
+
undo: 'Rückgängig',
|
24
|
+
redo: 'Wiederholen',
|
25
|
+
|
26
|
+
pickColorFromScreen: 'Farbe von Bildschirm auswählen',
|
27
|
+
clickToPickColorAnnouncement: 'Klicke auf den Bildschirm, um eine Farbe auszuwählen',
|
28
|
+
selectionToolKeyboardShortcuts: 'Auswahl-Werkzeug: Verwende die Pfeiltasten, um ausgewählte Elemente zu verschieben und ‚i‘ und ‚o‘, um ihre Größe zu ändern.',
|
29
|
+
touchPanning: 'Ansicht mit Touchscreen verschieben',
|
30
|
+
anyDevicePanning: 'Ansicht mit jedem Eingabegerät verschieben',
|
31
|
+
|
32
|
+
selectObjectType: 'Objekt-Typ: ',
|
33
|
+
freehandPen: 'Freihand',
|
34
|
+
arrowPen: 'Pfeil',
|
35
|
+
linePen: 'Linie',
|
36
|
+
outlinedRectanglePen: 'Umrissenes Rechteck',
|
37
|
+
filledRectanglePen: 'Ausgefülltes Rechteck',
|
38
|
+
|
39
|
+
dropdownShown: t=>`Dropdown-Menü für ${t} angezeigt`,
|
40
|
+
dropdownHidden: t=>`Dropdown-Menü für ${t} versteckt`,
|
41
|
+
zoomLevel: t=>`Vergößerung: ${t}%`,
|
42
|
+
colorChangedAnnouncement: t=>`Farbe zu ${t} geändert`,
|
43
|
+
penTool: t=>`Stift ${t}`,
|
44
|
+
|
45
|
+
selectionTool: 'Auswahl',
|
46
|
+
eraserTool: 'Radiergummi',
|
47
|
+
touchPanTool: 'Ansicht mit Touchscreen verschieben',
|
48
|
+
twoFingerPanZoomTool: 'Ansicht verschieben und vergrößern',
|
49
|
+
undoRedoTool: 'Rückgängig/Wiederholen',
|
50
|
+
rightClickDragPanTool: 'Rechtsklick-Ziehen',
|
51
|
+
pipetteTool: 'Farbe von Bildschirm auswählen',
|
52
|
+
keyboardPanZoom: 'Tastaturkürzel zum Verschieben/Vergrößern der Ansicht',
|
53
|
+
textTool: 'Text',
|
54
|
+
enterTextToInsert: 'Einzufügender Text',
|
55
|
+
|
56
|
+
toolEnabledAnnouncement: t=>`${t} aktiviert`,
|
57
|
+
toolDisabledAnnouncement: t=>`${t} deaktiviert`,
|
58
|
+
updatedViewport: 'Transformierte Ansicht',
|
59
|
+
transformedElements: t=>`${t} Element${1===t?'':'e'} transformiert`,
|
60
|
+
resizeOutputCommand: t=>`Bildgröße auf ${t.w}x${t.h} geändert`,
|
61
|
+
addElementAction: t=>`${t} hinzugefügt`,
|
62
|
+
eraseAction: (t,e)=>`${e} ${t} gelöscht`,
|
63
|
+
duplicateAction: (t,e)=>`${e} ${t} dupliziert`,
|
64
|
+
inverseOf: t=>`Umkehrung von ${t}`,
|
65
|
+
|
66
|
+
elements: 'Elemente',
|
67
|
+
erasedNoElements: 'Nichts entfernt',
|
68
|
+
duplicatedNoElements: 'Nichts dupliziert',
|
69
|
+
rotatedBy: t=>`${Math.abs(t)} Grad ${t<0?'im Uhrzeigersinn':'gegen den Uhrzeigersinn'} gedreht`,
|
70
|
+
|
71
|
+
movedLeft: 'Nacht links bewegt',
|
72
|
+
movedUp: 'Nacht oben bewegt',
|
73
|
+
movedDown: 'Nacht unten bewegt',
|
74
|
+
movedRight: 'Nacht rechts bewegt',
|
75
|
+
zoomedOut: 'Ansicht verkleinert',
|
76
|
+
zoomedIn: 'Ansicht vergrößert',
|
77
|
+
|
78
|
+
selectedElements: t=>`${t} Element${ 1===t ? '' : 'e' } ausgewählt`,
|
79
|
+
stroke: 'Strich',
|
80
|
+
svgObject: 'SVG-Objekt',
|
81
|
+
|
82
|
+
text: t=>`Text-Objekt: ${t}`,
|
83
|
+
pathNodeCount: t=>`Es gibt ${t} sichtbare Pfad-Objekte.`,
|
84
|
+
textNodeCount: t=>`Es gibt ${t} sichtbare Text-Knotenpunkte.`,
|
85
|
+
textNode: t=>`Text: ${t}`,
|
86
|
+
|
87
|
+
rerenderAsText: 'Als Text darstellen',
|
88
|
+
accessibilityInputInstructions: 'Drücke ‚t‘, um den Inhalt des Ansichtsfensters als Text zu lesen. Verwende die Pfeiltasten, um die Ansicht zu verschieben, und klicke und ziehe, um Striche zu zeichnen. Drücke ‚w‘ zum Vergrößern und ‚s‘ zum Verkleinern der Ansicht.',
|
89
|
+
|
90
|
+
loading: t=>`Laden ${t}%...`,
|
91
|
+
doneLoading: 'Laden fertig',
|
92
|
+
|
93
|
+
imageEditor: 'Bild-Editor',
|
94
|
+
undoAnnouncement: t=>`Rückgangig gemacht ${t}`,
|
95
|
+
redoAnnouncement: t=>`Wiederholt ${t}`,
|
96
|
+
};
|
97
|
+
|
98
|
+
export default localization;
|
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
|
+
};
|