js-draw 0.0.3 → 0.0.6

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 (87) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +108 -0
  3. package/build_tools/BundledFile.ts +167 -0
  4. package/build_tools/bundle.ts +11 -0
  5. package/dist/build_tools/BundledFile.d.ts +13 -0
  6. package/dist/build_tools/BundledFile.js +157 -0
  7. package/dist/build_tools/bundle.d.ts +1 -0
  8. package/dist/build_tools/bundle.js +5 -0
  9. package/dist/bundle.js +1 -0
  10. package/dist/src/Display.js +4 -1
  11. package/dist/src/Editor.d.ts +9 -2
  12. package/dist/src/Editor.js +36 -7
  13. package/dist/src/EditorImage.d.ts +4 -2
  14. package/dist/src/EditorImage.js +29 -5
  15. package/dist/src/Pointer.js +1 -1
  16. package/dist/src/SVGLoader.js +3 -1
  17. package/dist/src/Viewport.d.ts +2 -2
  18. package/dist/src/bundle/bundled.d.ts +4 -0
  19. package/dist/src/bundle/bundled.js +5 -0
  20. package/dist/src/components/AbstractComponent.d.ts +1 -1
  21. package/dist/src/components/Stroke.d.ts +1 -1
  22. package/dist/src/components/Stroke.js +1 -1
  23. package/dist/src/components/UnknownSVGObject.d.ts +1 -1
  24. package/dist/src/components/builders/ArrowBuilder.d.ts +17 -0
  25. package/dist/src/components/builders/ArrowBuilder.js +83 -0
  26. package/dist/src/{StrokeBuilder.d.ts → components/builders/FreehandLineBuilder.d.ts} +9 -13
  27. package/dist/src/{StrokeBuilder.js → components/builders/FreehandLineBuilder.js} +42 -12
  28. package/dist/src/components/builders/LineBuilder.d.ts +16 -0
  29. package/dist/src/components/builders/LineBuilder.js +57 -0
  30. package/dist/src/components/builders/RectangleBuilder.d.ts +18 -0
  31. package/dist/src/components/builders/RectangleBuilder.js +41 -0
  32. package/dist/src/components/builders/types.d.ts +12 -0
  33. package/dist/src/components/builders/types.js +1 -0
  34. package/dist/src/geometry/Path.d.ts +1 -0
  35. package/dist/src/geometry/Path.js +43 -0
  36. package/dist/src/geometry/Vec3.d.ts +2 -0
  37. package/dist/src/geometry/Vec3.js +13 -0
  38. package/dist/src/localization.d.ts +1 -1
  39. package/dist/src/localization.js +2 -2
  40. package/dist/src/rendering/AbstractRenderer.js +3 -25
  41. package/dist/src/toolbar/HTMLToolbar.d.ts +5 -3
  42. package/dist/src/toolbar/HTMLToolbar.js +139 -30
  43. package/dist/src/toolbar/localization.d.ts +20 -0
  44. package/dist/src/toolbar/localization.js +19 -0
  45. package/dist/src/toolbar/types.d.ts +0 -13
  46. package/dist/src/tools/Pen.d.ts +13 -3
  47. package/dist/src/tools/Pen.js +37 -28
  48. package/dist/src/tools/SelectionTool.js +1 -1
  49. package/dist/src/tools/ToolController.js +3 -3
  50. package/dist/src/types.d.ts +14 -2
  51. package/dist/src/types.js +1 -0
  52. package/dist-test/test-dist-bundle.html +35 -0
  53. package/package.json +15 -5
  54. package/src/Display.ts +3 -1
  55. package/src/Editor.css +0 -1
  56. package/src/Editor.ts +62 -13
  57. package/src/EditorImage.test.ts +5 -3
  58. package/src/EditorImage.ts +31 -3
  59. package/src/Pointer.ts +1 -1
  60. package/src/SVGLoader.ts +5 -1
  61. package/src/Viewport.ts +1 -1
  62. package/src/bundle/bundled.ts +7 -0
  63. package/src/components/AbstractComponent.ts +1 -1
  64. package/src/components/Stroke.ts +2 -2
  65. package/src/components/UnknownSVGObject.ts +1 -1
  66. package/src/components/builders/ArrowBuilder.ts +104 -0
  67. package/src/{StrokeBuilder.ts → components/builders/FreehandLineBuilder.ts} +59 -22
  68. package/src/components/builders/LineBuilder.ts +75 -0
  69. package/src/components/builders/RectangleBuilder.ts +59 -0
  70. package/src/components/builders/types.ts +15 -0
  71. package/src/geometry/Path.fromString.test.ts +11 -24
  72. package/src/geometry/Path.ts +56 -0
  73. package/src/geometry/Vec2.test.ts +1 -0
  74. package/src/geometry/Vec3.test.ts +14 -0
  75. package/src/geometry/Vec3.ts +16 -0
  76. package/src/localization.ts +2 -3
  77. package/src/rendering/AbstractRenderer.ts +3 -32
  78. package/src/{editorStyles.js → styles.js} +0 -0
  79. package/src/toolbar/HTMLToolbar.ts +167 -39
  80. package/src/toolbar/localization.ts +44 -0
  81. package/src/toolbar/toolbar.css +12 -0
  82. package/src/toolbar/types.ts +0 -16
  83. package/src/tools/Pen.ts +56 -34
  84. package/src/tools/SelectionTool.test.ts +1 -1
  85. package/src/tools/SelectionTool.ts +1 -1
  86. package/src/tools/ToolController.ts +3 -3
  87. package/src/types.ts +16 -1
