js-draw 0.18.2 → 0.19.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 (227) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/bundle.js +2 -2
  3. package/dist/bundledStyles.js +1 -0
  4. package/dist/cjs/src/Color4.d.ts +8 -0
  5. package/dist/cjs/src/Color4.js +67 -0
  6. package/dist/cjs/src/Editor.d.ts +2 -2
  7. package/dist/cjs/src/Editor.js +2 -2
  8. package/dist/cjs/src/SVGLoader.js +8 -5
  9. package/dist/cjs/src/components/AbstractComponent.d.ts +2 -2
  10. package/dist/cjs/src/components/AbstractComponent.js +3 -3
  11. package/dist/cjs/src/components/ImageBackground.js +1 -1
  12. package/dist/cjs/src/components/RestylableComponent.d.ts +21 -2
  13. package/dist/cjs/src/components/Stroke.d.ts +35 -0
  14. package/dist/cjs/src/components/Stroke.js +36 -2
  15. package/dist/cjs/src/components/TextComponent.d.ts +26 -4
  16. package/dist/cjs/src/components/TextComponent.js +22 -0
  17. package/dist/cjs/src/components/lib.d.ts +3 -2
  18. package/dist/cjs/src/lib.d.ts +30 -0
  19. package/dist/cjs/src/lib.js +30 -0
  20. package/dist/cjs/src/rendering/RenderingStyle.d.ts +4 -4
  21. package/dist/cjs/src/rendering/TextRenderingStyle.d.ts +10 -10
  22. package/dist/cjs/src/rendering/lib.d.ts +2 -0
  23. package/dist/cjs/src/rendering/renderers/AbstractRenderer.d.ts +2 -2
  24. package/dist/cjs/src/rendering/renderers/CanvasRenderer.d.ts +2 -2
  25. package/dist/cjs/src/rendering/renderers/DummyRenderer.d.ts +2 -2
  26. package/dist/cjs/src/rendering/renderers/SVGRenderer.d.ts +2 -2
  27. package/dist/cjs/src/rendering/renderers/TextOnlyRenderer.d.ts +2 -2
  28. package/dist/cjs/src/toolbar/IconProvider.d.ts +2 -2
  29. package/dist/cjs/src/toolbar/localization.js +1 -1
  30. package/dist/cjs/src/toolbar/widgets/BaseWidget.js +1 -1
  31. package/dist/cjs/src/tools/SoundUITool.d.ts +24 -0
  32. package/dist/cjs/src/tools/SoundUITool.js +164 -0
  33. package/dist/cjs/src/tools/TextTool.d.ts +2 -2
  34. package/dist/cjs/src/tools/ToolController.js +6 -1
  35. package/dist/cjs/src/tools/lib.d.ts +1 -0
  36. package/dist/cjs/src/tools/lib.js +3 -1
  37. package/dist/cjs/src/tools/localization.d.ts +3 -0
  38. package/dist/cjs/src/tools/localization.js +3 -0
  39. package/dist/mjs/src/Color4.d.ts +8 -0
  40. package/dist/mjs/src/Color4.mjs +64 -0
  41. package/dist/mjs/src/Editor.d.ts +2 -2
  42. package/dist/mjs/src/Editor.mjs +2 -2
  43. package/dist/mjs/src/SVGLoader.mjs +8 -5
  44. package/dist/mjs/src/components/AbstractComponent.d.ts +2 -2
  45. package/dist/mjs/src/components/AbstractComponent.mjs +3 -3
  46. package/dist/mjs/src/components/ImageBackground.mjs +1 -1
  47. package/dist/mjs/src/components/RestylableComponent.d.ts +21 -2
  48. package/dist/mjs/src/components/Stroke.d.ts +35 -0
  49. package/dist/mjs/src/components/Stroke.mjs +36 -2
  50. package/dist/mjs/src/components/TextComponent.d.ts +26 -4
  51. package/dist/mjs/src/components/TextComponent.mjs +22 -0
  52. package/dist/mjs/src/components/lib.d.ts +3 -2
  53. package/dist/mjs/src/lib.d.ts +30 -0
  54. package/dist/mjs/src/lib.mjs +30 -0
  55. package/dist/mjs/src/rendering/RenderingStyle.d.ts +4 -4
  56. package/dist/mjs/src/rendering/TextRenderingStyle.d.ts +10 -10
  57. package/dist/mjs/src/rendering/lib.d.ts +2 -0
  58. package/dist/mjs/src/rendering/renderers/AbstractRenderer.d.ts +2 -2
  59. package/dist/mjs/src/rendering/renderers/CanvasRenderer.d.ts +2 -2
  60. package/dist/mjs/src/rendering/renderers/DummyRenderer.d.ts +2 -2
  61. package/dist/mjs/src/rendering/renderers/SVGRenderer.d.ts +2 -2
  62. package/dist/mjs/src/rendering/renderers/TextOnlyRenderer.d.ts +2 -2
  63. package/dist/mjs/src/toolbar/IconProvider.d.ts +2 -2
  64. package/dist/mjs/src/toolbar/localization.mjs +1 -1
  65. package/dist/mjs/src/toolbar/widgets/BaseWidget.mjs +1 -1
  66. package/dist/mjs/src/tools/SoundUITool.d.ts +24 -0
  67. package/dist/mjs/src/tools/SoundUITool.mjs +158 -0
  68. package/dist/mjs/src/tools/TextTool.d.ts +2 -2
  69. package/dist/mjs/src/tools/ToolController.mjs +6 -1
  70. package/dist/mjs/src/tools/lib.d.ts +1 -0
  71. package/dist/mjs/src/tools/lib.mjs +1 -0
  72. package/dist/mjs/src/tools/localization.d.ts +3 -0
  73. package/dist/mjs/src/tools/localization.mjs +3 -0
  74. package/package.json +6 -4
  75. package/src/Editor.css +2 -2
  76. package/src/tools/SoundUITool.css +15 -0
  77. package/src/tools/tools.css +4 -0
  78. package/src/Color4.test.ts +0 -40
  79. package/src/Color4.ts +0 -236
  80. package/src/Editor.loadFrom.test.ts +0 -24
  81. package/src/Editor.toSVG.test.ts +0 -111
  82. package/src/Editor.ts +0 -1122
  83. package/src/EditorImage.test.ts +0 -120
  84. package/src/EditorImage.ts +0 -603
  85. package/src/EventDispatcher.test.ts +0 -123
  86. package/src/EventDispatcher.ts +0 -71
  87. package/src/Pointer.ts +0 -127
  88. package/src/SVGLoader.test.ts +0 -114
  89. package/src/SVGLoader.ts +0 -511
  90. package/src/UndoRedoHistory.test.ts +0 -33
  91. package/src/UndoRedoHistory.ts +0 -102
  92. package/src/Viewport.ts +0 -319
  93. package/src/bundle/bundled.ts +0 -7
  94. package/src/commands/Command.ts +0 -45
  95. package/src/commands/Duplicate.ts +0 -48
  96. package/src/commands/Erase.ts +0 -74
  97. package/src/commands/SerializableCommand.ts +0 -49
  98. package/src/commands/UnresolvedCommand.ts +0 -37
  99. package/src/commands/invertCommand.ts +0 -51
  100. package/src/commands/lib.ts +0 -16
  101. package/src/commands/localization.ts +0 -47
  102. package/src/commands/uniteCommands.test.ts +0 -23
  103. package/src/commands/uniteCommands.ts +0 -135
  104. package/src/components/AbstractComponent.transformBy.test.ts +0 -22
  105. package/src/components/AbstractComponent.ts +0 -364
  106. package/src/components/ImageBackground.test.ts +0 -35
  107. package/src/components/ImageBackground.ts +0 -176
  108. package/src/components/ImageComponent.ts +0 -171
  109. package/src/components/RestylableComponent.ts +0 -142
  110. package/src/components/SVGGlobalAttributesObject.ts +0 -81
  111. package/src/components/Stroke.test.ts +0 -139
  112. package/src/components/Stroke.ts +0 -245
  113. package/src/components/TextComponent.test.ts +0 -99
  114. package/src/components/TextComponent.ts +0 -315
  115. package/src/components/UnknownSVGObject.test.ts +0 -10
  116. package/src/components/UnknownSVGObject.ts +0 -60
  117. package/src/components/builders/ArrowBuilder.ts +0 -107
  118. package/src/components/builders/FreehandLineBuilder.ts +0 -212
  119. package/src/components/builders/LineBuilder.ts +0 -77
  120. package/src/components/builders/PressureSensitiveFreehandLineBuilder.ts +0 -454
  121. package/src/components/builders/RectangleBuilder.ts +0 -74
  122. package/src/components/builders/types.ts +0 -15
  123. package/src/components/lib.ts +0 -25
  124. package/src/components/localization.ts +0 -22
  125. package/src/components/util/StrokeSmoother.ts +0 -293
  126. package/src/components/util/describeComponentList.ts +0 -18
  127. package/src/lib.ts +0 -37
  128. package/src/localization.ts +0 -34
  129. package/src/localizations/de.ts +0 -98
  130. package/src/localizations/en.ts +0 -8
  131. package/src/localizations/es.ts +0 -74
  132. package/src/localizations/getLocalizationTable.test.ts +0 -27
  133. package/src/localizations/getLocalizationTable.ts +0 -55
  134. package/src/math/LineSegment2.test.ts +0 -99
  135. package/src/math/LineSegment2.ts +0 -160
  136. package/src/math/Mat33.test.ts +0 -244
  137. package/src/math/Mat33.ts +0 -437
  138. package/src/math/Path.fromString.test.ts +0 -223
  139. package/src/math/Path.test.ts +0 -198
  140. package/src/math/Path.toString.test.ts +0 -77
  141. package/src/math/Path.ts +0 -790
  142. package/src/math/Rect2.test.ts +0 -204
  143. package/src/math/Rect2.ts +0 -315
  144. package/src/math/Triangle.ts +0 -29
  145. package/src/math/Vec2.test.ts +0 -30
  146. package/src/math/Vec2.ts +0 -18
  147. package/src/math/Vec3.test.ts +0 -44
  148. package/src/math/Vec3.ts +0 -218
  149. package/src/math/lib.ts +0 -15
  150. package/src/math/rounding.test.ts +0 -65
  151. package/src/math/rounding.ts +0 -156
  152. package/src/rendering/Display.ts +0 -249
  153. package/src/rendering/RenderingStyle.test.ts +0 -68
  154. package/src/rendering/RenderingStyle.ts +0 -55
  155. package/src/rendering/TextRenderingStyle.ts +0 -45
  156. package/src/rendering/caching/CacheRecord.test.ts +0 -49
  157. package/src/rendering/caching/CacheRecord.ts +0 -77
  158. package/src/rendering/caching/CacheRecordManager.ts +0 -71
  159. package/src/rendering/caching/RenderingCache.test.ts +0 -44
  160. package/src/rendering/caching/RenderingCache.ts +0 -66
  161. package/src/rendering/caching/RenderingCacheNode.ts +0 -405
  162. package/src/rendering/caching/testUtils.ts +0 -35
  163. package/src/rendering/caching/types.ts +0 -34
  164. package/src/rendering/lib.ts +0 -6
  165. package/src/rendering/localization.ts +0 -20
  166. package/src/rendering/renderers/AbstractRenderer.ts +0 -222
  167. package/src/rendering/renderers/CanvasRenderer.ts +0 -296
  168. package/src/rendering/renderers/DummyRenderer.test.ts +0 -42
  169. package/src/rendering/renderers/DummyRenderer.ts +0 -136
  170. package/src/rendering/renderers/SVGRenderer.ts +0 -354
  171. package/src/rendering/renderers/TextOnlyRenderer.ts +0 -70
  172. package/src/testing/beforeEachFile.ts +0 -8
  173. package/src/testing/createEditor.ts +0 -11
  174. package/src/testing/global.d.ts +0 -17
  175. package/src/testing/lib.ts +0 -3
  176. package/src/testing/loadExpectExtensions.ts +0 -25
  177. package/src/testing/sendPenEvent.ts +0 -31
  178. package/src/testing/sendTouchEvent.ts +0 -78
  179. package/src/toolbar/HTMLToolbar.ts +0 -492
  180. package/src/toolbar/IconProvider.ts +0 -736
  181. package/src/toolbar/lib.ts +0 -4
  182. package/src/toolbar/localization.ts +0 -106
  183. package/src/toolbar/makeColorInput.ts +0 -145
  184. package/src/toolbar/types.ts +0 -5
  185. package/src/toolbar/widgets/ActionButtonWidget.ts +0 -39
  186. package/src/toolbar/widgets/BaseToolWidget.ts +0 -56
  187. package/src/toolbar/widgets/BaseWidget.ts +0 -377
  188. package/src/toolbar/widgets/DocumentPropertiesWidget.ts +0 -167
  189. package/src/toolbar/widgets/EraserToolWidget.ts +0 -85
  190. package/src/toolbar/widgets/HandToolWidget.ts +0 -250
  191. package/src/toolbar/widgets/InsertImageWidget.ts +0 -223
  192. package/src/toolbar/widgets/OverflowWidget.ts +0 -92
  193. package/src/toolbar/widgets/PenToolWidget.ts +0 -288
  194. package/src/toolbar/widgets/SelectionToolWidget.ts +0 -190
  195. package/src/toolbar/widgets/TextToolWidget.ts +0 -145
  196. package/src/toolbar/widgets/lib.ts +0 -13
  197. package/src/tools/BaseTool.ts +0 -76
  198. package/src/tools/Eraser.test.ts +0 -103
  199. package/src/tools/Eraser.ts +0 -139
  200. package/src/tools/FindTool.ts +0 -152
  201. package/src/tools/PanZoom.test.ts +0 -310
  202. package/src/tools/PanZoom.ts +0 -520
  203. package/src/tools/PasteHandler.ts +0 -95
  204. package/src/tools/Pen.test.ts +0 -194
  205. package/src/tools/Pen.ts +0 -226
  206. package/src/tools/PipetteTool.ts +0 -55
  207. package/src/tools/SelectionTool/SelectAllShortcutHandler.ts +0 -28
  208. package/src/tools/SelectionTool/Selection.ts +0 -607
  209. package/src/tools/SelectionTool/SelectionHandle.ts +0 -108
  210. package/src/tools/SelectionTool/SelectionTool.test.ts +0 -261
  211. package/src/tools/SelectionTool/SelectionTool.ts +0 -480
  212. package/src/tools/SelectionTool/TransformMode.ts +0 -114
  213. package/src/tools/SelectionTool/types.ts +0 -11
  214. package/src/tools/TextTool.ts +0 -326
  215. package/src/tools/ToolController.ts +0 -178
  216. package/src/tools/ToolEnabledGroup.ts +0 -14
  217. package/src/tools/ToolSwitcherShortcut.ts +0 -39
  218. package/src/tools/ToolbarShortcutHandler.ts +0 -34
  219. package/src/tools/UndoRedoShortcut.test.ts +0 -56
  220. package/src/tools/UndoRedoShortcut.ts +0 -25
  221. package/src/tools/lib.ts +0 -21
  222. package/src/tools/localization.ts +0 -66
  223. package/src/types.ts +0 -234
  224. package/src/util/assertions.ts +0 -55
  225. package/src/util/fileToBase64.ts +0 -18
  226. package/src/util/untilNextAnimationFrame.ts +0 -9
  227. package/src/util/waitForTimeout.ts +0 -9
