js-draw 0.1.11 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (220) hide show
  1. package/.eslintrc.js +1 -0
  2. package/.firebaserc +5 -0
  3. package/.github/workflows/firebase-hosting-merge.yml +25 -0
  4. package/.github/workflows/firebase-hosting-pull-request.yml +22 -0
  5. package/.github/workflows/github-pages.yml +52 -0
  6. package/CHANGELOG.md +13 -0
  7. package/README.md +11 -6
  8. package/dist/bundle.js +1 -1
  9. package/dist/src/Color4.d.ts +19 -0
  10. package/dist/src/Color4.js +24 -3
  11. package/dist/src/Editor.d.ts +133 -4
  12. package/dist/src/Editor.js +124 -27
  13. package/dist/src/EditorImage.d.ts +8 -3
  14. package/dist/src/EditorImage.js +42 -26
  15. package/dist/src/EventDispatcher.d.ts +18 -0
  16. package/dist/src/EventDispatcher.js +19 -4
  17. package/dist/src/Pointer.d.ts +1 -1
  18. package/dist/src/Pointer.js +4 -3
  19. package/dist/src/SVGLoader.d.ts +1 -1
  20. package/dist/src/SVGLoader.js +14 -6
  21. package/dist/src/UndoRedoHistory.js +15 -2
  22. package/dist/src/Viewport.d.ts +8 -25
  23. package/dist/src/Viewport.js +18 -10
  24. package/dist/src/bundle/bundled.d.ts +1 -2
  25. package/dist/src/bundle/bundled.js +1 -2
  26. package/dist/src/commands/Command.d.ts +2 -2
  27. package/dist/src/commands/Command.js +4 -4
  28. package/dist/src/commands/Duplicate.d.ts +2 -2
  29. package/dist/src/commands/Duplicate.js +4 -5
  30. package/dist/src/commands/Erase.d.ts +2 -2
  31. package/dist/src/commands/Erase.js +7 -6
  32. package/dist/src/commands/SerializableCommand.d.ts +4 -5
  33. package/dist/src/commands/SerializableCommand.js +12 -4
  34. package/dist/src/commands/invertCommand.d.ts +4 -0
  35. package/dist/src/commands/invertCommand.js +44 -0
  36. package/dist/src/commands/lib.d.ts +6 -0
  37. package/dist/src/commands/lib.js +6 -0
  38. package/dist/src/commands/localization.d.ts +2 -1
  39. package/dist/src/commands/localization.js +1 -0
  40. package/dist/src/components/AbstractComponent.d.ts +16 -11
  41. package/dist/src/components/AbstractComponent.js +28 -17
  42. package/dist/src/components/SVGGlobalAttributesObject.d.ts +4 -4
  43. package/dist/src/components/SVGGlobalAttributesObject.js +8 -2
  44. package/dist/src/components/Stroke.d.ts +16 -6
  45. package/dist/src/components/Stroke.js +12 -9
  46. package/dist/src/components/Text.d.ts +5 -5
  47. package/dist/src/components/Text.js +9 -9
  48. package/dist/src/components/UnknownSVGObject.d.ts +4 -4
  49. package/dist/src/components/UnknownSVGObject.js +7 -2
  50. package/dist/src/components/builders/ArrowBuilder.d.ts +1 -1
  51. package/dist/src/components/builders/ArrowBuilder.js +1 -1
  52. package/dist/src/components/builders/FreehandLineBuilder.d.ts +8 -3
  53. package/dist/src/components/builders/FreehandLineBuilder.js +142 -71
  54. package/dist/src/components/builders/LineBuilder.d.ts +1 -1
  55. package/dist/src/components/builders/LineBuilder.js +1 -1
  56. package/dist/src/components/builders/RectangleBuilder.d.ts +1 -1
  57. package/dist/src/components/builders/RectangleBuilder.js +3 -3
  58. package/dist/src/components/builders/types.d.ts +1 -1
  59. package/dist/src/components/lib.d.ts +4 -0
  60. package/dist/src/components/lib.js +4 -0
  61. package/dist/src/lib.d.ts +25 -0
  62. package/dist/src/lib.js +25 -0
  63. package/dist/src/localization.d.ts +1 -0
  64. package/dist/src/localization.js +5 -1
  65. package/dist/src/localizations/es.js +1 -1
  66. package/dist/src/{geometry → math}/LineSegment2.d.ts +0 -0
  67. package/dist/src/{geometry → math}/LineSegment2.js +0 -0
  68. package/dist/src/math/Mat33.d.ts +78 -0
  69. package/dist/src/{geometry → math}/Mat33.js +48 -20
  70. package/dist/src/{geometry → math}/Path.d.ts +2 -1
  71. package/dist/src/{geometry → math}/Path.js +59 -52
  72. package/dist/src/{geometry → math}/Rect2.d.ts +2 -2
  73. package/dist/src/{geometry → math}/Rect2.js +0 -0
  74. package/dist/src/{geometry → math}/Vec2.d.ts +0 -0
  75. package/dist/src/{geometry → math}/Vec2.js +0 -0
  76. package/dist/src/math/Vec3.d.ts +96 -0
  77. package/dist/src/{geometry → math}/Vec3.js +63 -15
  78. package/dist/src/math/lib.d.ts +7 -0
  79. package/dist/src/math/lib.js +7 -0
  80. package/dist/src/math/rounding.d.ts +3 -0
  81. package/dist/src/math/rounding.js +121 -0
  82. package/dist/src/rendering/Display.d.ts +47 -1
  83. package/dist/src/rendering/Display.js +60 -15
  84. package/dist/src/rendering/caching/CacheRecord.d.ts +3 -2
  85. package/dist/src/rendering/caching/CacheRecord.js +4 -1
  86. package/dist/src/rendering/caching/CacheRecordManager.d.ts +5 -4
  87. package/dist/src/rendering/caching/CacheRecordManager.js +16 -4
  88. package/dist/src/rendering/caching/RenderingCache.d.ts +2 -3
  89. package/dist/src/rendering/caching/RenderingCache.js +10 -11
  90. package/dist/src/rendering/caching/RenderingCacheNode.d.ts +2 -1
  91. package/dist/src/rendering/caching/RenderingCacheNode.js +18 -7
  92. package/dist/src/rendering/caching/testUtils.js +1 -1
  93. package/dist/src/rendering/caching/types.d.ts +2 -4
  94. package/dist/src/rendering/localization.d.ts +2 -0
  95. package/dist/src/rendering/localization.js +2 -0
  96. package/dist/src/rendering/renderers/AbstractRenderer.d.ts +4 -4
  97. package/dist/src/rendering/renderers/AbstractRenderer.js +2 -2
  98. package/dist/src/rendering/renderers/CanvasRenderer.d.ts +4 -4
  99. package/dist/src/rendering/renderers/CanvasRenderer.js +2 -2
  100. package/dist/src/rendering/renderers/DummyRenderer.d.ts +4 -4
  101. package/dist/src/rendering/renderers/DummyRenderer.js +1 -1
  102. package/dist/src/rendering/renderers/SVGRenderer.d.ts +3 -3
  103. package/dist/src/rendering/renderers/SVGRenderer.js +8 -2
  104. package/dist/src/rendering/renderers/TextOnlyRenderer.d.ts +5 -3
  105. package/dist/src/rendering/renderers/TextOnlyRenderer.js +13 -3
  106. package/dist/src/toolbar/HTMLToolbar.js +1 -0
  107. package/dist/src/toolbar/icons.d.ts +3 -0
  108. package/dist/src/toolbar/icons.js +142 -132
  109. package/dist/src/toolbar/localization.d.ts +2 -1
  110. package/dist/src/toolbar/localization.js +2 -1
  111. package/dist/src/toolbar/makeColorInput.js +3 -2
  112. package/dist/src/toolbar/widgets/ActionButtonWidget.d.ts +13 -0
  113. package/dist/src/toolbar/widgets/ActionButtonWidget.js +21 -0
  114. package/dist/src/toolbar/widgets/BaseWidget.js +2 -0
  115. package/dist/src/toolbar/widgets/HandToolWidget.js +3 -3
  116. package/dist/src/toolbar/widgets/PenWidget.js +1 -0
  117. package/dist/src/toolbar/widgets/SelectionWidget.d.ts +0 -1
  118. package/dist/src/toolbar/widgets/SelectionWidget.js +23 -30
  119. package/dist/src/tools/Eraser.js +1 -1
  120. package/dist/src/tools/PanZoom.d.ts +1 -1
  121. package/dist/src/tools/PanZoom.js +24 -14
  122. package/dist/src/tools/Pen.d.ts +1 -2
  123. package/dist/src/tools/Pen.js +8 -1
  124. package/dist/src/tools/PipetteTool.js +1 -0
  125. package/dist/src/tools/SelectionTool.d.ts +3 -3
  126. package/dist/src/tools/SelectionTool.js +51 -28
  127. package/dist/src/tools/TextTool.js +1 -1
  128. package/dist/src/types.d.ts +21 -10
  129. package/dist/src/types.js +7 -5
  130. package/firebase.json +16 -0
  131. package/package.json +118 -101
  132. package/src/Color4.ts +23 -2
  133. package/src/Editor.ts +181 -37
  134. package/src/EditorImage.test.ts +2 -4
  135. package/src/EditorImage.ts +46 -28
  136. package/src/EventDispatcher.ts +21 -6
  137. package/src/Pointer.ts +4 -3
  138. package/src/SVGLoader.ts +14 -6
  139. package/src/UndoRedoHistory.ts +18 -2
  140. package/src/Viewport.ts +23 -18
  141. package/src/bundle/bundled.ts +1 -2
  142. package/src/commands/Command.ts +5 -5
  143. package/src/commands/Duplicate.ts +4 -5
  144. package/src/commands/Erase.ts +7 -6
  145. package/src/commands/SerializableCommand.ts +17 -9
  146. package/src/commands/invertCommand.ts +51 -0
  147. package/src/commands/lib.ts +14 -0
  148. package/src/commands/localization.ts +3 -1
  149. package/src/components/AbstractComponent.ts +35 -24
  150. package/src/components/SVGGlobalAttributesObject.ts +11 -4
  151. package/src/components/Stroke.test.ts +4 -6
  152. package/src/components/Stroke.ts +15 -11
  153. package/src/components/Text.test.ts +2 -2
  154. package/src/components/Text.ts +9 -10
  155. package/src/components/UnknownSVGObject.ts +10 -4
  156. package/src/components/builders/ArrowBuilder.ts +2 -2
  157. package/src/components/builders/FreehandLineBuilder.ts +190 -80
  158. package/src/components/builders/LineBuilder.ts +2 -2
  159. package/src/components/builders/RectangleBuilder.ts +3 -3
  160. package/src/components/builders/types.ts +1 -1
  161. package/src/components/lib.ts +9 -0
  162. package/src/lib.ts +28 -0
  163. package/src/localization.ts +6 -0
  164. package/src/localizations/es.ts +2 -1
  165. package/src/{geometry → math}/LineSegment2.test.ts +0 -0
  166. package/src/{geometry → math}/LineSegment2.ts +0 -0
  167. package/src/{geometry → math}/Mat33.test.ts +0 -0
  168. package/src/{geometry → math}/Mat33.ts +48 -20
  169. package/src/{geometry → math}/Path.fromString.test.ts +0 -0
  170. package/src/{geometry → math}/Path.test.ts +0 -0
  171. package/src/{geometry → math}/Path.toString.test.ts +11 -2
  172. package/src/{geometry → math}/Path.ts +61 -58
  173. package/src/{geometry → math}/Rect2.test.ts +0 -0
  174. package/src/{geometry → math}/Rect2.ts +2 -2
  175. package/src/{geometry → math}/Vec2.test.ts +0 -0
  176. package/src/{geometry → math}/Vec2.ts +0 -0
  177. package/src/{geometry → math}/Vec3.test.ts +0 -0
  178. package/src/{geometry → math}/Vec3.ts +64 -16
  179. package/src/math/lib.ts +15 -0
  180. package/src/math/rounding.test.ts +40 -0
  181. package/src/math/rounding.ts +147 -0
  182. package/src/rendering/Display.ts +63 -15
  183. package/src/rendering/caching/CacheRecord.test.ts +3 -3
  184. package/src/rendering/caching/CacheRecord.ts +6 -2
  185. package/src/rendering/caching/CacheRecordManager.ts +34 -8
  186. package/src/rendering/caching/RenderingCache.test.ts +3 -3
  187. package/src/rendering/caching/RenderingCache.ts +11 -16
  188. package/src/rendering/caching/RenderingCacheNode.ts +23 -7
  189. package/src/rendering/caching/testUtils.ts +1 -1
  190. package/src/rendering/caching/types.ts +2 -7
  191. package/src/rendering/localization.ts +4 -0
  192. package/src/rendering/renderers/AbstractRenderer.ts +4 -4
  193. package/src/rendering/renderers/CanvasRenderer.ts +5 -5
  194. package/src/rendering/renderers/DummyRenderer.test.ts +2 -2
  195. package/src/rendering/renderers/DummyRenderer.ts +4 -4
  196. package/src/rendering/renderers/SVGRenderer.ts +10 -4
  197. package/src/rendering/renderers/TextOnlyRenderer.ts +17 -6
  198. package/src/toolbar/HTMLToolbar.ts +1 -0
  199. package/src/toolbar/icons.ts +157 -137
  200. package/src/toolbar/localization.ts +4 -2
  201. package/src/toolbar/makeColorInput.ts +3 -2
  202. package/src/toolbar/toolbar.css +1 -1
  203. package/src/toolbar/widgets/ActionButtonWidget.ts +31 -0
  204. package/src/toolbar/widgets/BaseWidget.ts +2 -0
  205. package/src/toolbar/widgets/HandToolWidget.ts +3 -3
  206. package/src/toolbar/widgets/PenWidget.ts +2 -0
  207. package/src/toolbar/widgets/SelectionWidget.ts +46 -41
  208. package/src/tools/Eraser.ts +2 -2
  209. package/src/tools/PanZoom.ts +28 -17
  210. package/src/tools/Pen.ts +11 -2
  211. package/src/tools/PipetteTool.ts +2 -0
  212. package/src/tools/SelectionTool.test.ts +2 -4
  213. package/src/tools/SelectionTool.ts +52 -24
  214. package/src/tools/TextTool.ts +2 -2
  215. package/src/tools/UndoRedoShortcut.test.ts +1 -1
  216. package/src/types.ts +23 -7
  217. package/tsconfig.json +4 -1
  218. package/typedoc.json +20 -0
  219. package/dist/src/geometry/Mat33.d.ts +0 -32
  220. package/dist/src/geometry/Vec3.d.ts +0 -34
