js-draw 0.18.2 → 0.20.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 (269) hide show
  1. package/.eslintrc.js +1 -0
  2. package/CHANGELOG.md +10 -0
  3. package/dist/bundle.js +2 -2
  4. package/dist/bundledStyles.js +1 -0
  5. package/dist/cjs/src/Color4.d.ts +8 -0
  6. package/dist/cjs/src/Color4.js +67 -0
  7. package/dist/cjs/src/Editor.d.ts +2 -2
  8. package/dist/cjs/src/Editor.js +7 -7
  9. package/dist/cjs/src/SVGLoader.js +77 -12
  10. package/dist/cjs/src/Viewport.d.ts +2 -0
  11. package/dist/cjs/src/Viewport.js +6 -2
  12. package/dist/cjs/src/components/AbstractComponent.d.ts +2 -2
  13. package/dist/cjs/src/components/AbstractComponent.js +3 -3
  14. package/dist/cjs/src/components/{ImageBackground.d.ts → BackgroundComponent.d.ts} +23 -3
  15. package/dist/cjs/src/components/BackgroundComponent.js +309 -0
  16. package/dist/cjs/src/components/RestylableComponent.d.ts +21 -2
  17. package/dist/cjs/src/components/Stroke.d.ts +35 -0
  18. package/dist/cjs/src/components/Stroke.js +37 -3
  19. package/dist/cjs/src/components/TextComponent.d.ts +27 -17
  20. package/dist/cjs/src/components/TextComponent.js +23 -1
  21. package/dist/cjs/src/components/lib.d.ts +4 -3
  22. package/dist/cjs/src/components/lib.js +2 -2
  23. package/dist/cjs/src/components/util/StrokeSmoother.js +25 -15
  24. package/dist/cjs/src/lib.d.ts +30 -0
  25. package/dist/cjs/src/lib.js +30 -0
  26. package/dist/cjs/src/localizations/de.js +1 -1
  27. package/dist/cjs/src/localizations/es.js +1 -1
  28. package/dist/cjs/src/math/Path.js +1 -1
  29. package/dist/cjs/src/math/polynomial/QuadraticBezier.d.ts +28 -0
  30. package/dist/cjs/src/math/polynomial/QuadraticBezier.js +115 -0
  31. package/dist/cjs/src/math/polynomial/solveQuadratic.d.ts +6 -0
  32. package/dist/cjs/src/math/polynomial/solveQuadratic.js +36 -0
  33. package/dist/cjs/src/rendering/RenderingStyle.d.ts +4 -4
  34. package/dist/cjs/src/rendering/TextRenderingStyle.d.ts +10 -10
  35. package/dist/cjs/src/rendering/lib.d.ts +2 -0
  36. package/dist/cjs/src/rendering/renderers/AbstractRenderer.d.ts +2 -2
  37. package/dist/cjs/src/rendering/renderers/CanvasRenderer.d.ts +2 -2
  38. package/dist/cjs/src/rendering/renderers/CanvasRenderer.js +5 -3
  39. package/dist/cjs/src/rendering/renderers/DummyRenderer.d.ts +2 -2
  40. package/dist/cjs/src/rendering/renderers/SVGRenderer.d.ts +2 -2
  41. package/dist/cjs/src/rendering/renderers/SVGRenderer.js +15 -6
  42. package/dist/cjs/src/rendering/renderers/TextOnlyRenderer.d.ts +2 -2
  43. package/dist/cjs/src/toolbar/IconProvider.d.ts +2 -2
  44. package/dist/cjs/src/toolbar/localization.d.ts +2 -1
  45. package/dist/cjs/src/toolbar/localization.js +3 -2
  46. package/dist/cjs/src/toolbar/widgets/BaseWidget.js +1 -1
  47. package/dist/cjs/src/toolbar/widgets/DocumentPropertiesWidget.d.ts +5 -0
  48. package/dist/cjs/src/toolbar/widgets/DocumentPropertiesWidget.js +77 -2
  49. package/dist/cjs/src/toolbar/widgets/PenToolWidget.js +1 -1
  50. package/dist/cjs/src/tools/FindTool.js +1 -1
  51. package/dist/cjs/src/tools/SoundUITool.d.ts +24 -0
  52. package/dist/cjs/src/tools/SoundUITool.js +164 -0
  53. package/dist/cjs/src/tools/TextTool.d.ts +2 -2
  54. package/dist/cjs/src/tools/ToolController.js +6 -1
  55. package/dist/cjs/src/tools/lib.d.ts +1 -0
  56. package/dist/cjs/src/tools/lib.js +3 -1
  57. package/dist/cjs/src/tools/localization.d.ts +3 -0
  58. package/dist/cjs/src/tools/localization.js +3 -0
  59. package/dist/mjs/src/Color4.d.ts +8 -0
  60. package/dist/mjs/src/Color4.mjs +64 -0
  61. package/dist/mjs/src/Editor.d.ts +2 -2
  62. package/dist/mjs/src/Editor.mjs +6 -6
  63. package/dist/mjs/src/SVGLoader.mjs +76 -11
  64. package/dist/mjs/src/Viewport.d.ts +2 -0
  65. package/dist/mjs/src/Viewport.mjs +6 -2
  66. package/dist/mjs/src/components/AbstractComponent.d.ts +2 -2
  67. package/dist/mjs/src/components/AbstractComponent.mjs +3 -3
  68. package/dist/mjs/src/components/{ImageBackground.d.ts → BackgroundComponent.d.ts} +23 -3
  69. package/dist/mjs/src/components/BackgroundComponent.mjs +279 -0
  70. package/dist/mjs/src/components/RestylableComponent.d.ts +21 -2
  71. package/dist/mjs/src/components/Stroke.d.ts +35 -0
  72. package/dist/mjs/src/components/Stroke.mjs +37 -3
  73. package/dist/mjs/src/components/TextComponent.d.ts +27 -17
  74. package/dist/mjs/src/components/TextComponent.mjs +23 -1
  75. package/dist/mjs/src/components/lib.d.ts +4 -3
  76. package/dist/mjs/src/components/lib.mjs +2 -2
  77. package/dist/mjs/src/components/util/StrokeSmoother.mjs +25 -15
  78. package/dist/mjs/src/lib.d.ts +30 -0
  79. package/dist/mjs/src/lib.mjs +30 -0
  80. package/dist/mjs/src/localizations/de.mjs +1 -1
  81. package/dist/mjs/src/localizations/es.mjs +1 -1
  82. package/dist/mjs/src/math/Path.mjs +1 -1
  83. package/dist/mjs/src/math/polynomial/QuadraticBezier.d.ts +28 -0
  84. package/dist/mjs/src/math/polynomial/QuadraticBezier.mjs +109 -0
  85. package/dist/mjs/src/math/polynomial/solveQuadratic.d.ts +6 -0
  86. package/dist/mjs/src/math/polynomial/solveQuadratic.mjs +34 -0
  87. package/dist/mjs/src/rendering/RenderingStyle.d.ts +4 -4
  88. package/dist/mjs/src/rendering/TextRenderingStyle.d.ts +10 -10
  89. package/dist/mjs/src/rendering/lib.d.ts +2 -0
  90. package/dist/mjs/src/rendering/renderers/AbstractRenderer.d.ts +2 -2
  91. package/dist/mjs/src/rendering/renderers/CanvasRenderer.d.ts +2 -2
  92. package/dist/mjs/src/rendering/renderers/CanvasRenderer.mjs +5 -3
  93. package/dist/mjs/src/rendering/renderers/DummyRenderer.d.ts +2 -2
  94. package/dist/mjs/src/rendering/renderers/SVGRenderer.d.ts +2 -2
  95. package/dist/mjs/src/rendering/renderers/SVGRenderer.mjs +15 -6
  96. package/dist/mjs/src/rendering/renderers/TextOnlyRenderer.d.ts +2 -2
  97. package/dist/mjs/src/toolbar/IconProvider.d.ts +2 -2
  98. package/dist/mjs/src/toolbar/localization.d.ts +2 -1
  99. package/dist/mjs/src/toolbar/localization.mjs +3 -2
  100. package/dist/mjs/src/toolbar/widgets/BaseWidget.mjs +1 -1
  101. package/dist/mjs/src/toolbar/widgets/DocumentPropertiesWidget.d.ts +5 -0
  102. package/dist/mjs/src/toolbar/widgets/DocumentPropertiesWidget.mjs +54 -2
  103. package/dist/mjs/src/toolbar/widgets/PenToolWidget.mjs +1 -1
  104. package/dist/mjs/src/tools/FindTool.mjs +1 -1
  105. package/dist/mjs/src/tools/SoundUITool.d.ts +24 -0
  106. package/dist/mjs/src/tools/SoundUITool.mjs +158 -0
  107. package/dist/mjs/src/tools/TextTool.d.ts +2 -2
  108. package/dist/mjs/src/tools/ToolController.mjs +6 -1
  109. package/dist/mjs/src/tools/lib.d.ts +1 -0
  110. package/dist/mjs/src/tools/lib.mjs +1 -0
  111. package/dist/mjs/src/tools/localization.d.ts +3 -0
  112. package/dist/mjs/src/tools/localization.mjs +3 -0
  113. package/jest.config.js +1 -1
  114. package/package.json +19 -17
  115. package/src/Editor.css +2 -2
  116. package/src/tools/SoundUITool.css +15 -0
  117. package/src/tools/tools.css +4 -0
  118. package/dist/cjs/src/components/ImageBackground.js +0 -146
  119. package/dist/mjs/src/components/ImageBackground.mjs +0 -139
  120. package/src/Color4.test.ts +0 -40
  121. package/src/Color4.ts +0 -236
  122. package/src/Editor.loadFrom.test.ts +0 -24
  123. package/src/Editor.toSVG.test.ts +0 -111
  124. package/src/Editor.ts +0 -1122
  125. package/src/EditorImage.test.ts +0 -120
  126. package/src/EditorImage.ts +0 -603
  127. package/src/EventDispatcher.test.ts +0 -123
  128. package/src/EventDispatcher.ts +0 -71
  129. package/src/Pointer.ts +0 -127
  130. package/src/SVGLoader.test.ts +0 -114
  131. package/src/SVGLoader.ts +0 -511
  132. package/src/UndoRedoHistory.test.ts +0 -33
  133. package/src/UndoRedoHistory.ts +0 -102
  134. package/src/Viewport.ts +0 -319
  135. package/src/bundle/bundled.ts +0 -7
  136. package/src/commands/Command.ts +0 -45
  137. package/src/commands/Duplicate.ts +0 -48
  138. package/src/commands/Erase.ts +0 -74
  139. package/src/commands/SerializableCommand.ts +0 -49
  140. package/src/commands/UnresolvedCommand.ts +0 -37
  141. package/src/commands/invertCommand.ts +0 -51
  142. package/src/commands/lib.ts +0 -16
  143. package/src/commands/localization.ts +0 -47
  144. package/src/commands/uniteCommands.test.ts +0 -23
  145. package/src/commands/uniteCommands.ts +0 -135
  146. package/src/components/AbstractComponent.transformBy.test.ts +0 -22
  147. package/src/components/AbstractComponent.ts +0 -364
  148. package/src/components/ImageBackground.test.ts +0 -35
  149. package/src/components/ImageBackground.ts +0 -176
  150. package/src/components/ImageComponent.ts +0 -171
  151. package/src/components/RestylableComponent.ts +0 -142
  152. package/src/components/SVGGlobalAttributesObject.ts +0 -81
  153. package/src/components/Stroke.test.ts +0 -139
  154. package/src/components/Stroke.ts +0 -245
  155. package/src/components/TextComponent.test.ts +0 -99
  156. package/src/components/TextComponent.ts +0 -315
  157. package/src/components/UnknownSVGObject.test.ts +0 -10
  158. package/src/components/UnknownSVGObject.ts +0 -60
  159. package/src/components/builders/ArrowBuilder.ts +0 -107
  160. package/src/components/builders/FreehandLineBuilder.ts +0 -212
  161. package/src/components/builders/LineBuilder.ts +0 -77
  162. package/src/components/builders/PressureSensitiveFreehandLineBuilder.ts +0 -454
  163. package/src/components/builders/RectangleBuilder.ts +0 -74
  164. package/src/components/builders/types.ts +0 -15
  165. package/src/components/lib.ts +0 -25
  166. package/src/components/localization.ts +0 -22
  167. package/src/components/util/StrokeSmoother.ts +0 -293
  168. package/src/components/util/describeComponentList.ts +0 -18
  169. package/src/lib.ts +0 -37
  170. package/src/localization.ts +0 -34
  171. package/src/localizations/de.ts +0 -98
  172. package/src/localizations/en.ts +0 -8
  173. package/src/localizations/es.ts +0 -74
  174. package/src/localizations/getLocalizationTable.test.ts +0 -27
  175. package/src/localizations/getLocalizationTable.ts +0 -55
  176. package/src/math/LineSegment2.test.ts +0 -99
  177. package/src/math/LineSegment2.ts +0 -160
  178. package/src/math/Mat33.test.ts +0 -244
  179. package/src/math/Mat33.ts +0 -437
  180. package/src/math/Path.fromString.test.ts +0 -223
  181. package/src/math/Path.test.ts +0 -198
  182. package/src/math/Path.toString.test.ts +0 -77
  183. package/src/math/Path.ts +0 -790
  184. package/src/math/Rect2.test.ts +0 -204
  185. package/src/math/Rect2.ts +0 -315
  186. package/src/math/Triangle.ts +0 -29
  187. package/src/math/Vec2.test.ts +0 -30
  188. package/src/math/Vec2.ts +0 -18
  189. package/src/math/Vec3.test.ts +0 -44
  190. package/src/math/Vec3.ts +0 -218
  191. package/src/math/lib.ts +0 -15
  192. package/src/math/rounding.test.ts +0 -65
  193. package/src/math/rounding.ts +0 -156
  194. package/src/rendering/Display.ts +0 -249
  195. package/src/rendering/RenderingStyle.test.ts +0 -68
  196. package/src/rendering/RenderingStyle.ts +0 -55
  197. package/src/rendering/TextRenderingStyle.ts +0 -45
  198. package/src/rendering/caching/CacheRecord.test.ts +0 -49
  199. package/src/rendering/caching/CacheRecord.ts +0 -77
  200. package/src/rendering/caching/CacheRecordManager.ts +0 -71
  201. package/src/rendering/caching/RenderingCache.test.ts +0 -44
  202. package/src/rendering/caching/RenderingCache.ts +0 -66
  203. package/src/rendering/caching/RenderingCacheNode.ts +0 -405
  204. package/src/rendering/caching/testUtils.ts +0 -35
  205. package/src/rendering/caching/types.ts +0 -34
  206. package/src/rendering/lib.ts +0 -6
  207. package/src/rendering/localization.ts +0 -20
  208. package/src/rendering/renderers/AbstractRenderer.ts +0 -222
  209. package/src/rendering/renderers/CanvasRenderer.ts +0 -296
  210. package/src/rendering/renderers/DummyRenderer.test.ts +0 -42
  211. package/src/rendering/renderers/DummyRenderer.ts +0 -136
  212. package/src/rendering/renderers/SVGRenderer.ts +0 -354
  213. package/src/rendering/renderers/TextOnlyRenderer.ts +0 -70
  214. package/src/testing/beforeEachFile.ts +0 -8
  215. package/src/testing/createEditor.ts +0 -11
  216. package/src/testing/global.d.ts +0 -17
  217. package/src/testing/lib.ts +0 -3
  218. package/src/testing/loadExpectExtensions.ts +0 -25
  219. package/src/testing/sendPenEvent.ts +0 -31
  220. package/src/testing/sendTouchEvent.ts +0 -78
  221. package/src/toolbar/HTMLToolbar.ts +0 -492
  222. package/src/toolbar/IconProvider.ts +0 -736
  223. package/src/toolbar/lib.ts +0 -4
  224. package/src/toolbar/localization.ts +0 -106
  225. package/src/toolbar/makeColorInput.ts +0 -145
  226. package/src/toolbar/types.ts +0 -5
  227. package/src/toolbar/widgets/ActionButtonWidget.ts +0 -39
  228. package/src/toolbar/widgets/BaseToolWidget.ts +0 -56
  229. package/src/toolbar/widgets/BaseWidget.ts +0 -377
  230. package/src/toolbar/widgets/DocumentPropertiesWidget.ts +0 -167
  231. package/src/toolbar/widgets/EraserToolWidget.ts +0 -85
  232. package/src/toolbar/widgets/HandToolWidget.ts +0 -250
  233. package/src/toolbar/widgets/InsertImageWidget.ts +0 -223
  234. package/src/toolbar/widgets/OverflowWidget.ts +0 -92
  235. package/src/toolbar/widgets/PenToolWidget.ts +0 -288
  236. package/src/toolbar/widgets/SelectionToolWidget.ts +0 -190
  237. package/src/toolbar/widgets/TextToolWidget.ts +0 -145
  238. package/src/toolbar/widgets/lib.ts +0 -13
  239. package/src/tools/BaseTool.ts +0 -76
  240. package/src/tools/Eraser.test.ts +0 -103
  241. package/src/tools/Eraser.ts +0 -139
  242. package/src/tools/FindTool.ts +0 -152
  243. package/src/tools/PanZoom.test.ts +0 -310
  244. package/src/tools/PanZoom.ts +0 -520
  245. package/src/tools/PasteHandler.ts +0 -95
  246. package/src/tools/Pen.test.ts +0 -194
  247. package/src/tools/Pen.ts +0 -226
  248. package/src/tools/PipetteTool.ts +0 -55
  249. package/src/tools/SelectionTool/SelectAllShortcutHandler.ts +0 -28
  250. package/src/tools/SelectionTool/Selection.ts +0 -607
  251. package/src/tools/SelectionTool/SelectionHandle.ts +0 -108
  252. package/src/tools/SelectionTool/SelectionTool.test.ts +0 -261
  253. package/src/tools/SelectionTool/SelectionTool.ts +0 -480
  254. package/src/tools/SelectionTool/TransformMode.ts +0 -114
  255. package/src/tools/SelectionTool/types.ts +0 -11
  256. package/src/tools/TextTool.ts +0 -326
  257. package/src/tools/ToolController.ts +0 -178
  258. package/src/tools/ToolEnabledGroup.ts +0 -14
  259. package/src/tools/ToolSwitcherShortcut.ts +0 -39
  260. package/src/tools/ToolbarShortcutHandler.ts +0 -34
  261. package/src/tools/UndoRedoShortcut.test.ts +0 -56
  262. package/src/tools/UndoRedoShortcut.ts +0 -25
  263. package/src/tools/lib.ts +0 -21
  264. package/src/tools/localization.ts +0 -66
  265. package/src/types.ts +0 -234
  266. package/src/util/assertions.ts +0 -55
  267. package/src/util/fileToBase64.ts +0 -18
  268. package/src/util/untilNextAnimationFrame.ts +0 -9
  269. package/src/util/waitForTimeout.ts +0 -9
