js-draw 0.0.10 → 0.1.2

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 (122) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/bundle.js +1 -1
  3. package/dist/src/Editor.d.ts +2 -2
  4. package/dist/src/Editor.js +17 -7
  5. package/dist/src/EditorImage.d.ts +15 -7
  6. package/dist/src/EditorImage.js +46 -37
  7. package/dist/src/Pointer.d.ts +3 -2
  8. package/dist/src/Pointer.js +12 -3
  9. package/dist/src/SVGLoader.d.ts +6 -2
  10. package/dist/src/SVGLoader.js +20 -8
  11. package/dist/src/Viewport.d.ts +4 -0
  12. package/dist/src/Viewport.js +51 -0
  13. package/dist/src/components/AbstractComponent.d.ts +9 -2
  14. package/dist/src/components/AbstractComponent.js +14 -0
  15. package/dist/src/components/SVGGlobalAttributesObject.d.ts +1 -1
  16. package/dist/src/components/SVGGlobalAttributesObject.js +1 -1
  17. package/dist/src/components/Stroke.d.ts +1 -1
  18. package/dist/src/components/Stroke.js +1 -1
  19. package/dist/src/components/UnknownSVGObject.d.ts +1 -1
  20. package/dist/src/components/UnknownSVGObject.js +1 -1
  21. package/dist/src/components/builders/ArrowBuilder.d.ts +1 -1
  22. package/dist/src/components/builders/FreehandLineBuilder.d.ts +1 -1
  23. package/dist/src/components/builders/FreehandLineBuilder.js +1 -1
  24. package/dist/src/components/builders/LineBuilder.d.ts +1 -1
  25. package/dist/src/components/builders/RectangleBuilder.d.ts +1 -1
  26. package/dist/src/components/builders/types.d.ts +1 -1
  27. package/dist/src/geometry/Mat33.js +3 -0
  28. package/dist/src/geometry/Path.d.ts +1 -1
  29. package/dist/src/geometry/Path.js +102 -69
  30. package/dist/src/geometry/Rect2.d.ts +1 -0
  31. package/dist/src/geometry/Rect2.js +47 -9
  32. package/dist/src/{Display.d.ts → rendering/Display.d.ts} +5 -2
  33. package/dist/src/{Display.js → rendering/Display.js} +34 -4
  34. package/dist/src/rendering/caching/CacheRecord.d.ts +19 -0
  35. package/dist/src/rendering/caching/CacheRecord.js +52 -0
  36. package/dist/src/rendering/caching/CacheRecordManager.d.ts +11 -0
  37. package/dist/src/rendering/caching/CacheRecordManager.js +31 -0
  38. package/dist/src/rendering/caching/RenderingCache.d.ts +12 -0
  39. package/dist/src/rendering/caching/RenderingCache.js +42 -0
  40. package/dist/src/rendering/caching/RenderingCacheNode.d.ts +28 -0
  41. package/dist/src/rendering/caching/RenderingCacheNode.js +301 -0
  42. package/dist/src/rendering/caching/testUtils.d.ts +9 -0
  43. package/dist/src/rendering/caching/testUtils.js +20 -0
  44. package/dist/src/rendering/caching/types.d.ts +21 -0
  45. package/dist/src/rendering/caching/types.js +1 -0
  46. package/dist/src/rendering/{AbstractRenderer.d.ts → renderers/AbstractRenderer.d.ts} +20 -9
  47. package/dist/src/rendering/{AbstractRenderer.js → renderers/AbstractRenderer.js} +37 -3
  48. package/dist/src/rendering/{CanvasRenderer.d.ts → renderers/CanvasRenderer.d.ts} +10 -5
  49. package/dist/src/rendering/{CanvasRenderer.js → renderers/CanvasRenderer.js} +60 -20
  50. package/dist/src/rendering/{DummyRenderer.d.ts → renderers/DummyRenderer.d.ts} +9 -5
  51. package/dist/src/rendering/{DummyRenderer.js → renderers/DummyRenderer.js} +35 -4
  52. package/dist/src/rendering/{SVGRenderer.d.ts → renderers/SVGRenderer.d.ts} +7 -5
  53. package/dist/src/rendering/{SVGRenderer.js → renderers/SVGRenderer.js} +35 -18
  54. package/dist/src/testing/createEditor.js +1 -1
  55. package/dist/src/toolbar/HTMLToolbar.d.ts +2 -1
  56. package/dist/src/toolbar/HTMLToolbar.js +165 -154
  57. package/dist/src/toolbar/icons.d.ts +10 -0
  58. package/dist/src/toolbar/icons.js +180 -0
  59. package/dist/src/toolbar/localization.d.ts +4 -1
  60. package/dist/src/toolbar/localization.js +4 -1
  61. package/dist/src/toolbar/types.d.ts +4 -0
  62. package/dist/src/tools/PanZoom.d.ts +9 -6
  63. package/dist/src/tools/PanZoom.js +30 -21
  64. package/dist/src/tools/Pen.js +8 -3
  65. package/dist/src/tools/SelectionTool.js +9 -24
  66. package/dist/src/tools/ToolController.d.ts +5 -6
  67. package/dist/src/tools/ToolController.js +8 -10
  68. package/dist/src/tools/localization.d.ts +1 -0
  69. package/dist/src/tools/localization.js +1 -0
  70. package/dist/src/types.d.ts +2 -1
  71. package/package.json +1 -1
  72. package/src/Editor.ts +19 -8
  73. package/src/EditorImage.test.ts +2 -2
  74. package/src/EditorImage.ts +58 -42
  75. package/src/Pointer.ts +13 -4
  76. package/src/SVGLoader.ts +36 -10
  77. package/src/Viewport.ts +68 -0
  78. package/src/components/AbstractComponent.ts +21 -2
  79. package/src/components/SVGGlobalAttributesObject.ts +2 -2
  80. package/src/components/Stroke.ts +2 -2
  81. package/src/components/UnknownSVGObject.ts +2 -2
  82. package/src/components/builders/ArrowBuilder.ts +1 -1
  83. package/src/components/builders/FreehandLineBuilder.ts +2 -2
  84. package/src/components/builders/LineBuilder.ts +1 -1
  85. package/src/components/builders/RectangleBuilder.ts +1 -1
  86. package/src/components/builders/types.ts +1 -1
  87. package/src/geometry/Mat33.ts +3 -0
  88. package/src/geometry/Path.fromString.test.ts +94 -4
  89. package/src/geometry/Path.toString.test.ts +12 -2
  90. package/src/geometry/Path.ts +107 -71
  91. package/src/geometry/Rect2.test.ts +47 -8
  92. package/src/geometry/Rect2.ts +57 -9
  93. package/src/{Display.ts → rendering/Display.ts} +39 -6
  94. package/src/rendering/caching/CacheRecord.test.ts +49 -0
  95. package/src/rendering/caching/CacheRecord.ts +73 -0
  96. package/src/rendering/caching/CacheRecordManager.ts +45 -0
  97. package/src/rendering/caching/RenderingCache.test.ts +44 -0
  98. package/src/rendering/caching/RenderingCache.ts +63 -0
  99. package/src/rendering/caching/RenderingCacheNode.ts +378 -0
  100. package/src/rendering/caching/testUtils.ts +35 -0
  101. package/src/rendering/caching/types.ts +39 -0
  102. package/src/rendering/{AbstractRenderer.ts → renderers/AbstractRenderer.ts} +57 -9
  103. package/src/rendering/{CanvasRenderer.ts → renderers/CanvasRenderer.ts} +74 -25
  104. package/src/rendering/renderers/DummyRenderer.test.ts +43 -0
  105. package/src/rendering/{DummyRenderer.ts → renderers/DummyRenderer.ts} +50 -7
  106. package/src/rendering/{SVGRenderer.ts → renderers/SVGRenderer.ts} +39 -23
  107. package/src/testing/createEditor.ts +1 -1
  108. package/src/toolbar/HTMLToolbar.ts +199 -170
  109. package/src/toolbar/icons.ts +203 -0
  110. package/src/toolbar/localization.ts +9 -2
  111. package/src/toolbar/toolbar.css +21 -8
  112. package/src/toolbar/types.ts +5 -0
  113. package/src/tools/PanZoom.ts +37 -27
  114. package/src/tools/Pen.ts +7 -3
  115. package/src/tools/SelectionTool.test.ts +1 -1
  116. package/src/tools/SelectionTool.ts +12 -33
  117. package/src/tools/ToolController.ts +3 -5
  118. package/src/tools/localization.ts +2 -0
  119. package/src/types.ts +10 -3
  120. package/tsconfig.json +1 -0
  121. package/dist/__mocks__/coloris.d.ts +0 -2
  122. package/dist/__mocks__/coloris.js +0 -5