@@ -1,6 +1,6 @@
1
- import LineSegment2 from '../geometry/LineSegment2';
2
- import Mat33 from '../geometry/Mat33';
3
- import Rect2 from '../geometry/Rect2';
1
+ import LineSegment2 from '../math/LineSegment2';
2
+ import Mat33 from '../math/Mat33';
3
+ import Rect2 from '../math/Rect2';
4
4
  import AbstractRenderer from '../rendering/renderers/AbstractRenderer';
5
5
  import RenderingStyle, { styleFromJSON, styleToJSON } from '../rendering/RenderingStyle';
6
6
  import AbstractComponent from './AbstractComponent';
@@ -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,6 +1,12 @@
1
- import LineSegment2 from '../geometry/LineSegment2';
2
- import Mat33 from '../geometry/Mat33';
3
- import Rect2 from '../geometry/Rect2';
1
+ //
2
+ // Stores objects loaded from an SVG that aren't recognised by the editor.
3
+ // @internal
4
+ // @packageDocumentation
5
+ //
6
+
7
+ import LineSegment2 from '../math/LineSegment2';
8
+ import Mat33 from '../math/Mat33';
9
+ import Rect2 from '../math/Rect2';
4
10
  import AbstractRenderer from '../rendering/renderers/AbstractRenderer';
