js-draw 0.12.0 → 0.13.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.
Files changed (70) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/dist/bundle.js +1 -1
  3. package/dist/src/Color4.d.ts +12 -0
  4. package/dist/src/Color4.js +16 -0
  5. package/dist/src/Editor.d.ts +33 -18
  6. package/dist/src/Editor.js +22 -19
  7. package/dist/src/EditorImage.d.ts +12 -0
  8. package/dist/src/EditorImage.js +12 -0
  9. package/dist/src/Pointer.d.ts +1 -0
  10. package/dist/src/Pointer.js +8 -0
  11. package/dist/src/SVGLoader.d.ts +5 -0
  12. package/dist/src/SVGLoader.js +6 -1
  13. package/dist/src/Viewport.d.ts +30 -1
  14. package/dist/src/Viewport.js +39 -9
  15. package/dist/src/commands/invertCommand.js +1 -1
  16. package/dist/src/components/AbstractComponent.d.ts +19 -0
  17. package/dist/src/components/AbstractComponent.js +17 -2
  18. package/dist/src/lib.d.ts +6 -3
  19. package/dist/src/lib.js +4 -1
  20. package/dist/src/math/Mat33.d.ts +1 -1
  21. package/dist/src/math/Mat33.js +1 -1
  22. package/dist/src/rendering/Display.d.ts +9 -11
  23. package/dist/src/rendering/Display.js +12 -14
  24. package/dist/src/rendering/lib.d.ts +3 -0
  25. package/dist/src/rendering/lib.js +3 -0
  26. package/dist/src/rendering/renderers/DummyRenderer.js +2 -2
  27. package/dist/src/rendering/renderers/SVGRenderer.js +4 -0
  28. package/dist/src/toolbar/IconProvider.d.ts +1 -1
  29. package/dist/src/toolbar/IconProvider.js +90 -29
  30. package/dist/src/tools/PanZoom.js +1 -1
  31. package/dist/src/tools/PasteHandler.d.ts +11 -4
  32. package/dist/src/tools/PasteHandler.js +12 -5
  33. package/dist/src/tools/Pen.d.ts +7 -2
  34. package/dist/src/tools/Pen.js +39 -6
  35. package/dist/src/tools/SelectionTool/SelectionHandle.d.ts +3 -0
  36. package/dist/src/tools/SelectionTool/SelectionHandle.js +6 -0
  37. package/dist/src/tools/SelectionTool/SelectionTool.d.ts +3 -1
  38. package/dist/src/tools/SelectionTool/SelectionTool.js +53 -15
  39. package/dist/src/tools/ToolSwitcherShortcut.d.ts +8 -0
  40. package/dist/src/tools/ToolSwitcherShortcut.js +9 -3
  41. package/dist/src/tools/UndoRedoShortcut.js +2 -4
  42. package/package.json +2 -2
  43. package/src/Color4.test.ts +11 -0
  44. package/src/Color4.ts +22 -0
  45. package/src/Editor.ts +36 -22
  46. package/src/EditorImage.ts +12 -0
  47. package/src/Pointer.ts +19 -0
  48. package/src/SVGLoader.ts +6 -1
  49. package/src/Viewport.ts +50 -11
  50. package/src/commands/invertCommand.ts +1 -1
  51. package/src/components/AbstractComponent.ts +33 -2
  52. package/src/lib.ts +6 -3
  53. package/src/math/Mat33.ts +1 -1
  54. package/src/rendering/Display.ts +12 -15
  55. package/src/rendering/RenderingStyle.ts +1 -1
  56. package/src/rendering/lib.ts +4 -0
  57. package/src/rendering/renderers/DummyRenderer.ts +2 -3
  58. package/src/rendering/renderers/SVGRenderer.ts +4 -0
  59. package/src/rendering/renderers/TextOnlyRenderer.ts +0 -1
  60. package/src/toolbar/HTMLToolbar.ts +1 -1
  61. package/src/toolbar/IconProvider.ts +98 -31
  62. package/src/tools/PanZoom.ts +1 -1
  63. package/src/tools/PasteHandler.ts +12 -6
  64. package/src/tools/Pen.test.ts +44 -1
  65. package/src/tools/Pen.ts +53 -8
  66. package/src/tools/SelectionTool/SelectionHandle.ts +9 -0
  67. package/src/tools/SelectionTool/SelectionTool.ts +67 -15
  68. package/src/tools/ToolSwitcherShortcut.ts +10 -5
  69. package/src/tools/UndoRedoShortcut.ts +2 -5
  70. package/typedoc.json +2 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "js-draw",