package/CHANGELOG.md CHANGED
@@ -1,3 +1,20 @@
1
1
 
2
+ # 0.0.6
3
+ * Fixes a bug that caused saved images to grow in size after loading them, then re-saving.
4
+ * Stops the pressure decrease on pen-up events from preventing line/arrow objects from having variable width.
5
+
6
+ # 0.0.5
7
+ * Configuration options:
8
+ - Ability to disable touch panning
9
+ - The `new Editor(container, ...)` constructor now takes a configuration object as its second argument.
10
+ * A pre-bundled version of `js-draw` is now distributed.
11
+
12
+ # 0.0.4
13
+ * Preset shapes
14
+ * Arrow
15
+ * Filled rectangle
16
+ * Outlined rectangle
17
+ * Line
18
+
2
19
  # 0.0.2
3
20
  * Adjust default editor colors based on system theme.
package/README.md CHANGED
@@ -12,6 +12,7 @@ To use `js-draw`,
12
12
 
13
13
  ## Creating an `Editor`
14
14
 
15
+ ### With a bundler that supports importing `.css` files
15
16
  To create a new `Editor` and add it as a child of `document.body`,
16
17
  ```ts
17
18
  import Editor from 'js-draw';
@@ -22,6 +23,30 @@ const editor = new Editor(document.body);
22
23
 
23
24
  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/)
24
25
 
26
+ ### With a bundler that doesn't support importing `.css` files
27
+ Import the pre-bundled version of the editor to apply CSS after loading the page.
28
+ ```ts
29
+ import Editor from 'js-draw';
30
+ import 'js-draw/bundle';
31
+
32
+ const editor = new Editor(document.body);
33
+ ```
34
+ `js-draw/bundle` is a version of the editor pre-processed by `Webpack`. As such, `import`ing it applies editor-specific CSS to the document.
35
+
36
+ ### Without a bundler
37
+ If you're not using a bundler, consider using the pre-bundled editor:
38
+ ```html
39
+ <!-- Replace 0.0.5 with the latest version of js-draw -->
40
+ <script src="https://cdn.jsdelivr.net/npm/js-draw@0.0.5/dist/bundle.js"></script>
41
+ <script>
42
+ const editor = new jsdraw.Editor(document.body);
43
+ editor.addToolbar();
44
+ editor.getRootElement().style.height = '600px';
45
+ </script>
46
+ ```
47
+
48
+ **Note**: To ensure the CDN-hosted version of `js-draw` hasn't been tampered with, consider [including an `integrity="..."` attribute](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity). [Read more about using SRI with JSDelivr](https://www.jsdelivr.com/using-sri-with-dynamic-files).
49
+
25
50
 
26
51
  ## Adding a toolbar
27
52
 
@@ -74,3 +99,86 @@ but exports to
74
99
 
75
100
  which **does** contain the `<circle/>` element.
76
101
 
102
+ ## Settings/configuration
103
+ ### Disabling touchpad panning
104
+
105
+ Touchpad/mousewheel pan gestures can conflict with gestures used to scroll the document. To turn off touchpad pan gestures (and scrolling the editor with the mousewheel),
106
+ ```ts
107
+ const editor = new Editor(document.body, {
108
+ wheelEventsEnabled: false,
109
+ });
110
+ ```
111
+
112
+ ### Localization
113
+
114
+ See [src/localization.ts](src/localization.ts) for a list of strings.
115
+
116
+ Some of the default strings in the editor might be overridden like this:
117
+ ```ts
118
+ const editor = new Editor(document.body, {
119
+ // Example partial Spanish localization
120
+ localization: {
121
+ // Not all translated strings need to be specified. If a string isn't given,
122
+ // the English (default) localization will be used
123
+
124
+ // Strings for the main editor interface
125
+ // (see src/localization.ts)
126
+ loading: (percentage: number) => `Cargando: ${percentage}%...`,
127
+ imageEditor: 'Editor de dibujos',
128
+
129
+ undoAnnouncement: (commandDescription: string) => `${commandDescription} fue deshecho`,
130
+ redoAnnouncement: (commandDescription: string) => `${commandDescription} fue rehecho`,
131
+
132
+ // Strings for the toolbar
133
+ // (see src/toolbar/localization.ts)
134
+ pen: 'Lapiz',
135
+ eraser: 'Borrador',
136
+ select: 'Selecciona',
137
+ touchDrawing: 'Dibuja con un dedo',
138
+ thicknessLabel: 'Tamaño: ',
139
+ colorLabel: 'Color: ',
140
+
141
+ ...
142
+ },
143
+ });
144
+ ```
145
+
146
+
147
+ ## Changing the editor's color theme
148
+
149
+ The editor's color theme is specified using CSS. Its default theme looks like this:
150
+ ```css
151
+ .imageEditorContainer {
152
+ /* Deafult colors for the editor -- light mode */
153
+
154
+ --primary-background-color: white;
155
+ --primary-background-color-transparent: rgba(255, 255, 255, 0.5);
156
+ --secondary-background-color: #faf;
157
+ --primary-foreground-color: black;
158
+ --secondary-foreground-color: black;
159
+ }
160
+
161
+ @media (prefers-color-scheme: dark) {
162
+ .imageEditorContainer {
163
+ /* Deafult colors for the editor -- dark mode */
164
+
165
+ --primary-background-color: #151515;
166
+ --primary-background-color-transparent: rgba(50, 50, 50, 0.5);
167
+ --secondary-background-color: #607;
168
+ --primary-foreground-color: white;
169
+ --secondary-foreground-color: white;
170
+ }
171
+ }
172
+ ```
173
+
174
+ To override it, use a more specific CSS selector to set the theme variables. For example,
175
+ ```css
176
+ body .imageEditorContainer {
177
+ --primary-background-color: green;
178
+ --primary-background-color-transparent: rgba(255, 240, 200, 0.5);
179
+ --secondary-background-color: yellow;
180
+ --primary-foreground-color: black;
181
+ --secondary-foreground-color: black;
182
+ }
183
+ ```
184
+ disables the dark theme and creates a theme that primarially uses yellow/green colors.
@@ -0,0 +1,167 @@
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
+
5
+ import { dirname, extname, basename } from 'path';
6
+ import TerserPlugin from 'terser-webpack-plugin';
7
+
8
+ import webpack from 'webpack';
9
+
10
+ export default class BundledFile {
11
+ private readonly bundleBaseName: string;
12
+ private readonly rootFileDirectory: string;
13
+ private readonly outputDirectory: string;
14
+ private readonly outputFilename: string;
15
+
16
+ public constructor(
17
+ public readonly bundleName: string,
18
+ private readonly sourceFilePath: string,
19
+ outputFilepath?: string,
20
+ ) {
21
+ this.rootFileDirectory = dirname(sourceFilePath);
22
+ this.bundleBaseName = basename(sourceFilePath, extname(sourceFilePath));
23
+
24
+ if (outputFilepath) {
25
+ this.outputDirectory = dirname(outputFilepath);
26
+ this.outputFilename = basename(outputFilepath);
27
+ } else {
28
+ this.outputDirectory = this.rootFileDirectory;
29
+ this.outputFilename = `${this.bundleBaseName}.bundle.js`;
30
+ }
31
+ }
32
+
33
+ private getWebpackOptions(mode: 'production' | 'development'): webpack.Configuration {
34
+ const config: webpack.Configuration = {
35
+ mode,
36
+ entry: this.sourceFilePath,
37
+ output: {
38
+ path: this.outputDirectory,
39
+ filename: this.outputFilename,
40
+
41
+ library: {
42
+ type: 'window',
43
+ name: this.bundleName,
44
+ },
45
+ },
46
+ // See https://webpack.js.org/guides/typescript/
47
+ module: {
48
+ rules: [
49
+ {
50
+ // Include .tsx to include react components
51
+ test: /\.tsx?$/i,
52
+ use: 'ts-loader',
53
+ exclude: /node_modules/,
54
+ },
55
+ {
56
+ test: /\.css$/i,
57
+ use: ['style-loader', 'css-loader'],
58
+ },
59
+ ],
60
+ },
61
+ optimization: {
62
+ minimizer: [
63
+ // Don't create separate files for comments.
64
+ // See https://stackoverflow.com/a/65650316/17055750
65
+ new TerserPlugin({
66
+ extractComments: false,
67
+ }),
68
+ ],
69
+ },
70
+ // Increase the minimum size required
71
+ // to trigger warnings.
72
+ // See https://stackoverflow.com/a/53517149/17055750
73
+ performance: {
74
+ maxAssetSize: 2_000_000, // 2-ish MiB
75
+ maxEntrypointSize: 2_000_000,
76
+ },
77
+ resolve: {
78
+ extensions: ['.tsx', '.ts', '.js'],
79
+ },
80
+ };
81
+
82
+ return config;
83
+ }
84
+
85
+ private handleErrors(err: Error | undefined | null, stats: webpack.Stats | undefined): boolean {
86
+ let failed = false;
87
+
88
+ if (err) {
89
+ console.error(`Error: ${err.name}`, err.message, err.stack);
90
+ failed = true;
91
+ } else if (stats?.hasErrors() || stats?.hasWarnings()) {
92
+ const data = stats.toJson();
93
+
94
+ if (data.warnings && data.warningsCount) {
95
+ console.warn('Warnings: ', data.warningsCount);
96
+ for (const warning of data.warnings) {
97
+ // Stack contains the message
98
+ if (warning.stack) {
99
+ console.warn(warning.stack);
100
+ } else {
101
+ console.warn(warning.message);
102
+ }
103
+ }
104
+ }
105
+ if (data.errors && data.errorsCount) {
106
+ console.error('Errors: ', data.errorsCount);
107
+ for (const error of data.errors) {
108
+ if (error.stack) {
109
+ console.error(error.stack);
110
+ } else {
111
+ console.error(error.message);
112
+ }
113
+ console.error();
114
+ }
115
+
116
+ failed = true;
117
+ }
118
+ }
119
+
120
+ return failed;
121
+ }
122
+
123
+ // Create a minified JS file in the same directory as `this.sourceFilePath` with
124
+ // the same name.
125
+ public build() {
126
+ const compiler = webpack(this.getWebpackOptions('production'));
127
+ return new Promise<void>((resolve, reject) => {
128
+ console.info(`Building bundle: ${this.bundleName}...`);
129
+
130
+ compiler.run((err, stats) => {
131
+ let failed = this.handleErrors(err, stats);
132
+
133
+ // Clean up.
134
+ compiler.close(async (error) => {
135
+ if (error) {
136
+ console.error('Error cleaning up:', error);
137
+ failed = true;
138
+ }
139
+ if (!failed) {
140
+ console.log('☑ Done building! ☑');
141
+ resolve();
142
+ } else {
143
+ reject();
144
+ }
145
+ });
146
+ });
147
+ });
148
+ }
149
+
150
+ public startWatching() {
151
+ const compiler = webpack(this.getWebpackOptions('development'));
152
+ const watchOptions = {
153
+ ignored: [
154
+ '**/node_modules',
155
+ '**/dist',
156
+ ],
157
+ };
158
+
159
+ console.info('Watching bundle: ', this.bundleName);
160
+ compiler.watch(watchOptions, async (err, stats) => {
161
+ const failed = this.handleErrors(err, stats);
162
+ if (!failed) {
163
+ console.log('☑ Built! ☑');
164
+ }
165
+ });
166
+ }
167
+ }
@@ -0,0 +1,11 @@
1
+ import { dirname } from 'path';
2
+ import BundledFile from './BundledFile';
3
+
4
+ const rootDir = dirname(__dirname);
5
+ const mainBundle = new BundledFile(
6
+ 'jsdraw',
7
+ `${rootDir}/src/bundle/bundled.ts`,
8
+ `${rootDir}/dist/bundle.js`,
9
+ );
10
+
11
+ void mainBundle.build();
@@ -0,0 +1,13 @@
1
+ export default class BundledFile {
2
+ readonly bundleName: string;
3
+ private readonly sourceFilePath;
4
+ private readonly bundleBaseName;
5
+ private readonly rootFileDirectory;
6
+ private readonly outputDirectory;
7
+ private readonly outputFilename;
8
+ constructor(bundleName: string, sourceFilePath: string, outputFilepath?: string);
9
+ private getWebpackOptions;
10
+ private handleErrors;
11
+ build(): Promise<void>;
12
+ startWatching(): void;
13
+ }
@@ -0,0 +1,157 @@
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, outputFilepath) {
18
+ this.bundleName = bundleName;
19
+ this.sourceFilePath = sourceFilePath;
20
+ this.rootFileDirectory = dirname(sourceFilePath);
21
+ this.bundleBaseName = basename(sourceFilePath, extname(sourceFilePath));
22
+ if (outputFilepath) {
23
+ this.outputDirectory = dirname(outputFilepath);
24
+ this.outputFilename = basename(outputFilepath);
25
+ }
26
+ else {
27
+ this.outputDirectory = this.rootFileDirectory;
28
+ this.outputFilename = `${this.bundleBaseName}.bundle.js`;
29
+ }
30
+ }
31
+ getWebpackOptions(mode) {
32
+ const config = {
33
+ mode,
34
+ entry: this.sourceFilePath,
35
+ output: {
36
+ path: this.outputDirectory,
37
+ filename: this.outputFilename,
38
+ library: {
39
+ type: 'window',
40
+ name: this.bundleName,
41
+ },
42
+ },
43
+ // See https://webpack.js.org/guides/typescript/
44
+ module: {
45
+ rules: [
46
+ {
47
+ // Include .tsx to include react components
48
+ test: /\.tsx?$/i,
49
+ use: 'ts-loader',
50
+ exclude: /node_modules/,
51
+ },
52
+ {
53
+ test: /\.css$/i,
54
+ use: ['style-loader', 'css-loader'],
55
+ },
56
+ ],
57
+ },
58
+ optimization: {
59
+ minimizer: [
60
+ // Don't create separate files for comments.
61
+ // See https://stackoverflow.com/a/65650316/17055750
62
+ new TerserPlugin({
63
+ extractComments: false,
64
+ }),
65
+ ],
66
+ },
67
+ // Increase the minimum size required
68
+ // to trigger warnings.
69
+ // See https://stackoverflow.com/a/53517149/17055750
70
+ performance: {
71
+ maxAssetSize: 2000000,
72
+ maxEntrypointSize: 2000000,
73
+ },
74
+ resolve: {
75
+ extensions: ['.tsx', '.ts', '.js'],
76
+ },
77
+ };
78
+ return config;
79
+ }
80
+ handleErrors(err, stats) {
81
+ let failed = false;
82
+ if (err) {
83
+ console.error(`Error: ${err.name}`, err.message, err.stack);
84
+ failed = true;
85
+ }
86
+ else if ((stats === null || stats === void 0 ? void 0 : stats.hasErrors()) || (stats === null || stats === void 0 ? void 0 : stats.hasWarnings())) {
87
+ const data = stats.toJson();
88
+ if (data.warnings && data.warningsCount) {
89
+ console.warn('Warnings: ', data.warningsCount);
90
+ for (const warning of data.warnings) {
91
+ // Stack contains the message
92
+ if (warning.stack) {
93
+ console.warn(warning.stack);
94
+ }
95
+ else {
96
+ console.warn(warning.message);
97
+ }
98
+ }
99
+ }
100
+ if (data.errors && data.errorsCount) {
101
+ console.error('Errors: ', data.errorsCount);
102
+ for (const error of data.errors) {
103
+ if (error.stack) {
104
+ console.error(error.stack);
105
+ }
106
+ else {
107
+ console.error(error.message);
108
+ }
109
+ console.error();
110
+ }
111
+ failed = true;
112
+ }
113
+ }
114
+ return failed;
115
+ }
116
+ // Create a minified JS file in the same directory as `this.sourceFilePath` with
117
+ // the same name.
118
+ build() {
119
+ const compiler = webpack(this.getWebpackOptions('production'));
120
+ return new Promise((resolve, reject) => {
121
+ console.info(`Building bundle: ${this.bundleName}...`);
122
+ compiler.run((err, stats) => {
123
+ let failed = this.handleErrors(err, stats);
124
+ // Clean up.
125
+ compiler.close((error) => __awaiter(this, void 0, void 0, function* () {
126
+ if (error) {
127
+ console.error('Error cleaning up:', error);
128
+ failed = true;
129
+ }
130
+ if (!failed) {
131
+ console.log('☑ Done building! ☑');
132
+ resolve();
133
+ }
134
+ else {
135
+ reject();
136
+ }
137
+ }));
138
+ });
139
+ });
140
+ }
141
+ startWatching() {
142
+ const compiler = webpack(this.getWebpackOptions('development'));
143
+ const watchOptions = {
144
+ ignored: [
145
+ '**/node_modules',
146
+ '**/dist',
147
+ ],
148
+ };
149
+ console.info('Watching bundle: ', this.bundleName);
150
+ compiler.watch(watchOptions, (err, stats) => __awaiter(this, void 0, void 0, function* () {
151
+ const failed = this.handleErrors(err, stats);
152
+ if (!failed) {
153
+ console.log('☑ Built! ☑');
154
+ }
155
+ }));
156
+ }
157
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,5 @@
1
+ import { dirname } from 'path';
2
+ import BundledFile from './BundledFile';
3
+ const rootDir = dirname(__dirname);
4
+ const mainBundle = new BundledFile('jsdraw', `${rootDir}/src/bundle/bundled.ts`, `${rootDir}/dist/bundle.js`);
5
+ void mainBundle.build();