@@ -1,5 +1,5 @@
1
- import Color4 from '../Color4';
2
- import { Vec2 } from '../geometry/Vec2';
1
+ import Color4 from '../../Color4';
2
+ import { Vec2 } from '../../geometry/Vec2';
3
3
  import AbstractRenderer from './AbstractRenderer';
4
4
  export default class CanvasRenderer extends AbstractRenderer {
5
5
  constructor(ctx, viewport) {
@@ -7,8 +7,29 @@ export default class CanvasRenderer extends AbstractRenderer {
7
7
  this.ctx = ctx;
8
8
  this.ignoreObjectsAboveLevel = null;
9
9
  this.ignoringObject = false;
10
+ this.clipLevels = [];
10
11
  this.setDraftMode(false);
11
12
  }
13
+ canRenderFromWithoutDataLoss(other) {
14
+ return other instanceof CanvasRenderer;
15
+ }
16
+ renderFromOtherOfSameType(transformBy, other) {
17
+ if (!(other instanceof CanvasRenderer)) {
18
+ throw new Error(`${other} cannot be rendered onto ${this}`);
19
+ }
20
+ transformBy = this.getCanvasToScreenTransform().rightMul(transformBy);
21
+ this.ctx.save();
22
+ // From MDN, transform(a,b,c,d,e,f)
23
+ // takes input such that
24
+ // ⎡ a c e ⎤
25
+ // ⎢ b d f ⎥ transforms content drawn to [ctx].
26
+ // ⎣ 0 0 1 ⎦
27
+ this.ctx.transform(transformBy.a1, transformBy.b1, // a, b
28
+ transformBy.a2, transformBy.b2, // c, d
29
+ transformBy.a3, transformBy.b3);
30
+ this.ctx.drawImage(other.ctx.canvas, 0, 0);
31
+ this.ctx.restore();
32
+ }
12
33
  // Set parameters for lower/higher quality rendering
13
34
  setDraftMode(draftMode) {
14
35
  if (draftMode) {
@@ -29,7 +50,7 @@ export default class CanvasRenderer extends AbstractRenderer {
29
50
  this.ctx.clearRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height);
30
51
  }
31
52
  beginPath(startPoint) {
32
- startPoint = this.viewport.canvasToScreen(startPoint);
53
+ startPoint = this.canvasToScreen(startPoint);
33
54
  this.ctx.beginPath();
34
55
  this.ctx.moveTo(startPoint.x, startPoint.y);
35
56
  }
@@ -38,23 +59,23 @@ export default class CanvasRenderer extends AbstractRenderer {
38
59
  this.ctx.fill();
39
60
  if (style.stroke) {
40
61
  this.ctx.strokeStyle = style.stroke.color.toHexString();
41
- this.ctx.lineWidth = this.viewport.getScaleFactor() * style.stroke.width;
62
+ this.ctx.lineWidth = this.getSizeOfCanvasPixelOnScreen() * style.stroke.width;
42
63
  this.ctx.stroke();
43
64
  }
44
65
  this.ctx.closePath();
45
66
  }
46
67
  lineTo(point) {
47
- point = this.viewport.canvasToScreen(point);
68
+ point = this.canvasToScreen(point);
48
69
  this.ctx.lineTo(point.x, point.y);
49
70
  }
50
71
  moveTo(point) {
51
- point = this.viewport.canvasToScreen(point);
72
+ point = this.canvasToScreen(point);
52
73
  this.ctx.moveTo(point.x, point.y);
53
74
  }
54
75
  traceCubicBezierCurve(p1, p2, p3) {
55
- p1 = this.viewport.canvasToScreen(p1);
56
- p2 = this.viewport.canvasToScreen(p2);
57
- p3 = this.viewport.canvasToScreen(p3);
76
+ p1 = this.canvasToScreen(p1);
77
+ p2 = this.canvasToScreen(p2);
78
+ p3 = this.canvasToScreen(p3);
58
79
  // Approximate the curve if small enough.
59
80
  const delta1 = p2.minus(p1);
60
81
  const delta2 = p3.minus(p2);
@@ -67,8 +88,8 @@ export default class CanvasRenderer extends AbstractRenderer {
67
88
  }
68
89
  }
69
90
  traceQuadraticBezierCurve(controlPoint, endPoint) {
70
- controlPoint = this.viewport.canvasToScreen(controlPoint);
71
- endPoint = this.viewport.canvasToScreen(endPoint);
91
+ controlPoint = this.canvasToScreen(controlPoint);
92
+ endPoint = this.canvasToScreen(endPoint);
72
93
  // Approximate the curve with a line if small enough
73
94
  const delta = controlPoint.minus(endPoint);
74
95
  if (delta.magnitudeSquared() < this.minSquareCurveApproxDist) {
@@ -84,20 +105,30 @@ export default class CanvasRenderer extends AbstractRenderer {
84
105
  }
85
106
  super.drawPath(path);
86
107
  }
87
- startObject(boundingBox) {
88
- // Should we ignore all objects within this object's bbox?
89
- const diagonal = this.viewport.canvasToScreenTransform.transformVec3(boundingBox.size);
90
- const bothDimenMinSize = this.minRenderSizeBothDimens;
91
- const bothTooSmall = Math.abs(diagonal.x) < bothDimenMinSize && Math.abs(diagonal.y) < bothDimenMinSize;
92
- const anyDimenMinSize = this.minRenderSizeAnyDimen;
93
- const anyTooSmall = Math.abs(diagonal.x) < anyDimenMinSize || Math.abs(diagonal.y) < anyDimenMinSize;
94
- if (bothTooSmall || anyTooSmall) {
108
+ startObject(boundingBox, clip) {
109
+ if (this.isTooSmallToRender(boundingBox)) {
95
110
  this.ignoreObjectsAboveLevel = this.getNestingLevel();
96
111
  this.ignoringObject = true;
97
112
  }
98
113
  super.startObject(boundingBox);
114
+ if (!this.ignoringObject && clip) {
115
+ this.clipLevels.push(this.objectLevel);
116
+ this.ctx.save();
117
+ this.ctx.beginPath();
118
+ for (const corner of boundingBox.corners) {
119
+ const screenCorner = this.canvasToScreen(corner);
120
+ this.ctx.lineTo(screenCorner.x, screenCorner.y);
121
+ }
122
+ this.ctx.clip();
123
+ }
99
124
  }
100
125
  endObject() {
126
+ if (!this.ignoringObject && this.clipLevels.length > 0) {
127
+ if (this.clipLevels[this.clipLevels.length - 1] === this.objectLevel) {
128
+ this.ctx.restore();
129
+ this.clipLevels.pop();
130
+ }
131
+ }
101
132
  super.endObject();
102
133
  // If exiting an object with a too-small-to-draw bounding box,
103
134
  if (this.ignoreObjectsAboveLevel !== null && this.getNestingLevel() <= this.ignoreObjectsAboveLevel) {
@@ -108,7 +139,7 @@ export default class CanvasRenderer extends AbstractRenderer {
108
139
  drawPoints(...points) {
109
140
  const pointRadius = 10;
110
141
  for (let i = 0; i < points.length; i++) {
111
- const point = this.viewport.canvasToScreen(points[i]);
142
+ const point = this.canvasToScreen(points[i]);
112
143
  this.ctx.beginPath();
113
144
  this.ctx.arc(point.x, point.y, pointRadius, 0, Math.PI * 2);
114
145
  this.ctx.fillStyle = Color4.ofRGBA(0.5 + Math.sin(i) / 2, 1.0, 0.5 + Math.cos(i * 0.2) / 4, 0.5).toHexString();
@@ -121,4 +152,13 @@ export default class CanvasRenderer extends AbstractRenderer {
121
152
  this.ctx.fillText(`${i}`, point.x, point.y, pointRadius * 2);
122
153
  }
123
154
  }
155
+ isTooSmallToRender(rect) {
156
+ // Should we ignore all objects within this object's bbox?
157
+ const diagonal = this.getCanvasToScreenTransform().transformVec3(rect.size);
158
+ const bothDimenMinSize = this.minRenderSizeBothDimens;
159
+ const bothTooSmall = Math.abs(diagonal.x) < bothDimenMinSize && Math.abs(diagonal.y) < bothDimenMinSize;
160
+ const anyDimenMinSize = this.minRenderSizeAnyDimen;
161
+ const anyTooSmall = Math.abs(diagonal.x) < anyDimenMinSize || Math.abs(diagonal.y) < anyDimenMinSize;
162
+ return bothTooSmall || anyTooSmall;
163
+ }
124
164
  }
@@ -1,7 +1,8 @@
1
- import Rect2 from '../geometry/Rect2';
2
- import { Point2, Vec2 } from '../geometry/Vec2';
3
- import Vec3 from '../geometry/Vec3';
4
- import Viewport from '../Viewport';
1
+ import Mat33 from '../../geometry/Mat33';
2
+ import Rect2 from '../../geometry/Rect2';
3
+ import { Point2, Vec2 } from '../../geometry/Vec2';
4
+ import Vec3 from '../../geometry/Vec3';
5
+ import Viewport from '../../Viewport';
5
6
  import AbstractRenderer, { RenderingStyle } from './AbstractRenderer';
6
7
  export default class DummyRenderer extends AbstractRenderer {
7
8
  clearedCount: number;
@@ -20,6 +21,9 @@ export default class DummyRenderer extends AbstractRenderer {
20
21
  protected traceCubicBezierCurve(p1: Vec3, p2: Vec3, p3: Vec3): void;
21
22
  protected traceQuadraticBezierCurve(controlPoint: Vec3, endPoint: Vec3): void;
22
23
  drawPoints(..._points: Vec3[]): void;
23
- startObject(boundingBox: Rect2): void;
24
+ startObject(boundingBox: Rect2, _clip: boolean): void;
24
25
  endObject(): void;
26
+ isTooSmallToRender(_rect: Rect2): boolean;
27
+ canRenderFromWithoutDataLoss(other: AbstractRenderer): boolean;
28
+ renderFromOtherOfSameType(transform: Mat33, other: AbstractRenderer): void;
25
29
  }
@@ -1,5 +1,5 @@
1
1
  // Renderer that outputs nothing. Useful for automated tests.
2
- import { Vec2 } from '../geometry/Vec2';
2
+ import { Vec2 } from '../../geometry/Vec2';
3
3
  import AbstractRenderer from './AbstractRenderer';
4
4
  export default class DummyRenderer extends AbstractRenderer {
5
5
  constructor(viewport) {
@@ -14,8 +14,15 @@ export default class DummyRenderer extends AbstractRenderer {
14
14
  this.pointBuffer = [];
15
15
  }
16
16
  displaySize() {
17
- // Return a dummy
18
- return Vec2.of(640, 480);
17
+ // Do we have a stored viewport size?
18
+ const viewportSize = this.getViewport().getResolution();
19
+ // Don't use a 0x0 viewport — DummyRenderer is often used
20
+ // for tests that run without a display, so pretend we have a
21
+ // reasonable-sized display.
22
+ if (viewportSize.x === 0 || viewportSize.y === 0) {
23
+ return Vec2.of(640, 480);
24
+ }
25
+ return viewportSize;
19
26
  }
20
27
  clear() {
21
28
  this.clearedCount++;
@@ -35,18 +42,25 @@ export default class DummyRenderer extends AbstractRenderer {
35
42
  this.lastFillStyle = style;
36
43
  }
37
44
  lineTo(point) {
45
+ point = this.canvasToScreen(point);
38
46
  this.lastPoint = point;
39
47
  this.pointBuffer.push(point);
40
48
  }
41
49
  moveTo(point) {
50
+ point = this.canvasToScreen(point);
42
51
  this.lastPoint = point;
43
52
  this.pointBuffer.push(point);
44
53
  }
45
54
  traceCubicBezierCurve(p1, p2, p3) {
55
+ p1 = this.canvasToScreen(p1);
56
+ p2 = this.canvasToScreen(p2);
57
+ p3 = this.canvasToScreen(p3);
46
58
  this.lastPoint = p3;
47
59
  this.pointBuffer.push(p1, p2, p3);
48
60
  }
49
61
  traceQuadraticBezierCurve(controlPoint, endPoint) {
62
+ controlPoint = this.canvasToScreen(controlPoint);
63
+ endPoint = this.canvasToScreen(endPoint);
50
64
  this.lastPoint = endPoint;
51
65
  this.pointBuffer.push(controlPoint, endPoint);
52
66
  }
@@ -54,7 +68,7 @@ export default class DummyRenderer extends AbstractRenderer {
54
68
  // drawPoints is intended for debugging.
55
69
  // As such, it is unlikely to be the target of automated tests.
56
70
  }
57
- startObject(boundingBox) {
71
+ startObject(boundingBox, _clip) {
58
72
  super.startObject(boundingBox);
59
73
  this.objectNestingLevel += 1;
60
74
  }
@@ -62,4 +76,21 @@ export default class DummyRenderer extends AbstractRenderer {
62
76
  super.endObject();
63
77
  this.objectNestingLevel -= 1;
64
78
  }
79
+ isTooSmallToRender(_rect) {
80
+ return false;
81
+ }
82
+ canRenderFromWithoutDataLoss(other) {
83
+ return other instanceof DummyRenderer;
84
+ }
85
+ renderFromOtherOfSameType(transform, other) {
86
+ if (!(other instanceof DummyRenderer)) {
87
+ throw new Error(`${other} cannot be rendered onto ${this}`);
88
+ }
89
+ this.renderedPathCount += other.renderedPathCount;
90
+ this.lastFillStyle = other.lastFillStyle;
91
+ this.lastPoint = other.lastPoint;
92
+ this.pointBuffer.push(...other.pointBuffer.map(point => {
93
+ return transform.transformVec2(point);
94
+ }));
95
+ }
65
96
  }
@@ -1,6 +1,7 @@
1
- import Rect2 from '../geometry/Rect2';
2
- import { Point2, Vec2 } from '../geometry/Vec2';
3
- import Viewport from '../Viewport';
1
+ import { LoadSaveDataTable } from '../../components/AbstractComponent';
2
+ import Rect2 from '../../geometry/Rect2';
3
+ import { Point2, Vec2 } from '../../geometry/Vec2';
4
+ import Viewport from '../../Viewport';
4
5
  import AbstractRenderer, { RenderingStyle } from './AbstractRenderer';
5
6
  export default class SVGRenderer extends AbstractRenderer {
6
7
  private elem;
@@ -9,7 +10,7 @@ export default class SVGRenderer extends AbstractRenderer {
9
10
  private lastPathStyle;
10
11
  private lastPath;
11
12
  private lastPathStart;
12
- private mainGroup;
13
+ private objectElems;
13
14
  private overwrittenAttrs;
14
15
  constructor(elem: SVGSVGElement, viewport: Viewport);
15
16
  setRootSVGAttribute(name: string, value: string | null): void;
@@ -19,11 +20,12 @@ export default class SVGRenderer extends AbstractRenderer {
19
20
  protected endPath(style: RenderingStyle): void;
20
21
  private addPathToSVG;
21
22
  startObject(boundingBox: Rect2): void;
22
- endObject(): void;
23
+ endObject(loaderData?: LoadSaveDataTable): void;
23
24
  protected lineTo(point: Point2): void;
24
25
  protected moveTo(point: Point2): void;
25
26
  protected traceCubicBezierCurve(controlPoint1: Point2, controlPoint2: Point2, endPoint: Point2): void;
26
27
  protected traceQuadraticBezierCurve(controlPoint: Point2, endPoint: Point2): void;
27
28
  drawPoints(...points: Point2[]): void;
28
29
  drawSVGElem(elem: SVGElement): void;
30
+ isTooSmallToRender(_rect: Rect2): boolean;
29
31
  }
@@ -1,11 +1,13 @@
1
- import Path, { PathCommandType } from '../geometry/Path';
2
- import { Vec2 } from '../geometry/Vec2';
1
+ import Path, { PathCommandType } from '../../geometry/Path';
2
+ import { Vec2 } from '../../geometry/Vec2';
3
+ import { svgAttributesDataKey } from '../../SVGLoader';
3
4
  import AbstractRenderer from './AbstractRenderer';
4
5
  const svgNameSpace = 'http://www.w3.org/2000/svg';
5
6
  export default class SVGRenderer extends AbstractRenderer {
6
7
  constructor(elem, viewport) {
7
8
  super(viewport);
8
9
  this.elem = elem;
10
+ this.objectElems = null;
9
11
  this.overwrittenAttrs = {};
10
12
  this.clear();
11
13
  }
@@ -26,7 +28,6 @@ export default class SVGRenderer extends AbstractRenderer {
26
28
  return Vec2.of(this.elem.clientWidth, this.elem.clientHeight);
27
29
  }
28
30
  clear() {
29
- this.mainGroup = document.createElementNS(svgNameSpace, 'g');
30
31
  // Restore all alltributes
31
32
  for (const attrName in this.overwrittenAttrs) {
32
33
  const value = this.overwrittenAttrs[attrName];
@@ -38,13 +39,11 @@ export default class SVGRenderer extends AbstractRenderer {
38
39
  }
39
40
  }
40
41
  this.overwrittenAttrs = {};
41
- // Remove all children
42
- this.elem.replaceChildren(this.mainGroup);
43
42
  }
44
43
  beginPath(startPoint) {
45
44
  var _a;
46
45
  this.currentPath = [];
47
- this.pathStart = this.viewport.canvasToScreen(startPoint);
46
+ this.pathStart = this.canvasToScreen(startPoint);
48
47
  (_a = this.lastPathStart) !== null && _a !== void 0 ? _a : (this.lastPathStart = this.pathStart);
49
48
  }
50
49
  endPath(style) {
@@ -72,6 +71,7 @@ export default class SVGRenderer extends AbstractRenderer {
72
71
  }
73
72
  // Push [this.fullPath] to the SVG
74
73
  addPathToSVG() {
74
+ var _a;
75
75
  if (!this.lastPathStyle || !this.lastPath) {
76
76
  return;
77
77
  }
@@ -83,7 +83,8 @@ export default class SVGRenderer extends AbstractRenderer {
83
83
  pathElem.setAttribute('stroke', style.stroke.color.toHexString());
84
84
  pathElem.setAttribute('stroke-width', style.stroke.width.toString());
85
85
  }
86
- this.mainGroup.appendChild(pathElem);
86
+ this.elem.appendChild(pathElem);
87
+ (_a = this.objectElems) === null || _a === void 0 ? void 0 : _a.push(pathElem);
87
88
  }
88
89
  startObject(boundingBox) {
89
90
  super.startObject(boundingBox);
@@ -91,30 +92,43 @@ export default class SVGRenderer extends AbstractRenderer {
91
92
  this.lastPath = null;
92
93
  this.lastPathStart = null;
93
94
  this.lastPathStyle = null;
95
+ this.objectElems = [];
94
96
  }
95
- endObject() {
96
- super.endObject();
97
+ endObject(loaderData) {
98
+ var _a;
99
+ super.endObject(loaderData);
97
100
  // Don't extend paths across objects
98
101
  this.addPathToSVG();
102
+ if (loaderData) {
103
+ // Restore any attributes unsupported by the app.
104
+ for (const elem of (_a = this.objectElems) !== null && _a !== void 0 ? _a : []) {
105
+ const attrs = loaderData[svgAttributesDataKey];
106
+ if (attrs) {
107
+ for (const [attr, value] of attrs) {
108
+ elem.setAttribute(attr, value);
109
+ }
110
+ }
111
+ }
112
+ }
99
113
  }
100
114
  lineTo(point) {
101
- point = this.viewport.canvasToScreen(point);
115
+ point = this.canvasToScreen(point);
102
116
  this.currentPath.push({
103
117
  kind: PathCommandType.LineTo,
104
118
  point,
105
119
  });
106
120
  }
107
121
  moveTo(point) {
108
- point = this.viewport.canvasToScreen(point);
122
+ point = this.canvasToScreen(point);
109
123
  this.currentPath.push({
110
124
  kind: PathCommandType.MoveTo,
111
125
  point,
112
126
  });
113
127
  }
114
128
  traceCubicBezierCurve(controlPoint1, controlPoint2, endPoint) {
115
- controlPoint1 = this.viewport.canvasToScreen(controlPoint1);
116
- controlPoint2 = this.viewport.canvasToScreen(controlPoint2);
117
- endPoint = this.viewport.canvasToScreen(endPoint);
129
+ controlPoint1 = this.canvasToScreen(controlPoint1);
130
+ controlPoint2 = this.canvasToScreen(controlPoint2);
131
+ endPoint = this.canvasToScreen(endPoint);
118
132
  this.currentPath.push({
119
133
  kind: PathCommandType.CubicBezierTo,
120
134
  controlPoint1,
@@ -123,8 +137,8 @@ export default class SVGRenderer extends AbstractRenderer {
123
137
  });
124
138
  }
125
139
  traceQuadraticBezierCurve(controlPoint, endPoint) {
126
- controlPoint = this.viewport.canvasToScreen(controlPoint);
127
- endPoint = this.viewport.canvasToScreen(endPoint);
140
+ controlPoint = this.canvasToScreen(controlPoint);
141
+ endPoint = this.canvasToScreen(endPoint);
128
142
  this.currentPath.push({
129
143
  kind: PathCommandType.QuadraticBezierTo,
130
144
  controlPoint,
@@ -137,11 +151,14 @@ export default class SVGRenderer extends AbstractRenderer {
137
151
  elem.setAttribute('cx', `${point.x}`);
138
152
  elem.setAttribute('cy', `${point.y}`);
139
153
  elem.setAttribute('r', '15');
140
- this.mainGroup.appendChild(elem);
154
+ this.elem.appendChild(elem);
141
155
  });
142
156
  }
143
- // Renders a copy of the given element.
157
+ // Renders a **copy** of the given element.
144
158
  drawSVGElem(elem) {
145
159
  this.elem.appendChild(elem.cloneNode(true));
146
160
  }
161
+ isTooSmallToRender(_rect) {
162
+ return false;
163
+ }
147
164
  }
@@ -1,3 +1,3 @@
1
- import { RenderingMode } from '../Display';
1
+ import { RenderingMode } from '../rendering/Display';
2
2
  import Editor from '../Editor';
3
3
  export default () => new Editor(document.body, { renderingMode: RenderingMode.DummyRenderer });
@@ -1,5 +1,6 @@
1
1
  import Editor from '../Editor';
2
2
  import { ToolbarLocalization } from './localization';
3
+ import { ActionButtonIcon } from './types';
3
4
  export default class HTMLToolbar {
4
5
  private editor;
5
6
  private localizationTable;
@@ -7,7 +8,7 @@ export default class HTMLToolbar {
7
8
  private penTypes;
8
9
  constructor(editor: Editor, parent: HTMLElement, localizationTable?: ToolbarLocalization);
9
10
  setupColorPickers(): void;
10
- addActionButton(text: string, command: () => void, parent?: Element): HTMLButtonElement;
11
+ addActionButton(title: string | ActionButtonIcon, command: () => void, parent?: Element): HTMLButtonElement;
11
12
  private addUndoRedoButtons;
12
13
  addDefaultToolWidgets(): void;
13
14
  addDefaultActionButtons(): void;