3
- "version": "0.12.0",
3
+ "version": "0.13.0",
4
4
  "description": "Draw pictures using a pen, touchscreen, or mouse! JS-draw is a drawing library for JavaScript and TypeScript. ",
5
5
  "main": "./dist/src/lib.d.ts",
6
6
  "types": "./dist/src/lib.js",
@@ -101,7 +101,7 @@
101
101
  "ts-jest": "^29.0.3",
102
102
  "ts-loader": "^9.4.2",
103
103
  "ts-node": "^10.9.1",
104
- "typedoc": "^0.23.23",
104
+ "typedoc": "^0.23.24",
105
105
  "typescript": "^4.9.4",
106
106
  "webpack": "^5.75.0"
107
107
  },
@@ -16,4 +16,15 @@ describe('Color4', () => {
16
16
  expect(Color4.fromString('rgba ( 255, 0,\t 0, 0.5)')).objEq(Color4.ofRGBA(1, 0, 0, 0.5));
17
17
  expect(Color4.fromString('rgba( 0, 0, 128, 0)')).objEq(Color4.ofRGBA(0, 0, 128/255, 0));
18
18
  });
19
+
20
+ it('should mix blue and red to get dark purple', () => {
21
+ expect(Color4.ofRGB(1, 0, 0).mix(Color4.ofRGB(0, 0, 1), 0.5)).objEq(Color4.ofRGB(0.5, 0, 0.5));
22
+ expect(Color4.ofRGB(1, 0, 0).mix(Color4.ofRGB(0, 0, 1), 0.1)).objEq(Color4.ofRGB(0.9, 0, 0.1));
23
+ });
24
+
25
+ it('should mix red and green to get yellow', () => {
26
+ expect(Color4.ofRGB(1, 0, 0).mix(Color4.ofRGB(0, 1, 0), 0.3)).objEq(
27
+ Color4.ofRGB(0.7, 0.3, 0)
28
+ );
29
+ });
19
30
  });
package/src/Color4.ts CHANGED
@@ -129,6 +129,28 @@ export default class Color4 {
129
129
  return this.toHexString() === other.toHexString();
130
130
  }
131
131
 
132
+ /**
133
+ * If `fractionTo` is not in the range [0, 1], it will be clamped to the nearest number
134
+ * in that range. For example, `a.mix(b, -1)` is equivalent to `a.mix(b, 0)`.
135
+ *
136
+ * @returns a color `fractionTo` of the way from this color to `other`.
137
+ *
138
+ * @example
139
+ * ```ts
140
+ * Color4.ofRGB(1, 0, 0).mix(Color4.ofRGB(0, 1, 0), 0.1) // -> Color4(0.9, 0.1, 0)
141
+ * ```
142
+ */
143
+ public mix(other: Color4, fractionTo: number): Color4 {
144
+ fractionTo = Math.min(Math.max(fractionTo, 0), 1);
145
+ const fractionOfThis = 1 - fractionTo;
146
+ return new Color4(
147
+ this.r * fractionOfThis + other.r * fractionTo,
148
+ this.g * fractionOfThis + other.g * fractionTo,
149
+ this.b * fractionOfThis + other.b * fractionTo,
150
+ this.a * fractionOfThis + other.a * fractionTo,
151
+ );
152
+ }
153
+
132
154
  private hexString: string|null = null;
