js-draw 0.1.12 → 0.2.1

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 (132) hide show
  1. package/.eslintrc.js +1 -0
  2. package/.firebaserc +5 -0
  3. package/.github/ISSUE_TEMPLATE/bug_report.md +34 -0
  4. package/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  5. package/.github/ISSUE_TEMPLATE/translation.md +96 -0
  6. package/.github/workflows/firebase-hosting-merge.yml +25 -0
  7. package/.github/workflows/firebase-hosting-pull-request.yml +22 -0
  8. package/.github/workflows/github-pages.yml +52 -0
  9. package/CHANGELOG.md +9 -0
  10. package/README.md +11 -6
  11. package/dist/bundle.js +1 -1
  12. package/dist/src/Color4.d.ts +19 -0
  13. package/dist/src/Color4.js +24 -3
  14. package/dist/src/Editor.d.ts +129 -2
  15. package/dist/src/Editor.js +94 -17
  16. package/dist/src/EditorImage.d.ts +7 -2
  17. package/dist/src/EditorImage.js +41 -25
  18. package/dist/src/EventDispatcher.d.ts +18 -0
  19. package/dist/src/EventDispatcher.js +19 -4
  20. package/dist/src/Pointer.js +3 -2
  21. package/dist/src/UndoRedoHistory.js +15 -2
  22. package/dist/src/Viewport.js +4 -1
  23. package/dist/src/bundle/bundled.d.ts +1 -2
  24. package/dist/src/bundle/bundled.js +1 -2
  25. package/dist/src/commands/Duplicate.d.ts +1 -1
  26. package/dist/src/commands/Duplicate.js +3 -4
  27. package/dist/src/commands/Erase.d.ts +1 -1
  28. package/dist/src/commands/Erase.js +6 -5
  29. package/dist/src/commands/SerializableCommand.d.ts +4 -5
  30. package/dist/src/commands/SerializableCommand.js +12 -4
  31. package/dist/src/commands/invertCommand.d.ts +4 -0
  32. package/dist/src/commands/invertCommand.js +44 -0
  33. package/dist/src/commands/lib.d.ts +6 -0
  34. package/dist/src/commands/lib.js +6 -0
  35. package/dist/src/commands/localization.d.ts +1 -0
  36. package/dist/src/commands/localization.js +1 -0
  37. package/dist/src/components/AbstractComponent.d.ts +13 -8
  38. package/dist/src/components/AbstractComponent.js +26 -15
  39. package/dist/src/components/SVGGlobalAttributesObject.d.ts +1 -1
  40. package/dist/src/components/SVGGlobalAttributesObject.js +7 -1
  41. package/dist/src/components/Stroke.d.ts +12 -2
  42. package/dist/src/components/Stroke.js +10 -7
  43. package/dist/src/components/Text.d.ts +2 -2
  44. package/dist/src/components/Text.js +6 -6
  45. package/dist/src/components/UnknownSVGObject.d.ts +1 -1
  46. package/dist/src/components/UnknownSVGObject.js +6 -1
  47. package/dist/src/components/lib.d.ts +4 -0
  48. package/dist/src/components/lib.js +4 -0
  49. package/dist/src/lib.d.ts +25 -0
  50. package/dist/src/lib.js +25 -0
  51. package/dist/src/localizations/de.d.ts +3 -0
  52. package/dist/src/localizations/de.js +4 -0
  53. package/dist/src/localizations/getLocalizationTable.js +2 -0
  54. package/dist/src/math/Mat33.d.ts +47 -1
  55. package/dist/src/math/Mat33.js +48 -20
  56. package/dist/src/math/Path.js +3 -3
  57. package/dist/src/math/Rect2.d.ts +2 -2
  58. package/dist/src/math/Vec3.d.ts +62 -0
  59. package/dist/src/math/Vec3.js +62 -14
  60. package/dist/src/math/lib.d.ts +7 -0
  61. package/dist/src/math/lib.js +7 -0
  62. package/dist/src/math/rounding.js +1 -0
  63. package/dist/src/rendering/Display.d.ts +44 -0
  64. package/dist/src/rendering/Display.js +45 -6
  65. package/dist/src/rendering/caching/CacheRecord.d.ts +1 -0
  66. package/dist/src/rendering/caching/CacheRecord.js +3 -0
  67. package/dist/src/rendering/caching/CacheRecordManager.d.ts +4 -3
  68. package/dist/src/rendering/caching/CacheRecordManager.js +16 -4
  69. package/dist/src/rendering/caching/RenderingCache.d.ts +2 -3
  70. package/dist/src/rendering/caching/RenderingCache.js +9 -10
  71. package/dist/src/rendering/caching/types.d.ts +1 -3
  72. package/dist/src/rendering/renderers/CanvasRenderer.js +1 -1
  73. package/dist/src/toolbar/HTMLToolbar.js +1 -0
  74. package/dist/src/toolbar/makeColorInput.js +1 -1
  75. package/dist/src/toolbar/widgets/PenWidget.js +1 -0
  76. package/dist/src/tools/Pen.d.ts +1 -2
  77. package/dist/src/tools/Pen.js +8 -1
  78. package/dist/src/tools/PipetteTool.js +1 -0
  79. package/dist/src/tools/SelectionTool.js +45 -22
  80. package/dist/src/types.d.ts +17 -6
  81. package/dist/src/types.js +7 -5
  82. package/firebase.json +16 -0
  83. package/package.json +118 -101
  84. package/src/Color4.ts +23 -2
  85. package/src/Editor.ts +147 -25
  86. package/src/EditorImage.ts +45 -27
  87. package/src/EventDispatcher.ts +21 -6
  88. package/src/Pointer.ts +3 -2
  89. package/src/UndoRedoHistory.ts +18 -2
  90. package/src/Viewport.ts +5 -2
  91. package/src/bundle/bundled.ts +1 -2
  92. package/src/commands/Duplicate.ts +3 -4
  93. package/src/commands/Erase.ts +6 -5
  94. package/src/commands/SerializableCommand.ts +17 -9
  95. package/src/commands/invertCommand.ts +51 -0
  96. package/src/commands/lib.ts +14 -0
  97. package/src/commands/localization.ts +2 -0
  98. package/src/components/AbstractComponent.ts +31 -20
  99. package/src/components/SVGGlobalAttributesObject.ts +8 -1
  100. package/src/components/Stroke.test.ts +1 -1
  101. package/src/components/Stroke.ts +11 -7
  102. package/src/components/Text.ts +6 -7
  103. package/src/components/UnknownSVGObject.ts +7 -1
  104. package/src/components/lib.ts +9 -0
  105. package/src/lib.ts +28 -0
  106. package/src/localizations/de.ts +98 -0
  107. package/src/localizations/getLocalizationTable.ts +2 -0
  108. package/src/math/Mat33.ts +48 -20
  109. package/src/math/Path.ts +3 -3
  110. package/src/math/Rect2.ts +2 -2
  111. package/src/math/Vec3.ts +62 -14
  112. package/src/math/lib.ts +15 -0
  113. package/src/math/rounding.ts +2 -0
  114. package/src/rendering/Display.ts +46 -6
  115. package/src/rendering/caching/CacheRecord.test.ts +1 -1
  116. package/src/rendering/caching/CacheRecord.ts +4 -0
  117. package/src/rendering/caching/CacheRecordManager.ts +33 -7
  118. package/src/rendering/caching/RenderingCache.ts +10 -15
  119. package/src/rendering/caching/types.ts +1 -6
  120. package/src/rendering/renderers/CanvasRenderer.ts +1 -1
  121. package/src/styles.js +4 -0
  122. package/src/toolbar/HTMLToolbar.ts +1 -0
  123. package/src/toolbar/makeColorInput.ts +1 -1
  124. package/src/toolbar/toolbar.css +8 -2
  125. package/src/toolbar/widgets/PenWidget.ts +2 -0
  126. package/src/tools/PanZoom.ts +0 -1
  127. package/src/tools/Pen.ts +11 -2
  128. package/src/tools/PipetteTool.ts +2 -0
  129. package/src/tools/SelectionTool.ts +46 -18
  130. package/src/types.ts +19 -3
  131. package/tsconfig.json +4 -1
  132. package/typedoc.json +20 -0
