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.
Files changed (132) hide show
  1. package/.eslintrc.js +1 -0
  2. package/.firebaserc +5 -0
  3. package/.github/ISSUE_TEMPLATE/bug_report.md +34 -0
  4. package/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  5. package/.github/ISSUE_TEMPLATE/translation.md +96 -0
  6. package/.github/workflows/firebase-hosting-merge.yml +25 -0
  7. package/.github/workflows/firebase-hosting-pull-request.yml +22 -0
  8. package/.github/workflows/github-pages.yml +52 -0
  9. package/CHANGELOG.md +9 -0
  10. package/README.md +11 -6
  11. package/dist/bundle.js +1 -1
  12. package/dist/src/Color4.d.ts +19 -0
  13. package/dist/src/Color4.js +24 -3
  14. package/dist/src/Editor.d.ts +129 -2
  15. package/dist/src/Editor.js +94 -17
  16. package/dist/src/EditorImage.d.ts +7 -2
  17. package/dist/src/EditorImage.js +41 -25
  18. package/dist/src/EventDispatcher.d.ts +18 -0
  19. package/dist/src/EventDispatcher.js +19 -4
  20. package/dist/src/Pointer.js +3 -2
  21. package/dist/src/UndoRedoHistory.js +15 -2
  22. package/dist/src/Viewport.js +4 -1
  23. package/dist/src/bundle/bundled.d.ts +1 -2
  24. package/dist/src/bundle/bundled.js +1 -2
  25. package/dist/src/commands/Duplicate.d.ts +1 -1
  26. package/dist/src/commands/Duplicate.js +3 -4
  27. package/dist/src/commands/Erase.d.ts +1 -1
  28. package/dist/src/commands/Erase.js +6 -5
  29. package/dist/src/commands/SerializableCommand.d.ts +4 -5
  30. package/dist/src/commands/SerializableCommand.js +12 -4
  31. package/dist/src/commands/invertCommand.d.ts +4 -0
  32. package/dist/src/commands/invertCommand.js +44 -0
  33. package/dist/src/commands/lib.d.ts +6 -0
  34. package/dist/src/commands/lib.js +6 -0
  35. package/dist/src/commands/localization.d.ts +1 -0
  36. package/dist/src/commands/localization.js +1 -0
  37. package/dist/src/components/AbstractComponent.d.ts +13 -8
  38. package/dist/src/components/AbstractComponent.js +26 -15
  39. package/dist/src/components/SVGGlobalAttributesObject.d.ts +1 -1
  40. package/dist/src/components/SVGGlobalAttributesObject.js +7 -1
  41. package/dist/src/components/Stroke.d.ts +12 -2
  42. package/dist/src/components/Stroke.js +10 -7
  43. package/dist/src/components/Text.d.ts +2 -2
  44. package/dist/src/components/Text.js +6 -6
  45. package/dist/src/components/UnknownSVGObject.d.ts +1 -1
  46. package/dist/src/components/UnknownSVGObject.js +6 -1
  47. package/dist/src/components/lib.d.ts +4 -0
  48. package/dist/src/components/lib.js +4 -0
  49. package/dist/src/lib.d.ts +25 -0
  50. package/dist/src/lib.js +25 -0
  51. package/dist/src/localizations/de.d.ts +3 -0
  52. package/dist/src/localizations/de.js +4 -0
  53. package/dist/src/localizations/getLocalizationTable.js +2 -0
  54. package/dist/src/math/Mat33.d.ts +47 -1
  55. package/dist/src/math/Mat33.js +48 -20
  56. package/dist/src/math/Path.js +3 -3
  57. package/dist/src/math/Rect2.d.ts +2 -2
  58. package/dist/src/math/Vec3.d.ts +62 -0
  59. package/dist/src/math/Vec3.js +62 -14
  60. package/dist/src/math/lib.d.ts +7 -0
  61. package/dist/src/math/lib.js +7 -0
  62. package/dist/src/math/rounding.js +1 -0
  63. package/dist/src/rendering/Display.d.ts +44 -0
  64. package/dist/src/rendering/Display.js +45 -6
  65. package/dist/src/rendering/caching/CacheRecord.d.ts +1 -0
  66. package/dist/src/rendering/caching/CacheRecord.js +3 -0
  67. package/dist/src/rendering/caching/CacheRecordManager.d.ts +4 -3
  68. package/dist/src/rendering/caching/CacheRecordManager.js +16 -4
  69. package/dist/src/rendering/caching/RenderingCache.d.ts +2 -3
  70. package/dist/src/rendering/caching/RenderingCache.js +9 -10
  71. package/dist/src/rendering/caching/types.d.ts +1 -3
  72. package/dist/src/rendering/renderers/CanvasRenderer.js +1 -1
  73. package/dist/src/toolbar/HTMLToolbar.js +1 -0
  74. package/dist/src/toolbar/makeColorInput.js +1 -1
  75. package/dist/src/toolbar/widgets/PenWidget.js +1 -0
  76. package/dist/src/tools/Pen.d.ts +1 -2
  77. package/dist/src/tools/Pen.js +8 -1
  78. package/dist/src/tools/PipetteTool.js +1 -0
  79. package/dist/src/tools/SelectionTool.js +45 -22
  80. package/dist/src/types.d.ts +17 -6
  81. package/dist/src/types.js +7 -5
  82. package/firebase.json +16 -0
  83. package/package.json +118 -101
  84. package/src/Color4.ts +23 -2
  85. package/src/Editor.ts +147 -25
  86. package/src/EditorImage.ts +45 -27
  87. package/src/EventDispatcher.ts +21 -6
  88. package/src/Pointer.ts +3 -2
  89. package/src/UndoRedoHistory.ts +18 -2
  90. package/src/Viewport.ts +5 -2
  91. package/src/bundle/bundled.ts +1 -2
  92. package/src/commands/Duplicate.ts +3 -4
  93. package/src/commands/Erase.ts +6 -5
  94. package/src/commands/SerializableCommand.ts +17 -9
  95. package/src/commands/invertCommand.ts +51 -0
  96. package/src/commands/lib.ts +14 -0
  97. package/src/commands/localization.ts +2 -0
  98. package/src/components/AbstractComponent.ts +31 -20
  99. package/src/components/SVGGlobalAttributesObject.ts +8 -1
  100. package/src/components/Stroke.test.ts +1 -1
  101. package/src/components/Stroke.ts +11 -7
  102. package/src/components/Text.ts +6 -7
  103. package/src/components/UnknownSVGObject.ts +7 -1
  104. package/src/components/lib.ts +9 -0
  105. package/src/lib.ts +28 -0
  106. package/src/localizations/de.ts +98 -0
  107. package/src/localizations/getLocalizationTable.ts +2 -0
  108. package/src/math/Mat33.ts +48 -20
  109. package/src/math/Path.ts +3 -3
  110. package/src/math/Rect2.ts +2 -2
  111. package/src/math/Vec3.ts +62 -14
  112. package/src/math/lib.ts +15 -0
  113. package/src/math/rounding.ts +2 -0
  114. package/src/rendering/Display.ts +46 -6
  115. package/src/rendering/caching/CacheRecord.test.ts +1 -1
  116. package/src/rendering/caching/CacheRecord.ts +4 -0
  117. package/src/rendering/caching/CacheRecordManager.ts +33 -7
  118. package/src/rendering/caching/RenderingCache.ts +10 -15
  119. package/src/rendering/caching/types.ts +1 -6
  120. package/src/rendering/renderers/CanvasRenderer.ts +1 -1
  121. package/src/styles.js +4 -0
  122. package/src/toolbar/HTMLToolbar.ts +1 -0
  123. package/src/toolbar/makeColorInput.ts +1 -1
  124. package/src/toolbar/toolbar.css +8 -2
  125. package/src/toolbar/widgets/PenWidget.ts +2 -0
  126. package/src/tools/PanZoom.ts +0 -1
  127. package/src/tools/Pen.ts +11 -2
  128. package/src/tools/PipetteTool.ts +2 -0
  129. package/src/tools/SelectionTool.ts +46 -18
  130. package/src/types.ts +19 -3
  131. package/tsconfig.json +4 -1
  132. package/typedoc.json +20 -0