@@ -1,354 +0,0 @@
1
-
2
- import { LoadSaveDataTable } from '../../components/AbstractComponent';
3
- import Mat33 from '../../math/Mat33';
4
- import Path from '../../math/Path';
5
- import Rect2 from '../../math/Rect2';
6
- import { toRoundedString } from '../../math/rounding';
7
- import { Point2, Vec2 } from '../../math/Vec2';
8
- import { svgAttributesDataKey, SVGLoaderUnknownAttribute, SVGLoaderUnknownStyleAttribute, svgStyleAttributesDataKey } from '../../SVGLoader';
9
- import Viewport from '../../Viewport';
10
- import RenderingStyle from '../RenderingStyle';
11
- import TextStyle from '../TextRenderingStyle';
12
- import AbstractRenderer, { RenderableImage, RenderablePathSpec } from './AbstractRenderer';
13
-
14
- export const renderedStylesheetId = 'js-draw-style-sheet';
15
-
16
- const svgNameSpace = 'http://www.w3.org/2000/svg';
17
-
18
- /**
19
- * Renders onto an `SVGElement`.
20
- *
21
- * @see {@link Editor.toSVG}
22
- */
23
- export default class SVGRenderer extends AbstractRenderer {
24
- private lastPathStyle: RenderingStyle|null = null;
25
- private lastPathString: string[] = [];
26
- private objectElems: SVGElement[]|null = null;
27
-
28
- private overwrittenAttrs: Record<string, string|null> = {};
29
-
30
- /**
31
- * Creates a renderer that renders onto `elem`. If `sanitize`, don't render potentially untrusted data.
32
- *
33
- * `viewport` is used to determine the translation/rotation/scaling/output size of the rendered
34
- * data.
35
- */
36
- public constructor(private elem: SVGSVGElement, viewport: Viewport, private sanitize: boolean = false) {
37
- super(viewport);
38
- this.clear();
39
-
40
- this.addStyleSheet();
41
- }
42
-
43
- private addStyleSheet() {
44
- if (!this.elem.querySelector(`#${renderedStylesheetId}`)) {
45
- // Default to rounded strokes.
46
- const styleSheet = document.createElementNS('http://www.w3.org/2000/svg', 'style');
47
- styleSheet.innerHTML = `
48
- path {
49
- stroke-linecap: round;
50
- stroke-linejoin: round;
51
- }
52
-
53
- text {
54
- white-space: pre;
55
- }
56
- `.replace(/\s+/g, '');
57
- styleSheet.setAttribute('id', renderedStylesheetId);
58
- this.elem.appendChild(styleSheet);
59
- }
60
- }
61
-
62
- // Sets an attribute on the root SVG element.
63
- public setRootSVGAttribute(name: string, value: string|null) {
64
- if (this.sanitize) {
65
- return;
66
- }
67
-
68
- // Make the original value of the attribute restorable on clear
69
- if (!(name in this.overwrittenAttrs)) {
70
- this.overwrittenAttrs[name] = this.elem.getAttribute(name);
71
- }
72
-
73
- if (value !== null) {
74
- this.elem.setAttribute(name, value);
75
- } else {
76
- this.elem.removeAttribute(name);
77
- }
78
- }
79
-
80
- public displaySize(): Vec2 {
81
- return Vec2.of(this.elem.clientWidth, this.elem.clientHeight);
82
- }
83
-
84
- public clear() {
85
- this.lastPathString = [];
86
-
87
- if (!this.sanitize) {
88
- // Restore all all attributes
89
- for (const attrName in this.overwrittenAttrs) {
90
- const value = this.overwrittenAttrs[attrName];
91
-
92
- if (value) {
93
- this.elem.setAttribute(attrName, value);
94
- } else {
95
- this.elem.removeAttribute(attrName);
96
- }
97
- }
98
- this.overwrittenAttrs = {};
99
- }
100
- }
101
-
102
- // Push [this.fullPath] to the SVG
103
- private addPathToSVG() {
104
- if (!this.lastPathStyle || this.lastPathString.length === 0) {
105
- return;
106
- }
107
-
108
- const pathElem = document.createElementNS(svgNameSpace, 'path');
109
- pathElem.setAttribute('d', this.lastPathString.join(' '));
110
-
111
- const style = this.lastPathStyle;
112
- if (style.fill.a > 0) {
113
- pathElem.setAttribute('fill', style.fill.toHexString());
114
- } else {
115
- pathElem.setAttribute('fill', 'none');
116
- }
117
-
118
- if (style.stroke) {
119
- pathElem.setAttribute('stroke', style.stroke.color.toHexString());
120
- pathElem.setAttribute('stroke-width', toRoundedString(style.stroke.width));
121
- }
122
-
123
- this.elem.appendChild(pathElem);
124
- this.objectElems?.push(pathElem);
125
- }
126
-
127
- public drawPath(pathSpec: RenderablePathSpec) {
128
- const style = pathSpec.style;
129
- const path = Path.fromRenderable(pathSpec).transformedBy(this.getCanvasToScreenTransform());
130
-
131
- // Try to extend the previous path, if possible
132
- if (!style.fill.eq(this.lastPathStyle?.fill) || this.lastPathString.length === 0) {
133
- this.addPathToSVG();
134
- this.lastPathStyle = style;
135
- this.lastPathString = [];
136
- }
137
- this.lastPathString.push(path.toString());
138
- }
139
-
140
- // Apply [elemTransform] to [elem]. Uses both a `matrix` and `.x`, `.y` properties if `setXY` is true.
141
- // Otherwise, just uses a `matrix`.
142
- private transformFrom(elemTransform: Mat33, elem: SVGElement, inCanvasSpace: boolean = false, setXY: boolean = true) {
143
- let transform = !inCanvasSpace ? this.getCanvasToScreenTransform().rightMul(elemTransform) : elemTransform;
144
- const translation = transform.transformVec2(Vec2.zero);
145
-
146
- if (setXY) {
147
- transform = transform.rightMul(Mat33.translation(translation.times(-1)));
148
- }
149
-
150
- if (!transform.eq(Mat33.identity)) {
151
- elem.style.transform = `matrix(
152
- ${transform.a1}, ${transform.b1},
153
- ${transform.a2}, ${transform.b2},
154
- ${transform.a3}, ${transform.b3}
155
- )`;
156
- } else {
157
- elem.style.transform = '';
158
- }
159
-
160
- if (setXY) {
161
- elem.setAttribute('x', `${toRoundedString(translation.x)}`);
162
- elem.setAttribute('y', `${toRoundedString(translation.y)}`);
163
- }
164
- }
165
-
166
- private textContainer: SVGTextElement|null = null;
167
- private textContainerTransform: Mat33|null = null;
168
- private textParentStyle: TextStyle|null = null;
169
- public drawText(text: string, transform: Mat33, style: TextStyle): void {
170
- const applyTextStyles = (elem: SVGTextElement|SVGTSpanElement, style: TextStyle) => {
171
- if (style.fontFamily !== this.textParentStyle?.fontFamily) {
172
- elem.style.fontFamily = style.fontFamily;
173
- }
174
- if (style.fontVariant !== this.textParentStyle?.fontVariant) {
175
- elem.style.fontVariant = style.fontVariant ?? '';
176
- }
177
- if (style.fontWeight !== this.textParentStyle?.fontWeight) {
178
- elem.style.fontWeight = style.fontWeight ?? '';
179
- }
180
- if (style.size !== this.textParentStyle?.size) {
181
- elem.style.fontSize = style.size + 'px';
182
- }
183
-
184
- const fillString = style.renderingStyle.fill.toHexString();
185
- // TODO: Uncomment at some future major version release --- currently causes incompatibility due
186
- // to an SVG parsing bug in older versions.
187
- //const parentFillString = this.textParentStyle?.renderingStyle?.fill?.toHexString();
188
- //if (fillString !== parentFillString) {
189
- elem.style.fill = fillString;
190
- //}
191
-
192
- if (style.renderingStyle.stroke) {
193
- const strokeStyle = style.renderingStyle.stroke;
194
- elem.style.stroke = strokeStyle.color.toHexString();
195
- elem.style.strokeWidth = strokeStyle.width + 'px';
196
- }
197
- };
198
- transform = this.getCanvasToScreenTransform().rightMul(transform);
199
-
200
- if (!this.textContainer) {
201
- const container = document.createElementNS(svgNameSpace, 'text');
202
- container.appendChild(document.createTextNode(text));
203
-
204
- // Don't set .x/.y properties (just use .style.transform).
205
- // Child nodes aren't translated by .x/.y properties, but are by .style.transform.
206
- const setXY = false;
207
- this.transformFrom(transform, container, true, setXY);
208
- applyTextStyles(container, style);
209
-
210
- this.elem.appendChild(container);
211
- this.objectElems?.push(container);
212
- if (this.objectLevel > 0) {
213
- this.textContainer = container;
214
- this.textContainerTransform = transform;
215
- this.textParentStyle = style;
216
- }
217
- } else {
218
- const elem = document.createElementNS(svgNameSpace, 'tspan');
219
- elem.appendChild(document.createTextNode(text));
220
- this.textContainer.appendChild(elem);
221
-
222
- // Make .x/.y relative to the parent.
223
- transform = this.textContainerTransform!.inverse().rightMul(transform);
224
-
225
- // .style.transform does nothing to tspan elements. As such, we need to set x/y:
226
- const translation = transform.transformVec2(Vec2.zero);
227
- elem.setAttribute('x', `${toRoundedString(translation.x)}`);
228
- elem.setAttribute('y', `${toRoundedString(translation.y)}`);
229
-
230
- applyTextStyles(elem, style);
231
- }
232
- }
233
-
234
- public drawImage(image: RenderableImage) {
235
- let label = image.label ?? image.image.getAttribute('aria-label') ?? '';
236
- if (label === '') {
237
- label = image.image.getAttribute('alt') ?? '';
238
- }
239
-
240
- const svgImgElem = document.createElementNS(svgNameSpace, 'image');
241
- svgImgElem.setAttribute('href', image.base64Url);
242
- svgImgElem.setAttribute('width', image.image.getAttribute('width') ?? '');
243
- svgImgElem.setAttribute('height', image.image.getAttribute('height') ?? '');
244
- svgImgElem.setAttribute('aria-label', label);
245
- this.transformFrom(image.transform, svgImgElem);
246
-
247
- this.elem.appendChild(svgImgElem);
248
- this.objectElems?.push(svgImgElem);
249
- }
250
-
251
- public startObject(boundingBox: Rect2) {
252
- super.startObject(boundingBox);
253
-
254
- // Only accumulate a path within an object
255
- this.lastPathString = [];
256
- this.lastPathStyle = null;
257
- this.textContainer = null;
258
- this.textParentStyle = null;
259
- this.objectElems = [];
260
- }
261
-
262
- public endObject(loaderData?: LoadSaveDataTable, elemClassNames?: string[]) {
263
- super.endObject(loaderData);
264
-
265
- // Don't extend paths across objects
266
- this.addPathToSVG();
267
-
268
- if (loaderData && !this.sanitize) {
269
- // Restore any attributes unsupported by the app.
270
- for (const elem of this.objectElems ?? []) {
271
- const attrs = loaderData[svgAttributesDataKey] as SVGLoaderUnknownAttribute[]|undefined;
272
- const styleAttrs = loaderData[svgStyleAttributesDataKey] as SVGLoaderUnknownStyleAttribute[]|undefined;
273
-
274
- if (attrs) {
275
- for (const [ attr, value ] of attrs) {
276
- elem.setAttribute(attr, value);
277
- }
278
- }
279
-
280
- if (styleAttrs) {
281
- for (const attr of styleAttrs) {
282
- elem.style.setProperty(attr.key, attr.value, attr.priority);
283
- }
284
- }
285
- }
286
- }
287
-
288
- // Add class names to the object, if given.
289
- if (elemClassNames) {
290
- for (const elem of this.objectElems ?? []) {
291
- elem.classList.add(...elemClassNames);
292
- }
293
- }
294
- }
295
-
296
- // Not implemented -- use drawPath instead.
297
- private unimplementedMessage() { throw new Error('Not implemenented!'); }
298
- protected beginPath(_startPoint: Point2) { this.unimplementedMessage(); }
299
- protected endPath(_style: RenderingStyle) { this.unimplementedMessage(); }
300
- protected lineTo(_point: Point2) { this.unimplementedMessage(); }
301
- protected moveTo(_point: Point2) { this.unimplementedMessage(); }
302
- protected traceCubicBezierCurve(
303
- _controlPoint1: Point2, _controlPoint2: Point2, _endPoint: Point2
304
- ) { this.unimplementedMessage(); }
305
- protected traceQuadraticBezierCurve(_controlPoint: Point2, _endPoint: Point2) { this.unimplementedMessage(); }
306
-
307
- public drawPoints(...points: Point2[]) {
308
- points.map(point => {
309
- const elem = document.createElementNS(svgNameSpace, 'circle');
310
- elem.setAttribute('cx', `${point.x}`);
311
- elem.setAttribute('cy', `${point.y}`);
312
- elem.setAttribute('r', '15');
313
- this.elem.appendChild(elem);
314
- });
315
- }
316
-
317
- // Renders a **copy** of the given element.
318
- public drawSVGElem(elem: SVGElement) {
319
- if (this.sanitize) {
320
- return;
321
- }
322
-
323
- // Don't add multiple copies of the default stylesheet.
324
- if (elem.tagName.toLowerCase() === 'style' && elem.getAttribute('id') === renderedStylesheetId) {
325
- return;
326
- }
327
-
328
- this.elem.appendChild(elem.cloneNode(true));
329
- }
330
-
331
- public isTooSmallToRender(_rect: Rect2): boolean {
332
- return false;
333
- }
334
-
335
- // Creates a new SVG element and SVGRenerer with attributes set for the given Viewport.
336
- public static fromViewport(viewport: Viewport, sanitize: boolean = true) {
337
- const svgNameSpace = 'http://www.w3.org/2000/svg';
338
- const result = document.createElementNS(svgNameSpace, 'svg');
339
-
340
- const rect = viewport.getScreenRectSize();
341
- // rect.x -> size of rect in x direction, rect.y -> size of rect in y direction.
342
- result.setAttribute('viewBox', [0, 0, rect.x, rect.y].map(part => toRoundedString(part)).join(' '));
343
- result.setAttribute('width', toRoundedString(rect.x));
344
- result.setAttribute('height', toRoundedString(rect.y));
345
-
346
- // Ensure the image can be identified as an SVG if downloaded.
347
- // See https://jwatt.org/svg/authoring/
348
- result.setAttribute('version', '1.1');
349
- result.setAttribute('baseProfile', 'full');
350
- result.setAttribute('xmlns', svgNameSpace);
351
-
352
- return { element: result, renderer: new SVGRenderer(result, viewport, sanitize) };
353
- }
354
- }
@@ -1,70 +0,0 @@
1
- import Mat33 from '../../math/Mat33';
2
- import Rect2 from '../../math/Rect2';
3
- import { Vec2 } from '../../math/Vec2';
4
- import Vec3 from '../../math/Vec3';
5
- import Viewport from '../../Viewport';
6
- import { TextRendererLocalization } from '../localization';
7
- import RenderingStyle from '../RenderingStyle';
8
- import TextStyle from '../TextRenderingStyle';
9
- import AbstractRenderer, { RenderableImage } from './AbstractRenderer';
10
-
11
- // Outputs a description of what was rendered.
12
- export default class TextOnlyRenderer extends AbstractRenderer {
13
- private descriptionBuilder: string[] = [];
14
- private pathCount: number = 0;
15
- private textNodeCount: number = 0;
16
- private imageNodeCount: number = 0;
17
-
18
- public constructor(viewport: Viewport, private localizationTable: TextRendererLocalization) {
19
- super(viewport);
20
- }
21
-
22
- public displaySize(): Vec3 {
23
- // We don't have a graphical display, export a reasonable size.
24
- return Vec2.of(500, 500);
25
- }
26
-
27
- public clear(): void {
28
- this.descriptionBuilder = [];
29
- this.pathCount = 0;
30
- this.textNodeCount = 0;
31
- }
32
-
33
- public getDescription(): string {
34
- return [
35
- this.localizationTable.pathNodeCount(this.pathCount),
36
- ...(this.textNodeCount > 0 ? [this.localizationTable.textNodeCount(this.textNodeCount)] : []),
37
- ...(this.imageNodeCount > 0 ? [this.localizationTable.imageNodeCount(this.imageNodeCount)] : []),
38
- ...this.descriptionBuilder
39
- ].join('\n');
40
- }
41
-
42
- protected beginPath(_startPoint: Vec3): void {
43
- }
44
- protected endPath(_style: RenderingStyle): void {
45
- this.pathCount ++;
46
- }
47
- protected lineTo(_point: Vec3): void {
48
- }
49
- protected moveTo(_point: Vec3): void {
50
- }
51
- protected traceCubicBezierCurve(_p1: Vec3, _p2: Vec3, _p3: Vec3): void {
52
- }
53
- protected traceQuadraticBezierCurve(_controlPoint: Vec3, _endPoint: Vec3): void {
54
- }
55
- public drawText(text: string, _transform: Mat33, _style: TextStyle): void {
56
- this.descriptionBuilder.push(this.localizationTable.textNode(text));
57
- this.textNodeCount ++;
58
- }
59
- public drawImage(image: RenderableImage) {
60
- const label = image.label ? this.localizationTable.imageNode(image.label) : this.localizationTable.unlabeledImageNode;
61
-
62
- this.descriptionBuilder.push(label);
63
- this.imageNodeCount ++;
64
- }
65
- public isTooSmallToRender(rect: Rect2): boolean {
66
- return rect.maxDimension < 15 / this.getSizeOfCanvasPixelOnScreen();
67
- }
68
- public drawPoints(..._points: Vec3[]): void {
69
- }
70
- }
@@ -1,8 +0,0 @@
1
- import loadExpectExtensions from './loadExpectExtensions';
2
- loadExpectExtensions();
3
- jest.useFakeTimers();
4
-
5
- // jsdom doesn't support HTMLCanvasElement#getContext — it logs an error
6
- // to the console. Make it return null so we can handle a non-existent Canvas
7
- // at runtime (e.g. use something else, if available).
8
- HTMLCanvasElement.prototype.getContext = () => null;
@@ -1,11 +0,0 @@
1
- import { RenderingMode } from '../rendering/Display';
2
- import Editor from '../Editor';
3
-
4
- /** Creates an editor. Should only be used in test files. */
5
- export default () => {
6
- if (jest === undefined) {
7
- throw new Error('Files in the testing/ folder should only be used in tests!');
8
- }
9
-
10
- return new Editor(document.body, { renderingMode: RenderingMode.DummyRenderer });
11
- };
@@ -1,17 +0,0 @@
1
-
2
-
3
- // Type declarations for custom matchers
4
- interface CustomMatchers<R = unknown> {
5
- objEq(expected: {
6
- eq: (other: any, ...args: any)=> boolean;
7
- }, ...opts: any): R;
8
- }
9
-
10
- declare namespace jest {
11
- interface Expect extends CustomMatchers {}
12
- interface Matchers<R> extends CustomMatchers<R> {}
13
- interface AsyncAsymmetricMatchers extends CustomMatchers {}
14
- }
15
-
16
- declare interface JestMatchers<T> extends CustomMatchers<T> {
17
- }
@@ -1,3 +0,0 @@
1
-
2
- export { default as sendPenEvent } from './sendPenEvent';
3
- export { default as sendTouchEvent } from './sendTouchEvent';
@@ -1,25 +0,0 @@
1
- export const loadExpectExtensions = () => {
2
- // Custom matchers. See
3
- // https://jestjs.io/docs/expect#expectextendmatchers
4
- expect.extend({
5
- // Determine whether expected = actual based on the objects'
6
- // .eq methods
7
- objEq(actual: any, expected: any, ...eqArgs: any) {
8
- let pass = false;
9
- if ((expected ?? null) === null) {
10
- pass = actual.eq(expected, ...eqArgs);
11
- } else {
12
- pass = expected.eq(actual, ...eqArgs);
13
- }
14
-
15
- return {
16
- pass,
17
- message: () => {
18
- return `Expected ${pass ? '!' : ''}(${actual}).eq(${expected}). Options(${eqArgs})`;
19
- },
20
- };
21
- },
22
- });
23
- };
24
-
25
- export default loadExpectExtensions;
@@ -1,31 +0,0 @@
1
- import Editor from '../Editor';
2
- import { Point2 } from '../math/Vec2';
3
- import Pointer from '../Pointer';
4
- import { InputEvtType } from '../types';
5
-
6
- /**
7
- * Dispatch a pen event to the currently selected tool.
8
- * Intended for unit tests.
9
- *
10
- * @see {@link sendTouchEvent}
11
- */
12
- const sendPenEvent = (
13
- editor: Editor,
14
- eventType: InputEvtType.PointerDownEvt|InputEvtType.PointerMoveEvt|InputEvtType.PointerUpEvt,
15
- point: Point2,
16
-
17
- allPointers?: Pointer[]
18
- ) => {
19
- const mainPointer = Pointer.ofCanvasPoint(
20
- point, eventType !== InputEvtType.PointerUpEvt, editor.viewport
21
- );
22
-
23
- editor.toolController.dispatchInputEvent({
24
- kind: eventType,
25
- allPointers: allPointers ?? [
26
- mainPointer,
27
- ],
28
- current: mainPointer,
29
- });
30
- };
31
- export default sendPenEvent;
@@ -1,78 +0,0 @@
1
- import Editor from '../Editor';
2
- import { Vec2 } from '../math/Vec2';
3
- import Pointer, { PointerDevice } from '../Pointer';
4
- import { InputEvtType } from '../types';
5
-
6
- /**
7
- * Dispatch a touch event to the currently selected tool. Intended for unit tests.
8
- *
9
- * @see {@link sendPenEvent}
10
- *
11
- * @example
12
- * **Simulating a horizontal swipe gesture:**
13
- * ```ts
14
- * sendTouchEvent(editor, InputEvtType.PointerDownEvt, Vec2.of(0, 0));
15
- * for (let i = 1; i <= 10; i++) {
16
- * jest.advanceTimersByTime(10);
17
- * sendTouchEvent(editor, InputEvtType.PointerMoveEvt, Vec2.of(i * 10, 0));
18
- * }
19
- * ```
20
- *
21
- * @example
22
- * **Simulating a pinch gesture.** This example assumes that you're using [Jest with timer mocks enabled](https://jestjs.io/docs/timer-mocks).
23
- * ```ts
24
- * let firstPointer = sendTouchEvent(editor, InputEvtType.PointerDownEvt, Vec2.of(0, 0));
25
- * let secondPointer = sendTouchEvent(editor, InputEvtType.PointerDownEvt, Vec2.of(100, 0), [ firstPointer ]);
26
- *
27
- * // Simulate a pinch
28
- * const maxIterations = 10;
29
- * for (let i = 0; i < maxIterations; i++) {
30
- * // Use the unit testing framework's tool for increasing the current time
31
- * // returned by (new Date()).getTime(), etc.
32
- * jest.advanceTimersByTime(100);
33
- *
34
- * const point1 = Vec2.of(-i * 5, 0);
35
- * const point2 = Vec2.of(i * 5 + 100, 0);
36
- *
37
- * firstPointer = sendTouchEvent(editor, InputEvtType.PointerMoveEvt, point1, [ secondPointer ]);
38
- * secondPointer = sendTouchEvent(editor, InputEvtType.PointerMoveEvt, point2, [ firstPointer ]);
39
- * }
40
- * ```
41
- */
42
- const sendTouchEvent = (
43
- editor: Editor,
44
- eventType: InputEvtType.PointerDownEvt|InputEvtType.PointerMoveEvt|InputEvtType.PointerUpEvt,
45
- screenPos: Vec2,
46
- allOtherPointers?: Pointer[]
47
- ) => {
48
- const canvasPos = editor.viewport.screenToCanvas(screenPos);
49
-
50
- let ptrId = 0;
51
- let maxPtrId = 0;
52
-
53
- // Get a unique ID for the main pointer
54
- // (try to use id=0, but don't use it if it's already in use).
55
- for (const pointer of allOtherPointers ?? []) {
56
- maxPtrId = Math.max(pointer.id, maxPtrId);
57
- if (pointer.id === ptrId) {
58
- ptrId = maxPtrId + 1;
59
- }
60
- }
61
-
62
- const mainPointer = Pointer.ofCanvasPoint(
63
- canvasPos, eventType !== InputEvtType.PointerUpEvt, editor.viewport, ptrId, PointerDevice.Touch
64
- );
65
-
66
- editor.toolController.dispatchInputEvent({
67
- kind: eventType,
68
- allPointers: [
69
- ...(allOtherPointers ?? []),
70
- mainPointer,
71
- ],
72
- current: mainPointer,
73
- });
74
-
75
- return mainPointer;
76
- };
77
-
78
- export default sendTouchEvent;