@@ -1,3 +1,17 @@
1
+ /**
2
+ * Handles `HTMLCanvasElement`s (or other drawing surfaces if being used) used to display the editor's contents.
3
+ *
4
+ * @example
5
+ * ```
6
+ * const editor = new Editor(document.body);
7
+ * const w = editor.display.width;
8
+ * const h = editor.display.height;
9
+ * const center = Vec2.of(w / 2, h / 2);
10
+ * const colorAtCenter = editor.display.getColorAt(center);
11
+ * ```
12
+ *
13
+ * @packageDocumentation
14
+ */
1
15
  import CanvasRenderer from './renderers/CanvasRenderer';
2
16
  import { EditorEventType } from '../types';
3
17
  import DummyRenderer from './renderers/DummyRenderer';
@@ -12,10 +26,15 @@ export var RenderingMode;
12
26
  // SVGRenderer is not supported by the main display
13
27
  })(RenderingMode || (RenderingMode = {}));
14
28
  export default class Display {
29
+ /** @internal */
15
30
  constructor(editor, mode, parent) {
16
31
  this.editor = editor;
17
32
  this.parent = parent;
18
33
  this.textRerenderOutput = null;
34
+ /**
35
+ * @returns the color at the given point on the dry ink renderer, or `null` if `screenPos`
36
+ * is not on the display.
37
+ */
19
38
  this.getColorAt = (_screenPos) => {
20
39
  return null;
21
40
  };
@@ -52,7 +71,7 @@ export default class Display {
52
71
  return this.dryInkRenderer.canRenderFromWithoutDataLoss(renderer);
53
72
  },
54
73
  blockResolution: cacheBlockResolution,
55
- cacheSize: 500 * 500 * 4 * 220,
74
+ cacheSize: 500 * 500 * 4 * 150,
56
75
  maxScale: 1.5,
57
76
  minComponentsPerCache: 45,
58
77
  minComponentsToUseCache: 105,
@@ -65,15 +84,18 @@ export default class Display {
65
84
  (_a = this.resizeSurfacesCallback) === null || _a === void 0 ? void 0 : _a.call(this);
66
85
  });
67
86
  }
