js-draw 0.0.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 (156) hide show
  1. package/.eslintrc.js +57 -0
  2. package/.husky/pre-commit +4 -0
  3. package/LICENSE +21 -0
  4. package/README.md +74 -0
  5. package/__mocks__/coloris.ts +8 -0
  6. package/__mocks__/styleMock.js +1 -0
  7. package/dist/__mocks__/coloris.d.ts +2 -0
  8. package/dist/__mocks__/coloris.js +5 -0
  9. package/dist/build_tools/BundledFile.d.ts +12 -0
  10. package/dist/build_tools/BundledFile.js +153 -0
  11. package/dist/scripts/bundle.d.ts +1 -0
  12. package/dist/scripts/bundle.js +19 -0
  13. package/dist/scripts/watchBundle.d.ts +1 -0
  14. package/dist/scripts/watchBundle.js +9 -0
  15. package/dist/src/Color4.d.ts +23 -0
  16. package/dist/src/Color4.js +102 -0
  17. package/dist/src/Display.d.ts +22 -0
  18. package/dist/src/Display.js +93 -0
  19. package/dist/src/Editor.d.ts +55 -0
  20. package/dist/src/Editor.js +366 -0
  21. package/dist/src/EditorImage.d.ts +44 -0
  22. package/dist/src/EditorImage.js +243 -0
  23. package/dist/src/EventDispatcher.d.ts +11 -0
  24. package/dist/src/EventDispatcher.js +39 -0
  25. package/dist/src/Pointer.d.ts +22 -0
  26. package/dist/src/Pointer.js +57 -0
  27. package/dist/src/SVGLoader.d.ts +21 -0
  28. package/dist/src/SVGLoader.js +204 -0
  29. package/dist/src/StrokeBuilder.d.ts +35 -0
  30. package/dist/src/StrokeBuilder.js +275 -0
  31. package/dist/src/UndoRedoHistory.d.ts +17 -0
  32. package/dist/src/UndoRedoHistory.js +46 -0
  33. package/dist/src/Viewport.d.ts +39 -0
  34. package/dist/src/Viewport.js +134 -0
  35. package/dist/src/commands/Command.d.ts +15 -0
  36. package/dist/src/commands/Command.js +29 -0
  37. package/dist/src/commands/Erase.d.ts +11 -0
  38. package/dist/src/commands/Erase.js +37 -0
  39. package/dist/src/commands/localization.d.ts +19 -0
  40. package/dist/src/commands/localization.js +17 -0
  41. package/dist/src/components/AbstractComponent.d.ts +19 -0
  42. package/dist/src/components/AbstractComponent.js +46 -0
  43. package/dist/src/components/Stroke.d.ts +16 -0
  44. package/dist/src/components/Stroke.js +79 -0
  45. package/dist/src/components/UnknownSVGObject.d.ts +15 -0
  46. package/dist/src/components/UnknownSVGObject.js +25 -0
  47. package/dist/src/components/localization.d.ts +5 -0
  48. package/dist/src/components/localization.js +4 -0
  49. package/dist/src/geometry/LineSegment2.d.ts +19 -0
  50. package/dist/src/geometry/LineSegment2.js +100 -0
  51. package/dist/src/geometry/Mat33.d.ts +31 -0
  52. package/dist/src/geometry/Mat33.js +187 -0
  53. package/dist/src/geometry/Path.d.ts +55 -0
  54. package/dist/src/geometry/Path.js +364 -0
  55. package/dist/src/geometry/Rect2.d.ts +47 -0
  56. package/dist/src/geometry/Rect2.js +148 -0
  57. package/dist/src/geometry/Vec2.d.ts +13 -0
  58. package/dist/src/geometry/Vec2.js +13 -0
  59. package/dist/src/geometry/Vec3.d.ts +32 -0
  60. package/dist/src/geometry/Vec3.js +98 -0
  61. package/dist/src/localization.d.ts +12 -0
  62. package/dist/src/localization.js +5 -0
  63. package/dist/src/main.d.ts +3 -0
  64. package/dist/src/main.js +4 -0
  65. package/dist/src/rendering/AbstractRenderer.d.ts +38 -0
  66. package/dist/src/rendering/AbstractRenderer.js +108 -0
  67. package/dist/src/rendering/CanvasRenderer.d.ts +23 -0
  68. package/dist/src/rendering/CanvasRenderer.js +108 -0
  69. package/dist/src/rendering/DummyRenderer.d.ts +25 -0
  70. package/dist/src/rendering/DummyRenderer.js +65 -0
  71. package/dist/src/rendering/SVGRenderer.d.ts +27 -0
  72. package/dist/src/rendering/SVGRenderer.js +122 -0
  73. package/dist/src/testing/loadExpectExtensions.d.ts +17 -0
  74. package/dist/src/testing/loadExpectExtensions.js +27 -0
  75. package/dist/src/toolbar/HTMLToolbar.d.ts +12 -0
  76. package/dist/src/toolbar/HTMLToolbar.js +444 -0
  77. package/dist/src/toolbar/types.d.ts +17 -0
  78. package/dist/src/toolbar/types.js +5 -0
  79. package/dist/src/tools/BaseTool.d.ts +20 -0
  80. package/dist/src/tools/BaseTool.js +44 -0
  81. package/dist/src/tools/Eraser.d.ts +16 -0
  82. package/dist/src/tools/Eraser.js +53 -0
  83. package/dist/src/tools/PanZoom.d.ts +40 -0
  84. package/dist/src/tools/PanZoom.js +191 -0
  85. package/dist/src/tools/Pen.d.ts +25 -0
  86. package/dist/src/tools/Pen.js +97 -0
  87. package/dist/src/tools/SelectionTool.d.ts +49 -0
  88. package/dist/src/tools/SelectionTool.js +437 -0
  89. package/dist/src/tools/ToolController.d.ts +18 -0
  90. package/dist/src/tools/ToolController.js +110 -0
  91. package/dist/src/tools/ToolEnabledGroup.d.ts +6 -0
  92. package/dist/src/tools/ToolEnabledGroup.js +11 -0
  93. package/dist/src/tools/localization.d.ts +10 -0
  94. package/dist/src/tools/localization.js +9 -0
  95. package/dist/src/types.d.ts +88 -0
  96. package/dist/src/types.js +20 -0
  97. package/jest.config.js +22 -0
  98. package/lint-staged.config.js +6 -0
  99. package/package.json +82 -0
  100. package/src/Color4.test.ts +12 -0
  101. package/src/Color4.ts +122 -0
  102. package/src/Display.ts +118 -0
  103. package/src/Editor.css +58 -0
  104. package/src/Editor.ts +469 -0
  105. package/src/EditorImage.test.ts +90 -0
  106. package/src/EditorImage.ts +297 -0
  107. package/src/EventDispatcher.test.ts +123 -0
  108. package/src/EventDispatcher.ts +53 -0
  109. package/src/Pointer.ts +93 -0
  110. package/src/SVGLoader.ts +230 -0
  111. package/src/StrokeBuilder.ts +362 -0
  112. package/src/UndoRedoHistory.ts +61 -0
  113. package/src/Viewport.ts +168 -0
  114. package/src/commands/Command.ts +43 -0
  115. package/src/commands/Erase.ts +52 -0
  116. package/src/commands/localization.ts +38 -0
  117. package/src/components/AbstractComponent.ts +73 -0
  118. package/src/components/Stroke.test.ts +18 -0
  119. package/src/components/Stroke.ts +102 -0
  120. package/src/components/UnknownSVGObject.ts +36 -0
  121. package/src/components/localization.ts +9 -0
  122. package/src/editorStyles.js +3 -0
  123. package/src/geometry/LineSegment2.test.ts +77 -0
  124. package/src/geometry/LineSegment2.ts +127 -0
  125. package/src/geometry/Mat33.test.ts +144 -0
  126. package/src/geometry/Mat33.ts +268 -0
  127. package/src/geometry/Path.fromString.test.ts +146 -0
  128. package/src/geometry/Path.test.ts +96 -0
  129. package/src/geometry/Path.toString.test.ts +31 -0
  130. package/src/geometry/Path.ts +456 -0
  131. package/src/geometry/Rect2.test.ts +121 -0
  132. package/src/geometry/Rect2.ts +215 -0
  133. package/src/geometry/Vec2.test.ts +32 -0
  134. package/src/geometry/Vec2.ts +18 -0
  135. package/src/geometry/Vec3.test.ts +29 -0
  136. package/src/geometry/Vec3.ts +133 -0
  137. package/src/localization.ts +27 -0
  138. package/src/rendering/AbstractRenderer.ts +164 -0
  139. package/src/rendering/CanvasRenderer.ts +141 -0
  140. package/src/rendering/DummyRenderer.ts +80 -0
  141. package/src/rendering/SVGRenderer.ts +159 -0
  142. package/src/testing/loadExpectExtensions.ts +43 -0
  143. package/src/toolbar/HTMLToolbar.ts +551 -0
  144. package/src/toolbar/toolbar.css +110 -0
  145. package/src/toolbar/types.ts +20 -0
  146. package/src/tools/BaseTool.ts +58 -0
  147. package/src/tools/Eraser.ts +67 -0
  148. package/src/tools/PanZoom.ts +253 -0
  149. package/src/tools/Pen.ts +121 -0
  150. package/src/tools/SelectionTool.test.ts +85 -0
  151. package/src/tools/SelectionTool.ts +545 -0
  152. package/src/tools/ToolController.ts +126 -0
  153. package/src/tools/ToolEnabledGroup.ts +14 -0
  154. package/src/tools/localization.ts +22 -0
  155. package/src/types.ts +133 -0
  156. package/tsconfig.json +28 -0