@@ -3,12 +3,43 @@ import Rect2 from '../math/Rect2.mjs';
3
3
  import { styleFromJSON, styleToJSON } from '../rendering/RenderingStyle.mjs';
4
4
  import AbstractComponent from './AbstractComponent.mjs';
5
5
  import { createRestyleComponentCommand } from './RestylableComponent.mjs';
6
+ /**
7
+ * Represents an {@link AbstractComponent} made up of one or more {@link Path}s.
8
+ *
9
+ * @example
10
+ * For some {@link Editor} editor and `Stroke` stroke,
11
+ *
12
+ * **Restyling**:
13
+ * ```ts
14
+ * editor.dispatch(stroke.updateStyle({ color: Color4.red }));
15
+ * ```
16
+ *
17
+ * **Transforming**:
18
+ * ```ts
19
+ * editor.dispatch(stroke.transformBy(Mat33.translation(Vec2.of(10, 0))));
20
+ * ```
21
+ */
6
22
  export default class Stroke extends AbstractComponent {
7
- // Creates a `Stroke` from the given `parts`. All parts should have the
8
- // same color.
23
+ /**
24
+ * Creates a `Stroke` from the given `parts`. All parts should have the
25
+ * same color.
26
+ *
27
+ * @example
28
+ * ```ts
29
+ * // A path that starts at (1,1), moves to the right by (2, 0),
30
+ * // then moves down and right by (3, 3)
31
+ * const path = Path.fromString('m1,1 2,0 3,3');
32
+ *
33
+ * const stroke = new Stroke([
34
+ * // Fill with red
35
+ * path.toRenderable({ fill: Color4.red })
36
+ * ]);
37
+ * ```
38
+ */
9
39
  constructor(parts) {
10
40
  var _a;
11
41
  super('stroke');
42
+ // @internal
12
43
  // eslint-disable-next-line @typescript-eslint/prefer-as-const
13
44
  this.isRestylableComponent = true;
14
45
  this.approximateRenderingTime = 0;
@@ -94,7 +125,7 @@ export default class Stroke extends AbstractComponent {
94
125
  if (!bbox.intersects(visibleRect)) {
95
126
  continue;
96
127
  }
97
- const muchBiggerThanVisible = bbox.size.x > visibleRect.size.x * 2 || bbox.size.y > visibleRect.size.y * 2;
128
+ const muchBiggerThanVisible = bbox.size.x > visibleRect.size.x * 3 || bbox.size.y > visibleRect.size.y * 3;
98
129
  if (muchBiggerThanVisible && !part.path.roughlyIntersects(visibleRect, (_b = (_a = part.style.stroke) === null || _a === void 0 ? void 0 : _a.width) !== null && _b !== void 0 ? _b : 0)) {
99
130
  continue;
100
131
  }
@@ -141,6 +172,9 @@ export default class Stroke extends AbstractComponent {
141
172
  };
142
173
  });
143
174
  }