68
- // Returns the visible width of the display (e.g. how much
69
- // space the display's element takes up in the x direction
70
- // in the DOM).
87
+ /**
88
+ * @returns the visible width of the display (e.g. how much
89
+ * space the display's element takes up in the x direction
90
+ * in the DOM).
91
+ */
71
92
  get width() {
72
93
  return this.dryInkRenderer.displaySize().x;
73
94
  }
74
95
  get height() {
75
96
  return this.dryInkRenderer.displaySize().y;
76
97
  }
98
+ /** @internal */
77
99
  getCache() {
78
100
  return this.cache;
79
101
  }
@@ -135,6 +157,10 @@ export default class Display {
135
157
  textRendererOutputContainer.replaceChildren(rerenderButton, this.textRerenderOutput);
136
158
  this.editor.createHTMLOverlay(textRendererOutputContainer);
137
159
  }
160
+ /**
161
+ * Rerenders the text-based display.
162
+ * The text-based display is intended for screen readers and can be navigated to by pressing `tab`.
163
+ */
138
164
  rerenderAsText() {
139
165
  this.textRenderer.clear();
140
166
  this.editor.image.render(this.textRenderer, this.editor.viewport);
@@ -142,7 +168,11 @@ export default class Display {
142
168
  this.textRerenderOutput.innerText = this.textRenderer.getDescription();
143
169
  }
144
170
  }