package/.eslintrc.js ADDED
@@ -0,0 +1,57 @@
1
+ module.exports = {
2
+ 'env': {
3
+ 'browser': true,
4
+ 'es2021': true,
5
+ 'node': true
6
+ },
7
+ 'extends': [
8
+ 'eslint:recommended',
9
+ 'plugin:@typescript-eslint/eslint-recommended',
10
+ 'plugin:@typescript-eslint/recommended'
11
+ ],
12
+ 'overrides': [
13
+ ],
14
+ 'parser': '@typescript-eslint/parser',
15
+ 'parserOptions': {
16
+ 'ecmaVersion': 'latest',
17
+ 'sourceType': 'module'
18
+ },
19
+ 'plugins': [
20
+ '@typescript-eslint'
21
+ ],
22
+ 'rules': {
23
+ 'indent': [
24
+ 'error',
25
+ 'tab'
26
+ ],
27
+ 'linebreak-style': [
28
+ 'error',
29
+ 'unix'
30
+ ],
31
+ 'quotes': [
32
+ 'error',
33
+ 'single'
34
+ ],
35
+ 'semi': [
36
+ 'error',
37
+ 'always'
38
+ ],
39
+ '@typescript-eslint/no-empty-function': 'off',
40
+ '@typescript-eslint/no-empty-interface': 'off',
41
+ '@typescript-eslint/no-inferrable-types': 'off',
42
+ '@typescript-eslint/no-non-null-assertion': 'off',
43
+ '@typescript-eslint/no-unused-vars': [
44
+ 'error',
45
+ {
46
+ 'argsIgnorePattern': '^_',
47
+ }
48
+ ],
49
+ '@typescript-eslint/no-explicit-any': 'off',
50
+
51
+ // namespaces can be useful when defining helper methods for interfaces.
52
+ '@typescript-eslint/no-namespace': 'off',
53
+ },
54
+ 'ignorePatterns': [
55
+ '**/*.bundle.js',
56
+ ],
57
+ };
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env sh
2
+ . "$(dirname -- "$0")/_/husky.sh"
3
+
4
+ yarn lint-staged
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2022 Henry Heino
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,74 @@
1
+ # js-draw
2
+
3
+ ![](doc/img/js-draw.jpg)
4
+
5
+ For example usage, see [doc/example/example.html](doc/example/example.ts).
6
+
7
+ # API
8
+
9
+ To use `js-draw`,
10
+
11
+ ## Creating an `Editor`
12
+
13
+ To create a new `Editor` and add it as a child of `document.body`,
14
+ ```ts
15
+ import Editor from 'js-draw';
16
+ import 'js-draw/styles';
17
+
18
+ const editor = new Editor(document.body);
19
+ ```
20
+
21
+ The `import js-draw/styles` step requires a bundler that can import `.css` files. For example, [`webpack` with `css-loader`.](https://webpack.js.org/loaders/css-loader/)
22
+
23
+
24
+ ## Adding a toolbar
25
+
26
+ To create a toolbar with the default tools:
27
+ ```ts
28
+ const toolbar = editor.addToolbar();
29
+ ```
30
+
31
+ Custom actions can be added to the toolbar. For example, to add a `save` button:
32
+ ```ts
33
+ toolbar.addActionButton('Save', () => {
34
+ const svgElem = editor.toSVG();
35
+ console.log('The saved SVG:', svgElem.outerHTML);
36
+ });
37
+ ```
38
+
39
+ ## Loading from an SVG
40
+
41
+ ```ts
42
+ editor.loadFromSVG(`
43
+ <svg
44
+ viewBox="156 74 200 150"
45
+ width="200" height="150"
46
+ >
47
+ <path d="M156,150Q190,190 209,217L213,215Q193,187 160,148M209,217Q212,218 236,178L232,176Q210,215 213,215M236,178Q240,171 307,95L305,93Q237,168 232,176M307,95Q312,90 329,78L327,74Q309,87 305,93" fill="#07a837"></path>
48
+ </svg>
49
+ `);
50
+ ```
51
+
52
+ **Note**: While `js-draw` supports a small subset of the SVG markup language, it tries to preserve unrecognised SVG elements.
53
+
54
+ For example, although `js-draw` doesn't support `<circle/>` elements,
55
+ ```svg
56
+ <svg
57
+ viewBox="156 74 200 150"
58
+ width="200" height="150"
59
+ >
60
+ <path d="M156,150Q190,190 209,217L213,215Q193,187 160,148M209,217Q212,218 236,178L232,176Q210,215 213,215M236,178Q240,171 307,95L305,93Q237,168 232,176M307,95Q312,90 329,78L327,74Q309,87 305,93" fill="#07a837"></path>
61
+ <circle cx=200 cy=100 r=40 fill='red'/>
62
+ </svg>
63
+ ```
64
+ renders as
65
+
66
+ ![screenshot of the image editor, displaying a green checkmark. The circle is invisible](doc/img/unsupported-elements--in-editor.png)
67
+
68
+ but exports to
69
+ ```svg
70
+ <svg viewBox="156 74 200 150" width="200" height="150" version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg"><g><path d="M156,150M156,150Q190,190 209,217L213,215Q193,187 160,148M209,217M209,217Q212,218 236,178L232,176Q210,215 213,215M236,178M236,178Q240,171 307,95L305,93Q237,168 232,176M307,95M307,95Q312,90 329,78L327,74Q309,87 305,93" fill="#07a837"></path></g><circle cx="200" cy="100" r="40" fill="red"></circle></svg>
71
+ ```
72
+
73
+ which **does** contain the `<circle/>` element.
74
+
@@ -0,0 +1,8 @@
1
+
2
+ // @melloware/coloris tries to use the HTML5Canvas on import, which is not supported by
3
+ // JSDom (without installing additional packages). As such, we need to mock it.
4
+
5
+ export const coloris = (_options: any): void => {
6
+ };
7
+
8
+ export const init = () => {};
@@ -0,0 +1 @@
1
+ module.exports = {};
@@ -0,0 +1,2 @@
1
+ export declare const coloris: (_options: any) => void;
2
+ export declare const init: () => void;
@@ -0,0 +1,5 @@
1
+ // @melloware/coloris tries to use the HTML5Canvas on import, which is not supported by
2
+ // JSDom (without installing additional packages). As such, we need to mock it.
3
+ export const coloris = (_options) => {
4
+ };
5
+ export const init = () => { };
@@ -0,0 +1,12 @@
1
+ export default class BundledFile {
2
+ readonly bundleName: string;
3
+ private readonly sourceFilePath;
4
+ private readonly bundleBaseName;
5
+ private readonly rootFileDirectory;
6
+ constructor(bundleName: string, sourceFilePath: string);
7
+ private getWebpackOptions;
8
+ private handleErrors;
9
+ build(): Promise<void>;
10
+ startWatching(): void;
11
+ }
12
+ export declare const bundledFiles: BundledFile[];
@@ -0,0 +1,153 @@
1
+ // This file is taken from Joplin: https://github.com/laurent22/joplin
2
+ // js-draw was originally created as a part of a pull request for joplin. This
3
+ // is part of the functionality from Joplin it requires.
4
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
5
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
6
+ return new (P || (P = Promise))(function (resolve, reject) {
7
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
8
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
9
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
10
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
11
+ });
12
+ };
13
+ import { dirname, extname, basename } from 'path';
14
+ import TerserPlugin from 'terser-webpack-plugin';
15
+ import webpack from 'webpack';
16
+ export default class BundledFile {
17
+ constructor(bundleName, sourceFilePath) {
18
+ this.bundleName = bundleName;
19
+ this.sourceFilePath = sourceFilePath;
20
+ this.rootFileDirectory = dirname(sourceFilePath);
21
+ this.bundleBaseName = basename(sourceFilePath, extname(sourceFilePath));
22
+ }
23
+ getWebpackOptions(mode) {
24
+ const config = {
25
+ mode,
26
+ entry: this.sourceFilePath,
27
+ output: {
28
+ path: this.rootFileDirectory,
29
+ filename: `${this.bundleBaseName}.bundle.js`,
30
+ library: {
31
+ type: 'window',
32
+ name: this.bundleName,
33
+ },
34
+ },
35
+ // See https://webpack.js.org/guides/typescript/
36
+ module: {
37
+ rules: [
38
+ {
39
+ // Include .tsx to include react components
40
+ test: /\.tsx?$/i,
41
+ use: 'ts-loader',
42
+ exclude: /node_modules/,
43
+ },
44
+ {
45
+ test: /\.css$/i,
46
+ use: ['style-loader', 'css-loader'],
47
+ },
48
+ ],
49
+ },
50
+ optimization: {
51
+ minimizer: [
52
+ // Don't create separate files for comments.
53
+ // See https://stackoverflow.com/a/65650316/17055750
54
+ new TerserPlugin({
55
+ extractComments: false,
56
+ }),
57
+ ],
58
+ },
59
+ // Increase the minimum size required
60
+ // to trigger warnings.
61
+ // See https://stackoverflow.com/a/53517149/17055750
62
+ performance: {
63
+ maxAssetSize: 2000000,
64
+ maxEntrypointSize: 2000000,
65
+ },
66
+ resolve: {
67
+ extensions: ['.tsx', '.ts', '.js'],
68
+ },
69
+ };
70
+ return config;
71
+ }
72
+ handleErrors(err, stats) {
73
+ let failed = false;
74
+ if (err) {
75
+ console.error(`Error: ${err.name}`, err.message, err.stack);
76
+ failed = true;
77
+ }
78
+ else if ((stats === null || stats === void 0 ? void 0 : stats.hasErrors()) || (stats === null || stats === void 0 ? void 0 : stats.hasWarnings())) {
79
+ const data = stats.toJson();
80
+ if (data.warnings && data.warningsCount) {
81
+ console.warn('Warnings: ', data.warningsCount);
82
+ for (const warning of data.warnings) {
83
+ // Stack contains the message
84
+ if (warning.stack) {
85
+ console.warn(warning.stack);
86
+ }
87
+ else {
88
+ console.warn(warning.message);
89
+ }
90
+ }
91
+ }
92
+ if (data.errors && data.errorsCount) {
93
+ console.error('Errors: ', data.errorsCount);
94
+ for (const error of data.errors) {
95
+ if (error.stack) {
96
+ console.error(error.stack);
97
+ }
98
+ else {
99
+ console.error(error.message);
100
+ }
101
+ console.error();
102
+ }
103
+ failed = true;
104
+ }
105
+ }
106
+ return failed;
107
+ }
108
+ // Create a minified JS file in the same directory as `this.sourceFilePath` with
109
+ // the same name.
110
+ build() {
111
+ const compiler = webpack(this.getWebpackOptions('production'));
112
+ return new Promise((resolve, reject) => {
113
+ console.info(`Building bundle: ${this.bundleName}...`);
114
+ compiler.run((err, stats) => {
115
+ let failed = this.handleErrors(err, stats);
116
+ // Clean up.
117
+ compiler.close((error) => __awaiter(this, void 0, void 0, function* () {
118
+ if (error) {
119
+ console.error('Error cleaning up:', error);
120
+ failed = true;
121
+ }
122
+ if (!failed) {
123
+ console.log('☑ Done building! ☑');
124
+ resolve();
125
+ }
126
+ else {
127
+ reject();
128
+ }
129
+ }));
130
+ });
131
+ });
132
+ }
133
+ startWatching() {
134
+ const compiler = webpack(this.getWebpackOptions('development'));
135
+ const watchOptions = {
136
+ ignored: [
137
+ '**/node_modules',
138
+ '**/dist',
139
+ ],
140
+ };
141
+ console.info('Watching bundle: ', this.bundleName);
142
+ compiler.watch(watchOptions, (err, stats) => __awaiter(this, void 0, void 0, function* () {
143
+ const failed = this.handleErrors(err, stats);
144
+ if (!failed) {
145
+ console.log('☑ Built! ☑');
146
+ }
147
+ }));
148
+ }
149
+ }
150
+ const rootDir = dirname(__dirname);
151
+ export const bundledFiles = [
152
+ new BundledFile('jsdraw', `${rootDir}/src/main.ts`),
153
+ ];
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,19 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { bundledFiles } from '../build_tools/BundledFile';
11
+ function build() {
12
+ return __awaiter(this, void 0, void 0, function* () {
13
+ // Build all in parallel
14
+ yield Promise.all(bundledFiles.map((file) => __awaiter(this, void 0, void 0, function* () {
15
+ yield file.build();
16
+ })));
17
+ });
18
+ }
19
+ void build();
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,9 @@
1
+ import { bundledFiles } from '../build_tools/BundledFile';
2
+ console.log('Watching for changes...');
3
+ function watch() {
4
+ // Watch for changes
5
+ for (const file of bundledFiles) {
6
+ file.startWatching();
7
+ }
8
+ }
9
+ watch();
@@ -0,0 +1,23 @@
1
+ export default class Color4 {
2
+ readonly r: number;
3
+ readonly g: number;
4
+ readonly b: number;
5
+ readonly a: number;
6
+ private constructor();
7
+ static ofRGB(red: number, green: number, blue: number): Color4;
8
+ static ofRGBA(red: number, green: number, blue: number, alpha: number): Color4;
9
+ static fromHex(hexString: string): Color4;
10
+ static fromString(text: string): Color4;
11
+ eq(other: Color4 | null | undefined): boolean;
12
+ private hexString;
13
+ toHexString(): string;
14
+ static transparent: Color4;
15
+ static red: Color4;
16
+ static green: Color4;
17
+ static blue: Color4;
18
+ static purple: Color4;
19
+ static yellow: Color4;
20
+ static clay: Color4;
21
+ static black: Color4;
22
+ static white: Color4;
23
+ }
@@ -0,0 +1,102 @@
1
+ export default class Color4 {
2
+ constructor(r, g, b, a) {
3
+ this.r = r;
4
+ this.g = g;
5
+ this.b = b;
6
+ this.a = a;
7
+ this.hexString = null;
8
+ }
9
+ // Each component should be in the range [0, 1]
10
+ static ofRGB(red, green, blue) {
11
+ return new Color4(red, green, blue, 1.0);
12
+ }
13
+ static ofRGBA(red, green, blue, alpha) {
14
+ return new Color4(red, green, blue, alpha);
15
+ }
16
+ static fromHex(hexString) {
17
+ var _a;
18
+ // Remove starting '#' (if present)
19
+ hexString = ((_a = hexString.match(/^[#]?(.*)$/)) !== null && _a !== void 0 ? _a : [])[1];
20
+ hexString = hexString.toUpperCase();
21
+ if (!hexString.match(/^[0-9A-F]+$/)) {
22
+ throw new Error(`${hexString} is not in a valid format.`);
23
+ }
24
+ // RGBA or RGB
25
+ if (hexString.length === 3 || hexString.length === 4) {
26
+ // Each character is a component
27
+ const components = hexString.split('');
28
+ // Convert to RRGGBBAA or RRGGBB format
29
+ hexString = components.map(component => `${component}0`).join('');
30
+ }
31
+ if (hexString.length === 6) {
32
+ // Alpha component
33
+ hexString += 'FF';
34
+ }
35
+ const components = [];
36
+ for (let i = 2; i <= hexString.length; i += 2) {
37
+ const chunk = hexString.substring(i - 2, i);
38
+ components.push(parseInt(chunk, 16) / 255);
39
+ }
40
+ if (components.length !== 4) {
41
+ throw new Error(`Unable to parse ${hexString}: Wrong number of components.`);
42
+ }
43
+ return new Color4(components[0], components[1], components[2], components[3]);
44
+ }
45
+ // Like fromHex, but can handle additional colors if an HTML5Canvas is available.
46
+ static fromString(text) {
47
+ if (text.startsWith('#')) {
48
+ return Color4.fromHex(text);
49
+ }
50
+ else {
51
+ // Otherwise, try to use an HTML5Canvas to determine the color
52
+ const canvas = document.createElement('canvas');
53
+ canvas.width = 1;
54
+ canvas.height = 1;
55
+ const ctx = canvas.getContext('2d');
56
+ ctx.fillStyle = text;
57
+ ctx.fillRect(0, 0, 1, 1);
58
+ const data = ctx.getImageData(0, 0, 1, 1);
59
+ const red = data.data[0] / 255;
60
+ const green = data.data[1] / 255;
61
+ const blue = data.data[2] / 255;
62
+ const alpha = data.data[3] / 255;
63
+ return Color4.ofRGBA(red, green, blue, alpha);
64
+ }
65
+ }
66
+ eq(other) {
67
+ if (other == null) {
68
+ return false;
69
+ }
70
+ return this.toHexString() === other.toHexString();
71
+ }
72
+ toHexString() {
73
+ if (this.hexString) {
74
+ return this.hexString;
75
+ }
76
+ const componentToHex = (component) => {
77
+ const res = Math.round(255 * component).toString(16);
78
+ if (res.length === 1) {
79
+ return `0${res}`;
80
+ }
81
+ return res;
82
+ };
83
+ const alpha = componentToHex(this.a);
84
+ const red = componentToHex(this.r);
85
+ const green = componentToHex(this.g);
86
+ const blue = componentToHex(this.b);
87
+ if (alpha === 'ff') {
88
+ return `#${red}${green}${blue}`;
89
+ }
90
+ this.hexString = `#${red}${green}${blue}${alpha}`;
91
+ return this.hexString;
92
+ }
93
+ }
94
+ Color4.transparent = Color4.ofRGBA(0, 0, 0, 0);
95
+ Color4.red = Color4.ofRGB(1.0, 0.0, 0.0);
96
+ Color4.green = Color4.ofRGB(0.0, 1.0, 0.0);
97
+ Color4.blue = Color4.ofRGB(0.0, 0.0, 1.0);
98
+ Color4.purple = Color4.ofRGB(0.5, 0.2, 0.5);
99
+ Color4.yellow = Color4.ofRGB(1, 1, 0.1);
100
+ Color4.clay = Color4.ofRGB(0.8, 0.4, 0.2);
101
+ Color4.black = Color4.ofRGB(0, 0, 0);
102
+ Color4.white = Color4.ofRGB(1, 1, 1);
@@ -0,0 +1,22 @@
1
+ import AbstractRenderer from './rendering/AbstractRenderer';
2
+ import { Editor } from './Editor';
3
+ export declare enum RenderingMode {
4
+ DummyRenderer = 0,
5
+ CanvasRenderer = 1
6
+ }
7
+ export default class Display {
8
+ private editor;
9
+ private parent;
10
+ private dryInkRenderer;
11
+ private wetInkRenderer;
12
+ private resizeSurfacesCallback?;
13
+ private flattenCallback?;
14
+ constructor(editor: Editor, mode: RenderingMode, parent: HTMLElement | null);
15
+ get width(): number;
16
+ get height(): number;
17
+ private initializeCanvasRendering;
18
+ startRerender(): AbstractRenderer;
19
+ getDryInkRenderer(): AbstractRenderer;
20
+ getWetInkRenderer(): AbstractRenderer;
21
+ flatten(): void;
22
+ }
@@ -0,0 +1,93 @@
1
+ import CanvasRenderer from './rendering/CanvasRenderer';
2
+ import { EditorEventType } from './types';
3
+ import DummyRenderer from './rendering/DummyRenderer';
4
+ import { Vec2 } from './geometry/Vec2';
5
+ export var RenderingMode;
6
+ (function (RenderingMode) {
7
+ RenderingMode[RenderingMode["DummyRenderer"] = 0] = "DummyRenderer";
8
+ RenderingMode[RenderingMode["CanvasRenderer"] = 1] = "CanvasRenderer";
9
+ // SVGRenderer is not supported by the main display
10
+ })(RenderingMode || (RenderingMode = {}));
11
+ export default class Display {
12
+ constructor(editor, mode, parent) {
13
+ this.editor = editor;
14
+ this.parent = parent;
15
+ if (mode === RenderingMode.CanvasRenderer) {
16
+ this.initializeCanvasRendering();
17
+ }
18
+ else {
19
+ this.dryInkRenderer = new DummyRenderer(editor.viewport);
20
+ this.wetInkRenderer = new DummyRenderer(editor.viewport);
21
+ }
22
+ this.editor.notifier.on(EditorEventType.DisplayResized, event => {
23
+ var _a;
24
+ if (event.kind !== EditorEventType.DisplayResized) {
25
+ throw new Error('Mismatched event.kinds!');
26
+ }
27
+ (_a = this.resizeSurfacesCallback) === null || _a === void 0 ? void 0 : _a.call(this);
28
+ });
29
+ }
30
+ // Returns the visible width of the display (e.g. how much
31
+ // space the display's element takes up in the x direction
32
+ // in the DOM).
33
+ get width() {
34
+ return this.dryInkRenderer.displaySize().x;
35
+ }
36
+ get height() {
37
+ return this.dryInkRenderer.displaySize().y;
38
+ }
39
+ initializeCanvasRendering() {
40
+ const dryInkCanvas = document.createElement('canvas');
41
+ const wetInkCanvas = document.createElement('canvas');
42
+ const dryInkCtx = dryInkCanvas.getContext('2d');
43
+ const wetInkCtx = wetInkCanvas.getContext('2d');
44
+ this.dryInkRenderer = new CanvasRenderer(dryInkCtx, this.editor.viewport);
45
+ this.wetInkRenderer = new CanvasRenderer(wetInkCtx, this.editor.viewport);
46
+ dryInkCanvas.className = 'dryInkCanvas';
47
+ wetInkCanvas.className = 'wetInkCanvas';
48
+ if (this.parent) {
49
+ this.parent.appendChild(dryInkCanvas);
50
+ this.parent.appendChild(wetInkCanvas);
51
+ }
52
+ this.resizeSurfacesCallback = () => {
53
+ const hasSizeMismatch = (canvas) => {
54
+ return canvas.clientHeight !== canvas.height || canvas.clientWidth !== canvas.width;
55
+ };
56
+ // Ensure that the drawing surfaces sizes match the
57
+ // canvas' sizes to prevent stretching.
58
+ if (hasSizeMismatch(dryInkCanvas) || hasSizeMismatch(wetInkCanvas)) {
59
+ dryInkCanvas.width = dryInkCanvas.clientWidth;
60
+ dryInkCanvas.height = dryInkCanvas.clientHeight;
61
+ wetInkCanvas.width = wetInkCanvas.clientWidth;
62
+ wetInkCanvas.height = wetInkCanvas.clientHeight;
63
+ this.editor.notifier.dispatch(EditorEventType.DisplayResized, {
64
+ kind: EditorEventType.DisplayResized,
65
+ newSize: Vec2.of(this.width, this.height),
66
+ });
67
+ }
68
+ };
69
+ this.resizeSurfacesCallback();
70
+ this.flattenCallback = () => {
71
+ dryInkCtx.drawImage(wetInkCanvas, 0, 0);
72
+ };
73
+ }
74
+ // Clears the drawing surfaces and otherwise prepares for a rerender.
75
+ startRerender() {
76
+ var _a;
77
+ (_a = this.resizeSurfacesCallback) === null || _a === void 0 ? void 0 : _a.call(this);
78
+ this.wetInkRenderer.clear();
79
+ this.dryInkRenderer.clear();
80
+ return this.dryInkRenderer;
81
+ }
82
+ getDryInkRenderer() {
83
+ return this.dryInkRenderer;
84
+ }
85
+ getWetInkRenderer() {
86
+ return this.wetInkRenderer;
87
+ }
88
+ // Re-renders the contents of the wetInkRenderer onto the dryInkRenderer
89
+ flatten() {
90
+ var _a;
91
+ (_a = this.flattenCallback) === null || _a === void 0 ? void 0 : _a.call(this);
92
+ }
93
+ }