@@ -111,19 +111,23 @@ export default class Stroke extends AbstractComponent {
111
111
  return new Stroke(this.parts);
112
112
  }
113
113
 
114
- protected serializeToString(): string | null {
115
- return JSON.stringify(this.parts.map(part => {
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
- public static deserializeFromString(data: string): Stroke {
124
- const json = JSON.parse(data);
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(`${data} is missing required field, parts, or parts is of the wrong type.`);
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.deserializeFromString);
141
+ AbstractComponent.registerComponent('stroke', Stroke.deserializeFromJSON);
@@ -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 serializeToString(): string {
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.serializeToString(),
169
+ json: text.serializeToJSON(),
169
170
  };
170
171
  }
171
172
  });
172
173
 
173
- return JSON.stringify({
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(data: string, getTextDimens: GetTextDimensCallback = Text.getTextDimens): Text {
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 serializeToString(): string | null {
48
+ protected serializeToJSON(): string | null {
43
49
  return JSON.stringify({
44
50
  html: this.svgObject.outerHTML,
45
51
  });
@@ -0,0 +1,9 @@
1
+ import AbstractComponent from './AbstractComponent';
2
+ import Stroke from './Stroke';
3
+ import Text from './Text';
4
+
5
+ export {
6
+ AbstractComponent,
7
+ Stroke,
8
+ Text,
9
+ };
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;
@@ -1,9 +1,11 @@
1
1
 
2
2
  import { defaultEditorLocalization, EditorLocalization } from '../localization';
3
+ import de from './de';
3
4
  import en from './en';
4
5
  import es from './es';
5
6
 
6
7
  const allLocales: Record<string, EditorLocalization> = {
8
+ de,
7
9
  en,
8
10
  es,
9
11
  };
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
- // 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).
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
- // ⎡ a1 a2 a3 ⎤
11
- // b1 b2 b3
12
- // ⎣ c1 c2 c3 ⎦
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
- // Either returns the inverse of this, or, if this matrix is singular/uninvertable,
48
- // returns Mat33.identity.
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
- // Applies this as an affine transformation to the given vector.
166
- // Returns a transformed version of [other].
167
- public transformVec2(other: Vec3): Vec2 {
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
- // Applies this as a linear transformation to the given vector (doesn't translate).
183
- // This is the standard way of transforming vectors in ℝ³.
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
- // Returns true iff this = other ± fuzz
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
- `.trimRight();
232
+ `.trimEnd().trimStart();
209
233
  }
210
234
 
211
- // result[0] = top left element
212
- // result[1] = element at row zero, column 1
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
- // Constructs a 3x3 translation matrix (for translating Vec2s)
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
- // Converts a CSS-form matrix(a, b, c, d, e, f) to a Mat33.
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
- // [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.
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,t shorthands.
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
- // An object that can be converted to a Rect2.
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
- // A vector with three components. Can also be used to represent a two-component vector
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
- // Returns the x, y components of this
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
- // Returns this' [idx]th component
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
- // Alias for this.magnitude
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
- // Return this' angle in the XY plane (treats this as a Vec2)
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
- // Returns a vector orthogonal to this. If this is a Vec2, returns [this] rotated
85
- // 90 degrees counter-clockwise.
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
- // Returns this plus a vector of length [distance] in [direction]
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
- // Returns a vector [fractionTo] of the way to target from this.
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
- // [zip] Maps a component of this and a corresponding component of
106
- // [other] to a component of the output vector.
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
- // Returns a vector with each component acted on by [fn]
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
- // [fuzz] The maximum difference between two components for this and [other]
129
- // to be considered equal.
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) {
@@ -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
+ };
@@ -1,3 +1,5 @@
1
+ // @packageDocumentation @internal
2
+
1
3
  // Clean up stringified numbers
2
4
  const cleanUpNumber = (text: string) => {
3
5
  // Regular expression substitions can be somewhat expensive. Only do them