133
155
 
134
156
  /**
package/src/Editor.ts CHANGED
@@ -1,22 +1,3 @@
1
- /**
2
- * The main entrypoint for the full editor.
3
- *
4
- * @example
5
- * To create an editor with a toolbar,
6
- * ```
7
- * const editor = new Editor(document.body);
8
- *
9
- * const toolbar = editor.addToolbar();
10
- * toolbar.addActionButton('Save', () => {
11
- * const saveData = editor.toSVG().outerHTML;
12
- * // Do something with saveData...
13
- * });
14
- * ```
15
- *
16
- * @packageDocumentation
17
- */
18
-
19
-
20
1
  import EditorImage from './EditorImage';
21
2
  import ToolController from './tools/ToolController';
22
3
  import { InputEvtType, PointerEvt, EditorNotifier, EditorEventType, ImageLoader } from './types';
@@ -70,12 +51,27 @@ export interface EditorSettings {
70
51
  iconProvider: IconProvider,
71
52
  }
72
53
 
73
- // { @inheritDoc Editor! }
54
+ /**
55
+ * The main entrypoint for the full editor.
56
+ *
57
+ * @example
58
+ * To create an editor with a toolbar,
59
+ * ```
60
+ * const editor = new Editor(document.body);
61
+ *
62
+ * const toolbar = editor.addToolbar();
63
+ * toolbar.addActionButton('Save', () => {
64
+ * const saveData = editor.toSVG().outerHTML;
65
+ * // Do something with saveData...
66
+ * });
67
+ * ```
68
+ */
74
69
  export class Editor {
75
70
  // Wrapper around the viewport and toolbar
76
71
  private container: HTMLElement;
77
72
  private renderingRegion: HTMLElement;
78
73
 
74
+ /** Manages drawing surfaces/{@link lib!AbstractRenderer}s. */
79
75
  public display: Display;
80
76
 
81
77
  /**
@@ -116,11 +112,23 @@ export class Editor {
116
112
  /** Viewport for the exported/imported image. */
117
113
  private importExportViewport: Viewport;
118
114
 
115
+ /**
116
+ * Allows transforming the view and querying information about
117
+ * what is currently visible.
118
+ */
119
+ public readonly viewport: Viewport;
120
+
119
121
  /** @internal */
120
122
  public readonly localization: EditorLocalization;
121
123
 
124
+ /** {@link lib!EditorSettings.iconProvider} */
122
125
  public readonly icons: IconProvider;
123
- public readonly viewport: Viewport;
126
+
127
+ /**
128
+ * Controls the list of tools. See
129
+ * [the custom tool example](https://github.com/personalizedrefrigerator/js-draw/tree/main/docs/example-custom-tools)
130
+ * for more.
131
+ */
124
132
  public readonly toolController: ToolController;
125
133
 
126
134
  /**
@@ -765,12 +773,18 @@ export class Editor {
765
773
  this.nextRerenderListeners = [];
766
774
  }
767
775
 
776
+ /**
777
+ * @see {@link Display.getWetInkRenderer} {@link Display.flatten}
778
+ */
768
779
  public drawWetInk(...path: RenderablePathSpec[]) {
769
780
  for (const part of path) {
770
781
  this.display.getWetInkRenderer().drawPath(part);
771
782
  }
772
783
  }
773
784
 
785
+ /**
786
+ * @see {@link Display.getWetInkRenderer}
787
+ */
774
788
  public clearWetInk() {
775
789
  this.display.getWetInkRenderer().clear();
776
790
  }
@@ -895,7 +909,7 @@ export class Editor {
895
909
  public toDataURL(format: 'image/png'|'image/jpeg'|'image/webp' = 'image/png'): string {
896
910
  const canvas = document.createElement('canvas');
897
911
 
898
- const resolution = this.importExportViewport.getResolution();
912
+ const resolution = this.importExportViewport.getScreenRectSize();
899
913
 
900
914
  canvas.width = resolution.x;
901
915
  canvas.height = resolution.y;
@@ -75,6 +75,11 @@ export default class EditorImage {
75
75
  delete this.componentsById[elem.getId()];
76
76
  }
77
77
 
78
+ /**
79
+ * @returns the AbstractComponent with `id`, if it exists.
80
+ *
81
+ * @see {@link AbstractComponent.getId}
82
+ */
78
83
  public lookupElement(id: string): AbstractComponent|null {
79
84
  return this.componentsById[id] ?? null;
80
85
  }
@@ -84,6 +89,13 @@ export default class EditorImage {
84
89
  return this.root.addLeaf(elem);
85
90
  }
86
91
 
92
+ /**
93
+ * Returns a command that adds the given element to the `EditorImage`.
94
+ * If `applyByFlattening` is true, the content of the wet ink renderer is
95
+ * rendered onto the main rendering canvas instead of doing a full re-render.
96
+ *
97
+ * @see {@link Display.flatten}
98
+ */
87
99
  public static addElement(elem: AbstractComponent, applyByFlattening: boolean = false): SerializableCommand {
88
100
  return new EditorImage.AddElementCommand(elem, applyByFlattening);
89
101
  }
package/src/Pointer.ts CHANGED
@@ -36,6 +36,25 @@ export default class Pointer {
36
36
  ) {
37
37
  }
38
38
 
39
+ // Snaps this pointer to the nearest grid point (rounds the coordinates of this
40
+ // pointer based on the current zoom). Returns a new Pointer and does not modify
41
+ // this.
42
+ public snappedToGrid(viewport: Viewport): Pointer {
43
+ const snappedCanvasPos = viewport.snapToGrid(this.canvasPos);
44
+ const snappedScreenPos = viewport.canvasToScreen(snappedCanvasPos);
45
+
46
+ return new Pointer(
47
+ snappedScreenPos,
48
+ snappedCanvasPos,
49
+ this.pressure,
50
+ this.isPrimary,
51
+ this.down,
52
+ this.device,
53
+ this.id,
54
+ this.timeStamp,
55
+ );
56
+ }
57
+
39
58
  // Creates a Pointer from a DOM event. If `relativeTo` is given, (0, 0) in screen coordinates is
40
59
  // considered the top left of `relativeTo`.
41
60
  public static ofEvent(evt: PointerEvent, isDown: boolean, viewport: Viewport, relativeTo?: HTMLElement): Pointer {
package/src/SVGLoader.ts CHANGED
@@ -31,6 +31,7 @@ export type SVGLoaderUnknownStyleAttribute = { key: string, value: string, prior
31
31
 
32
32
  const supportedStrokeFillStyleAttrs = [ 'stroke', 'fill', 'stroke-width' ];
33
33
 
34
+ // Handles loading images from SVG.
34
35
  export default class SVGLoader implements ImageLoader {
35
36
  private onAddComponent: ComponentAddedListener|null = null;
36
37
  private onProgress: OnProgressListener|null = null;
@@ -422,7 +423,11 @@ export default class SVGLoader implements ImageLoader {
422
423
  this.onFinish?.();
423
424
  }
424
425
 
425
- // @param sanitize - if `true`, don't store unknown attributes.
426
+ /**
427
+ * @see {@link Editor.loadFrom}
428
+ * @param text - Textual representation of the SVG (e.g. `<svg viewbox='...'>...</svg>`).
429
+ * @param sanitize - if `true`, don't store unknown attributes.
430
+ */
426
431
  public static fromString(text: string, sanitize: boolean = false): SVGLoader {
427
432
  const sandbox = document.createElement('iframe');
428
433
  sandbox.src = 'about:blank';
package/src/Viewport.ts CHANGED
@@ -92,26 +92,30 @@ export class Viewport {
92
92
  this.screenRect = this.screenRect.resizedTo(screenSize);
93
93
  }
94
94
 
95
- // Get the screen's visible region transformed into canvas space.
95
+ /** Get the screen's visible region transformed into canvas space. */
96
96
  public get visibleRect(): Rect2 {
97
97
  return this.screenRect.transformedBoundingBox(this.inverseTransform);
98
98
  }
99
99
 
100
- // the given point, but in canvas coordinates
100
+ /** @returns the given point, but in canvas coordinates */
101
101
  public screenToCanvas(screenPoint: Point2): Point2 {
102
102
  return this.inverseTransform.transformVec2(screenPoint);
103
103
  }
104
104
 
105
+ /** @returns the given point transformed into screen coordinates. */
105
106
  public canvasToScreen(canvasPoint: Point2): Point2 {
106
107
  return this.transform.transformVec2(canvasPoint);
107
108
  }
108
109
 
110
+ /** @returns a command that transforms the canvas by `transform`. */
109
111
  public static transformBy(transform: Mat33): ViewportTransform {
110
112
  return new Viewport.ViewportTransform(transform);
111
113
  }
112
114
 
113
- // Updates the transformation directly. Using `transformBy` is preferred.
114
- // [newTransform] should map from canvas coordinates to screen coordinates.
115
+ /**
116
+ * Updates the transformation directly. Using `transformBy` is preferred.
117
+ * @param newTransform - should map from canvas coordinates to screen coordinates.
118
+ */
115
119
  public resetTransform(newTransform: Mat33 = Mat33.identity) {
116
120
  const oldTransform = this.transform;
117
121
  this.transform = newTransform;
@@ -131,29 +135,64 @@ export class Viewport {
131
135
  return this.transform;
132
136
  }
133
137
 
134
- public getResolution(): Vec2 {
138
+ /** @returns the size of the visible region in pixels. */
139
+ public getScreenRectSize(): Vec2 {
135
140
  return this.screenRect.size;
136
141
  }
137
142
 
138
- // Returns the amount a vector on the canvas is scaled to become a vector on the screen.
143
+ /** Alias for `getScreenRectSize`. @deprecated */
144
+ public getResolution() {
145
+ return this.getScreenRectSize();
146
+ }
147
+
148
+ /** @returns the amount a vector on the canvas is scaled to become a vector on the screen. */
139
149
  public getScaleFactor(): number {
140
150
  // Use transformVec3 to avoid translating the vector
141
151
  return this.transform.transformVec3(Vec3.unitX).magnitude();
142
152
  }
143
153
 
144
- // Returns the size of one screen pixel in canvas units.
154
+ /**
155
+ * @returns `getScaleFactor()` rounded to the nearest power of 10.
156
+ * For example, if `getScaleFactor()` returns 101, `getScaleFactorToNearestPowerOfTen()`
157
+ * should return `100` because `100` is the nearest power of 10 to 101.
158
+ */
159
+ public getScaleFactorToNearestPowerOfTen() {
160
+ const scaleFactor = this.getScaleFactor();
161
+ return Math.pow(10, Math.round(Math.log10(scaleFactor)));
162
+ }
163
+
164
+ public snapToGrid(canvasPos: Point2) {
165
+ const snapCoordinate = (coordinate: number) => {
166
+ const scaleFactor = this.getScaleFactorToNearestPowerOfTen();
167
+ const roundFactor = scaleFactor / 100;
168
+ const snapped = Math.round(coordinate * roundFactor) / roundFactor;
169
+
170
+ return snapped;
171
+ };
172
+
173
+ const snappedCanvasPos = Vec2.of(
174
+ snapCoordinate(canvasPos.x), snapCoordinate(canvasPos.y)
175
+ );
176
+ return snappedCanvasPos;
177
+ }
178
+
179
+ /** Returns the size of one screen pixel in canvas units. */
145
180
  public getSizeOfPixelOnCanvas(): number {
146
181
  return 1/this.getScaleFactor();
147
182
  }
148
183
 
149
- // Returns the angle of the canvas in radians.
150
- // This is the angle by which the canvas is rotated relative to the screen.
184
+ /**
185
+ * @returns the angle of the canvas in radians.
186
+ * This is the angle by which the canvas is rotated relative to the screen.
187
+ */
151
188
  public getRotationAngle(): number {
152
189
  return this.transform.transformVec3(Vec3.unitX).angle();
153
190
  }
154
191
 
155
- // Rounds the given `point` to a multiple of 10 such that it is within `tolerance` of
156
- // its original location. This is useful for preparing data for base-10 conversion.
192
+ /**
193
+ * Rounds the given `point` to a multiple of 10 such that it is within `tolerance` of
194
+ * its original location. This is useful for preparing data for base-10 conversion.
195
+ */
157
196
  public static roundPoint<T extends Point2|number>(
158
197
  point: T, tolerance: number,
159
198
  ): PointDataType<T>;
@@ -3,7 +3,7 @@ import { EditorLocalization } from '../localization';
3
3
  import Command from './Command';
4
4
  import SerializableCommand from './SerializableCommand';
5
5
 
6
- // Returns a command taht does the opposite of the given command --- `result.apply()` calls
6
+ // Returns a command that does the opposite of the given command --- `result.apply()` calls
7
7
  // `command.unapply()` and `result.unapply()` calls `command.apply()`.
8
8
  const invertCommand = <T extends Command> (command: T): T extends SerializableCommand ? SerializableCommand : Command => {
9
9
  if (command instanceof SerializableCommand) {
@@ -13,9 +13,20 @@ export type LoadSaveDataTable = Record<string, Array<LoadSaveData>>;
13
13
  export type DeserializeCallback = (data: string)=>AbstractComponent;
14
14
  type ComponentId = string;
15
15
 
16
+ /**
17
+ * A base class for everything that can be added to an {@link EditorImage}.
18
+ */
16
19
  export default abstract class AbstractComponent {
20
+ // The timestamp (milliseconds) at which the component was
21
+ // last changed (i.e. created/translated).
22
+ // @deprecated
17
23
  protected lastChangedTime: number;
24
+
25
+ // The bounding box of this component.
26
+ // {@link getBBox}, by default, returns `contentBBox`.
27
+ // This must be set by components.
18
28
  protected abstract contentBBox: Rect2;
29
+
19
30
  private zIndex: number;
20
31
  private id: string;
21
32
 
@@ -38,7 +49,7 @@ export default abstract class AbstractComponent {
38
49
  }
39
50
 
40
51
  // Returns a unique ID for this element.
41
- // @see { @link EditorImage!default.lookupElement }
52
+ // @see { @link lib!EditorImage.lookupElement }
42
53
  public getId() {
43
54
  return this.id;
44
55
  }
@@ -55,14 +66,22 @@ export default abstract class AbstractComponent {
55
66
  this.deserializationCallbacks[componentKind] = deserialize ?? null;
56
67
  }
57
68
 
58
- // Get and manage data attached by a loader.
69
+ // Stores data attached by a loader.
59
70
  private loadSaveData: LoadSaveDataTable = {};
71
+
72
+ /**
73
+ * Attach data that can be used while exporting the component (e.g. to SVG).
74
+ *
75
+ * This is intended for use by a {@link ImageLoader}.
76
+ */
60
77
  public attachLoadSaveData(key: string, data: LoadSaveData) {
61
78
  if (!this.loadSaveData[key]) {
62
79
  this.loadSaveData[key] = [];
63
80
  }
64
81
  this.loadSaveData[key].push(data);
65
82
  }
83
+
84
+ /** See {@link attachLoadSaveData} */
66
85
  public getLoadSaveData(): LoadSaveDataTable {
67
86
  return this.loadSaveData;
68
87
  }
@@ -71,13 +90,20 @@ export default abstract class AbstractComponent {
71
90
  return this.zIndex;
72
91
  }
73
92
 
93
+ /** @returns the bounding box of */
74
94
  public getBBox(): Rect2 {
75
95
  return this.contentBBox;
76
96
  }
77
97
 
78
98
  public abstract render(canvas: AbstractRenderer, visibleRect?: Rect2): void;
99
+
100
+ /** @return true if `lineSegment` intersects this component. */
79
101
  public abstract intersects(lineSegment: LineSegment2): boolean;
80
102
 
103
+ /**
104
+ * @returns true if this component intersects `rect` -- it is entirely contained
105
+ * within the rectangle or one of the rectangle's edges intersects this component.
106
+ */
81
107
  public intersectsRect(rect: Rect2): boolean {
82
108
  // If this component intersects rect,
83
109
  // it is either contained entirely within rect or intersects one of rect's edges.
@@ -200,6 +226,7 @@ export default abstract class AbstractComponent {
200
226
  }
201
227
 
202
228
  this.component.applyTransformation(newTransfm);
229
+ this.component.lastChangedTime = (new Date()).getTime();
203
230
 
204
231
  // Add the element back to the document.
205
232
  if (hadParent) {
@@ -250,6 +277,10 @@ export default abstract class AbstractComponent {
250
277
  }
251
278
  };
252
279
 
280
+ /**
281
+ * @return a description that could be read by a screen reader
282
+ * (e.g. when adding/erasing the component)
283
+ */
253
284
  public abstract description(localizationTable: ImageComponentLocalization): string;
254
285
 
255
286
  // Component-specific implementation of {@link clone}.
package/src/lib.ts CHANGED
@@ -8,25 +8,28 @@
8
8
  * ```
9
9
  *
10
10
  * @see
11
- * {@link Editor!}
11
+ * {@link Editor}
12
12
  *
13
13
  * @packageDocumentation
14
14
  */
15
15
 
16
- import Editor from './Editor';
16
+ import Editor, { EditorSettings } from './Editor';
17
17
  export { default as EditorImage } from './EditorImage';
18
18
  export * from './types';
19
19
  export { default as getLocalizationTable } from './localizations/getLocalizationTable';
20
20
  export * from './localization';
21
21
 
22
22
  export { default as Color4 } from './Color4';
23
+ export { default as SVGLoader } from './SVGLoader';
24
+ export { default as Viewport } from './Viewport';
23
25
  export * from './math/lib';
24
26
  export * from './components/lib';
25
27
  export * from './commands/lib';
26
28
  export * from './tools/lib';
27
29
  export * from './toolbar/lib';
30
+ export * from './rendering/lib';
28
31
  export { default as Pointer, PointerDevice } from './Pointer';
29
32
  export { default as HTMLToolbar } from './toolbar/HTMLToolbar';
30
33
 
31
- export { Editor };
34
+ export { Editor, EditorSettings };
32
35
  export default Editor;
package/src/math/Mat33.ts CHANGED
@@ -338,7 +338,7 @@ export default class Mat33 {
338
338
  return result.rightMul(Mat33.translation(center.times(-1)));
339
339
  }
340
340
 
341
- /** @see {@link !fromCSSMatrix} */
341
+ /** @see {@link fromCSSMatrix} */
342
342
  public toCSSMatrix(): string {
343
343
  return `matrix(${this.a1},${this.b1},${this.a2},${this.b2},${this.a3},${this.b3})`;
344
344
  }
@@ -1,18 +1,3 @@
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
-
16
1
  import AbstractRenderer from './renderers/AbstractRenderer';
17
2
  import CanvasRenderer from './renderers/CanvasRenderer';
18
3
  import { Editor } from '../Editor';
@@ -29,6 +14,18 @@ export enum RenderingMode {
29
14
  // SVGRenderer is not supported by the main display
30
15
  }
31
16
 
17
+ /**
18
+ * Handles `HTMLCanvasElement`s (or other drawing surfaces if being used) used to display the editor's contents.
19
+ *
20
+ * @example
21
+ * ```
22
+ * const editor = new Editor(document.body);
23
+ * const w = editor.display.width;
24
+ * const h = editor.display.height;
25
+ * const center = Vec2.of(w / 2, h / 2);
26
+ * const colorAtCenter = editor.display.getColorAt(center);
27
+ * ```
28
+ */
32
29
  export default class Display {
33
30
  private dryInkRenderer: AbstractRenderer;
34
31
  private wetInkRenderer: AbstractRenderer;
@@ -13,7 +13,7 @@ export default RenderingStyle;
13
13
  export const stylesEqual = (a: RenderingStyle, b: RenderingStyle): boolean => {
14
14
  const result = a === b || (a.fill.eq(b.fill)
15
15
  && (a.stroke == undefined) === (b.stroke == undefined)
16
- && (a.stroke?.color?.eq(b.stroke?.color) ?? true)
16
+ && (a.stroke?.color?.eq(b.stroke?.color) ?? true)
17
17
  && a.stroke?.width === b.stroke?.width);
18
18
 
19
19
  // Map undefined/null -> false
@@ -0,0 +1,4 @@
1
+
2
+ export { default as AbstractRenderer } from './renderers/AbstractRenderer';
3
+ export { default as DummyRenderer } from './renderers/DummyRenderer';
4
+ export { default as Display } from './Display';
@@ -1,5 +1,3 @@
1
- // Renderer that outputs nothing. Useful for automated tests.
2
-
3
1
  import { TextStyle } from '../../components/TextComponent';
4
2
  import Mat33 from '../../math/Mat33';
5
3
  import Rect2 from '../../math/Rect2';
@@ -9,6 +7,7 @@ import Viewport from '../../Viewport';
9
7
  import RenderingStyle from '../RenderingStyle';
10
8
  import AbstractRenderer, { RenderableImage } from './AbstractRenderer';
11
9
 
10
+ // Renderer that outputs almost nothing. Useful for automated tests.
12
11
  export default class DummyRenderer extends AbstractRenderer {
13
12
  // Variables that track the state of what's been rendered
14
13
  public clearedCount: number = 0;
@@ -28,7 +27,7 @@ export default class DummyRenderer extends AbstractRenderer {
28
27
 
29
28
  public displaySize(): Vec2 {
30
29
  // Do we have a stored viewport size?
31
- const viewportSize = this.getViewport().getResolution();
30
+ const viewportSize = this.getViewport().getScreenRectSize();
32
31
 
33
32
  // Don't use a 0x0 viewport — DummyRenderer is often used
34
33
  // for tests that run without a display, so pretend we have a
@@ -38,6 +38,10 @@ export default class SVGRenderer extends AbstractRenderer {
38
38
  stroke-linecap: round;
39
39
  stroke-linejoin: round;
40
40
  }
41
+
42
+ text {
43
+ white-space: pre;
44
+ }
41
45
  `.replace(/\s+/g, '');
42
46
  styleSheet.setAttribute('id', renderedStylesheetId);
43
47
  this.elem.appendChild(styleSheet);
@@ -9,7 +9,6 @@ import RenderingStyle from '../RenderingStyle';
9
9
  import AbstractRenderer, { RenderableImage } from './AbstractRenderer';
10
10
 
11
11
  // Outputs a description of what was rendered.
12
-
13
12
  export default class TextOnlyRenderer extends AbstractRenderer {
14
13
  private descriptionBuilder: string[] = [];
15
14
  private pathCount: number = 0;
@@ -169,7 +169,7 @@ export default class HTMLToolbar {
169
169
  * toolbar.addSpacer({ grow: 1 });
170
170
  * toolbar.addDefaults();
171
171
  * toolbar.addSpacer({ grow: 1 });
172
- *
172
+ *
173
173
  * toolbar.addActionButton({
174
174
  * label: 'Save',
175
175
  * icon: editor.icons.makeSaveIcon(),