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.
- package/.eslintrc.js +57 -0
- package/.husky/pre-commit +4 -0
- package/LICENSE +21 -0
- package/README.md +74 -0
- package/__mocks__/coloris.ts +8 -0
- package/__mocks__/styleMock.js +1 -0
- package/dist/__mocks__/coloris.d.ts +2 -0
- package/dist/__mocks__/coloris.js +5 -0
- package/dist/build_tools/BundledFile.d.ts +12 -0
- package/dist/build_tools/BundledFile.js +153 -0
- package/dist/scripts/bundle.d.ts +1 -0
- package/dist/scripts/bundle.js +19 -0
- package/dist/scripts/watchBundle.d.ts +1 -0
- package/dist/scripts/watchBundle.js +9 -0
- package/dist/src/Color4.d.ts +23 -0
- package/dist/src/Color4.js +102 -0
- package/dist/src/Display.d.ts +22 -0
- package/dist/src/Display.js +93 -0
- package/dist/src/Editor.d.ts +55 -0
- package/dist/src/Editor.js +366 -0
- package/dist/src/EditorImage.d.ts +44 -0
- package/dist/src/EditorImage.js +243 -0
- package/dist/src/EventDispatcher.d.ts +11 -0
- package/dist/src/EventDispatcher.js +39 -0
- package/dist/src/Pointer.d.ts +22 -0
- package/dist/src/Pointer.js +57 -0
- package/dist/src/SVGLoader.d.ts +21 -0
- package/dist/src/SVGLoader.js +204 -0
- package/dist/src/StrokeBuilder.d.ts +35 -0
- package/dist/src/StrokeBuilder.js +275 -0
- package/dist/src/UndoRedoHistory.d.ts +17 -0
- package/dist/src/UndoRedoHistory.js +46 -0
- package/dist/src/Viewport.d.ts +39 -0
- package/dist/src/Viewport.js +134 -0
- package/dist/src/commands/Command.d.ts +15 -0
- package/dist/src/commands/Command.js +29 -0
- package/dist/src/commands/Erase.d.ts +11 -0
- package/dist/src/commands/Erase.js +37 -0
- package/dist/src/commands/localization.d.ts +19 -0
- package/dist/src/commands/localization.js +17 -0
- package/dist/src/components/AbstractComponent.d.ts +19 -0
- package/dist/src/components/AbstractComponent.js +46 -0
- package/dist/src/components/Stroke.d.ts +16 -0
- package/dist/src/components/Stroke.js +79 -0
- package/dist/src/components/UnknownSVGObject.d.ts +15 -0
- package/dist/src/components/UnknownSVGObject.js +25 -0
- package/dist/src/components/localization.d.ts +5 -0
- package/dist/src/components/localization.js +4 -0
- package/dist/src/geometry/LineSegment2.d.ts +19 -0
- package/dist/src/geometry/LineSegment2.js +100 -0
- package/dist/src/geometry/Mat33.d.ts +31 -0
- package/dist/src/geometry/Mat33.js +187 -0
- package/dist/src/geometry/Path.d.ts +55 -0
- package/dist/src/geometry/Path.js +364 -0
- package/dist/src/geometry/Rect2.d.ts +47 -0
- package/dist/src/geometry/Rect2.js +148 -0
- package/dist/src/geometry/Vec2.d.ts +13 -0
- package/dist/src/geometry/Vec2.js +13 -0
- package/dist/src/geometry/Vec3.d.ts +32 -0
- package/dist/src/geometry/Vec3.js +98 -0
- package/dist/src/localization.d.ts +12 -0
- package/dist/src/localization.js +5 -0
- package/dist/src/main.d.ts +3 -0
- package/dist/src/main.js +4 -0
- package/dist/src/rendering/AbstractRenderer.d.ts +38 -0
- package/dist/src/rendering/AbstractRenderer.js +108 -0
- package/dist/src/rendering/CanvasRenderer.d.ts +23 -0
- package/dist/src/rendering/CanvasRenderer.js +108 -0
- package/dist/src/rendering/DummyRenderer.d.ts +25 -0
- package/dist/src/rendering/DummyRenderer.js +65 -0
- package/dist/src/rendering/SVGRenderer.d.ts +27 -0
- package/dist/src/rendering/SVGRenderer.js +122 -0
- package/dist/src/testing/loadExpectExtensions.d.ts +17 -0
- package/dist/src/testing/loadExpectExtensions.js +27 -0
- package/dist/src/toolbar/HTMLToolbar.d.ts +12 -0
- package/dist/src/toolbar/HTMLToolbar.js +444 -0
- package/dist/src/toolbar/types.d.ts +17 -0
- package/dist/src/toolbar/types.js +5 -0
- package/dist/src/tools/BaseTool.d.ts +20 -0
- package/dist/src/tools/BaseTool.js +44 -0
- package/dist/src/tools/Eraser.d.ts +16 -0
- package/dist/src/tools/Eraser.js +53 -0
- package/dist/src/tools/PanZoom.d.ts +40 -0
- package/dist/src/tools/PanZoom.js +191 -0
- package/dist/src/tools/Pen.d.ts +25 -0
- package/dist/src/tools/Pen.js +97 -0
- package/dist/src/tools/SelectionTool.d.ts +49 -0
- package/dist/src/tools/SelectionTool.js +437 -0
- package/dist/src/tools/ToolController.d.ts +18 -0
- package/dist/src/tools/ToolController.js +110 -0
- package/dist/src/tools/ToolEnabledGroup.d.ts +6 -0
- package/dist/src/tools/ToolEnabledGroup.js +11 -0
- package/dist/src/tools/localization.d.ts +10 -0
- package/dist/src/tools/localization.js +9 -0
- package/dist/src/types.d.ts +88 -0
- package/dist/src/types.js +20 -0
- package/jest.config.js +22 -0
- package/lint-staged.config.js +6 -0
- package/package.json +82 -0
- package/src/Color4.test.ts +12 -0
- package/src/Color4.ts +122 -0
- package/src/Display.ts +118 -0
- package/src/Editor.css +58 -0
- package/src/Editor.ts +469 -0
- package/src/EditorImage.test.ts +90 -0
- package/src/EditorImage.ts +297 -0
- package/src/EventDispatcher.test.ts +123 -0
- package/src/EventDispatcher.ts +53 -0
- package/src/Pointer.ts +93 -0
- package/src/SVGLoader.ts +230 -0
- package/src/StrokeBuilder.ts +362 -0
- package/src/UndoRedoHistory.ts +61 -0
- package/src/Viewport.ts +168 -0
- package/src/commands/Command.ts +43 -0
- package/src/commands/Erase.ts +52 -0
- package/src/commands/localization.ts +38 -0
- package/src/components/AbstractComponent.ts +73 -0
- package/src/components/Stroke.test.ts +18 -0
- package/src/components/Stroke.ts +102 -0
- package/src/components/UnknownSVGObject.ts +36 -0
- package/src/components/localization.ts +9 -0
- package/src/editorStyles.js +3 -0
- package/src/geometry/LineSegment2.test.ts +77 -0
- package/src/geometry/LineSegment2.ts +127 -0
- package/src/geometry/Mat33.test.ts +144 -0
- package/src/geometry/Mat33.ts +268 -0
- package/src/geometry/Path.fromString.test.ts +146 -0
- package/src/geometry/Path.test.ts +96 -0
- package/src/geometry/Path.toString.test.ts +31 -0
- package/src/geometry/Path.ts +456 -0
- package/src/geometry/Rect2.test.ts +121 -0
- package/src/geometry/Rect2.ts +215 -0
- package/src/geometry/Vec2.test.ts +32 -0
- package/src/geometry/Vec2.ts +18 -0
- package/src/geometry/Vec3.test.ts +29 -0
- package/src/geometry/Vec3.ts +133 -0
- package/src/localization.ts +27 -0
- package/src/rendering/AbstractRenderer.ts +164 -0
- package/src/rendering/CanvasRenderer.ts +141 -0
- package/src/rendering/DummyRenderer.ts +80 -0
- package/src/rendering/SVGRenderer.ts +159 -0
- package/src/testing/loadExpectExtensions.ts +43 -0
- package/src/toolbar/HTMLToolbar.ts +551 -0
- package/src/toolbar/toolbar.css +110 -0
- package/src/toolbar/types.ts +20 -0
- package/src/tools/BaseTool.ts +58 -0
- package/src/tools/Eraser.ts +67 -0
- package/src/tools/PanZoom.ts +253 -0
- package/src/tools/Pen.ts +121 -0
- package/src/tools/SelectionTool.test.ts +85 -0
- package/src/tools/SelectionTool.ts +545 -0
- package/src/tools/ToolController.ts +126 -0
- package/src/tools/ToolEnabledGroup.ts +14 -0
- package/src/tools/localization.ts +22 -0
- package/src/types.ts +133 -0
- 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
|
+
};
|
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
|
+

|
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
|
+

|
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 @@
|
|
1
|
+
module.exports = {};
|
@@ -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,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
|
+
}
|