175
+ /**
176
+ * @returns the {@link Path.union} of all paths that make up this stroke.
177
+ */
144
178
  getPath() {
145
179
  let result = null;
146
180
  for (const part of this.parts) {
@@ -4,18 +4,26 @@ import Mat33 from '../math/Mat33';
4
4
  import Rect2 from '../math/Rect2';
5
5
  import Editor from '../Editor';
6
6
  import AbstractRenderer from '../rendering/renderers/AbstractRenderer';
7
- import { TextStyle } from '../rendering/TextRenderingStyle';
7
+ import { TextRenderingStyle } from '../rendering/TextRenderingStyle';
8
8
  import AbstractComponent from './AbstractComponent';
9
9
  import { ImageComponentLocalization } from './localization';
10
10
  import RestyleableComponent, { ComponentStyle } from './RestylableComponent';
11
+ /**
12
+ * Displays text.
13
+ */
11
14
  export default class TextComponent extends AbstractComponent implements RestyleableComponent {
12
15
  protected readonly textObjects: Array<string | TextComponent>;
13
16
  private transform;
14
17
  private style;
15
18
  protected contentBBox: Rect2;
16
19
  readonly isRestylableComponent: true;
17
- constructor(textObjects: Array<string | TextComponent>, transform: Mat33, style: TextStyle);
18
- static applyTextStyles(ctx: CanvasRenderingContext2D, style: TextStyle): void;
20
+ /**
21
+ * Creates a new text object from a list of component text or child TextComponents.
22
+ *
23
+ * @see {@link fromLines}
24
+ */
25
+ constructor(textObjects: Array<string | TextComponent>, transform: Mat33, style: TextRenderingStyle);
26
+ static applyTextStyles(ctx: CanvasRenderingContext2D, style: TextRenderingStyle): void;
19
27
  private static textMeasuringCtx;
20
28
  private static estimateTextDimens;
21
29
  private static getTextDimens;
@@ -28,19 +36,7 @@ export default class TextComponent extends AbstractComponent implements Restylea
28
36
  getStyle(): ComponentStyle;
29
37
  updateStyle(style: ComponentStyle): SerializableCommand;
30
38
  forceStyle(style: ComponentStyle, editor: Editor | null): void;
31
- getTextStyle(): {
32
- renderingStyle: {
33
- fill: import("../Color4").default;
34
- stroke: {
35
- color: import("../Color4").default;
36
- width: number;
37
- } | undefined;
38
- };
39
- size: number;
40
- fontFamily: string;
41
- fontWeight?: string | undefined;
42
- fontVariant?: string | undefined;
43
- };
39
+ getTextStyle(): TextRenderingStyle;
44
40
  getBaselinePos(): import("../lib").Vec3;
45
41
  getTransform(): Mat33;
46
42
  protected applyTransformation(affineTransfm: Mat33): void;
@@ -49,5 +45,19 @@ export default class TextComponent extends AbstractComponent implements Restylea
49
45
  description(localizationTable: ImageComponentLocalization): string;
50
46
  protected serializeToJSON(): Record<string, any>;
51
47
  static deserializeFromString(json: any): TextComponent;
52
- static fromLines(lines: string[], transform: Mat33, style: TextStyle): AbstractComponent;
48
+ /**
49
+ * Creates a `TextComponent` from `lines`.
50
+ *
51
+ * @example
52
+ * ```ts
53
+ * const textStyle = {
54
+ * size: 12,
55
+ * fontFamily: 'serif',
56
+ * renderingStyle: { fill: Color4.black },
57
+ * };
58
+ *
59
+ * const text = TextComponent.fromLines('foo\nbar'.split('\n'), Mat33.identity, textStyle);
60
+ * ```
61
+ */
62
+ static fromLines(lines: string[], transform: Mat33, style: TextRenderingStyle): AbstractComponent;
53
63
  }
@@ -6,7 +6,15 @@ import { cloneTextStyle, textStyleFromJSON, textStyleToJSON } from '../renderi
6
6
  import AbstractComponent from './AbstractComponent.mjs';
7
7
  import { createRestyleComponentCommand } from './RestylableComponent.mjs';
8
8
  const componentTypeId = 'text';
9
+ /**
10
+ * Displays text.
11
+ */
9
12
  export default class TextComponent extends AbstractComponent {
13
+ /**
14
+ * Creates a new text object from a list of component text or child TextComponents.
15
+ *
16
+ * @see {@link fromLines}
17
+ */
10
18
  constructor(textObjects, transform, style) {
11
19
  super(componentTypeId);
12
20
  this.textObjects = textObjects;
@@ -150,7 +158,7 @@ export default class TextComponent extends AbstractComponent {
150
158
  editor.queueRerender();
151
159
  }
152
160
  }
153
- // See this.getStyle
161
+ // See {@link getStyle}
154
162
  getTextStyle() {
155
163
  return cloneTextStyle(this.style);
156
164
  }
@@ -232,6 +240,20 @@ export default class TextComponent extends AbstractComponent {
232
240
  const transform = new Mat33(...transformData);
233
241
  return new TextComponent(textObjects, transform, style);
234
242
  }
243
+ /**
244
+ * Creates a `TextComponent` from `lines`.
245
+ *
246
+ * @example
247
+ * ```ts
248
+ * const textStyle = {
249
+ * size: 12,
250
+ * fontFamily: 'serif',
251
+ * renderingStyle: { fill: Color4.black },
252
+ * };
253
+ *
254
+ * const text = TextComponent.fromLines('foo\nbar'.split('\n'), Mat33.identity, textStyle);
255
+ * ```
256
+ */
235
257
  static fromLines(lines, transform, style) {
236
258
  let lastComponent = null;
237
259
  const components = [];
@@ -7,6 +7,7 @@ export { default as AbstractComponent } from './AbstractComponent';
7
7
  import Stroke from './Stroke';
8
8
  import TextComponent from './TextComponent';
9
9
  import ImageComponent from './ImageComponent';
10
- import RestyleableComponent, { createRestyleComponentCommand, isRestylableComponent } from './RestylableComponent';
11
- import ImageBackground from './ImageBackground';
12
- export { Stroke, TextComponent as Text, RestyleableComponent, createRestyleComponentCommand, isRestylableComponent, TextComponent, Stroke as StrokeComponent, ImageBackground as BackgroundComponent, ImageComponent, };
10
+ import RestyleableComponent from './RestylableComponent';
11
+ import { createRestyleComponentCommand, isRestylableComponent, ComponentStyle as RestyleableComponentStyle } from './RestylableComponent';
12
+ import BackgroundComponent from './BackgroundComponent';
13
+ export { Stroke, TextComponent as Text, RestyleableComponent, createRestyleComponentCommand, isRestylableComponent, RestyleableComponentStyle, TextComponent, Stroke as StrokeComponent, BackgroundComponent, ImageComponent, };
@@ -8,5 +8,5 @@ import Stroke from './Stroke.mjs';
8
8
  import TextComponent from './TextComponent.mjs';
9
9
  import ImageComponent from './ImageComponent.mjs';
10
10
  import { createRestyleComponentCommand, isRestylableComponent } from './RestylableComponent.mjs';
11
- import ImageBackground from './ImageBackground.mjs';
12
- export { Stroke, TextComponent as Text, createRestyleComponentCommand, isRestylableComponent, TextComponent, Stroke as StrokeComponent, ImageBackground as BackgroundComponent, ImageComponent, };
11
+ import BackgroundComponent from './BackgroundComponent.mjs';
12
+ export { Stroke, TextComponent as Text, createRestyleComponentCommand, isRestylableComponent, TextComponent, Stroke as StrokeComponent, BackgroundComponent, ImageComponent, };
@@ -1,7 +1,7 @@
1
- import { Bezier } from 'bezier-js';
2
1
  import { Vec2 } from '../../math/Vec2.mjs';
3
2
  import Rect2 from '../../math/Rect2.mjs';
4
3
  import LineSegment2 from '../../math/LineSegment2.mjs';
4
+ import QuadraticBezier from '../../math/polynomial/QuadraticBezier.mjs';
5
5
  // Handles stroke smoothing
6
6
  export class StrokeSmoother {
7
7
  constructor(startPoint,
@@ -38,9 +38,9 @@ export class StrokeSmoother {
38
38
  if (!this.currentCurve) {
39
39
  return 0;
40
40
  }
41
- const startPt = Vec2.ofXY(this.currentCurve.points[0]);
42
- const controlPt = Vec2.ofXY(this.currentCurve.points[1]);
43
- const endPt = Vec2.ofXY(this.currentCurve.points[2]);
41
+ const startPt = this.currentCurve.p0;
42
+ const controlPt = this.currentCurve.p1;
43
+ const endPt = this.currentCurve.p2;
44
44
  const toControlDist = startPt.minus(controlPt).length();
45
45
  const toEndDist = endPt.minus(controlPt).length();
46
46
  return toControlDist + toEndDist;
@@ -52,7 +52,7 @@ export class StrokeSmoother {
52
52
  }
53
53
  this.onCurveAdded(this.currentSegmentToPath());
54
54
  const lastPoint = this.buffer[this.buffer.length - 1];
55
- this.lastExitingVec = Vec2.ofXY(this.currentCurve.points[2]).minus(Vec2.ofXY(this.currentCurve.points[1]));
55
+ this.lastExitingVec = this.currentCurve.p2.minus(this.currentCurve.p1);
56
56
  console.assert(this.lastExitingVec.magnitude() !== 0, 'lastExitingVec has zero length!');
57
57
  // Use the last two points to start a new curve (the last point isn't used
58
58
  // in the current curve and we want connected curves to share end points)
@@ -67,13 +67,13 @@ export class StrokeSmoother {
67
67
  if (this.currentCurve == null) {
68
68
  throw new Error('Invalid State: currentCurve is null!');
69
69
  }
70
- const startVec = Vec2.ofXY(this.currentCurve.normal(0)).normalized();
70
+ const startVec = this.currentCurve.normal(0).normalized();
71
71
  if (!isFinite(startVec.magnitude())) {
72
72
  throw new Error(`startVec(${startVec}) is NaN or ∞`);
73
73
  }
74
- const startPt = Vec2.ofXY(this.currentCurve.get(0));
75
- const endPt = Vec2.ofXY(this.currentCurve.get(1));
76
- const controlPoint = Vec2.ofXY(this.currentCurve.points[1]);
74
+ const startPt = this.currentCurve.at(0);
75
+ const endPt = this.currentCurve.at(1);
76
+ const controlPoint = this.currentCurve.p1;
77
77
  return {
78
78
  startPoint: startPt,
79
79
  controlPoint,
@@ -125,7 +125,7 @@ export class StrokeSmoother {
125
125
  const p2 = lastPoint.pos.plus((_b = this.lastExitingVec) !== null && _b !== void 0 ? _b : Vec2.unitX);
126
126
  const p3 = newPoint.pos;
127
127
  // Quadratic Bézier curve
128
- this.currentCurve = new Bezier(p1.xy, p2.xy, p3.xy);
128
+ this.currentCurve = new QuadraticBezier(p1, p2, p3);
129
129
  console.assert(!isNaN(p1.magnitude()) && !isNaN(p2.magnitude()) && !isNaN(p3.magnitude()), 'Expected !NaN');
130
130
  if (this.isFirstSegment) {
131
131
  // The start of a curve often lacks accurate pressure information. Update it.
@@ -176,19 +176,29 @@ export class StrokeSmoother {
176
176
  console.assert(!segmentStart.eq(controlPoint, 1e-11), 'Start and control points are equal!');
177
177
  console.assert(!controlPoint.eq(segmentEnd, 1e-11), 'Control and end points are equal!');
178
178
  const prevCurve = this.currentCurve;
179
- this.currentCurve = new Bezier(segmentStart.xy, controlPoint.xy, segmentEnd.xy);
180
- if (isNaN(Vec2.ofXY(this.currentCurve.normal(0)).magnitude())) {
179
+ this.currentCurve = new QuadraticBezier(segmentStart, controlPoint, segmentEnd);
180
+ if (isNaN(this.currentCurve.normal(0).magnitude())) {
181
181
  console.error('NaN normal at 0. Curve:', this.currentCurve);
182
182
  this.currentCurve = prevCurve;
183
183
  }
184
184
  // Should we start making a new curve? Check whether all buffer points are within
185
185
  // ±strokeWidth of the curve.
186
186
  const curveMatchesPoints = (curve) => {
187
+ let nonMatching = 0;
188
+ const maxNonMatching = 2;
189
+ const minFit = Math.max(Math.min(this.curveStartWidth, this.curveEndWidth) / 3, this.minFitAllowed);
187
190
  for (const point of this.buffer) {
188
- const proj = Vec2.ofXY(curve.project(point.xy));
189
- const dist = proj.minus(point).magnitude();
190
- const minFit = Math.max(Math.min(this.curveStartWidth, this.curveEndWidth) / 3, this.minFitAllowed);
191
+ let dist = curve.approximateDistance(point);
191
192
  if (dist > minFit || dist > this.maxFitAllowed) {
193
+ // Avoid using the slower .distance
194
+ if (nonMatching >= maxNonMatching - 1) {
195
+ dist = curve.distance(point);
196
+ }
197
+ if (dist > minFit || dist > this.maxFitAllowed) {
198
+ nonMatching++;
199
+ }
200
+ }
201
+ if (nonMatching >= maxNonMatching) {
192
202
  return false;
193
203
  }
194
204
  }
@@ -5,10 +5,40 @@
5
5
  * @example
6
6
  * ```
7
7
  * import { Editor, Vec3, Mat33 } from 'js-draw';
8
+ *
9
+ * // Apply js-draw CSS
10
+ * import 'js-draw/styles';
11
+ * // If your bundler doesn't support the above, try
12
+ * // import 'js-draw/bundledStyles';
13
+ *
14
+ * (async () => {
15
+ * const editor = new Editor(document.body);
16
+ * const toolbar = editor.addToolbar();
17
+ * editor.getRootElement().style.height = '600px';
18
+ *
19
+ * await editor.loadFromSVG(`
20
+ * <svg viewBox="0 0 500 500" width="500" height="500" version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg">
21
+ * <style id="js-draw-style-sheet">path{stroke-linecap:round;stroke-linejoin:round;}text{white-space:pre;}</style>
22
+ * <path d="M500,500L500,0L0,0L0,500L500,500" fill="#423131bf" class="js-draw-image-background"></path>
23
+ * <text style="transform: matrix(1, 0, 0, 1, 57, 192); font-family: serif; font-size: 32px; fill: rgb(204, 102, 51);">Testing...</text>
24
+ * </svg>
25
+ * `);
26
+ *
27
+ * toolbar.addActionButton({
28
+ * label: 'Save',
29
+ * icon: editor.icons.makeSaveIcon(),
30
+ * }, () => {
31
+ * const saveData = editor.toSVG().outerHTML;
32
+ *
33
+ * // Do something with saveData
34
+ * });
35
+ * })();
8
36
  * ```
9
37
  *
10
38
  * @see
11
39
  * {@link Editor}
40
+ * {@link Editor.loadFromSVG}
41
+ * {@link HTMLToolbar.addActionButton }
12
42
  *
13
43
  * @packageDocumentation
14
44
  */
@@ -5,10 +5,40 @@
5
5
  * @example
6
6
  * ```
7
7
  * import { Editor, Vec3, Mat33 } from 'js-draw';
8
+ *
9
+ * // Apply js-draw CSS
10
+ * import 'js-draw/styles';
11
+ * // If your bundler doesn't support the above, try
12
+ * // import 'js-draw/bundledStyles';
13
+ *
14
+ * (async () => {
15
+ * const editor = new Editor(document.body);
16
+ * const toolbar = editor.addToolbar();
17
+ * editor.getRootElement().style.height = '600px';
18
+ *
19
+ * await editor.loadFromSVG(`
20
+ * <svg viewBox="0 0 500 500" width="500" height="500" version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg">
21
+ * <style id="js-draw-style-sheet">path{stroke-linecap:round;stroke-linejoin:round;}text{white-space:pre;}</style>
22
+ * <path d="M500,500L500,0L0,0L0,500L500,500" fill="#423131bf" class="js-draw-image-background"></path>
23
+ * <text style="transform: matrix(1, 0, 0, 1, 57, 192); font-family: serif; font-size: 32px; fill: rgb(204, 102, 51);">Testing...</text>
24
+ * </svg>
25
+ * `);
26
+ *
27
+ * toolbar.addActionButton({
28
+ * label: 'Save',
29
+ * icon: editor.icons.makeSaveIcon(),
30
+ * }, () => {
31
+ * const saveData = editor.toSVG().outerHTML;
32
+ *
33
+ * // Do something with saveData
34
+ * });
35
+ * })();
8
36
  * ```
9
37
  *
10
38
  * @see
11
39
  * {@link Editor}
40
+ * {@link Editor.loadFromSVG}
41
+ * {@link HTMLToolbar.addActionButton }
12
42
  *
13
43
  * @packageDocumentation
14
44
  */
@@ -1,4 +1,4 @@
1
1
  import { defaultEditorLocalization } from '../localization.mjs';
2
2
  // German localization
3
- const localization = Object.assign(Object.assign({}, defaultEditorLocalization), { pen: 'Stift', eraser: 'Radierer', select: 'Auswahl', handTool: 'Verschieben', zoom: 'Vergrößerung', resetView: 'Ansicht zurücksetzen', thicknessLabel: 'Dicke: ', colorLabel: 'Farbe: ', fontLabel: 'Schriftart: ', resizeImageToSelection: 'Bildgröße an Auswahl anpassen', deleteSelection: 'Auswahl löschen', duplicateSelection: 'Auswahl duplizieren', undo: 'Rückgängig', redo: 'Wiederholen', pickColorFromScreen: 'Farbe von Bildschirm auswählen', clickToPickColorAnnouncement: 'Klicke auf den Bildschirm, um eine Farbe auszuwählen', selectionToolKeyboardShortcuts: 'Auswahl-Werkzeug: Verwende die Pfeiltasten, um ausgewählte Elemente zu verschieben und ‚i‘ und ‚o‘, um ihre Größe zu ändern.', touchPanning: 'Ansicht mit Touchscreen verschieben', anyDevicePanning: 'Ansicht mit jedem Eingabegerät verschieben', selectObjectType: 'Objekt-Typ: ', freehandPen: 'Freihand', arrowPen: 'Pfeil', linePen: 'Linie', outlinedRectanglePen: 'Umrissenes Rechteck', filledRectanglePen: 'Ausgefülltes Rechteck', dropdownShown: t => `Dropdown-Menü für ${t} angezeigt`, dropdownHidden: t => `Dropdown-Menü für ${t} versteckt`, zoomLevel: t => `Vergößerung: ${t}%`, colorChangedAnnouncement: t => `Farbe zu ${t} geändert`, penTool: t => `Stift ${t}`, selectionTool: 'Auswahl', eraserTool: 'Radiergummi', touchPanTool: 'Ansicht mit Touchscreen verschieben', twoFingerPanZoomTool: 'Ansicht verschieben und vergrößern', undoRedoTool: 'Rückgängig/Wiederholen', rightClickDragPanTool: 'Rechtsklick-Ziehen', pipetteTool: 'Farbe von Bildschirm auswählen', keyboardPanZoom: 'Tastaturkürzel zum Verschieben/Vergrößern der Ansicht', textTool: 'Text', enterTextToInsert: 'Einzufügender Text', toolEnabledAnnouncement: t => `${t} aktiviert`, toolDisabledAnnouncement: t => `${t} deaktiviert`, updatedViewport: 'Transformierte Ansicht', transformedElements: t => `${t} Element${1 === t ? '' : 'e'} transformiert`, resizeOutputCommand: t => `Bildgröße auf ${t.w}x${t.h} geändert`, addElementAction: t => `${t} hinzugefügt`, eraseAction: (t, e) => `${e} ${t} gelöscht`, duplicateAction: (t, e) => `${e} ${t} dupliziert`, inverseOf: t => `Umkehrung von ${t}`, elements: 'Elemente', erasedNoElements: 'Nichts entfernt', duplicatedNoElements: 'Nichts dupliziert', rotatedBy: t => `${Math.abs(t)} Grad ${t < 0 ? 'im Uhrzeigersinn' : 'gegen den Uhrzeigersinn'} gedreht`, movedLeft: 'Nacht links bewegt', movedUp: 'Nacht oben bewegt', movedDown: 'Nacht unten bewegt', movedRight: 'Nacht rechts bewegt', zoomedOut: 'Ansicht verkleinert', zoomedIn: 'Ansicht vergrößert', selectedElements: t => `${t} Element${1 === t ? '' : 'e'} ausgewählt`, stroke: 'Strich', svgObject: 'SVG-Objekt', text: t => `Text-Objekt: ${t}`, pathNodeCount: t => `Es gibt ${t} sichtbare Pfad-Objekte.`, textNodeCount: t => `Es gibt ${t} sichtbare Text-Knotenpunkte.`, textNode: t => `Text: ${t}`, rerenderAsText: 'Als Text darstellen', 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.', loading: t => `Laden ${t}%...`, doneLoading: 'Laden fertig', imageEditor: 'Bild-Editor', undoAnnouncement: t => `Rückgangig gemacht ${t}`, redoAnnouncement: t => `Wiederholt ${t}` });
3
+ const localization = Object.assign(Object.assign({}, defaultEditorLocalization), { pen: 'Stift', eraser: 'Radierer', select: 'Auswahl', handTool: 'Verschieben', zoom: 'Vergrößerung', resetView: 'Ansicht zurücksetzen', thicknessLabel: 'Dicke: ', colorLabel: 'Farbe: ', fontLabel: 'Schriftart: ', resizeImageToSelection: 'Bildgröße an Auswahl anpassen', deleteSelection: 'Auswahl löschen', duplicateSelection: 'Auswahl duplizieren', undo: 'Rückgängig', redo: 'Wiederholen', pickColorFromScreen: 'Farbe von Bildschirm auswählen', clickToPickColorAnnouncement: 'Klicke auf den Bildschirm, um eine Farbe auszuwählen', selectionToolKeyboardShortcuts: 'Auswahl-Werkzeug: Verwende die Pfeiltasten, um ausgewählte Elemente zu verschieben und ‚i‘ und ‚o‘, um ihre Größe zu ändern.', touchPanning: 'Ansicht mit Touchscreen verschieben', anyDevicePanning: 'Ansicht mit jedem Eingabegerät verschieben', selectPenType: 'Objekt-Typ: ', freehandPen: 'Freihand', arrowPen: 'Pfeil', linePen: 'Linie', outlinedRectanglePen: 'Umrissenes Rechteck', filledRectanglePen: 'Ausgefülltes Rechteck', dropdownShown: t => `Dropdown-Menü für ${t} angezeigt`, dropdownHidden: t => `Dropdown-Menü für ${t} versteckt`, zoomLevel: t => `Vergößerung: ${t}%`, colorChangedAnnouncement: t => `Farbe zu ${t} geändert`, penTool: t => `Stift ${t}`, selectionTool: 'Auswahl', eraserTool: 'Radiergummi', touchPanTool: 'Ansicht mit Touchscreen verschieben', twoFingerPanZoomTool: 'Ansicht verschieben und vergrößern', undoRedoTool: 'Rückgängig/Wiederholen', rightClickDragPanTool: 'Rechtsklick-Ziehen', pipetteTool: 'Farbe von Bildschirm auswählen', keyboardPanZoom: 'Tastaturkürzel zum Verschieben/Vergrößern der Ansicht', textTool: 'Text', enterTextToInsert: 'Einzufügender Text', toolEnabledAnnouncement: t => `${t} aktiviert`, toolDisabledAnnouncement: t => `${t} deaktiviert`, updatedViewport: 'Transformierte Ansicht', transformedElements: t => `${t} Element${1 === t ? '' : 'e'} transformiert`, resizeOutputCommand: t => `Bildgröße auf ${t.w}x${t.h} geändert`, addElementAction: t => `${t} hinzugefügt`, eraseAction: (t, e) => `${e} ${t} gelöscht`, duplicateAction: (t, e) => `${e} ${t} dupliziert`, inverseOf: t => `Umkehrung von ${t}`, elements: 'Elemente', erasedNoElements: 'Nichts entfernt', duplicatedNoElements: 'Nichts dupliziert', rotatedBy: t => `${Math.abs(t)} Grad ${t < 0 ? 'im Uhrzeigersinn' : 'gegen den Uhrzeigersinn'} gedreht`, movedLeft: 'Nacht links bewegt', movedUp: 'Nacht oben bewegt', movedDown: 'Nacht unten bewegt', movedRight: 'Nacht rechts bewegt', zoomedOut: 'Ansicht verkleinert', zoomedIn: 'Ansicht vergrößert', selectedElements: t => `${t} Element${1 === t ? '' : 'e'} ausgewählt`, stroke: 'Strich', svgObject: 'SVG-Objekt', text: t => `Text-Objekt: ${t}`, pathNodeCount: t => `Es gibt ${t} sichtbare Pfad-Objekte.`, textNodeCount: t => `Es gibt ${t} sichtbare Text-Knotenpunkte.`, textNode: t => `Text: ${t}`, rerenderAsText: 'Als Text darstellen', 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.', loading: t => `Laden ${t}%...`, doneLoading: 'Laden fertig', imageEditor: 'Bild-Editor', undoAnnouncement: t => `Rückgangig gemacht ${t}`, redoAnnouncement: t => `Wiederholt ${t}` });
4
4
  export default localization;
@@ -6,7 +6,7 @@ const localization = Object.assign(Object.assign({}, defaultEditorLocalization),
6
6
  loading: (percentage) => `Cargando: ${percentage}%...`, imageEditor: 'Editor de dibujos', undoAnnouncement: (commandDescription) => `${commandDescription} fue deshecho`, redoAnnouncement: (commandDescription) => `${commandDescription} fue rehecho`, undo: 'Deshace', redo: 'Rehace',
7
7
  // Strings for the toolbar
8
8
  // (see src/toolbar/localization.ts)
9
- pen: 'Lapiz', eraser: 'Borrador', select: 'Selecciona', thicknessLabel: 'Tamaño: ', colorLabel: 'Color: ', doneLoading: 'El cargado terminó', fontLabel: 'Fuente: ', anyDevicePanning: 'Mover la pantalla con todo dispotivo', touchPanning: 'Mover la pantalla con un dedo', touchPanTool: 'Instrumento de mover la pantalla con un dedo', outlinedRectanglePen: 'Rectángulo con nada más que un borde', filledRectanglePen: 'Rectángulo sin borde', linePen: 'Línea', arrowPen: 'Flecha', freehandPen: 'Dibuja sin restricción de forma', selectObjectType: 'Forma de dibuja:', handTool: 'Mover', zoom: 'Zoom', resetView: 'Reiniciar vista', resizeImageToSelection: 'Redimensionar la imagen a lo que está seleccionado', deleteSelection: 'Borra la selección', duplicateSelection: 'Duplica la selección', pickColorFromScreen: 'Selecciona un color de la pantalla', clickToPickColorAnnouncement: 'Haga un clic en la pantalla para seleccionar un color', dropdownShown(toolName) {
9
+ pen: 'Lapiz', eraser: 'Borrador', select: 'Selecciona', thicknessLabel: 'Tamaño: ', colorLabel: 'Color: ', doneLoading: 'El cargado terminó', fontLabel: 'Fuente: ', anyDevicePanning: 'Mover la pantalla con todo dispotivo', touchPanning: 'Mover la pantalla con un dedo', touchPanTool: 'Instrumento de mover la pantalla con un dedo', outlinedRectanglePen: 'Rectángulo con nada más que un borde', filledRectanglePen: 'Rectángulo sin borde', linePen: 'Línea', arrowPen: 'Flecha', freehandPen: 'Dibuja sin restricción de forma', selectPenType: 'Forma de dibuja:', handTool: 'Mover', zoom: 'Zoom', resetView: 'Reiniciar vista', resizeImageToSelection: 'Redimensionar la imagen a lo que está seleccionado', deleteSelection: 'Borra la selección', duplicateSelection: 'Duplica la selección', pickColorFromScreen: 'Selecciona un color de la pantalla', clickToPickColorAnnouncement: 'Haga un clic en la pantalla para seleccionar un color', dropdownShown(toolName) {
10
10
  return `Menú por ${toolName} es visible`;
11
11
  }, dropdownHidden: function (toolName) {
12
12
  return `Menú por ${toolName} fue ocultado`;
@@ -341,7 +341,7 @@ export default class Path {
341
341
  const onlyStroked = strokeWidth > 0 && renderablePath.style.fill.a === 0;
342
342
  // Scale the expanded rect --- the visual equivalent is only close for huge strokes.
343
343
  const expandedRect = visibleRect.grownBy(strokeWidth)
344
- .transformedBoundingBox(Mat33.scaling2D(2, visibleRect.center));
344
+ .transformedBoundingBox(Mat33.scaling2D(4, visibleRect.center));
345
345
  // TODO: Handle simplifying very small paths.
346
346
  if (expandedRect.containsRect(path.bbox.grownBy(strokeWidth))) {
347
347
  return renderablePath;
@@ -0,0 +1,28 @@
1
+ import { Point2, Vec2 } from '../Vec2';
2
+ export default class QuadraticBezier {
3
+ readonly p0: Point2;
4
+ readonly p1: Point2;
5
+ readonly p2: Point2;
6
+ private bezierJs;
7
+ constructor(p0: Point2, p1: Point2, p2: Point2);
8
+ /**
9
+ * Returns a component of a quadratic Bézier curve at t, where p0,p1,p2 are either all x or
10
+ * all y components of the target curve.
11
+ */
12
+ private static componentAt;
13
+ private static derivativeComponentAt;
14
+ /**
15
+ * @returns the curve evaluated at `t`.
16
+ */
17
+ at(t: number): Point2;
18
+ derivativeAt(t: number): Point2;
19
+ /**
20
+ * @returns the approximate distance from `point` to this curve.
21
+ */
22
+ approximateDistance(point: Point2): number;
23
+ /**
24
+ * @returns the exact distance from `point` to this.
25
+ */
26
+ distance(point: Point2): number;
27
+ normal(t: number): Vec2;
28
+ }
@@ -0,0 +1,109 @@
1
+ import { Bezier } from 'bezier-js';
2
+ import { Vec2 } from '../Vec2.mjs';
3
+ import solveQuadratic from './solveQuadratic.mjs';
4
+ export default class QuadraticBezier {
5
+ constructor(p0, p1, p2) {
6
+ this.p0 = p0;
7
+ this.p1 = p1;
8
+ this.p2 = p2;
9
+ this.bezierJs = null;
10
+ }
11
+ /**
12
+ * Returns a component of a quadratic Bézier curve at t, where p0,p1,p2 are either all x or
13
+ * all y components of the target curve.
14
+ */
15
+ static componentAt(t, p0, p1, p2) {
16
+ return p0 + t * (-2 * p0 + 2 * p1) + t * t * (p0 - 2 * p1 + p2);
17
+ }
18
+ static derivativeComponentAt(t, p0, p1, p2) {
19
+ return -2 * p0 + 2 * p1 + 2 * t * (p0 - 2 * p1 + p2);
20
+ }
21
+ /**
22
+ * @returns the curve evaluated at `t`.
23
+ */
24
+ at(t) {
25
+ const p0 = this.p0;
26
+ const p1 = this.p1;
27
+ const p2 = this.p2;
28
+ return Vec2.of(QuadraticBezier.componentAt(t, p0.x, p1.x, p2.x), QuadraticBezier.componentAt(t, p0.y, p1.y, p2.y));
29
+ }
30
+ derivativeAt(t) {
31
+ const p0 = this.p0;
32
+ const p1 = this.p1;
33
+ const p2 = this.p2;
34
+ return Vec2.of(QuadraticBezier.derivativeComponentAt(t, p0.x, p1.x, p2.x), QuadraticBezier.derivativeComponentAt(t, p0.y, p1.y, p2.y));
35
+ }
36
+ /**
37
+ * @returns the approximate distance from `point` to this curve.
38
+ */
39
+ approximateDistance(point) {
40
+ // We want to minimize f(t) = |B(t) - p|².
41
+ // Expanding,
42
+ // f(t) = (Bₓ(t) - pₓ)² + (Bᵧ(t) - pᵧ)²
43
+ // ⇒ f'(t) = Dₜ(Bₓ(t) - pₓ)² + Dₜ(Bᵧ(t) - pᵧ)²
44
+ //
45
+ // Considering just one component,
46
+ // Dₜ(Bₓ(t) - pₓ)² = 2(Bₓ(t) - pₓ)(DₜBₓ(t))
47
+ // = 2(Bₓ(t)DₜBₓ(t) - pₓBₓ(t))
48
+ // = 2(p0ₓ + (t)(-2p0ₓ + 2p1ₓ) + (t²)(p0ₓ - 2p1ₓ + p2ₓ) - pₓ)((-2p0ₓ + 2p1ₓ) + 2(t)(p0ₓ - 2p1ₓ + p2ₓ))
49
+ // - (pₓ)((-2p0ₓ + 2p1ₓ) + (t)(p0ₓ - 2p1ₓ + p2ₓ))
50
+ const A = this.p0.x - point.x;
51
+ const B = -2 * this.p0.x + 2 * this.p1.x;
52
+ const C = this.p0.x - 2 * this.p1.x + this.p2.x;
53
+ // Let A = p0ₓ - pₓ, B = -2p0ₓ + 2p1ₓ, C = p0ₓ - 2p1ₓ + p2ₓ. We then have,
54
+ // Dₜ(Bₓ(t) - pₓ)²
55
+ // = 2(A + tB + t²C)(B + 2tC) - (pₓ)(B + 2tC)
56
+ // = 2(AB + tB² + t²BC + 2tCA + 2tCtB + 2tCt²C) - pₓB - pₓ2tC
57
+ // = 2(AB + tB² + 2tCA + t²BC + 2t²CB + 2C²t³) - pₓB - pₓ2tC
58
+ // = 2AB + 2t(B² + 2CA) + 2t²(BC + 2CB) + 4C²t³ - pₓB - pₓ2tC
59
+ // = 2AB + 2t(B² + 2CA - pₓC) + 2t²(BC + 2CB) + 4C²t³ - pₓB
60
+ //
61
+ const D = this.p0.y - point.y;
62
+ const E = -2 * this.p0.y + 2 * this.p1.y;
63
+ const F = this.p0.y - 2 * this.p1.y + this.p2.y;
64
+ // Using D = p0ᵧ - pᵧ, E = -2p0ᵧ + 2p1ᵧ, F = p0ᵧ - 2p1ᵧ + p2ᵧ, we thus have,
65
+ // f'(t) = 2AB + 2t(B² + 2CA - pₓC) + 2t²(BC + 2CB) + 4C²t³ - pₓB
66
+ // + 2DE + 2t(E² + 2FD - pᵧF) + 2t²(EF + 2FE) + 4F²t³ - pᵧE
67
+ const a = 2 * A * B + 2 * D * E - point.x * B - point.y * E;
68
+ const b = 2 * B * B + 2 * E * E + 2 * C * A + 2 * F * D - point.x * C - point.y * F;
69
+ const c = 2 * E * F + 2 * B * C + 2 * C * B + 2 * F * E;
70
+ //const d = 4 * C * C + 4 * F * F;
71
+ // Thus,
72
+ // f'(t) = a + bt + ct² + dt³
73
+ const fDerivAtZero = a;
74
+ const f2ndDerivAtZero = b;
75
+ const f3rdDerivAtZero = 2 * c;
76
+ // Using the first few terms of a Maclaurin series to approximate f'(t),
77
+ // f'(t) ≈ f'(0) + t f''(0) + t² f'''(0) / 2
78
+ let [min1, min2] = solveQuadratic(f3rdDerivAtZero / 2, f2ndDerivAtZero, fDerivAtZero);
79
+ // If the quadratic has no solutions, approximate.
80
+ if (isNaN(min1)) {
81
+ min1 = 0.25;
82
+ }
83
+ if (isNaN(min2)) {
84
+ min2 = 0.75;
85
+ }
86
+ const at1 = this.at(min1);
87
+ const at2 = this.at(min2);
88
+ const sqrDist1 = at1.minus(point).magnitudeSquared();
89
+ const sqrDist2 = at2.minus(point).magnitudeSquared();
90
+ const sqrDist3 = this.at(0).minus(point).magnitudeSquared();
91
+ const sqrDist4 = this.at(1).minus(point).magnitudeSquared();
92
+ return Math.sqrt(Math.min(sqrDist1, sqrDist2, sqrDist3, sqrDist4));
93
+ }
94
+ /**
95
+ * @returns the exact distance from `point` to this.
96
+ */
97
+ distance(point) {
98
+ if (!this.bezierJs) {
99
+ this.bezierJs = new Bezier([this.p0.xy, this.p1.xy, this.p2.xy]);
100
+ }
101
+ const proj = Vec2.ofXY(this.bezierJs.project(point.xy));
102
+ const dist = proj.minus(point).magnitude();
103
+ return dist;
104
+ }
105
+ normal(t) {
106
+ const tangent = this.derivativeAt(t);
107
+ return tangent.orthog().normalized();
108
+ }
109
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Solves an equation of the form ax² + bx + c = 0.
3
+ * The larger solution is returned first.
4
+ */
5
+ declare const solveQuadratic: (a: number, b: number, c: number) => [number, number];
6
+ export default solveQuadratic;
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Solves an equation of the form ax² + bx + c = 0.
3
+ * The larger solution is returned first.
4
+ */
5
+ const solveQuadratic = (a, b, c) => {
6
+ // See also https://en.wikipedia.org/wiki/Quadratic_formula
7
+ if (a === 0) {
8
+ let solution;
9
+ if (b === 0) {
10
+ solution = c === 0 ? 0 : NaN;
11
+ }
12
+ else {
13
+ // Then we have bx + c = 0
14
+ // which implies bx = -c.
15
+ // Thus, x = -c/b
16
+ solution = -c / b;
17
+ }
18
+ return [solution, solution];
19
+ }
20
+ const discriminant = b * b - 4 * a * c;
21
+ if (discriminant < 0) {
22
+ return [NaN, NaN];
23
+ }
24
+ const rootDiscriminant = Math.sqrt(discriminant);
25
+ const solution1 = (-b + rootDiscriminant) / (2 * a);
26
+ const solution2 = (-b - rootDiscriminant) / (2 * a);
27
+ if (solution1 > solution2) {
28
+ return [solution1, solution2];
29
+ }
30
+ else {
31
+ return [solution2, solution1];
32
+ }
33
+ };
34
+ export default solveQuadratic;
@@ -1,9 +1,9 @@
1
1
  import Color4 from '../Color4';
2
2
  interface RenderingStyle {
3
- fill: Color4;
4
- stroke?: {
5
- color: Color4;
6
- width: number;
3
+ readonly fill: Color4;
4
+ readonly stroke?: {
5
+ readonly color: Color4;
6
+ readonly width: number;
7
7
  };
8
8
  }
9
9
  export default RenderingStyle;
@@ -1,13 +1,13 @@
1
1
  import RenderingStyle from './RenderingStyle';
2
- export interface TextStyle {
3
- size: number;
4
- fontFamily: string;
5
- fontWeight?: string;
6
- fontVariant?: string;
7
- renderingStyle: RenderingStyle;
2
+ export interface TextRenderingStyle {
3
+ readonly size: number;
4
+ readonly fontFamily: string;
5
+ readonly fontWeight?: string;
6
+ readonly fontVariant?: string;
7
+ readonly renderingStyle: RenderingStyle;
8
8
  }
9
- export default TextStyle;
10
- export declare const cloneTextStyle: (style: TextStyle) => {
9
+ export default TextRenderingStyle;
10
+ export declare const cloneTextStyle: (style: TextRenderingStyle) => {
11
11
  renderingStyle: {
12
12
  fill: import("../Color4").default;
13
13
  stroke: {
@@ -20,8 +20,8 @@ export declare const cloneTextStyle: (style: TextStyle) => {
20
20
  fontWeight?: string | undefined;
21
21
  fontVariant?: string | undefined;
22
22
  };
23
- export declare const textStyleFromJSON: (json: any) => TextStyle;
24
- export declare const textStyleToJSON: (style: TextStyle) => {
23
+ export declare const textStyleFromJSON: (json: any) => TextRenderingStyle;
24
+ export declare const textStyleToJSON: (style: TextRenderingStyle) => {
25
25
  renderingStyle: {
26
26
  fill: string;
27
27
  stroke: {