js-draw 0.0.4 → 0.0.5
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/CHANGELOG.md +6 -0
- package/README.md +95 -0
- package/build_tools/BundledFile.ts +167 -0
- package/build_tools/bundle.ts +11 -0
- package/dist/build_tools/BundledFile.d.ts +13 -0
- package/dist/build_tools/BundledFile.js +157 -0
- package/dist/build_tools/bundle.d.ts +1 -0
- package/dist/build_tools/bundle.js +5 -0
- package/dist/bundle.js +1 -0
- package/dist/src/Display.js +4 -1
- package/dist/src/Editor.d.ts +8 -1
- package/dist/src/Editor.js +22 -5
- package/dist/src/bundle/bundled.d.ts +4 -0
- package/dist/src/bundle/bundled.js +5 -0
- package/dist/src/localization.d.ts +1 -1
- package/dist/src/localization.js +2 -2
- package/dist/src/toolbar/HTMLToolbar.d.ts +1 -2
- package/dist/src/toolbar/HTMLToolbar.js +2 -20
- package/dist/src/toolbar/localization.d.ts +20 -0
- package/dist/src/toolbar/localization.js +19 -0
- package/dist/src/toolbar/types.d.ts +0 -19
- package/dist/src/tools/SelectionTool.js +2 -1
- package/dist-test/test-dist-bundle.html +35 -0
- package/package.json +12 -3
- package/src/Display.ts +3 -1
- package/src/Editor.css +0 -1
- package/src/Editor.ts +42 -10
- package/src/EditorImage.test.ts +5 -3
- package/src/bundle/bundled.ts +7 -0
- package/src/localization.ts +2 -3
- package/src/toolbar/HTMLToolbar.ts +2 -24
- package/src/toolbar/localization.ts +44 -0
- package/src/toolbar/types.ts +0 -22
- package/src/tools/SelectionTool.test.ts +1 -1
- package/src/tools/SelectionTool.ts +1 -1
@@ -0,0 +1,35 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<meta name="viewport" content="width=device-width,initial-scale=1.0"/>
|
5
|
+
<meta charset="utf-8"/>
|
6
|
+
<title>Editor from a bundle</title>
|
7
|
+
<style>
|
8
|
+
body .imageEditorContainer {
|
9
|
+
height: 800px;
|
10
|
+
|
11
|
+
--primary-background-color: green;
|
12
|
+
--primary-background-color-transparent: rgba(255, 240, 200, 0.5);
|
13
|
+
--secondary-background-color: yellow;
|
14
|
+
--primary-foreground-color: black;
|
15
|
+
--secondary-foreground-color: black;
|
16
|
+
}
|
17
|
+
</style>
|
18
|
+
</head>
|
19
|
+
<body>
|
20
|
+
<p>
|
21
|
+
This file tests the bundled version of <code>js-draw</code>.
|
22
|
+
Be sure to run <code>yarn build</code> before opening this!
|
23
|
+
</p>
|
24
|
+
<script src="../dist/bundle.js"></script>
|
25
|
+
<script>
|
26
|
+
const editor1 = new jsdraw.Editor(document.body, {
|
27
|
+
wheelEventsEnabled: false,
|
28
|
+
});
|
29
|
+
editor1.addToolbar();
|
30
|
+
|
31
|
+
const editor2 = new jsdraw.Editor(document.body);
|
32
|
+
editor2.addToolbar();
|
33
|
+
</script>
|
34
|
+
</body>
|
35
|
+
</html>
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "js-draw",
|
3
|
-
"version": "0.0.
|
3
|
+
"version": "0.0.5",
|
4
4
|
"description": "Draw pictures using a pen, touchscreen, or mouse! JS-draw is a drawing library for JavaScript and TypeScript. ",
|
5
5
|
"main": "dist/src/Editor.js",
|
6
6
|
"types": "dist/src/Editor.d.ts",
|
@@ -29,6 +29,9 @@
|
|
29
29
|
},
|
30
30
|
"./toolbar/toolbar.css": {
|
31
31
|
"default": "./src/toolbar/toolbar.css"
|
32
|
+
},
|
33
|
+
"./bundle": {
|
34
|
+
"default": "./dist/bundle.js"
|
32
35
|
}
|
33
36
|
},
|
34
37
|
"repository": {
|
@@ -40,7 +43,7 @@
|
|
40
43
|
"private": false,
|
41
44
|
"scripts": {
|
42
45
|
"test": "jest",
|
43
|
-
"build": "yarn tsc",
|
46
|
+
"build": "rm -rf ./dist; mkdir dist && yarn tsc && ts-node ./build_tools/bundle.ts",
|
44
47
|
"lint": "eslint .",
|
45
48
|
"linter-precommit": "eslint --fix --ext .js --ext .ts",
|
46
49
|
"lint-staged": "lint-staged",
|
@@ -59,6 +62,7 @@
|
|
59
62
|
"@types/node": "^18.7.9",
|
60
63
|
"@typescript-eslint/eslint-plugin": "^5.33.1",
|
61
64
|
"@typescript-eslint/parser": "^5.33.1",
|
65
|
+
"css-loader": "^6.7.1",
|
62
66
|
"eslint": "^8.22.0",
|
63
67
|
"husky": "^8.0.1",
|
64
68
|
"jest": "^28.1.3",
|
@@ -66,8 +70,13 @@
|
|
66
70
|
"jsdom": "^20.0.0",
|
67
71
|
"lint-staged": "^13.0.3",
|
68
72
|
"pinst": "^3.0.0",
|
73
|
+
"style-loader": "^3.3.1",
|
74
|
+
"terser-webpack-plugin": "^5.3.5",
|
69
75
|
"ts-jest": "^28.0.8",
|
70
|
-
"
|
76
|
+
"ts-loader": "^9.3.1",
|
77
|
+
"ts-node": "^10.9.1",
|
78
|
+
"typescript": "^4.7.4",
|
79
|
+
"webpack": "^5.74.0"
|
71
80
|
},
|
72
81
|
"bugs": {
|
73
82
|
"url": "https://github.com/personalizedrefrigerator/js-draw/issues"
|
package/src/Display.ts
CHANGED
@@ -22,9 +22,11 @@ export default class Display {
|
|
22
22
|
) {
|
23
23
|
if (mode === RenderingMode.CanvasRenderer) {
|
24
24
|
this.initializeCanvasRendering();
|
25
|
-
} else {
|
25
|
+
} else if (mode === RenderingMode.DummyRenderer) {
|
26
26
|
this.dryInkRenderer = new DummyRenderer(editor.viewport);
|
27
27
|
this.wetInkRenderer = new DummyRenderer(editor.viewport);
|
28
|
+
} else {
|
29
|
+
throw new Error(`Unknown rendering mode, ${mode}!`);
|
28
30
|
}
|
29
31
|
|
30
32
|
|
package/src/Editor.css
CHANGED
package/src/Editor.ts
CHANGED
@@ -19,6 +19,19 @@ import Mat33 from './geometry/Mat33';
|
|
19
19
|
import Rect2 from './geometry/Rect2';
|
20
20
|
import { defaultEditorLocalization, EditorLocalization } from './localization';
|
21
21
|
|
22
|
+
export interface EditorSettings {
|
23
|
+
// Defaults to RenderingMode.CanvasRenderer
|
24
|
+
renderingMode: RenderingMode,
|
25
|
+
|
26
|
+
// Uses a default English localization if a translation is not given.
|
27
|
+
localization: Partial<EditorLocalization>,
|
28
|
+
|
29
|
+
// True if touchpad/mousewheel scrolling should scroll the editor instead of the document.
|
30
|
+
// This does not include pinch-zoom events.
|
31
|
+
// Defaults to true.
|
32
|
+
wheelEventsEnabled: boolean;
|
33
|
+
}
|
34
|
+
|
22
35
|
export class Editor {
|
23
36
|
// Wrapper around the viewport and toolbar
|
24
37
|
private container: HTMLElement;
|
@@ -39,23 +52,29 @@ export class Editor {
|
|
39
52
|
private loadingWarning: HTMLElement;
|
40
53
|
private accessibilityAnnounceArea: HTMLElement;
|
41
54
|
|
55
|
+
private settings: EditorSettings;
|
56
|
+
|
42
57
|
public constructor(
|
43
58
|
parent: HTMLElement,
|
44
|
-
|
45
|
-
|
46
|
-
// Uses a default English localization if a translation is not given.
|
47
|
-
localization?: Partial<EditorLocalization>,
|
59
|
+
settings: Partial<EditorSettings> = {},
|
48
60
|
) {
|
61
|
+
this.localization = {
|
62
|
+
...this.localization,
|
63
|
+
...settings.localization,
|
64
|
+
};
|
65
|
+
|
66
|
+
// Fill default settings.
|
67
|
+
this.settings = {
|
68
|
+
wheelEventsEnabled: settings.wheelEventsEnabled ?? true,
|
69
|
+
renderingMode: settings.renderingMode ?? RenderingMode.CanvasRenderer,
|
70
|
+
localization: this.localization,
|
71
|
+
};
|
72
|
+
|
49
73
|
this.container = document.createElement('div');
|
50
74
|
this.renderingRegion = document.createElement('div');
|
51
75
|
this.container.appendChild(this.renderingRegion);
|
52
76
|
this.container.className = 'imageEditorContainer';
|
53
77
|
|
54
|
-
this.localization = {
|
55
|
-
...this.localization,
|
56
|
-
...localization,
|
57
|
-
};
|
58
|
-
|
59
78
|
this.loadingWarning = document.createElement('div');
|
60
79
|
this.loadingWarning.classList.add('loadingMessage');
|
61
80
|
this.loadingWarning.ariaLive = 'polite';
|
@@ -74,7 +93,7 @@ export class Editor {
|
|
74
93
|
this.notifier = new EventDispatcher();
|
75
94
|
this.importExportViewport = new Viewport(this.notifier);
|
76
95
|
this.viewport = new Viewport(this.notifier);
|
77
|
-
this.display = new Display(this, renderingMode, this.renderingRegion);
|
96
|
+
this.display = new Display(this, this.settings.renderingMode, this.renderingRegion);
|
78
97
|
this.image = new EditorImage();
|
79
98
|
this.history = new UndoRedoHistory(this, this.announceRedoCallback, this.announceUndoCallback);
|
80
99
|
this.toolController = new ToolController(this, this.localization);
|
@@ -93,6 +112,13 @@ export class Editor {
|
|
93
112
|
this.hideLoadingWarning();
|
94
113
|
}
|
95
114
|
|
115
|
+
// Returns a reference to this' container.
|
116
|
+
// Example usage:
|
117
|
+
// editor.getRootElement().style.height = '500px';
|
118
|
+
public getRootElement(): HTMLElement {
|
119
|
+
return this.container;
|
120
|
+
}
|
121
|
+
|
96
122
|
// [fractionLoaded] should be a number from 0 to 1, where 1 represents completely loaded.
|
97
123
|
public showLoadingWarning(fractionLoaded: number) {
|
98
124
|
const loadingPercent = Math.round(fractionLoaded * 100);
|
@@ -210,6 +236,12 @@ export class Editor {
|
|
210
236
|
this.container.addEventListener('wheel', evt => {
|
211
237
|
let delta = Vec3.of(evt.deltaX, evt.deltaY, evt.deltaZ);
|
212
238
|
|
239
|
+
// Process wheel events if the ctrl key is down -- we do want to handle
|
240
|
+
// pinch-zooming.
|
241
|
+
if (!this.settings.wheelEventsEnabled && !evt.ctrlKey) {
|
242
|
+
return;
|
243
|
+
}
|
244
|
+
|
213
245
|
if (evt.deltaMode === WheelEvent.DOM_DELTA_LINE) {
|
214
246
|
delta = delta.times(15);
|
215
247
|
} else if (evt.deltaMode === WheelEvent.DOM_DELTA_PAGE) {
|
package/src/EditorImage.test.ts
CHANGED
@@ -10,6 +10,8 @@ import { RenderingMode } from './Display';
|
|
10
10
|
import DummyRenderer from './rendering/DummyRenderer';
|
11
11
|
import { RenderingStyle } from './rendering/AbstractRenderer';
|
12
12
|
|
13
|
+
const createEditor = () => new Editor(document.body, { renderingMode: RenderingMode.DummyRenderer });
|
14
|
+
|
13
15
|
describe('EditorImage', () => {
|
14
16
|
const testStroke = new Stroke([
|
15
17
|
{
|
@@ -29,7 +31,7 @@ describe('EditorImage', () => {
|
|
29
31
|
const addTestStrokeCommand = new EditorImage.AddElementCommand(testStroke);
|
30
32
|
|
31
33
|
it('elements added to the image should be findable', () => {
|
32
|
-
const editor =
|
34
|
+
const editor = createEditor();
|
33
35
|
const image = editor.image;
|
34
36
|
|
35
37
|
// We haven't activated the command, so testStroke's parent should be null.
|
@@ -39,7 +41,7 @@ describe('EditorImage', () => {
|
|
39
41
|
});
|
40
42
|
|
41
43
|
it('should render an element added to the image', () => {
|
42
|
-
const editor =
|
44
|
+
const editor = createEditor();
|
43
45
|
const renderer = editor.display.getDryInkRenderer();
|
44
46
|
if (!(renderer instanceof DummyRenderer)) {
|
45
47
|
throw new Error('Wrong display type!');
|
@@ -56,7 +58,7 @@ describe('EditorImage', () => {
|
|
56
58
|
});
|
57
59
|
|
58
60
|
it('should have a 1-deep tree if two non-overlapping strokes are added', () => {
|
59
|
-
const editor =
|
61
|
+
const editor = createEditor();
|
60
62
|
const image = editor.image;
|
61
63
|
|
62
64
|
const leftmostStroke = new Stroke([
|
package/src/localization.ts
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
import { CommandLocalization, defaultCommandLocalization } from './commands/localization';
|
2
2
|
import { defaultComponentLocalization, ImageComponentLocalization } from './components/localization';
|
3
|
-
import
|
4
|
-
import { ToolbarLocalization } from './toolbar/types';
|
3
|
+
import { defaultToolbarLocalization, ToolbarLocalization } from './toolbar/localization';
|
5
4
|
import { defaultToolLocalization, ToolLocalization } from './tools/localization';
|
6
5
|
|
7
6
|
|
@@ -14,7 +13,7 @@ export interface EditorLocalization extends ToolbarLocalization, ToolLocalizatio
|
|
14
13
|
}
|
15
14
|
|
16
15
|
export const defaultEditorLocalization: EditorLocalization = {
|
17
|
-
...
|
16
|
+
...defaultToolbarLocalization,
|
18
17
|
...defaultToolLocalization,
|
19
18
|
...defaultCommandLocalization,
|
20
19
|
...defaultComponentLocalization,
|
@@ -8,7 +8,6 @@ import Pen from '../tools/Pen';
|
|
8
8
|
import Eraser from '../tools/Eraser';
|
9
9
|
import BaseTool from '../tools/BaseTool';
|
10
10
|
import SelectionTool from '../tools/SelectionTool';
|
11
|
-
import { ToolbarLocalization } from './types';
|
12
11
|
import { makeFreehandLineBuilder } from '../components/builders/FreehandLineBuilder';
|
13
12
|
import { Vec2 } from '../geometry/Vec2';
|
14
13
|
import SVGRenderer from '../rendering/SVGRenderer';
|
@@ -18,6 +17,7 @@ import { ComponentBuilderFactory } from '../components/builders/types';
|
|
18
17
|
import { makeArrowBuilder } from '../components/builders/ArrowBuilder';
|
19
18
|
import { makeLineBuilder } from '../components/builders/LineBuilder';
|
20
19
|
import { makeFilledRectangleBuilder, makeOutlinedRectangleBuilder } from '../components/builders/RectangleBuilder';
|
20
|
+
import { defaultToolbarLocalization, ToolbarLocalization } from './localization';
|
21
21
|
|
22
22
|
const primaryForegroundFill = `
|
23
23
|
style='fill: var(--primary-foreground-color);'
|
@@ -533,31 +533,9 @@ export default class HTMLToolbar {
|
|
533
533
|
private container: HTMLElement;
|
534
534
|
private penTypes: PenTypeRecord[];
|
535
535
|
|
536
|
-
public static defaultLocalization: ToolbarLocalization = {
|
537
|
-
pen: 'Pen',
|
538
|
-
eraser: 'Eraser',
|
539
|
-
select: 'Select',
|
540
|
-
touchDrawing: 'Touch Drawing',
|
541
|
-
thicknessLabel: 'Thickness: ',
|
542
|
-
colorLabel: 'Color: ',
|
543
|
-
resizeImageToSelection: 'Resize image to selection',
|
544
|
-
undo: 'Undo',
|
545
|
-
redo: 'Redo',
|
546
|
-
selectObjectType: 'Object type: ',
|
547
|
-
|
548
|
-
freehandPen: 'Freehand',
|
549
|
-
arrowPen: 'Arrow',
|
550
|
-
linePen: 'Line',
|
551
|
-
outlinedRectanglePen: 'Outlined rectangle',
|
552
|
-
filledRectanglePen: 'Filled rectangle',
|
553
|
-
|
554
|
-
dropdownShown: (toolName) => `Dropdown for ${toolName} shown`,
|
555
|
-
dropdownHidden: (toolName) => `Dropdown for ${toolName} hidden`,
|
556
|
-
};
|
557
|
-
|
558
536
|
public constructor(
|
559
537
|
private editor: Editor, parent: HTMLElement,
|
560
|
-
private localizationTable: ToolbarLocalization =
|
538
|
+
private localizationTable: ToolbarLocalization = defaultToolbarLocalization,
|
561
539
|
) {
|
562
540
|
this.container = document.createElement('div');
|
563
541
|
this.container.classList.add(`${toolbarCSSPrefix}root`);
|
@@ -0,0 +1,44 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
export interface ToolbarLocalization {
|
4
|
+
outlinedRectanglePen: string;
|
5
|
+
filledRectanglePen: string;
|
6
|
+
linePen: string;
|
7
|
+
arrowPen: string;
|
8
|
+
freehandPen: string;
|
9
|
+
selectObjectType: string;
|
10
|
+
colorLabel: string;
|
11
|
+
pen: string;
|
12
|
+
eraser: string;
|
13
|
+
select: string;
|
14
|
+
touchDrawing: string;
|
15
|
+
thicknessLabel: string;
|
16
|
+
resizeImageToSelection: string;
|
17
|
+
undo: string;
|
18
|
+
redo: string;
|
19
|
+
|
20
|
+
dropdownShown: (toolName: string)=>string;
|
21
|
+
dropdownHidden: (toolName: string)=>string;
|
22
|
+
}
|
23
|
+
|
24
|
+
export const defaultToolbarLocalization: ToolbarLocalization = {
|
25
|
+
pen: 'Pen',
|
26
|
+
eraser: 'Eraser',
|
27
|
+
select: 'Select',
|
28
|
+
touchDrawing: 'Touch Drawing',
|
29
|
+
thicknessLabel: 'Thickness: ',
|
30
|
+
colorLabel: 'Color: ',
|
31
|
+
resizeImageToSelection: 'Resize image to selection',
|
32
|
+
undo: 'Undo',
|
33
|
+
redo: 'Redo',
|
34
|
+
selectObjectType: 'Object type: ',
|
35
|
+
|
36
|
+
freehandPen: 'Freehand',
|
37
|
+
arrowPen: 'Arrow',
|
38
|
+
linePen: 'Line',
|
39
|
+
outlinedRectanglePen: 'Outlined rectangle',
|
40
|
+
filledRectanglePen: 'Filled rectangle',
|
41
|
+
|
42
|
+
dropdownShown: (toolName) => `Dropdown for ${toolName} shown`,
|
43
|
+
dropdownHidden: (toolName) => `Dropdown for ${toolName} hidden`,
|
44
|
+
};
|
package/src/toolbar/types.ts
CHANGED
@@ -2,25 +2,3 @@ export enum ToolbarButtonType {
|
|
2
2
|
ToggleButton,
|
3
3
|
ActionButton,
|
4
4
|
}
|
5
|
-
|
6
|
-
|
7
|
-
export interface ToolbarLocalization {
|
8
|
-
outlinedRectanglePen: string;
|
9
|
-
filledRectanglePen: string;
|
10
|
-
linePen: string;
|
11
|
-
arrowPen: string;
|
12
|
-
freehandPen: string;
|
13
|
-
selectObjectType: string;
|
14
|
-
colorLabel: string;
|
15
|
-
pen: string;
|
16
|
-
eraser: string;
|
17
|
-
select: string;
|
18
|
-
touchDrawing: string;
|
19
|
-
thicknessLabel: string;
|
20
|
-
resizeImageToSelection: string;
|
21
|
-
undo: string;
|
22
|
-
redo: string;
|
23
|
-
|
24
|
-
dropdownShown: (toolName: string)=>string;
|
25
|
-
dropdownHidden: (toolName: string)=>string;
|
26
|
-
}
|
@@ -15,7 +15,7 @@ const getSelectionTool = (editor: Editor): SelectionTool => {
|
|
15
15
|
return editor.toolController.getMatchingTools(ToolType.Selection)[0] as SelectionTool;
|
16
16
|
};
|
17
17
|
|
18
|
-
const createEditor = () => new Editor(document.body, RenderingMode.DummyRenderer);
|
18
|
+
const createEditor = () => new Editor(document.body, { renderingMode: RenderingMode.DummyRenderer });
|
19
19
|
|
20
20
|
const createSquareStroke = () => {
|
21
21
|
const testStroke = new Stroke([
|