5
11
  import SVGRenderer from '../rendering/renderers/SVGRenderer';
6
12
  import AbstractComponent from './AbstractComponent';
@@ -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
  });
@@ -1,5 +1,5 @@
1
- import { PathCommandType } from '../../geometry/Path';
2
- import Rect2 from '../../geometry/Rect2';
1
+ import { PathCommandType } from '../../math/Path';
2
+ import Rect2 from '../../math/Rect2';
3
3
  import AbstractRenderer from '../../rendering/renderers/AbstractRenderer';
4
4
  import { StrokeDataPoint } from '../../types';
5
5
  import Viewport from '../../Viewport';
@@ -1,9 +1,9 @@
1
1
  import { Bezier } from 'bezier-js';
2
2
  import AbstractRenderer, { RenderablePathSpec } from '../../rendering/renderers/AbstractRenderer';
3
- import { Point2, Vec2 } from '../../geometry/Vec2';
4
- import Rect2 from '../../geometry/Rect2';
5
- import { PathCommand, PathCommandType } from '../../geometry/Path';
6
- import LineSegment2 from '../../geometry/LineSegment2';
3
+ import { Point2, Vec2 } from '../../math/Vec2';
4
+ import Rect2 from '../../math/Rect2';
5
+ import { LinePathCommand, PathCommandType, QuadraticBezierPathCommand } from '../../math/Path';
6
+ import LineSegment2 from '../../math/LineSegment2';
7
7
  import Stroke from '../Stroke';
