js-draw 0.1.9 → 0.1.12
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 +18 -0
- package/README.md +15 -3
- package/dist/bundle.js +1 -1
- package/dist/src/Editor.d.ts +7 -2
- package/dist/src/Editor.js +74 -25
- package/dist/src/EditorImage.d.ts +1 -1
- package/dist/src/EditorImage.js +2 -2
- package/dist/src/Pointer.d.ts +1 -1
- package/dist/src/Pointer.js +1 -1
- package/dist/src/SVGLoader.d.ts +1 -1
- package/dist/src/SVGLoader.js +14 -6
- package/dist/src/UndoRedoHistory.js +3 -0
- package/dist/src/Viewport.d.ts +8 -25
- package/dist/src/Viewport.js +17 -10
- package/dist/src/bundle/bundled.d.ts +2 -1
- package/dist/src/bundle/bundled.js +2 -1
- package/dist/src/commands/Command.d.ts +2 -2
- package/dist/src/commands/Command.js +4 -4
- package/dist/src/commands/Duplicate.d.ts +1 -1
- package/dist/src/commands/Duplicate.js +1 -1
- package/dist/src/commands/Erase.d.ts +1 -1
- package/dist/src/commands/Erase.js +1 -1
- package/dist/src/commands/localization.d.ts +1 -1
- package/dist/src/components/AbstractComponent.d.ts +3 -3
- package/dist/src/components/AbstractComponent.js +2 -2
- package/dist/src/components/SVGGlobalAttributesObject.d.ts +3 -3
- package/dist/src/components/SVGGlobalAttributesObject.js +1 -1
- package/dist/src/components/Stroke.d.ts +4 -4
- package/dist/src/components/Stroke.js +2 -2
- package/dist/src/components/Text.d.ts +3 -3
- package/dist/src/components/Text.js +3 -3
- package/dist/src/components/UnknownSVGObject.d.ts +3 -3
- package/dist/src/components/UnknownSVGObject.js +1 -1
- package/dist/src/components/builders/ArrowBuilder.d.ts +1 -1
- package/dist/src/components/builders/ArrowBuilder.js +1 -1
- package/dist/src/components/builders/FreehandLineBuilder.d.ts +8 -3
- package/dist/src/components/builders/FreehandLineBuilder.js +142 -71
- package/dist/src/components/builders/LineBuilder.d.ts +1 -1
- package/dist/src/components/builders/LineBuilder.js +1 -1
- package/dist/src/components/builders/RectangleBuilder.d.ts +1 -1
- package/dist/src/components/builders/RectangleBuilder.js +3 -3
- package/dist/src/components/builders/types.d.ts +1 -1
- package/dist/src/localization.d.ts +1 -0
- package/dist/src/localization.js +5 -1
- package/dist/src/localizations/en.d.ts +3 -0
- package/dist/src/localizations/en.js +4 -0
- package/dist/src/localizations/es.d.ts +3 -0
- package/dist/src/localizations/es.js +18 -0
- package/dist/src/localizations/getLocalizationTable.d.ts +3 -0
- package/dist/src/localizations/getLocalizationTable.js +43 -0
- package/dist/src/{geometry → math}/LineSegment2.d.ts +1 -0
- package/dist/src/{geometry → math}/LineSegment2.js +16 -0
- package/dist/src/{geometry → math}/Mat33.d.ts +0 -0
- package/dist/src/{geometry → math}/Mat33.js +0 -0
- package/dist/src/{geometry → math}/Path.d.ts +2 -1
- package/dist/src/{geometry → math}/Path.js +58 -51
- package/dist/src/{geometry → math}/Rect2.d.ts +1 -0
- package/dist/src/{geometry → math}/Rect2.js +16 -0
- package/dist/src/{geometry → math}/Vec2.d.ts +0 -0
- package/dist/src/{geometry → math}/Vec2.js +0 -0
- package/dist/src/{geometry → math}/Vec3.d.ts +1 -1
- package/dist/src/{geometry → math}/Vec3.js +1 -1
- package/dist/src/math/rounding.d.ts +3 -0
- package/dist/src/math/rounding.js +120 -0
- package/dist/src/rendering/Display.d.ts +3 -1
- package/dist/src/rendering/Display.js +16 -10
- package/dist/src/rendering/caching/CacheRecord.d.ts +2 -2
- package/dist/src/rendering/caching/CacheRecord.js +1 -1
- package/dist/src/rendering/caching/CacheRecordManager.d.ts +1 -1
- package/dist/src/rendering/caching/RenderingCache.js +1 -1
- package/dist/src/rendering/caching/RenderingCacheNode.d.ts +2 -1
- package/dist/src/rendering/caching/RenderingCacheNode.js +18 -7
- package/dist/src/rendering/caching/testUtils.js +1 -1
- package/dist/src/rendering/caching/types.d.ts +1 -1
- package/dist/src/rendering/localization.d.ts +2 -0
- package/dist/src/rendering/localization.js +2 -0
- package/dist/src/rendering/renderers/AbstractRenderer.d.ts +4 -4
- package/dist/src/rendering/renderers/AbstractRenderer.js +2 -2
- package/dist/src/rendering/renderers/CanvasRenderer.d.ts +4 -4
- package/dist/src/rendering/renderers/CanvasRenderer.js +1 -1
- package/dist/src/rendering/renderers/DummyRenderer.d.ts +4 -4
- package/dist/src/rendering/renderers/DummyRenderer.js +1 -1
- package/dist/src/rendering/renderers/SVGRenderer.d.ts +3 -3
- package/dist/src/rendering/renderers/SVGRenderer.js +8 -2
- package/dist/src/rendering/renderers/TextOnlyRenderer.d.ts +5 -3
- package/dist/src/rendering/renderers/TextOnlyRenderer.js +13 -3
- package/dist/src/toolbar/HTMLToolbar.js +5 -7
- package/dist/src/toolbar/icons.d.ts +3 -0
- package/dist/src/toolbar/icons.js +152 -142
- package/dist/src/toolbar/localization.d.ts +4 -1
- package/dist/src/toolbar/localization.js +4 -1
- package/dist/src/toolbar/makeColorInput.js +2 -1
- package/dist/src/toolbar/widgets/ActionButtonWidget.d.ts +13 -0
- package/dist/src/toolbar/widgets/ActionButtonWidget.js +21 -0
- package/dist/src/toolbar/widgets/BaseWidget.js +31 -0
- package/dist/src/toolbar/widgets/HandToolWidget.js +10 -3
- package/dist/src/toolbar/widgets/SelectionWidget.d.ts +0 -1
- package/dist/src/toolbar/widgets/SelectionWidget.js +23 -30
- package/dist/src/tools/BaseTool.d.ts +2 -1
- package/dist/src/tools/BaseTool.js +3 -0
- package/dist/src/tools/Eraser.js +1 -1
- package/dist/src/tools/PanZoom.d.ts +3 -2
- package/dist/src/tools/PanZoom.js +32 -16
- package/dist/src/tools/SelectionTool.d.ts +11 -4
- package/dist/src/tools/SelectionTool.js +135 -23
- package/dist/src/tools/TextTool.js +1 -1
- package/dist/src/tools/ToolController.js +6 -2
- package/dist/src/tools/localization.d.ts +1 -0
- package/dist/src/tools/localization.js +1 -0
- package/dist/src/types.d.ts +13 -6
- package/dist/src/types.js +1 -0
- package/package.json +9 -1
- package/src/Editor.ts +86 -24
- package/src/EditorImage.test.ts +2 -4
- package/src/EditorImage.ts +2 -2
- package/src/Pointer.ts +1 -1
- package/src/SVGLoader.ts +14 -6
- package/src/UndoRedoHistory.ts +4 -0
- package/src/Viewport.ts +21 -17
- package/src/bundle/bundled.ts +2 -1
- package/src/commands/Command.ts +5 -5
- package/src/commands/Duplicate.ts +1 -1
- package/src/commands/Erase.ts +1 -1
- package/src/commands/localization.ts +1 -1
- package/src/components/AbstractComponent.ts +4 -4
- package/src/components/SVGGlobalAttributesObject.ts +3 -3
- package/src/components/Stroke.test.ts +3 -5
- package/src/components/Stroke.ts +4 -4
- package/src/components/Text.test.ts +2 -2
- package/src/components/Text.ts +3 -3
- package/src/components/UnknownSVGObject.ts +3 -3
- package/src/components/builders/ArrowBuilder.ts +2 -2
- package/src/components/builders/FreehandLineBuilder.ts +190 -80
- package/src/components/builders/LineBuilder.ts +2 -2
- package/src/components/builders/RectangleBuilder.ts +3 -3
- package/src/components/builders/types.ts +1 -1
- package/src/localization.ts +6 -0
- package/src/localizations/en.ts +8 -0
- package/src/localizations/es.ts +63 -0
- package/src/localizations/getLocalizationTable.test.ts +27 -0
- package/src/localizations/getLocalizationTable.ts +53 -0
- package/src/{geometry → math}/LineSegment2.test.ts +15 -0
- package/src/{geometry → math}/LineSegment2.ts +20 -0
- package/src/{geometry → math}/Mat33.test.ts +0 -0
- package/src/{geometry → math}/Mat33.ts +0 -0
- package/src/{geometry → math}/Path.fromString.test.ts +0 -0
- package/src/{geometry → math}/Path.test.ts +0 -0
- package/src/{geometry → math}/Path.toString.test.ts +11 -2
- package/src/{geometry → math}/Path.ts +60 -57
- package/src/{geometry → math}/Rect2.test.ts +20 -7
- package/src/{geometry → math}/Rect2.ts +19 -1
- package/src/{geometry → math}/Vec2.test.ts +0 -0
- package/src/{geometry → math}/Vec2.ts +0 -0
- package/src/{geometry → math}/Vec3.test.ts +0 -0
- package/src/{geometry → math}/Vec3.ts +2 -2
- package/src/math/rounding.test.ts +40 -0
- package/src/math/rounding.ts +145 -0
- package/src/rendering/Display.ts +18 -10
- package/src/rendering/caching/CacheRecord.test.ts +2 -2
- package/src/rendering/caching/CacheRecord.ts +2 -2
- package/src/rendering/caching/CacheRecordManager.ts +1 -1
- package/src/rendering/caching/RenderingCache.test.ts +3 -3
- package/src/rendering/caching/RenderingCache.ts +1 -1
- package/src/rendering/caching/RenderingCacheNode.ts +23 -7
- package/src/rendering/caching/testUtils.ts +1 -1
- package/src/rendering/caching/types.ts +1 -1
- package/src/rendering/localization.ts +4 -0
- package/src/rendering/renderers/AbstractRenderer.ts +4 -4
- package/src/rendering/renderers/CanvasRenderer.ts +4 -4
- package/src/rendering/renderers/DummyRenderer.test.ts +2 -2
- package/src/rendering/renderers/DummyRenderer.ts +4 -4
- package/src/rendering/renderers/SVGRenderer.ts +10 -4
- package/src/rendering/renderers/TextOnlyRenderer.ts +17 -6
- package/src/toolbar/HTMLToolbar.ts +5 -8
- package/src/toolbar/icons.ts +167 -147
- package/src/toolbar/localization.ts +8 -2
- package/src/toolbar/makeColorInput.ts +2 -1
- package/src/toolbar/toolbar.css +7 -3
- package/src/toolbar/widgets/ActionButtonWidget.ts +31 -0
- package/src/toolbar/widgets/BaseWidget.ts +36 -0
- package/src/toolbar/widgets/HandToolWidget.ts +14 -3
- package/src/toolbar/widgets/SelectionWidget.ts +46 -41
- package/src/tools/BaseTool.ts +5 -1
- package/src/tools/Eraser.ts +2 -2
- package/src/tools/PanZoom.ts +39 -18
- package/src/tools/SelectionTool.test.ts +26 -5
- package/src/tools/SelectionTool.ts +162 -27
- package/src/tools/TextTool.ts +2 -2
- package/src/tools/ToolController.ts +6 -2
- package/src/tools/UndoRedoShortcut.test.ts +1 -1
- package/src/tools/localization.ts +2 -0
- package/src/types.ts +14 -5
- package/dist-test/test-dist-bundle.html +0 -42
@@ -1,5 +1,5 @@
|
|
1
1
|
// Renderer that outputs nothing. Useful for automated tests.
|
2
|
-
import { Vec2 } from '../../
|
2
|
+
import { Vec2 } from '../../math/Vec2';
|
3
3
|
import AbstractRenderer from './AbstractRenderer';
|
4
4
|
export default class DummyRenderer extends AbstractRenderer {
|
5
5
|
constructor(viewport) {
|
@@ -1,8 +1,8 @@
|
|
1
1
|
import { LoadSaveDataTable } from '../../components/AbstractComponent';
|
2
2
|
import { TextStyle } from '../../components/Text';
|
3
|
-
import Mat33 from '../../
|
4
|
-
import Rect2 from '../../
|
5
|
-
import { Point2, Vec2 } from '../../
|
3
|
+
import Mat33 from '../../math/Mat33';
|
4
|
+
import Rect2 from '../../math/Rect2';
|
5
|
+
import { Point2, Vec2 } from '../../math/Vec2';
|
6
6
|
import Viewport from '../../Viewport';
|
7
7
|
import RenderingStyle from '../RenderingStyle';
|
8
8
|
import AbstractRenderer from './AbstractRenderer';
|
@@ -1,5 +1,7 @@
|
|
1
|
-
import
|
2
|
-
import {
|
1
|
+
import Mat33 from '../../math/Mat33';
|
2
|
+
import Path, { PathCommandType } from '../../math/Path';
|
3
|
+
import { toRoundedString } from '../../math/rounding';
|
4
|
+
import { Vec2 } from '../../math/Vec2';
|
3
5
|
import { svgAttributesDataKey, svgStyleAttributesDataKey } from '../../SVGLoader';
|
4
6
|
import AbstractRenderer from './AbstractRenderer';
|
5
7
|
const svgNameSpace = 'http://www.w3.org/2000/svg';
|
@@ -89,6 +91,8 @@ export default class SVGRenderer extends AbstractRenderer {
|
|
89
91
|
drawText(text, transform, style) {
|
90
92
|
var _a, _b, _c;
|
91
93
|
transform = this.getCanvasToScreenTransform().rightMul(transform);
|
94
|
+
const translation = transform.transformVec2(Vec2.zero);
|
95
|
+
transform = transform.rightMul(Mat33.translation(translation.times(-1)));
|
92
96
|
const textElem = document.createElementNS(svgNameSpace, 'text');
|
93
97
|
textElem.appendChild(document.createTextNode(text));
|
94
98
|
textElem.style.transform = `matrix(
|
@@ -101,6 +105,8 @@ export default class SVGRenderer extends AbstractRenderer {
|
|
101
105
|
textElem.style.fontWeight = (_b = style.fontWeight) !== null && _b !== void 0 ? _b : '';
|
102
106
|
textElem.style.fontSize = style.size + 'px';
|
103
107
|
textElem.style.fill = style.renderingStyle.fill.toHexString();
|
108
|
+
textElem.setAttribute('x', `${toRoundedString(translation.x)}`);
|
109
|
+
textElem.setAttribute('y', `${toRoundedString(translation.y)}`);
|
104
110
|
if (style.renderingStyle.stroke) {
|
105
111
|
const strokeStyle = style.renderingStyle.stroke;
|
106
112
|
textElem.style.stroke = strokeStyle.color.toHexString();
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import { TextStyle } from '../../components/Text';
|
2
|
-
import Mat33 from '../../
|
3
|
-
import Rect2 from '../../
|
4
|
-
import Vec3 from '../../
|
2
|
+
import Mat33 from '../../math/Mat33';
|
3
|
+
import Rect2 from '../../math/Rect2';
|
4
|
+
import Vec3 from '../../math/Vec3';
|
5
5
|
import Viewport from '../../Viewport';
|
6
6
|
import { TextRendererLocalization } from '../localization';
|
7
7
|
import RenderingStyle from '../RenderingStyle';
|
@@ -9,6 +9,8 @@ import AbstractRenderer from './AbstractRenderer';
|
|
9
9
|
export default class TextOnlyRenderer extends AbstractRenderer {
|
10
10
|
private localizationTable;
|
11
11
|
private descriptionBuilder;
|
12
|
+
private pathCount;
|
13
|
+
private textNodeCount;
|
12
14
|
constructor(viewport: Viewport, localizationTable: TextRendererLocalization);
|
13
15
|
displaySize(): Vec3;
|
14
16
|
clear(): void;
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import { Vec2 } from '../../
|
1
|
+
import { Vec2 } from '../../math/Vec2';
|
2
2
|
import AbstractRenderer from './AbstractRenderer';
|
3
3
|
// Outputs a description of what was rendered.
|
4
4
|
export default class TextOnlyRenderer extends AbstractRenderer {
|
@@ -6,6 +6,8 @@ export default class TextOnlyRenderer extends AbstractRenderer {
|
|
6
6
|
super(viewport);
|
7
7
|
this.localizationTable = localizationTable;
|
8
8
|
this.descriptionBuilder = [];
|
9
|
+
this.pathCount = 0;
|
10
|
+
this.textNodeCount = 0;
|
9
11
|
}
|
10
12
|
displaySize() {
|
11
13
|
// We don't have a graphical display, export a reasonable size.
|
@@ -13,13 +15,20 @@ export default class TextOnlyRenderer extends AbstractRenderer {
|
|
13
15
|
}
|
14
16
|
clear() {
|
15
17
|
this.descriptionBuilder = [];
|
18
|
+
this.pathCount = 0;
|
19
|
+
this.textNodeCount = 0;
|
16
20
|
}
|
17
21
|
getDescription() {
|
18
|
-
return
|
22
|
+
return [
|
23
|
+
this.localizationTable.pathNodeCount(this.pathCount),
|
24
|
+
this.localizationTable.textNodeCount(this.textNodeCount),
|
25
|
+
...this.descriptionBuilder
|
26
|
+
].join('\n');
|
19
27
|
}
|
20
28
|
beginPath(_startPoint) {
|
21
29
|
}
|
22
30
|
endPath(_style) {
|
31
|
+
this.pathCount++;
|
23
32
|
}
|
24
33
|
lineTo(_point) {
|
25
34
|
}
|
@@ -31,9 +40,10 @@ export default class TextOnlyRenderer extends AbstractRenderer {
|
|
31
40
|
}
|
32
41
|
drawText(text, _transform, _style) {
|
33
42
|
this.descriptionBuilder.push(this.localizationTable.textNode(text));
|
43
|
+
this.textNodeCount++;
|
34
44
|
}
|
35
45
|
isTooSmallToRender(rect) {
|
36
|
-
return rect.maxDimension <
|
46
|
+
return rect.maxDimension < 15 / this.getSizeOfCanvasPixelOnScreen();
|
37
47
|
}
|
38
48
|
drawPoints(..._points) {
|
39
49
|
}
|
@@ -108,13 +108,13 @@ export default class HTMLToolbar {
|
|
108
108
|
const undoRedoGroup = document.createElement('div');
|
109
109
|
undoRedoGroup.classList.add(`${toolbarCSSPrefix}buttonGroup`);
|
110
110
|
const undoButton = this.addActionButton({
|
111
|
-
label:
|
111
|
+
label: this.localizationTable.undo,
|
112
112
|
icon: makeUndoIcon()
|
113
113
|
}, () => {
|
114
114
|
this.editor.history.undo();
|
115
115
|
}, undoRedoGroup);
|
116
116
|
const redoButton = this.addActionButton({
|
117
|
-
label:
|
117
|
+
label: this.localizationTable.redo,
|
118
118
|
icon: makeRedoIcon(),
|
119
119
|
}, () => {
|
120
120
|
this.editor.history.redo();
|
@@ -157,11 +157,9 @@ export default class HTMLToolbar {
|
|
157
157
|
}
|
158
158
|
(new TextToolWidget(this.editor, tool, this.localizationTable)).addTo(this.container);
|
159
159
|
}
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
}
|
164
|
-
(new HandToolWidget(this.editor, tool, this.localizationTable)).addTo(this.container);
|
160
|
+
const panZoomTool = toolController.getMatchingTools(ToolType.PanZoom)[0];
|
161
|
+
if (panZoomTool && panZoomTool instanceof PanZoom) {
|
162
|
+
(new HandToolWidget(this.editor, panZoomTool, this.localizationTable)).addTo(this.container);
|
165
163
|
}
|
166
164
|
this.setupColorPickers();
|
167
165
|
}
|
@@ -15,3 +15,6 @@ export declare const makeTextIcon: (textStyle: TextStyle) => SVGSVGElement;
|
|
15
15
|
export declare const makePenIcon: (tipThickness: number, color: string) => SVGSVGElement;
|
16
16
|
export declare const makeIconFromFactory: (pen: Pen, factory: ComponentBuilderFactory) => SVGSVGElement;
|
17
17
|
export declare const makePipetteIcon: (color?: Color4) => SVGSVGElement;
|
18
|
+
export declare const makeResizeViewportIcon: () => SVGSVGElement;
|
19
|
+
export declare const makeDuplicateSelectionIcon: () => SVGSVGElement;
|
20
|
+
export declare const makeDeleteSelectionIcon: () => SVGSVGElement;
|
@@ -1,13 +1,13 @@
|
|
1
1
|
import EventDispatcher from '../EventDispatcher';
|
2
|
-
import { Vec2 } from '../
|
2
|
+
import { Vec2 } from '../math/Vec2';
|
3
3
|
import SVGRenderer from '../rendering/renderers/SVGRenderer';
|
4
4
|
import Viewport from '../Viewport';
|
5
5
|
const svgNamespace = 'http://www.w3.org/2000/svg';
|
6
|
-
const
|
7
|
-
style='fill: var(--
|
6
|
+
const iconColorFill = `
|
7
|
+
style='fill: var(--icon-color);'
|
8
8
|
`;
|
9
|
-
const
|
10
|
-
style='fill: var(--
|
9
|
+
const iconColorStrokeFill = `
|
10
|
+
style='fill: var(--icon-color); stroke: var(--icon-color);'
|
11
11
|
`;
|
12
12
|
const checkerboardPatternDef = `
|
13
13
|
<pattern
|
@@ -31,7 +31,7 @@ export const makeRedoIcon = (mirror = false) => {
|
|
31
31
|
icon.innerHTML = `
|
32
32
|
<style>
|
33
33
|
.toolbar-svg-undo-redo-icon {
|
34
|
-
stroke: var(--
|
34
|
+
stroke: var(--icon-color);
|
35
35
|
stroke-width: 12;
|
36
36
|
stroke-linejoin: round;
|
37
37
|
stroke-linecap: round;
|
@@ -54,7 +54,7 @@ export const makeDropdownIcon = () => {
|
|
54
54
|
<g>
|
55
55
|
<path
|
56
56
|
d='M5,10 L50,90 L95,10 Z'
|
57
|
-
${
|
57
|
+
${iconColorFill}
|
58
58
|
/>
|
59
59
|
</g>
|
60
60
|
`;
|
@@ -69,7 +69,7 @@ export const makeEraserIcon = () => {
|
|
69
69
|
<rect x=10 y=50 width=80 height=30 rx=10 fill='pink' />
|
70
70
|
<rect
|
71
71
|
x=10 y=10 width=80 height=50
|
72
|
-
${
|
72
|
+
${iconColorFill}
|
73
73
|
/>
|
74
74
|
</g>
|
75
75
|
`;
|
@@ -88,147 +88,130 @@ export const makeSelectionIcon = () => {
|
|
88
88
|
icon.setAttribute('viewBox', '0 0 100 100');
|
89
89
|
return icon;
|
90
90
|
};
|
91
|
-
|
91
|
+
const pathIcon = (pathData, fill = 'var(--icon-color)', strokeColor = 'none', strokeWidth = '0px') => {
|
92
92
|
const icon = document.createElementNS(svgNamespace, 'svg');
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
H 90
|
100
|
-
V 30
|
101
|
-
C 90,20 75,20 75,30
|
102
|
-
V 60
|
103
|
-
20
|
104
|
-
C 75,10 60,10 60,20
|
105
|
-
V 60
|
106
|
-
15
|
107
|
-
C 60,5 45,5 45,15
|
108
|
-
V 60
|
109
|
-
25
|
110
|
-
C 45,15 30,15 30,25
|
111
|
-
V 60
|
112
|
-
75
|
113
|
-
L 25,60
|
114
|
-
C 20,45 10,50 10,60
|
115
|
-
Z'
|
116
|
-
|
117
|
-
fill='none'
|
118
|
-
style='
|
119
|
-
stroke: var(--primary-foreground-color);
|
120
|
-
stroke-width: 2;
|
121
|
-
'
|
122
|
-
/>
|
123
|
-
</g>
|
124
|
-
`;
|
93
|
+
const path = document.createElementNS(svgNamespace, 'path');
|
94
|
+
path.setAttribute('d', pathData);
|
95
|
+
path.style.fill = fill;
|
96
|
+
path.style.stroke = strokeColor;
|
97
|
+
path.style.strokeWidth = strokeWidth;
|
98
|
+
icon.appendChild(path);
|
125
99
|
icon.setAttribute('viewBox', '0 0 100 100');
|
126
100
|
return icon;
|
127
101
|
};
|
102
|
+
export const makeHandToolIcon = () => {
|
103
|
+
const fill = 'none';
|
104
|
+
const strokeColor = 'var(--icon-color)';
|
105
|
+
const strokeWidth = '3';
|
106
|
+
// Draw a cursor-like shape (like some of the other icons, made with Inkscape)
|
107
|
+
return pathIcon(`
|
108
|
+
m 10,60
|
109
|
+
5,30
|
110
|
+
H 90
|
111
|
+
V 30
|
112
|
+
C 90,20 75,20 75,30
|
113
|
+
V 60
|
114
|
+
20
|
115
|
+
C 75,10 60,10 60,20
|
116
|
+
V 60
|
117
|
+
15
|
118
|
+
C 60,5 45,5 45,15
|
119
|
+
V 60
|
120
|
+
25
|
121
|
+
C 45,15 30,15 30,25
|
122
|
+
V 60
|
123
|
+
75
|
124
|
+
L 25,60
|
125
|
+
C 20,45 10,50 10,60
|
126
|
+
Z
|
127
|
+
`, fill, strokeColor, strokeWidth);
|
128
|
+
};
|
128
129
|
export const makeTouchPanningIcon = () => {
|
129
|
-
const
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
130
|
+
const fill = 'none';
|
131
|
+
const strokeColor = 'var(--icon-color)';
|
132
|
+
const strokeWidth = '3';
|
133
|
+
return pathIcon(`
|
134
|
+
M 5,5.5
|
135
|
+
V 17.2
|
136
|
+
L 16.25,5.46
|
137
|
+
Z
|
137
138
|
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
139
|
+
m 33.75,0
|
140
|
+
L 50,17
|
141
|
+
V 5.5
|
142
|
+
Z
|
142
143
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
fill='none'
|
160
|
-
style='
|
161
|
-
stroke: var(--primary-foreground-color);
|
162
|
-
stroke-width: 2;
|
163
|
-
'
|
164
|
-
/>
|
165
|
-
`;
|
166
|
-
icon.setAttribute('viewBox', '0 0 100 100');
|
167
|
-
return icon;
|
144
|
+
M 5,40.7
|
145
|
+
v 11.7
|
146
|
+
h 11.25
|
147
|
+
z
|
148
|
+
|
149
|
+
M 26,19
|
150
|
+
C 19.8,19.4 17.65,30.4 21.9,34.8
|
151
|
+
L 50,70
|
152
|
+
H 27.5
|
153
|
+
c -11.25,0 -11.25,17.6 0,17.6
|
154
|
+
H 61.25
|
155
|
+
C 94.9,87.8 95,87.6 95,40.7 78.125,23 67,29 55.6,46.5
|
156
|
+
L 33.1,23
|
157
|
+
C 30.3125,20.128192 27.9,19 25.830078,19.119756
|
158
|
+
Z
|
159
|
+
`, fill, strokeColor, strokeWidth);
|
168
160
|
};
|
169
161
|
export const makeAllDevicePanningIcon = () => {
|
170
|
-
const
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
M 42.5 5
|
181
|
-
L 55 17.5
|
182
|
-
55 5
|
183
|
-
42.5 5
|
184
|
-
z
|
185
|
-
|
186
|
-
M 70 10
|
187
|
-
L 70 21
|
188
|
-
61 15
|
189
|
-
55.5 23
|
190
|
-
66 30
|
191
|
-
56 37
|
192
|
-
61 45
|
193
|
-
70 39
|
194
|
-
70 50
|
195
|
-
80 50
|
196
|
-
80 39
|
197
|
-
89 45
|
198
|
-
95 36
|
199
|
-
84 30
|
200
|
-
95 23
|
201
|
-
89 15
|
202
|
-
80 21
|
203
|
-
80 10
|
204
|
-
70 10
|
205
|
-
z
|
162
|
+
const fill = 'none';
|
163
|
+
const strokeColor = 'var(--icon-color)';
|
164
|
+
const strokeWidth = '3';
|
165
|
+
return pathIcon(`
|
166
|
+
M 5 5
|
167
|
+
L 5 17.5
|
168
|
+
17.5 5
|
169
|
+
5 5
|
170
|
+
z
|
206
171
|
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
172
|
+
M 42.5 5
|
173
|
+
L 55 17.5
|
174
|
+
55 5
|
175
|
+
42.5 5
|
176
|
+
z
|
177
|
+
|
178
|
+
M 70 10
|
179
|
+
L 70 21
|
180
|
+
61 15
|
181
|
+
55.5 23
|
182
|
+
66 30
|
183
|
+
56 37
|
184
|
+
61 45
|
185
|
+
70 39
|
186
|
+
70 50
|
187
|
+
80 50
|
188
|
+
80 39
|
189
|
+
89 45
|
190
|
+
95 36
|
191
|
+
84 30
|
192
|
+
95 23
|
193
|
+
89 15
|
194
|
+
80 21
|
195
|
+
80 10
|
196
|
+
70 10
|
197
|
+
z
|
198
|
+
|
199
|
+
M 27.5 26.25
|
200
|
+
L 27.5 91.25
|
201
|
+
L 43.75 83.125
|
202
|
+
L 52 99
|
203
|
+
L 68 91
|
204
|
+
L 60 75
|
205
|
+
L 76.25 66.875
|
206
|
+
L 27.5 26.25
|
207
|
+
z
|
208
|
+
|
209
|
+
M 5 42.5
|
210
|
+
L 5 55
|
211
|
+
L 17.5 55
|
212
|
+
L 5 42.5
|
213
|
+
z
|
214
|
+
`, fill, strokeColor, strokeWidth);
|
232
215
|
};
|
233
216
|
export const makeZoomIcon = () => {
|
234
217
|
const icon = document.createElementNS(svgNamespace, 'svg');
|
@@ -241,7 +224,7 @@ export const makeZoomIcon = () => {
|
|
241
224
|
textNode.style.textAlign = 'center';
|
242
225
|
textNode.style.textAnchor = 'middle';
|
243
226
|
textNode.style.fontSize = '55px';
|
244
|
-
textNode.style.fill = 'var(--
|
227
|
+
textNode.style.fill = 'var(--icon-color)';
|
245
228
|
textNode.style.fontFamily = 'monospace';
|
246
229
|
icon.appendChild(textNode);
|
247
230
|
};
|
@@ -282,7 +265,7 @@ export const makePenIcon = (tipThickness, color) => {
|
|
282
265
|
<!-- Pen grip -->
|
283
266
|
<path
|
284
267
|
d='M10,10 L90,10 L90,60 L${50 + halfThickness},80 L${50 - halfThickness},80 L10,60 Z'
|
285
|
-
${
|
268
|
+
${iconColorStrokeFill}
|
286
269
|
/>
|
287
270
|
</g>
|
288
271
|
<g>
|
@@ -348,7 +331,7 @@ export const makePipetteIcon = (color) => {
|
|
348
331
|
65,15 65,5 47,6
|
349
332
|
Z
|
350
333
|
`);
|
351
|
-
pipette.style.fill = 'var(--
|
334
|
+
pipette.style.fill = 'var(--icon-color)';
|
352
335
|
if (color) {
|
353
336
|
const defs = document.createElementNS(svgNamespace, 'defs');
|
354
337
|
defs.innerHTML = checkerboardPatternDef;
|
@@ -369,3 +352,30 @@ export const makePipetteIcon = (color) => {
|
|
369
352
|
icon.setAttribute('viewBox', '0 0 100 100');
|
370
353
|
return icon;
|
371
354
|
};
|
355
|
+
export const makeResizeViewportIcon = () => {
|
356
|
+
return pathIcon(`
|
357
|
+
M 75 5 75 10 90 10 90 25 95 25 95 5 75 5 z
|
358
|
+
M 15 15 15 30 20 30 20 20 30 20 30 15 15 15 z
|
359
|
+
M 84 15 82 17 81 16 81 20 85 20 84 19 86 17 84 15 z
|
360
|
+
M 26 24 24 26 26 28 25 29 29 29 29 25 28 26 26 24 z
|
361
|
+
M 25 71 26 72 24 74 26 76 28 74 29 75 29 71 25 71 z
|
362
|
+
M 15 75 15 85 25 85 25 80 20 80 20 75 15 75 z
|
363
|
+
M 90 75 90 90 75 90 75 95 95 95 95 75 90 75 z
|
364
|
+
M 81 81 81 85 82 84 84 86 86 84 84 82 85 81 81 81 z
|
365
|
+
`);
|
366
|
+
};
|
367
|
+
export const makeDuplicateSelectionIcon = () => {
|
368
|
+
return pathIcon(`
|
369
|
+
M 45,10 45,55 90,55 90,10 45,10 z
|
370
|
+
M 10,25 10,90 70,90 70,60 40,60 40,25 10,25 z
|
371
|
+
`);
|
372
|
+
};
|
373
|
+
export const makeDeleteSelectionIcon = () => {
|
374
|
+
const strokeWidth = '5px';
|
375
|
+
const strokeColor = 'var(--icon-color)';
|
376
|
+
const fillColor = 'none';
|
377
|
+
return pathIcon(`
|
378
|
+
M 10,10 90,90
|
379
|
+
M 10,90 90,10
|
380
|
+
`, fillColor, strokeColor, strokeWidth);
|
381
|
+
};
|
@@ -17,10 +17,13 @@ export interface ToolbarLocalization {
|
|
17
17
|
resizeImageToSelection: string;
|
18
18
|
deleteSelection: string;
|
19
19
|
duplicateSelection: string;
|
20
|
-
|
20
|
+
pickColorFromScreen: string;
|
21
|
+
clickToPickColorAnnouncement: string;
|
21
22
|
undo: string;
|
22
23
|
redo: string;
|
23
24
|
zoom: string;
|
25
|
+
resetView: string;
|
26
|
+
selectionToolKeyboardShortcuts: string;
|
24
27
|
dropdownShown: (toolName: string) => string;
|
25
28
|
dropdownHidden: (toolName: string) => string;
|
26
29
|
zoomLevel: (zoomPercentage: number) => string;
|
@@ -4,6 +4,7 @@ export const defaultToolbarLocalization = {
|
|
4
4
|
select: 'Select',
|
5
5
|
handTool: 'Pan',
|
6
6
|
zoom: 'Zoom',
|
7
|
+
resetView: 'Reset view',
|
7
8
|
thicknessLabel: 'Thickness: ',
|
8
9
|
colorLabel: 'Color: ',
|
9
10
|
fontLabel: 'Font: ',
|
@@ -13,7 +14,9 @@ export const defaultToolbarLocalization = {
|
|
13
14
|
undo: 'Undo',
|
14
15
|
redo: 'Redo',
|
15
16
|
selectObjectType: 'Object type: ',
|
16
|
-
|
17
|
+
pickColorFromScreen: 'Pick color from screen',
|
18
|
+
clickToPickColorAnnouncement: 'Click on the screen to pick a color',
|
19
|
+
selectionToolKeyboardShortcuts: 'Selection tool: Use arrow keys to move selected items, lowercase/uppercase ‘i’ and ‘o’ to resize.',
|
17
20
|
touchPanning: 'Touchscreen panning',
|
18
21
|
anyDevicePanning: 'Any device panning',
|
19
22
|
freehandPen: 'Freehand',
|
@@ -53,7 +53,7 @@ export const makeColorInput = (editor, onColorChange) => {
|
|
53
53
|
const addPipetteTool = (editor, container, onColorChange) => {
|
54
54
|
const pipetteButton = document.createElement('button');
|
55
55
|
pipetteButton.classList.add('pipetteButton');
|
56
|
-
pipetteButton.title = editor.localization.
|
56
|
+
pipetteButton.title = editor.localization.pickColorFromScreen;
|
57
57
|
pipetteButton.setAttribute('alt', pipetteButton.title);
|
58
58
|
const updatePipetteIcon = (color) => {
|
59
59
|
pipetteButton.replaceChildren(makePipetteIcon(color));
|
@@ -88,6 +88,7 @@ const addPipetteTool = (editor, container, onColorChange) => {
|
|
88
88
|
pipetteTool === null || pipetteTool === void 0 ? void 0 : pipetteTool.setColorListener(pipetteColorPreview, pipetteColorSelect);
|
89
89
|
if (pipetteTool) {
|
90
90
|
pipetteButton.classList.add('active');
|
91
|
+
editor.announceForAccessibility(editor.localization.clickToPickColorAnnouncement);
|
91
92
|
}
|
92
93
|
};
|
93
94
|
container.appendChild(pipetteButton);
|
@@ -0,0 +1,13 @@
|
|
1
|
+
import Editor from '../../Editor';
|
2
|
+
import { ToolbarLocalization } from '../localization';
|
3
|
+
import BaseWidget from './BaseWidget';
|
4
|
+
export default class ActionButtonWidget extends BaseWidget {
|
5
|
+
protected makeIcon: () => Element;
|
6
|
+
protected title: string;
|
7
|
+
protected clickAction: () => void;
|
8
|
+
constructor(editor: Editor, localizationTable: ToolbarLocalization, makeIcon: () => Element, title: string, clickAction: () => void);
|
9
|
+
protected handleClick(): void;
|
10
|
+
protected getTitle(): string;
|
11
|
+
protected createIcon(): Element;
|
12
|
+
protected fillDropdown(_dropdown: HTMLElement): boolean;
|
13
|
+
}
|
@@ -0,0 +1,21 @@
|
|
1
|
+
import BaseWidget from './BaseWidget';
|
2
|
+
export default class ActionButtonWidget extends BaseWidget {
|
3
|
+
constructor(editor, localizationTable, makeIcon, title, clickAction) {
|
4
|
+
super(editor, localizationTable);
|
5
|
+
this.makeIcon = makeIcon;
|
6
|
+
this.title = title;
|
7
|
+
this.clickAction = clickAction;
|
8
|
+
}
|
9
|
+
handleClick() {
|
10
|
+
this.clickAction();
|
11
|
+
}
|
12
|
+
getTitle() {
|
13
|
+
return this.title;
|
14
|
+
}
|
15
|
+
createIcon() {
|
16
|
+
return this.makeIcon();
|
17
|
+
}
|
18
|
+
fillDropdown(_dropdown) {
|
19
|
+
return false;
|
20
|
+
}
|
21
|
+
}
|
@@ -10,6 +10,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
10
10
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
11
11
|
};
|
12
12
|
var _BaseWidget_hasDropdown;
|
13
|
+
import { InputEvtType } from '../../types';
|
13
14
|
import { toolbarCSSPrefix } from '../HTMLToolbar';
|
14
15
|
import { makeDropdownIcon } from '../icons';
|
15
16
|
export default class BaseWidget {
|
@@ -44,6 +45,34 @@ export default class BaseWidget {
|
|
44
45
|
return true;
|
45
46
|
}
|
46
47
|
setupActionBtnClickListener(button) {
|
48
|
+
const clickTriggers = { Enter: true, ' ': true, };
|
49
|
+
button.onkeydown = (evt) => {
|
50
|
+
let handled = false;
|
51
|
+
if (evt.key in clickTriggers) {
|
52
|
+
if (!this.disabled) {
|
53
|
+
this.handleClick();
|
54
|
+
handled = true;
|
55
|
+
}
|
56
|
+
}
|
57
|
+
// If we didn't do anything with the event, send it to the editor.
|
58
|
+
if (!handled) {
|
59
|
+
this.editor.toolController.dispatchInputEvent({
|
60
|
+
kind: InputEvtType.KeyPressEvent,
|
61
|
+
key: evt.key,
|
62
|
+
ctrlKey: evt.ctrlKey,
|
63
|
+
});
|
64
|
+
}
|
65
|
+
};
|
66
|
+
button.onkeyup = evt => {
|
67
|
+
if (evt.key in clickTriggers) {
|
68
|
+
return;
|
69
|
+
}
|
70
|
+
this.editor.toolController.dispatchInputEvent({
|
71
|
+
kind: InputEvtType.KeyUpEvent,
|
72
|
+
key: evt.key,
|
73
|
+
ctrlKey: evt.ctrlKey,
|
74
|
+
});
|
75
|
+
};
|
47
76
|
button.onclick = () => {
|
48
77
|
if (!this.disabled) {
|
49
78
|
this.handleClick();
|
@@ -85,9 +114,11 @@ export default class BaseWidget {
|
|
85
114
|
this.disabled = disabled;
|
86
115
|
if (this.disabled) {
|
87
116
|
this.button.classList.add('disabled');
|
117
|
+
this.button.setAttribute('aria-disabled', 'true');
|
88
118
|
}
|
89
119
|
else {
|
90
120
|
this.button.classList.remove('disabled');
|
121
|
+
this.button.removeAttribute('aria-disabled');
|
91
122
|
}
|
92
123
|
}
|
93
124
|
setSelected(selected) {
|