145
- // Clears the drawing surfaces and otherwise prepares for a rerender.
171
+ /**
172
+ * Clears the drawing surfaces and otherwise prepares for a rerender.
173
+ *
174
+ * @returns the dry ink renderer.
175
+ */
146
176
  startRerender() {
147
177
  var _a;
148
178
  (_a = this.resizeSurfacesCallback) === null || _a === void 0 ? void 0 : _a.call(this);
@@ -150,16 +180,25 @@ export default class Display {
150
180
  this.dryInkRenderer.clear();
151
181
  return this.dryInkRenderer;
152
182
  }
183
+ /**
184
+ * If `draftMode`, the dry ink renderer is configured to render
185
+ * low-quality output.
186
+ */
153
187
  setDraftMode(draftMode) {
154
188
  this.dryInkRenderer.setDraftMode(draftMode);
155
189
  }
190
+ /** @internal */
156
191
  getDryInkRenderer() {
157
192
  return this.dryInkRenderer;
158
193
  }
194
+ /**
195
+ * @returns The renderer used for showing action previews (e.g. an unfinished stroke).
196
+ * The `wetInkRenderer`'s surface is stacked above the `dryInkRenderer`'s.
197
+ */
159
198
  getWetInkRenderer() {
160
199
  return this.wetInkRenderer;
161
200
  }
162
- // Re-renders the contents of the wetInkRenderer onto the dryInkRenderer
201
+ /** Re-renders the contents of the wetInkRenderer onto the dryInkRenderer. */
163
202
  flatten() {
164
203
  var _a;
165
204
  (_a = this.flattenCallback) === null || _a === void 0 ? void 0 : _a.call(this);
@@ -8,6 +8,7 @@ export default class CacheRecord {
8
8
  private renderer;
9
9
  private lastUsedCycle;
10
10
  private allocd;
11
+ allocCount: number;
11
12
  constructor(onBeforeDeallocCallback: BeforeDeallocCallback | null, cacheState: CacheState);
12
13
  startRender(): AbstractRenderer;
13
14
  dealloc(): void;
@@ -6,6 +6,8 @@ export default class CacheRecord {
6
6
  this.onBeforeDeallocCallback = onBeforeDeallocCallback;
7
7
  this.cacheState = cacheState;
8
8
  this.allocd = false;
9
+ // For debugging
10
+ this.allocCount = 0;
9
11
  this.renderer = cacheState.props.createRenderer();
10
12
  this.lastUsedCycle = -1;
11
13
  this.allocd = true;
@@ -34,6 +36,7 @@ export default class CacheRecord {
34
36
  this.allocd = true;
35
37
  this.onBeforeDeallocCallback = newDeallocCallback;
36
38
  this.lastUsedCycle = this.cacheState.currentRenderingCycle;
39
+ this.allocCount++;
37
40
  }
38
41
  getLastUsedCycle() {
39
42
  return this.lastUsedCycle;
@@ -1,11 +1,12 @@
1
- import { BeforeDeallocCallback, PartialCacheState } from './types';
1
+ import { BeforeDeallocCallback, CacheProps, CacheState } from './types';
2
2
  import CacheRecord from './CacheRecord';
3
3
  import Rect2 from '../../math/Rect2';
4
4
  export declare class CacheRecordManager {
5
- private readonly cacheState;
6
5
  private cacheRecords;
7
6
  private maxCanvases;
8
- constructor(cacheState: PartialCacheState);
7
+ private cacheState;
8
+ constructor(cacheProps: CacheProps);
9
+ setSharedState(state: CacheState): void;
9
10
  allocCanvas(drawTo: Rect2, onDealloc: BeforeDeallocCallback): CacheRecord;
10
11
  private getLeastRecentlyUsedRecord;
11
12
  }
@@ -1,25 +1,37 @@
1
1
  import CacheRecord from './CacheRecord';
2
+ const debugMode = false;
2
3
  export class CacheRecordManager {
3
- constructor(cacheState) {
4
- this.cacheState = cacheState;
4
+ constructor(cacheProps) {
5
5
  // Fixed-size array: Cache blocks are assigned indicies into [cachedCanvases].
6
6
  this.cacheRecords = [];
7
- const cacheProps = cacheState.props;
8
7
  this.maxCanvases = Math.ceil(
9
8
  // Assuming four components per pixel:
10
9
  cacheProps.cacheSize / 4 / cacheProps.blockResolution.x / cacheProps.blockResolution.y);
11
10
  }
11
+ setSharedState(state) {
12
+ this.cacheState = state;
13
+ }
12
14
  allocCanvas(drawTo, onDealloc) {
13
15
  if (this.cacheRecords.length < this.maxCanvases) {
14
- const record = new CacheRecord(onDealloc, Object.assign(Object.assign({}, this.cacheState), { recordManager: this }));
16
+ const record = new CacheRecord(onDealloc, this.cacheState);
15
17
  record.setRenderingRegion(drawTo);
16
18
  this.cacheRecords.push(record);
19
+ if (debugMode) {
20
+ console.log('[Cache] Cache spaces used: ', this.cacheRecords.length, ' of ', this.maxCanvases);
21
+ }
17
22
  return record;
18
23
  }
19
24
  else {
20
25
  const lru = this.getLeastRecentlyUsedRecord();
26
+ if (debugMode) {
27
+ console.log('[Cache] Re-alloc. Times allocated: ', lru.allocCount, '\nLast used cycle: ', lru.getLastUsedCycle(), '\nCurrent cycle: ', this.cacheState.currentRenderingCycle);
28
+ }
21
29
  lru.realloc(onDealloc);
22
30
  lru.setRenderingRegion(drawTo);
31
+ if (debugMode) {
32
+ console.log('[Cache] Now re-alloc\'d. Last used cycle: ', lru.getLastUsedCycle());
33
+ console.assert(lru['cacheState'] === this.cacheState, '[Cache] Unequal cache states! cacheState should be a shared object!');
34
+ }
23
35
  return lru;
24
36
  }
25
37
  }
@@ -1,12 +1,11 @@
1
1
  import { ImageNode } from '../../EditorImage';
2
2
  import Viewport from '../../Viewport';
3
3
  import AbstractRenderer from '../renderers/AbstractRenderer';
4
- import { CacheProps, CacheState } from './types';
4
+ import { CacheProps } from './types';
5
5
  export default class RenderingCache {
6
- private partialSharedState;
6
+ private sharedState;
7
7
  private recordManager;
8
8
  private rootNode;
9
9
  constructor(cacheProps: CacheProps);
10
- getSharedState(): CacheState;
11
10
  render(screenRenderer: AbstractRenderer, image: ImageNode, viewport: Viewport): void;
12
11
  }
@@ -3,36 +3,35 @@ import RenderingCacheNode from './RenderingCacheNode';
3
3
  import { CacheRecordManager } from './CacheRecordManager';
4
4
  export default class RenderingCache {
5
5
  constructor(cacheProps) {
6
- this.partialSharedState = {
6
+ this.recordManager = new CacheRecordManager(cacheProps);
7
+ this.sharedState = {
7
8
  props: cacheProps,
8
9
  currentRenderingCycle: 0,
10
+ recordManager: this.recordManager,
9
11
  };
10
- this.recordManager = new CacheRecordManager(this.partialSharedState);
11
- }
12
- getSharedState() {
13
- return Object.assign(Object.assign({}, this.partialSharedState), { recordManager: this.recordManager });
12
+ this.recordManager.setSharedState(this.sharedState);
14
13
  }
15
14
  render(screenRenderer, image, viewport) {
16
15
  var _a;
17
16
  const visibleRect = viewport.visibleRect;
18
- this.partialSharedState.currentRenderingCycle++;
17
+ this.sharedState.currentRenderingCycle++;
19
18
  // If we can't use the cache,
20
- if (!this.partialSharedState.props.isOfCorrectType(screenRenderer)) {
19
+ if (!this.sharedState.props.isOfCorrectType(screenRenderer)) {
21
20
  image.render(screenRenderer, visibleRect);
22
21
  return;
23
22
  }
24
23
  if (!this.rootNode) {
25
24
  // Adjust the node so that it has the correct aspect ratio
26
- const res = this.partialSharedState.props.blockResolution;
25
+ const res = this.sharedState.props.blockResolution;
27
26
  const topLeft = visibleRect.topLeft;
28
- this.rootNode = new RenderingCacheNode(new Rect2(topLeft.x, topLeft.y, res.x, res.y), this.getSharedState());
27
+ this.rootNode = new RenderingCacheNode(new Rect2(topLeft.x, topLeft.y, res.x, res.y), this.sharedState);
29
28
  }
30
29
  while (!this.rootNode.region.containsRect(visibleRect)) {
31
30
  this.rootNode = this.rootNode.generateParent();
32
31
  }
33
32
  this.rootNode = (_a = this.rootNode.smallestChildContaining(visibleRect)) !== null && _a !== void 0 ? _a : this.rootNode;
34
33
  const visibleLeaves = image.getLeavesIntersectingRegion(viewport.visibleRect, rect => screenRenderer.isTooSmallToRender(rect));
35
- if (visibleLeaves.length > this.partialSharedState.props.minComponentsToUseCache) {
34
+ if (visibleLeaves.length > this.sharedState.props.minComponentsToUseCache) {
36
35
  this.rootNode.renderItems(screenRenderer, [image], viewport);
37
36
  }
38
37
  else {
@@ -12,10 +12,8 @@ export interface CacheProps {
12
12
  minComponentsPerCache: number;
13
13
  minComponentsToUseCache: number;
14
14
  }
15
- export interface PartialCacheState {
15
+ export interface CacheState {
16
16
  currentRenderingCycle: number;
17
17
  props: CacheProps;
18
- }
19
- export interface CacheState extends PartialCacheState {
20
18
  recordManager: CacheRecordManager;
21
19
  }
@@ -43,7 +43,7 @@ export default class CanvasRenderer extends AbstractRenderer {
43
43
  }
44
44
  else {
45
45
  this.minSquareCurveApproxDist = 1;
46
- this.minRenderSizeBothDimens = 1;
46
+ this.minRenderSizeBothDimens = 0.5;
47
47
  this.minRenderSizeAnyDimen = 0;
48
48
  }
49
49
  }
@@ -29,6 +29,7 @@ export default class HTMLToolbar {
29
29
  }
30
30
  this.setupColorPickers();
31
31
  }
32
+ // @internal
32
33
  setupColorPickers() {
33
34
  const closePickerOverlay = document.createElement('div');
34
35
  closePickerOverlay.className = `${toolbarCSSPrefix}closeColorPickerOverlay`;
@@ -2,7 +2,7 @@ import Color4 from '../Color4';
2
2
  import { ToolType } from '../tools/ToolController';
3
3
  import { EditorEventType } from '../types';
4
4
  import { makePipetteIcon } from './icons';
5
- // Returns [ input, container ].
5
+ // Returns [ color input, input container ].
6
6
  export const makeColorInput = (editor, onColorChange) => {
7
7
  const colorInputContainer = document.createElement('span');
8
8
  const colorInput = document.createElement('input');
@@ -1,3 +1,4 @@
1
+ // @internal @packageDocumentation
1
2
  import { makeArrowBuilder } from '../../components/builders/ArrowBuilder';
2
3
  import { makeFreehandLineBuilder } from '../../components/builders/FreehandLineBuilder';
3
4
  import { makeLineBuilder } from '../../components/builders/LineBuilder';
@@ -4,7 +4,7 @@ import { PointerEvt } from '../types';
4
4
  import BaseTool from './BaseTool';
5
5
  import { ToolType } from './ToolController';
6
6
  import { ComponentBuilderFactory } from '../components/builders/types';
7
- interface PenStyle {
7
+ export interface PenStyle {
8
8
  color: Color4;
9
9
  thickness: number;
10
10
  }
@@ -32,4 +32,3 @@ export default class Pen extends BaseTool {
32
32
  getColor(): Color4;
33
33
  getStrokeFactory(): ComponentBuilderFactory;
34
34
  }
35
- export {};
@@ -20,7 +20,14 @@ export default class Pen extends BaseTool {
20
20
  getStrokePoint(pointer) {
21
21
  var _a;
22
22
  const minPressure = 0.3;
23
- const pressure = Math.max((_a = pointer.pressure) !== null && _a !== void 0 ? _a : 1.0, minPressure);
23
+ let pressure = Math.max((_a = pointer.pressure) !== null && _a !== void 0 ? _a : 1.0, minPressure);
24
+ if (!isFinite(pressure)) {
25
+ console.warn('Non-finite pressure!', pointer);
26
+ pressure = minPressure;
27
+ }
28
+ console.assert(isFinite(pointer.canvasPos.length()), 'Non-finite canvas position!');
29
+ console.assert(isFinite(pointer.screenPos.length()), 'Non-finite screen position!');
30
+ console.assert(isFinite(pointer.timeStamp), 'Non-finite timeStamp on pointer!');
24
31
  return {
25
32
  pos: pointer.canvasPos,
26
33
  width: pressure * this.getPressureMultiplier(),
@@ -1,3 +1,4 @@
1
+ // @internal @packageDocumentation
1
2
  import BaseTool from './BaseTool';
2
3
  import { ToolType } from './ToolController';
3
4
  export default class PipetteTool extends BaseTool {
@@ -7,7 +7,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
7
7
  step((generator = generator.apply(thisArg, _arguments || [])).next());
8
8
  });
9
9
  };
10
- import Command from '../commands/Command';
10
+ var _a;
11
11
  import Duplicate from '../commands/Duplicate';
12
12
  import Erase from '../commands/Erase';
13
13
  import Mat33 from '../math/Mat33';
@@ -18,6 +18,7 @@ import { EditorEventType } from '../types';
18
18
  import Viewport from '../Viewport';
19
19
  import BaseTool from './BaseTool';
20
20
  import { ToolType } from './ToolController';
21
+ import SerializableCommand from '../commands/SerializableCommand';
21
22
  const handleScreenSize = 30;
22
23
  const styles = `
23
24
  .handleOverlay {
@@ -118,6 +119,7 @@ const makeDraggable = (element, onDrag, onDragEnd) => {
118
119
  };
119
120
  // Maximum number of strokes to transform without a re-render.
120
121
  const updateChunkSize = 100;
122
+ // @internal
121
123
  class Selection {
122
124
  constructor(startPoint, editor) {
123
125
  this.startPoint = startPoint;
@@ -228,7 +230,7 @@ class Selection {
228
230
  this.transform = Mat33.identity;
229
231
  this.region = this.region.transformedBoundingBox(inverseTransform);
230
232
  // Make the commands undo-able
231
- this.editor.dispatch(new Selection.ApplyTransformationCommand(this, currentTransfmCommands, fullTransform, inverseTransform, deltaBoxRotation));
233
+ this.editor.dispatch(new Selection.ApplyTransformationCommand(this, currentTransfmCommands, fullTransform, deltaBoxRotation));
232
234
  }
233
235
  // Preview the effects of the current transformation on the selection
234
236
  previewTransformCmds() {
@@ -352,36 +354,57 @@ class Selection {
352
354
  return new Duplicate(this.selectedElems);
353
355
  }
354
356
  }
355
- Selection.ApplyTransformationCommand = class extends Command {
356
- constructor(selection, currentTransfmCommands, fullTransform, inverseTransform, deltaBoxRotation) {
357
- super();
357
+ _a = Selection;
358
+ (() => {
359
+ SerializableCommand.register('selection-tool-transform', (json, editor) => {
360
+ // The selection box is lost when serializing/deserializing. No need to store box rotation
361
+ const guiBoxRotation = 0;
362
+ const fullTransform = new Mat33(...json.transform);
363
+ const commands = json.commands.map(data => SerializableCommand.deserialize(data, editor));
364
+ return new _a.ApplyTransformationCommand(null, commands, fullTransform, guiBoxRotation);
365
+ });
366
+ })();
367
+ Selection.ApplyTransformationCommand = class extends SerializableCommand {
368
+ constructor(selection, currentTransfmCommands, fullTransform, deltaBoxRotation) {
369
+ super('selection-tool-transform');
358
370
  this.selection = selection;
359
371
  this.currentTransfmCommands = currentTransfmCommands;
360
372
  this.fullTransform = fullTransform;
361
- this.inverseTransform = inverseTransform;
362
373
  this.deltaBoxRotation = deltaBoxRotation;
363
374
  }
364
375
  apply(editor) {
376
+ var _b, _c;
365
377
  return __awaiter(this, void 0, void 0, function* () {
366
378
  // Approximate the new selection
367
- this.selection.region = this.selection.region.transformedBoundingBox(this.fullTransform);
368
- this.selection.boxRotation += this.deltaBoxRotation;
369
- this.selection.updateUI();
379
+ if (this.selection) {
380
+ this.selection.region = this.selection.region.transformedBoundingBox(this.fullTransform);
381
+ this.selection.boxRotation += this.deltaBoxRotation;
382
+ this.selection.updateUI();
383
+ }
370
384
  yield editor.asyncApplyCommands(this.currentTransfmCommands, updateChunkSize);
371
- this.selection.recomputeRegion();
372
- this.selection.updateUI();
385
+ (_b = this.selection) === null || _b === void 0 ? void 0 : _b.recomputeRegion();
386
+ (_c = this.selection) === null || _c === void 0 ? void 0 : _c.updateUI();
373
387
  });
374
388
  }
375
389
  unapply(editor) {
390
+ var _b, _c;
376
391
  return __awaiter(this, void 0, void 0, function* () {
377
- this.selection.region = this.selection.region.transformedBoundingBox(this.inverseTransform);
378
- this.selection.boxRotation -= this.deltaBoxRotation;
379
- this.selection.updateUI();
392
+ if (this.selection) {
393
+ this.selection.region = this.selection.region.transformedBoundingBox(this.fullTransform.inverse());
394
+ this.selection.boxRotation -= this.deltaBoxRotation;
395
+ this.selection.updateUI();
396
+ }
380
397
  yield editor.asyncUnapplyCommands(this.currentTransfmCommands, updateChunkSize);
381
- this.selection.recomputeRegion();
382
- this.selection.updateUI();
398
+ (_b = this.selection) === null || _b === void 0 ? void 0 : _b.recomputeRegion();
399
+ (_c = this.selection) === null || _c === void 0 ? void 0 : _c.updateUI();
383
400
  });
384
401
  }
402
+ serializeToJSON() {
403
+ return {
404
+ commands: this.currentTransfmCommands.map(command => command.serialize()),
405
+ transform: this.fullTransform.toArray(),
406
+ };
407
+ }
385
408
  description(_editor, localizationTable) {
386
409
  return localizationTable.transformedElements(this.currentTransfmCommands.length);
387
410
  }
@@ -397,9 +420,9 @@ export default class SelectionTool extends BaseTool {
397
420
  this.handleOverlay.style.display = 'none';
398
421
  this.handleOverlay.classList.add('handleOverlay');
399
422
  editor.notifier.on(EditorEventType.ViewportChanged, _data => {
400
- var _a, _b;
401
- (_a = this.selectionBox) === null || _a === void 0 ? void 0 : _a.recomputeRegion();
402
- (_b = this.selectionBox) === null || _b === void 0 ? void 0 : _b.updateUI();
423
+ var _b, _c;
424
+ (_b = this.selectionBox) === null || _b === void 0 ? void 0 : _b.recomputeRegion();
425
+ (_c = this.selectionBox) === null || _c === void 0 ? void 0 : _c.updateUI();
403
426
  });
404
427
  this.editor.handleKeyEventsFrom(this.handleOverlay);
405
428
  }
@@ -447,11 +470,11 @@ export default class SelectionTool extends BaseTool {
447
470
  this.onGestureEnd();
448
471
  }
449
472
  onGestureCancel() {
450
- var _a, _b;
473
+ var _b, _c;
451
474
  // Revert to the previous selection, if any.
452
- (_a = this.selectionBox) === null || _a === void 0 ? void 0 : _a.cancelSelection();
475
+ (_b = this.selectionBox) === null || _b === void 0 ? void 0 : _b.cancelSelection();
453
476
  this.selectionBox = this.prevSelectionBox;
454
- (_b = this.selectionBox) === null || _b === void 0 ? void 0 : _b.appendBackgroundBoxTo(this.handleOverlay);
477
+ (_c = this.selectionBox) === null || _c === void 0 ? void 0 : _c.appendBackgroundBoxTo(this.handleOverlay);
455
478
  }
456
479
  onKeyPress(event) {
457
480
  let rotationSteps = 0;
@@ -7,6 +7,7 @@ import AbstractComponent from './components/AbstractComponent';
7
7
  import Rect2 from './math/Rect2';
8
8
  import Pointer from './Pointer';
9
9
  import Color4 from './Color4';
10
+ import Command from './commands/Command';
10
11
  export interface PointerEvtListener {
11
12
  onPointerDown(event: PointerEvt): boolean;
12
13
  onPointerMove(event: PointerEvt): void;
@@ -61,11 +62,13 @@ export declare enum EditorEventType {
61
62
  ToolDisabled = 1,
62
63
  ToolUpdated = 2,
63
64
  UndoRedoStackUpdated = 3,
64
- ObjectAdded = 4,
65
- ViewportChanged = 5,
66
- DisplayResized = 6,
67
- ColorPickerToggled = 7,
68
- ColorPickerColorSelected = 8
65
+ CommandDone = 4,
66
+ CommandUndone = 5,
67
+ ObjectAdded = 6,
68
+ ViewportChanged = 7,
69
+ DisplayResized = 8,
70
+ ColorPickerToggled = 9,
71
+ ColorPickerColorSelected = 10
69
72
  }
70
73
  declare type EditorToolEventType = EditorEventType.ToolEnabled | EditorEventType.ToolDisabled | EditorEventType.ToolUpdated;
71
74
  export interface EditorToolEvent {
@@ -90,6 +93,14 @@ export interface EditorUndoStackUpdated {
90
93
  readonly undoStackSize: number;
91
94
  readonly redoStackSize: number;
92
95
  }
96
+ export interface CommandDoneEvent {
97
+ readonly kind: EditorEventType.CommandDone;
98
+ readonly command: Command;
99
+ }
100
+ export interface CommandUndoneEvent {
101
+ readonly kind: EditorEventType.CommandUndone;
102
+ readonly command: Command;
103
+ }
93
104
  export interface ColorPickerToggled {
94
105
  readonly kind: EditorEventType.ColorPickerToggled;
95
106
  readonly open: boolean;
@@ -98,7 +109,7 @@ export interface ColorPickerColorSelected {
98
109
  readonly kind: EditorEventType.ColorPickerColorSelected;
99
110
  readonly color: Color4;
100
111
  }
101
- export declare type EditorEventDataType = EditorToolEvent | EditorObjectEvent | EditorViewportChangedEvent | DisplayResizedEvent | EditorUndoStackUpdated | ColorPickerToggled | ColorPickerColorSelected;
112
+ export declare type EditorEventDataType = EditorToolEvent | EditorObjectEvent | EditorViewportChangedEvent | DisplayResizedEvent | EditorUndoStackUpdated | CommandDoneEvent | CommandUndoneEvent | ColorPickerToggled | ColorPickerColorSelected;
102
113
  export declare type OnProgressListener = (amountProcessed: number, totalToProcess: number) => Promise<void> | null;
103
114
  export declare type ComponentAddedListener = (component: AbstractComponent) => void;
104
115
  export declare type OnDetermineExportRectListener = (exportRect: Rect2) => void;
package/dist/src/types.js CHANGED
@@ -15,9 +15,11 @@ export var EditorEventType;
15
15
  EditorEventType[EditorEventType["ToolDisabled"] = 1] = "ToolDisabled";
16
16
  EditorEventType[EditorEventType["ToolUpdated"] = 2] = "ToolUpdated";
17
17
  EditorEventType[EditorEventType["UndoRedoStackUpdated"] = 3] = "UndoRedoStackUpdated";
18
- EditorEventType[EditorEventType["ObjectAdded"] = 4] = "ObjectAdded";
19
- EditorEventType[EditorEventType["ViewportChanged"] = 5] = "ViewportChanged";
20
- EditorEventType[EditorEventType["DisplayResized"] = 6] = "DisplayResized";
21
- EditorEventType[EditorEventType["ColorPickerToggled"] = 7] = "ColorPickerToggled";
22
- EditorEventType[EditorEventType["ColorPickerColorSelected"] = 8] = "ColorPickerColorSelected";
18
+ EditorEventType[EditorEventType["CommandDone"] = 4] = "CommandDone";
19
+ EditorEventType[EditorEventType["CommandUndone"] = 5] = "CommandUndone";
20
+ EditorEventType[EditorEventType["ObjectAdded"] = 6] = "ObjectAdded";
21
+ EditorEventType[EditorEventType["ViewportChanged"] = 7] = "ViewportChanged";
22
+ EditorEventType[EditorEventType["DisplayResized"] = 8] = "DisplayResized";
23
+ EditorEventType[EditorEventType["ColorPickerToggled"] = 9] = "ColorPickerToggled";
24
+ EditorEventType[EditorEventType["ColorPickerColorSelected"] = 10] = "ColorPickerColorSelected";
23
25
  })(EditorEventType || (EditorEventType = {}));
package/firebase.json ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "hosting": {
3
+ "public": "docs",
4
+ "ignore": [
5
+ "firebase.json",
6
+ "src/**",
7
+ ".husky/**",
8
+ ".vscode/**",
9
+ "build_tools/**",
10
+ "dist/**",
11
+ "__mocks__/**",
12
+ "**/.*",
13
+ "**/node_modules/**"
14
+ ]
15
+ }
16
+ }