8
8
  import Viewport from '../../Viewport';
9
9
  import { StrokeDataPoint } from '../../types';
@@ -22,9 +22,35 @@ export const makeFreehandLineBuilder: ComponentBuilderFactory = (initialPoint: S
22
22
  );
23
23
  };
24
24
 
25
+ type CurrentSegmentToPathResult = {
26
+ upperCurve: QuadraticBezierPathCommand,
27
+ lowerToUpperConnector: LinePathCommand,
28
+ upperToLowerConnector: LinePathCommand,
29
+ lowerCurve: QuadraticBezierPathCommand,
30
+ };
31
+
25
32
  // Handles stroke smoothing and creates Strokes from user/stylus input.
26
33
  export default class FreehandLineBuilder implements ComponentBuilder {
27
- private segments: RenderablePathSpec[];
34
+ private isFirstSegment: boolean = true;
35
+ private pathStartConnector: LinePathCommand|null = null;
36
+ private mostRecentConnector: LinePathCommand|null = null;
37
+
38
+ // Beginning of the list of lower parts
39
+ // ↓
40
+ // /---pathStartConnector---/ ← Beginning of the list of upper parts
41
+ // ___/ __/
42
+ // / /
43
+ // /--Most recent connector--/ ← most recent upper part goes here
44
+ // ↑
45
+ // most recent lower part goes here
46
+ //
47
+ // The upperSegments form a path that goes in reverse from the most recent edge to the
48
+ // least recent edge.
49
+ // The lowerSegments form a path that goes from the least recent edge to the most
50
+ // recent edge.
51
+ private upperSegments: QuadraticBezierPathCommand[];
52
+ private lowerSegments: QuadraticBezierPathCommand[];
53
+
28
54
  private buffer: Point2[];
29
55
  private lastPoint: StrokeDataPoint;
30
56
  private lastExitingVec: Vec2;
@@ -47,7 +73,9 @@ export default class FreehandLineBuilder implements ComponentBuilder {
47
73
  private maxFitAllowed: number
48
74
  ) {
49
75
  this.lastPoint = this.startPoint;
50
- this.segments = [];
76
+ this.upperSegments = [];
77
+ this.lowerSegments = [];
78
+
51
79
  this.buffer = [this.startPoint.pos];
52
80
  this.momentum = Vec2.zero;
53
81
  this.currentCurve = null;
@@ -65,19 +93,82 @@ export default class FreehandLineBuilder implements ComponentBuilder {
65
93
  };
66
94
  }
67
95
 
68
- // Get the segments that make up this' path. Can be called after calling build()
69
- private getPreview(): RenderablePathSpec[] {
70
- if (this.currentCurve && this.lastPoint) {
71
- const currentPath = this.currentSegmentToPath();
72
- return this.segments.concat(currentPath);
96
+ private previewPath(): RenderablePathSpec|null {
97
+ let upperPath: QuadraticBezierPathCommand[];
98
+ let lowerPath: QuadraticBezierPathCommand[];
99
+ let lowerToUpperCap: LinePathCommand;
100
+ let pathStartConnector: LinePathCommand;
101
+ if (this.currentCurve) {
102
+ const { upperCurve, lowerToUpperConnector, upperToLowerConnector, lowerCurve } = this.currentSegmentToPath();
103
+ upperPath = this.upperSegments.concat(upperCurve);
104
+ lowerPath = this.lowerSegments.concat(lowerCurve);
105
+ lowerToUpperCap = lowerToUpperConnector;
106
+ pathStartConnector = this.pathStartConnector ?? upperToLowerConnector;
107
+ } else {
108
+ if (this.mostRecentConnector === null || this.pathStartConnector === null) {
109
+ return null;
110
+ }
111
+
112
+ upperPath = this.upperSegments.slice();
113
+ lowerPath = this.lowerSegments.slice();
114
+ lowerToUpperCap = this.mostRecentConnector;
115
+ pathStartConnector = this.pathStartConnector;
73
116
  }
117
+ const startPoint = lowerPath[lowerPath.length - 1].endPoint;
74
118
 
75
- return this.segments;
119
+
120
+ return {
121
+ // Start at the end of the lower curve:
122
+ // Start point
123
+ // ↓
124
+ // __/ __/ ← Most recent points on this end
125
+ // /___ /
126
+ // ↑
127
+ // Oldest points
128
+ startPoint,
129
+
130
+ commands: [
131
+ // Move to the most recent point on the upperPath:
132
+ // ----→•
133
+ // __/ __/
134
+ // /___ /
135
+ lowerToUpperCap,
136
+
137
+ // Move to the beginning of the upperPath:
138
+ // __/ __/
139
+ // /___ /
140
+ // • ←-
141
+ ...upperPath.reverse(),
142
+
143
+ // Move to the beginning of the lowerPath:
144
+ // __/ __/
145
+ // /___ /
146
+ // •
147
+ pathStartConnector,
148
+
149
+ // Move back to the start point:
150
+ // •
151
+ // __/ __/
152
+ // /___ /
153
+ ...lowerPath,
154
+ ],
155
+ style: this.getRenderingStyle(),
156
+ };
157
+ }
158
+
159
+ private previewStroke(): Stroke|null {
160
+ const pathPreview = this.previewPath();
161
+
162
+ if (pathPreview) {
163
+ return new Stroke([ pathPreview ]);
164
+ }
165
+ return null;
76
166
  }
77
167
 
78
168
  public preview(renderer: AbstractRenderer) {
79
- for (const part of this.getPreview()) {
80
- renderer.drawPath(part);
169
+ const path = this.previewPath();
170
+ if (path) {
171
+ renderer.drawPath(path);
81
172
  }
82
173
  }
83
174
 
@@ -85,9 +176,7 @@ export default class FreehandLineBuilder implements ComponentBuilder {
85
176
  if (this.lastPoint) {
86
177
  this.finalizeCurrentCurve();
87
178
  }
88
- return new Stroke(
89
- this.segments,
90
- );
179
+ return this.previewStroke()!;
91
180
  }
92
181
 
93
182
  private roundPoint(point: Point2): Point2 {
@@ -98,59 +187,77 @@ export default class FreehandLineBuilder implements ComponentBuilder {
98
187
  // Case where no points have been added
99
188
  if (!this.currentCurve) {
100
189
  // Don't create a circle around the initial point if the stroke has more than one point.
101
- if (this.segments.length > 0) {
190
+ if (!this.isFirstSegment) {
102
191
  return;
103
192
  }
104
193
 
105
- const width = Viewport.roundPoint(this.startPoint.width / 3, this.minFitAllowed);
194
+ const width = Viewport.roundPoint(this.startPoint.width / 3.5, this.minFitAllowed);
106
195
  const center = this.roundPoint(this.startPoint.pos);
107
196
 
197
+ // Start on the right, cycle clockwise:
198
+ // |
199
+ // ----- ←
200
+ // |
201
+ const startPoint = this.startPoint.pos.plus(Vec2.of(width, 0));
202
+
108
203
  // Draw a circle-ish shape around the start point
109
- this.segments.push({
110
- // Start on the right, cycle clockwise:
111
- // |
112
- // -----
113
- // |
114
- startPoint: this.startPoint.pos.plus(Vec2.of(width, 0)),
115
- commands: [
116
- {
117
- kind: PathCommandType.QuadraticBezierTo,
118
- controlPoint: center.plus(Vec2.of(width, width)),
119
-
120
- // Bottom of the circle
121
- // |
122
- // -----
123
- // |
124
- // ↑
125
- endPoint: center.plus(Vec2.of(0, width)),
126
- },
127
- {
128
- kind: PathCommandType.QuadraticBezierTo,
129
- controlPoint: center.plus(Vec2.of(-width, width)),
130
- endPoint: center.plus(Vec2.of(-width, 0)),
131
- },
132
- {
133
- kind: PathCommandType.QuadraticBezierTo,
134
- controlPoint: center.plus(Vec2.of(-width, -width)),
135
- endPoint: center.plus(Vec2.of(0, -width)),
136
- },
137
- {
138
- kind: PathCommandType.QuadraticBezierTo,
139
- controlPoint: center.plus(Vec2.of(width, -width)),
140
- endPoint: center.plus(Vec2.of(width, 0)),
141
- },
142
- ],
143
- style: this.getRenderingStyle(),
144
- });
204
+ this.lowerSegments.push(
205
+ {
206
+ kind: PathCommandType.QuadraticBezierTo,
207
+ controlPoint: center.plus(Vec2.of(width, width)),
208
+
209
+ // Bottom of the circle
210
+ // |
211
+ // -----
212
+ // |
213
+ // ↑
214
+ endPoint: center.plus(Vec2.of(0, width)),
215
+ },
216
+ {
217
+ kind: PathCommandType.QuadraticBezierTo,
218
+ controlPoint: center.plus(Vec2.of(-width, width)),
219
+ endPoint: center.plus(Vec2.of(-width, 0)),
220
+ },
221
+ {
222
+ kind: PathCommandType.QuadraticBezierTo,
223
+ controlPoint: center.plus(Vec2.of(-width, -width)),
224
+ endPoint: center.plus(Vec2.of(0, -width)),
225
+ },
226
+ {
227
+ kind: PathCommandType.QuadraticBezierTo,
228
+ controlPoint: center.plus(Vec2.of(width, -width)),
229
+ endPoint: center.plus(Vec2.of(width, 0)),
230
+ }
231
+ );
232
+ this.pathStartConnector = {
233
+ kind: PathCommandType.LineTo,
234
+ point: startPoint,
235
+ };
236
+ this.mostRecentConnector = this.pathStartConnector;
237
+
145
238
  return;
146
239
  }
147
240
 
148
- this.segments.push(this.currentSegmentToPath());
241
+ const { upperCurve, lowerToUpperConnector, upperToLowerConnector, lowerCurve } = this.currentSegmentToPath();
242
+
243
+ if (this.isFirstSegment) {
244
+ // We draw the upper path (reversed), then the lower path, so we need the
245
+ // upperToLowerConnector to join the two paths.
246
+ this.pathStartConnector = upperToLowerConnector;
247
+ this.isFirstSegment = false;
248
+ }
249
+ // With the most recent connector, we're joining the end of the lowerPath to the most recent
250
+ // upperPath:
251
+ this.mostRecentConnector = lowerToUpperConnector;
252
+
253
+ this.upperSegments.push(upperCurve);
254
+ this.lowerSegments.push(lowerCurve);
255
+
149
256
  const lastPoint = this.buffer[this.buffer.length - 1];
150
257
  this.lastExitingVec = Vec2.ofXY(
151
258
  this.currentCurve.points[2]
152
259
  ).minus(Vec2.ofXY(this.currentCurve.points[1]));
153
- console.assert(this.lastExitingVec.magnitude() !== 0);
260
+ console.assert(this.lastExitingVec.magnitude() !== 0, 'lastExitingVec has zero length!');
154
261
 
155
262
  // Use the last two points to start a new curve (the last point isn't used
156
263
  // in the current curve and we want connected curves to share end points)
@@ -160,7 +267,8 @@ export default class FreehandLineBuilder implements ComponentBuilder {
160
267
  this.currentCurve = null;
161
268
  }
162
269
 
163
- private currentSegmentToPath(): RenderablePathSpec {
270
+ // Returns [upper curve, connector, lower curve]
271
+ private currentSegmentToPath(): CurrentSegmentToPathResult {
164
272
  if (this.currentCurve == null) {
165
273
  throw new Error('Invalid State: currentCurve is null!');
166
274
  }
@@ -217,31 +325,33 @@ export default class FreehandLineBuilder implements ComponentBuilder {
217
325
  halfVec = halfVec.times(2);
218
326
  }
219
327
 
328
+ // Each starts at startPt ± startVec
220
329
 
221
- const pathCommands: PathCommand[] = [
222
- {
223
- kind: PathCommandType.QuadraticBezierTo,
224
- controlPoint: this.roundPoint(controlPoint.plus(halfVec)),
225
- endPoint: this.roundPoint(endPt.plus(endVec)),
226
- },
330
+ const lowerCurve: QuadraticBezierPathCommand = {
331
+ kind: PathCommandType.QuadraticBezierTo,
332
+ controlPoint: this.roundPoint(controlPoint.plus(halfVec)),
333
+ endPoint: this.roundPoint(endPt.plus(endVec)),
334
+ };
227
335
 
228
- {
229
- kind: PathCommandType.LineTo,
230
- point: this.roundPoint(endPt.minus(endVec)),
231
- },
232
-
233
- {
234
- kind: PathCommandType.QuadraticBezierTo,
235
- controlPoint: this.roundPoint(controlPoint.minus(halfVec)),
236
- endPoint: this.roundPoint(startPt.minus(startVec)),
237
- },
238
- ];
336
+ // From the end of the upperCurve to the start of the lowerCurve:
337
+ const upperToLowerConnector: LinePathCommand = {
338
+ kind: PathCommandType.LineTo,
339
+ point: this.roundPoint(startPt.plus(startVec)),
340
+ };
239
341
 
240
- return {
241
- startPoint: this.roundPoint(startPt.plus(startVec)),
242
- commands: pathCommands,
243
- style: this.getRenderingStyle(),
342
+ // From the end of lowerCurve to the start of upperCurve:
343
+ const lowerToUpperConnector: LinePathCommand = {
344
+ kind: PathCommandType.LineTo,
345
+ point: this.roundPoint(endPt.minus(endVec))
346
+ };
347
+
348
+ const upperCurve: QuadraticBezierPathCommand = {
349
+ kind: PathCommandType.QuadraticBezierTo,
350
+ controlPoint: this.roundPoint(controlPoint.minus(halfVec)),
351
+ endPoint: this.roundPoint(startPt.minus(startVec)),
244
352
  };
353
+
354
+ return { upperCurve, upperToLowerConnector, lowerToUpperConnector, lowerCurve };
245
355
  }
246
356
 
247
357
  // Compute the direction of the velocity at the end of this.buffer
@@ -264,7 +374,7 @@ export default class FreehandLineBuilder implements ComponentBuilder {
264
374
 
265
375
  const threshold = Math.min(this.lastPoint.width, newPoint.width) / 4;
266
376
  const shouldSnapToInitial = this.startPoint.pos.minus(newPoint.pos).magnitude() < threshold
267
- && this.segments.length === 0;
377
+ && this.isFirstSegment;
268
378
 
269
379
  // Snap to the starting point if the stroke is contained within a small ball centered
270
380
  // at the starting point.
@@ -1,5 +1,5 @@
1
- import { PathCommandType } from '../../geometry/Path';
2
- import Rect2 from '../../geometry/Rect2';
1
+ import { PathCommandType } from '../../math/Path';
2
+ import Rect2 from '../../math/Rect2';
3
3
  import AbstractRenderer from '../../rendering/renderers/AbstractRenderer';
4
4
  import { StrokeDataPoint } from '../../types';
5
5
  import Viewport from '../../Viewport';
@@ -1,6 +1,6 @@
1
- import Mat33 from '../../geometry/Mat33';
2
- import Path from '../../geometry/Path';
3
- import Rect2 from '../../geometry/Rect2';
1
+ import Mat33 from '../../math/Mat33';
2
+ import Path from '../../math/Path';
3
+ import Rect2 from '../../math/Rect2';
4
4
  import AbstractRenderer from '../../rendering/renderers/AbstractRenderer';
5
5
  import { StrokeDataPoint } from '../../types';
6
6
  import Viewport from '../../Viewport';
@@ -1,4 +1,4 @@
1
- import Rect2 from '../../geometry/Rect2';
1
+ import Rect2 from '../../math/Rect2';
2
2
  import AbstractRenderer from '../../rendering/renderers/AbstractRenderer';
3
3
  import { StrokeDataPoint } from '../../types';
4
4
  import Viewport from '../../Viewport';
@@ -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;
@@ -6,6 +6,7 @@ import { defaultToolLocalization, ToolLocalization } from './tools/localization'
6
6
 
7
7
 
8
8
  export interface EditorLocalization extends ToolbarLocalization, ToolLocalization, CommandLocalization, ImageComponentLocalization, TextRendererLocalization {
9
+ accessibilityInputInstructions: string;
9
10
  undoAnnouncement: (actionDescription: string)=> string;
10
11
  redoAnnouncement: (actionDescription: string)=> string;
11
12
  doneLoading: string;
@@ -19,6 +20,11 @@ export const defaultEditorLocalization: EditorLocalization = {
19
20
  ...defaultCommandLocalization,
20
21
  ...defaultComponentLocalization,
21
22
  ...defaultTextRendererLocalization,
23
+ accessibilityInputInstructions: [
24
+ 'Press "t" to read the contents of the viewport as text.',
25
+ 'Use the arrow keys to move the viewport, click and drag to draw strokes.',
26
+ 'Press "w" to zoom in and "s" to zoom out.',
27
+ ].join(' '),
22
28
  loading: (percentage: number) => `Loading ${percentage}%...`,
23
29
  imageEditor: 'Image Editor',
24
30
  doneLoading: 'Done loading',
@@ -38,7 +38,8 @@ const localization: EditorLocalization = {
38
38
  resizeImageToSelection: 'Redimensionar la imagen a lo que está seleccionado',
39
39
  deleteSelection: 'Borra la selección',
40
40
  duplicateSelection: 'Duplica la selección',
41
- pickColorFronScreen: 'Selecciona un color de la pantalla',
41
+ pickColorFromScreen: 'Selecciona un color de la pantalla',
42
+ clickToPickColorAnnouncement: 'Haga un clic en la pantalla para seleccionar un color',
42
43
  dropdownShown(toolName: string): string {
43
44
  return `Menú por ${toolName} es visible`;
44
45
  },
File without changes
File without changes
File without changes