js-draw 1.22.0 → 1.23.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/README.md +1 -1
- package/dist/bundle.js +1 -1
- package/dist/cjs/Editor.d.ts +1 -3
- package/dist/cjs/Editor.js +2 -4
- package/dist/cjs/SVGLoader/SVGLoader.js +2 -0
- package/dist/cjs/Viewport.d.ts +1 -1
- package/dist/cjs/Viewport.js +1 -1
- package/dist/cjs/components/AbstractComponent.d.ts +1 -1
- package/dist/cjs/components/AbstractComponent.js +1 -1
- package/dist/cjs/components/builders/ArrowBuilder.d.ts +1 -1
- package/dist/cjs/components/builders/ArrowBuilder.js +1 -1
- package/dist/cjs/image/EditorImage.d.ts +30 -7
- package/dist/cjs/image/EditorImage.js +30 -7
- package/dist/cjs/rendering/renderers/CanvasRenderer.d.ts +2 -25
- package/dist/cjs/rendering/renderers/CanvasRenderer.js +2 -25
- package/dist/cjs/rendering/renderers/SVGRenderer.js +2 -2
- package/dist/cjs/toolbar/AbstractToolbar.d.ts +19 -0
- package/dist/cjs/toolbar/AbstractToolbar.js +19 -0
- package/dist/cjs/toolbar/IconProvider.d.ts +5 -1
- package/dist/cjs/toolbar/IconProvider.js +112 -146
- package/dist/cjs/toolbar/localization.js +2 -2
- package/dist/cjs/toolbar/widgets/BaseWidget.d.ts +1 -1
- package/dist/cjs/toolbar/widgets/BaseWidget.js +1 -1
- package/dist/cjs/tools/PanZoom.js +1 -1
- package/dist/cjs/tools/Pen.d.ts +13 -0
- package/dist/cjs/tools/Pen.js +13 -0
- package/dist/cjs/tools/lib.d.ts +1 -0
- package/dist/cjs/tools/lib.js +3 -1
- package/dist/cjs/util/cloneElementWithStyles.js +1 -1
- package/dist/cjs/util/createElement.d.ts +62 -0
- package/dist/cjs/util/createElement.js +53 -0
- package/dist/cjs/version.js +1 -1
- package/dist/mjs/Editor.d.ts +1 -3
- package/dist/mjs/Editor.mjs +2 -4
- package/dist/mjs/SVGLoader/SVGLoader.mjs +2 -0
- package/dist/mjs/Viewport.d.ts +1 -1
- package/dist/mjs/Viewport.mjs +1 -1
- package/dist/mjs/components/AbstractComponent.d.ts +1 -1
- package/dist/mjs/components/AbstractComponent.mjs +1 -1
- package/dist/mjs/components/builders/ArrowBuilder.d.ts +1 -1
- package/dist/mjs/components/builders/ArrowBuilder.mjs +1 -1
- package/dist/mjs/image/EditorImage.d.ts +30 -7
- package/dist/mjs/image/EditorImage.mjs +30 -7
- package/dist/mjs/rendering/renderers/CanvasRenderer.d.ts +2 -25
- package/dist/mjs/rendering/renderers/CanvasRenderer.mjs +2 -25
- package/dist/mjs/rendering/renderers/SVGRenderer.mjs +2 -2
- package/dist/mjs/toolbar/AbstractToolbar.d.ts +19 -0
- package/dist/mjs/toolbar/AbstractToolbar.mjs +19 -0
- package/dist/mjs/toolbar/IconProvider.d.ts +5 -1
- package/dist/mjs/toolbar/IconProvider.mjs +112 -146
- package/dist/mjs/toolbar/localization.mjs +2 -2
- package/dist/mjs/toolbar/widgets/BaseWidget.d.ts +1 -1
- package/dist/mjs/toolbar/widgets/BaseWidget.mjs +1 -1
- package/dist/mjs/tools/PanZoom.mjs +1 -1
- package/dist/mjs/tools/Pen.d.ts +13 -0
- package/dist/mjs/tools/Pen.mjs +13 -0
- package/dist/mjs/tools/lib.d.ts +1 -0
- package/dist/mjs/tools/lib.mjs +1 -0
- package/dist/mjs/util/cloneElementWithStyles.mjs +1 -1
- package/dist/mjs/util/createElement.d.ts +62 -0
- package/dist/mjs/util/createElement.mjs +47 -0
- package/dist/mjs/version.mjs +1 -1
- package/package.json +4 -4
@@ -10,31 +10,32 @@ import Viewport from '../Viewport.mjs';
|
|
10
10
|
import { makeFreehandLineBuilder } from '../components/builders/FreehandLineBuilder.mjs';
|
11
11
|
import { makePolylineBuilder } from '../components/builders/PolylineBuilder.mjs';
|
12
12
|
import { EraserMode } from '../tools/Eraser.mjs';
|
13
|
+
import { createSvgElement, createSvgElements, createSvgPaths } from '../util/createElement.mjs';
|
13
14
|
const svgNamespace = 'http://www.w3.org/2000/svg';
|
14
|
-
const iconColorFill = `
|
15
|
-
style='fill: var(--icon-color);'
|
16
|
-
`;
|
17
|
-
const iconColorStrokeFill = `
|
18
|
-
style='fill: var(--icon-color); stroke: var(--icon-color);'
|
19
|
-
`;
|
20
15
|
let checkerboardIdCounter = 0;
|
21
16
|
const makeCheckerboardPattern = () => {
|
22
17
|
const id = `checkerboard-${checkerboardIdCounter++}`;
|
23
|
-
const
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
`;
|
18
|
+
const patternElement = createSvgElement('pattern', {
|
19
|
+
id: id,
|
20
|
+
viewBox: '0,0,10,10',
|
21
|
+
width: '20%',
|
22
|
+
height: '20%',
|
23
|
+
patternUnits: 'userSpaceOnUse',
|
24
|
+
children: createSvgElements('rect', [
|
25
|
+
{ x: 0, y: 0, width: 10, height: 10, fill: 'white' },
|
26
|
+
{ x: 0, y: 0, width: 5, height: 5, fill: 'gray' },
|
27
|
+
{ x: 5, y: 5, width: 5, height: 5, fill: 'gray' },
|
28
|
+
]),
|
29
|
+
});
|
36
30
|
const patternRef = `url(#${id})`;
|
37
|
-
return {
|
31
|
+
return {
|
32
|
+
patternDefElement: patternElement,
|
33
|
+
// @deprecated use patternDefElement
|
34
|
+
get patternDef() {
|
35
|
+
return patternElement.innerHTML;
|
36
|
+
},
|
37
|
+
patternRef,
|
38
|
+
};
|
38
39
|
};
|
39
40
|
const makeRedoIcon = (mirror) => {
|
40
41
|
const icon = document.createElementNS(svgNamespace, 'svg');
|
@@ -50,11 +51,14 @@ const makeRedoIcon = (mirror) => {
|
|
50
51
|
transform-origin: center;
|
51
52
|
}
|
52
53
|
</style>
|
53
|
-
<path
|
54
|
-
d='M20,20 A15,15 0 0 1 70,80 L80,90 L60,70 L65,90 L87,90 L65,80'
|
55
|
-
class='toolbar-svg-undo-redo-icon'
|
56
|
-
style='${mirror ? 'transform: scale(-1, 1);' : ''}'/>
|
57
54
|
`;
|
55
|
+
const path = document.createElementNS(svgNamespace, 'path');
|
56
|
+
path.setAttribute('d', 'M20,20 A15,15 0 0 1 70,80 L80,90 L60,70 L65,90 L87,90 L65,80');
|
57
|
+
path.classList.add('toolbar-svg-undo-redo-icon');
|
58
|
+
if (mirror) {
|
59
|
+
path.style.transform = 'scale(-1, 1)';
|
60
|
+
}
|
61
|
+
icon.appendChild(path);
|
58
62
|
icon.setAttribute('viewBox', '0 0 100 100');
|
59
63
|
return icon;
|
60
64
|
};
|
@@ -102,65 +106,62 @@ class IconProvider {
|
|
102
106
|
return makeRedoIcon(false);
|
103
107
|
}
|
104
108
|
makeDropdownIcon() {
|
105
|
-
const icon =
|
106
|
-
icon.innerHTML = `
|
107
|
-
<g>
|
108
|
-
<path
|
109
|
-
d='M5,10 L50,90 L95,10 Z'
|
110
|
-
${iconColorFill}
|
111
|
-
/>
|
112
|
-
</g>
|
113
|
-
`;
|
109
|
+
const icon = this.makeIconFromPath('M5,10 L50,90 L95,10 Z');
|
114
110
|
icon.setAttribute('viewBox', '-10 -10 110 110');
|
115
111
|
return icon;
|
116
112
|
}
|
117
113
|
makeEraserIcon(eraserSize, mode) {
|
118
|
-
const icon = document.createElementNS(svgNamespace, 'svg');
|
119
114
|
eraserSize ??= 10;
|
120
115
|
const scaledSize = eraserSize / 4;
|
121
116
|
const eraserColor = '#ff70af';
|
122
117
|
// Draw an eraser-like shape. Created with Inkscape
|
123
|
-
icon
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
118
|
+
const icon = createSvgElement('svg', {
|
119
|
+
viewBox: '0 0 120 120',
|
120
|
+
children: [
|
121
|
+
createSvgElement('defs', {
|
122
|
+
children: [
|
123
|
+
createSvgElement('linearGradient', {
|
124
|
+
id: 'dash-pattern',
|
125
|
+
children: createSvgElements('stop', [
|
126
|
+
{ offset: '80%', 'stop-color': eraserColor },
|
127
|
+
{ offset: '85%', 'stop-color': 'white' },
|
128
|
+
{ offset: '90%', 'stop-color': eraserColor },
|
129
|
+
]),
|
130
|
+
}),
|
131
|
+
],
|
132
|
+
}),
|
133
|
+
createSvgElement('path', {
|
134
|
+
fill: mode === EraserMode.PartialStroke ? 'url(#dash-pattern)' : eraserColor,
|
135
|
+
stroke: 'black',
|
136
|
+
transform: 'rotate(41.35)',
|
137
|
+
d: `
|
138
|
+
M 52.5 27
|
139
|
+
C 50 28.9 48.9 31.7 48.9 34.8
|
140
|
+
L 48.9 39.8
|
141
|
+
C 48.9 45.3 53.4 49.8 58.9 49.8
|
142
|
+
L 103.9 49.8
|
143
|
+
C 105.8 49.8 107.6 49.2 109.1 48.3
|
144
|
+
L 110.2 ${scaledSize + 49.5} L 159.7 ${scaledSize + 5}
|
145
|
+
L 157.7 ${-scaledSize + 5.2} L 112.4 ${49.5 - scaledSize}
|
146
|
+
C 113.4 43.5 113.9 41.7 113.9 39.8
|
147
|
+
L 113.9 34.8
|
148
|
+
C 113.9 29.3 109.4 24.8 103.9 24.8
|
149
|
+
L 58.9 24.8
|
150
|
+
C 56.5 24.8 54.3 25.7 52.5 27
|
151
|
+
z
|
152
|
+
`,
|
153
|
+
}),
|
154
|
+
createSvgElement('rect', {
|
155
|
+
stroke: '#cc8077',
|
156
|
+
fill: 'var(--icon-color)',
|
157
|
+
width: 65,
|
158
|
+
height: 75,
|
159
|
+
x: 48.9,
|
160
|
+
y: -38.7,
|
161
|
+
transform: 'rotate(41.35)',
|
162
|
+
}),
|
163
|
+
],
|
164
|
+
});
|
164
165
|
return icon;
|
165
166
|
}
|
166
167
|
makeSelectionIcon() {
|
@@ -168,8 +169,8 @@ class IconProvider {
|
|
168
169
|
// Draw a cursor-like shape
|
169
170
|
icon.innerHTML = `
|
170
171
|
<g>
|
171
|
-
<rect x=10 y=10 width=70 height=70 fill=
|
172
|
-
<rect x=75 y=75 width=10 height=10 fill=
|
172
|
+
<rect x="10" y="10" width="70" height="70" fill="pink" stroke="black"/>
|
173
|
+
<rect x="75" y="75" width="10" height="10" fill="white" stroke="black"/>
|
173
174
|
</g>
|
174
175
|
`;
|
175
176
|
icon.setAttribute('viewBox', '0 0 100 100');
|
@@ -432,8 +433,6 @@ class IconProvider {
|
|
432
433
|
const strokeSize = Math.round(Math.sqrt(penStyle.thickness) * 4);
|
433
434
|
const color = penStyle.color;
|
434
435
|
const rounded = this.isRoundedTipPen(penStyle);
|
435
|
-
const icon = document.createElementNS(svgNamespace, 'svg');
|
436
|
-
icon.setAttribute('viewBox', '0 0 100 100');
|
437
436
|
const tipThickness = strokeSize / 2;
|
438
437
|
const inkTipPath = `
|
439
438
|
M ${15 - tipThickness},${80 - tipThickness}
|
@@ -466,71 +465,35 @@ class IconProvider {
|
|
466
465
|
const pencilTipColor = Color4.fromHex('#f4d7d7');
|
467
466
|
const tipColor = pencilTipColor.mix(color, tipThickness / 40 - 0.1).toHexString();
|
468
467
|
const checkerboardPattern = makeCheckerboardPattern();
|
469
|
-
const
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
const grip = `
|
499
|
-
<path
|
500
|
-
${iconColorStrokeFill}
|
501
|
-
d="${gripMainPath}"
|
502
|
-
/>
|
503
|
-
|
504
|
-
<!-- shadows -->
|
505
|
-
<path
|
506
|
-
fill="rgba(150, 150, 150, 0.3)"
|
507
|
-
d="${gripShadow1Path}"
|
508
|
-
/>
|
509
|
-
<path
|
510
|
-
fill="rgba(100, 100, 100, 0.2)"
|
511
|
-
d="${gripShadow2Path}"
|
512
|
-
/>
|
513
|
-
|
514
|
-
<!-- color bubble -->
|
515
|
-
<path
|
516
|
-
fill="${checkerboardPattern.patternRef}"
|
517
|
-
d="${colorBubblePath}"
|
518
|
-
/>
|
519
|
-
<path
|
520
|
-
fill="${color}"
|
521
|
-
d="${colorBubblePath}"
|
522
|
-
/>
|
523
|
-
`;
|
524
|
-
icon.innerHTML = `
|
525
|
-
<defs>
|
526
|
-
${checkerboardPattern.patternDef}
|
527
|
-
</defs>
|
528
|
-
<g>
|
529
|
-
${ink}
|
530
|
-
${penTip}
|
531
|
-
${grip}
|
532
|
-
</g>
|
533
|
-
`;
|
468
|
+
const colorString = color.toHexString();
|
469
|
+
const ink = createSvgPaths({
|
470
|
+
fill: checkerboardPattern.patternRef,
|
471
|
+
d: inkTipPath,
|
472
|
+
}, {
|
473
|
+
fill: checkerboardPattern.patternRef,
|
474
|
+
d: inkTrailPath,
|
475
|
+
}, {
|
476
|
+
fill: colorString,
|
477
|
+
d: inkTipPath,
|
478
|
+
}, {
|
479
|
+
fill: colorString,
|
480
|
+
d: inkTrailPath,
|
481
|
+
});
|
482
|
+
const penTip = createSvgPaths({ fill: checkerboardPattern.patternRef, d: penTipPath }, { fill: tipColor, stroke: colorString, d: penTipPath });
|
483
|
+
const grip = createSvgPaths({ fill: 'var(--icon-color)', stroke: 'var(--icon-color)', d: gripMainPath },
|
484
|
+
// Shadows
|
485
|
+
{ fill: 'rgba(150, 150, 150, 0.3)', d: gripShadow1Path }, { fill: 'rgba(100, 100, 100, 0.2)', d: gripShadow2Path },
|
486
|
+
// Color bubble
|
487
|
+
{ fill: checkerboardPattern.patternRef, d: colorBubblePath }, { fill: colorString, d: colorBubblePath });
|
488
|
+
const icon = document.createElementNS(svgNamespace, 'svg');
|
489
|
+
icon.setAttribute('viewBox', '0 0 100 100');
|
490
|
+
const iconMainContent = createSvgElement('g', {
|
491
|
+
children: [ink, penTip, grip].flat(),
|
492
|
+
});
|
493
|
+
const defs = createSvgElement('defs', {
|
494
|
+
children: [checkerboardPattern.patternDefElement],
|
495
|
+
});
|
496
|
+
icon.replaceChildren(defs, iconMainContent);
|
534
497
|
return icon;
|
535
498
|
}
|
536
499
|
makeIconFromFactory(penStyle) {
|
@@ -562,7 +525,7 @@ class IconProvider {
|
|
562
525
|
if (includeTransparencyGrid) {
|
563
526
|
const checkerboardPattern = makeCheckerboardPattern();
|
564
527
|
const defs = document.createElementNS(svgNamespace, 'defs');
|
565
|
-
defs.
|
528
|
+
defs.appendChild(checkerboardPattern.patternDefElement);
|
566
529
|
icon.appendChild(defs);
|
567
530
|
const background = document.createElementNS(svgNamespace, 'g');
|
568
531
|
icon.appendChild(background);
|
@@ -636,7 +599,7 @@ class IconProvider {
|
|
636
599
|
if (color) {
|
637
600
|
const checkerboardPattern = makeCheckerboardPattern();
|
638
601
|
const defs = document.createElementNS(svgNamespace, 'defs');
|
639
|
-
defs.
|
602
|
+
defs.appendChild(checkerboardPattern.patternDefElement);
|
640
603
|
icon.appendChild(defs);
|
641
604
|
const fluidBackground = document.createElementNS(svgNamespace, 'path');
|
642
605
|
const fluid = document.createElementNS(svgNamespace, 'path');
|
@@ -841,6 +804,9 @@ class IconProvider {
|
|
841
804
|
* @returns An object with both the definition of a checkerboard pattern and the syntax to
|
842
805
|
* reference that pattern. The defs provided by this function should be wrapped within a
|
843
806
|
* `<defs></defs>` element.
|
807
|
+
*
|
808
|
+
* **Note**: This function's return value includes both `patternDefElement` (which returns
|
809
|
+
* an Element) and a (deprecated) `patternDef` string. Avoid using the `patternDef` result.
|
844
810
|
*/
|
845
811
|
makeCheckerboardPattern() {
|
846
812
|
return makeCheckerboardPattern();
|
@@ -45,7 +45,7 @@ export const defaultToolbarLocalization = {
|
|
45
45
|
about: 'About',
|
46
46
|
inputStabilization: 'Stabilization',
|
47
47
|
strokeAutocorrect: 'Autocorrect',
|
48
|
-
touchPanning: '
|
48
|
+
touchPanning: 'Scroll with touch',
|
49
49
|
roundedTipPen: 'Round',
|
50
50
|
roundedTipPen2: 'Polyline',
|
51
51
|
flatTipPen: 'Flat',
|
@@ -72,7 +72,7 @@ export const defaultToolbarLocalization = {
|
|
72
72
|
handDropdown__zoomOutHelpText: 'Zooms out.',
|
73
73
|
handDropdown__resetViewHelpText: 'Resets the zoom level to 100% and resets scroll.',
|
74
74
|
handDropdown__zoomDisplayHelpText: 'Shows the current zoom level. 100% shows the image at its actual size.',
|
75
|
-
handDropdown__touchPanningHelpText: 'When enabled,
|
75
|
+
handDropdown__touchPanningHelpText: 'When enabled, touchscreen gestures move the image rather than select or draw.',
|
76
76
|
handDropdown__lockRotationHelpText: 'When enabled, prevents touch gestures from rotating the screen.',
|
77
77
|
eraserDropdown__baseHelpText: 'This tool removes strokes, images, and text under the cursor.',
|
78
78
|
eraserDropdown__thicknessHelpText: 'Changes the size of the eraser.',
|
@@ -98,7 +98,7 @@ export default abstract class BaseWidget {
|
|
98
98
|
addTo(parent: HTMLElement): HTMLElement;
|
99
99
|
/**
|
100
100
|
* Remove this. This allows the widget to be added to a toolbar again
|
101
|
-
* in the future using
|
101
|
+
* in the future using `addTo`.
|
102
102
|
*/
|
103
103
|
remove(): void;
|
104
104
|
focus(): void;
|
@@ -427,7 +427,7 @@ export default class PanZoom extends BaseTool {
|
|
427
427
|
translation = translation.times(-1);
|
428
428
|
rotation = rotation * -1;
|
429
429
|
scale = 1 / scale;
|
430
|
-
// Work around an issue that seems to be related to rotation
|
430
|
+
// Work around an issue that seems to be related to rotation matrices losing precision on inversion.
|
431
431
|
// TODO: Figure out why and implement a better solution.
|
432
432
|
if (rotation !== 0) {
|
433
433
|
rotation += 0.0001;
|
package/dist/mjs/tools/Pen.d.ts
CHANGED
@@ -11,6 +11,12 @@ export interface PenStyle {
|
|
11
11
|
readonly thickness: number;
|
12
12
|
readonly factory: ComponentBuilderFactory;
|
13
13
|
}
|
14
|
+
/**
|
15
|
+
* A tool that allows drawing shapes and freehand lines.
|
16
|
+
*
|
17
|
+
* To change the type of shape drawn by the pen (e.g. to switch to the rectangle
|
18
|
+
* pen type), see {@link setStrokeFactory}.
|
19
|
+
*/
|
14
20
|
export default class Pen extends BaseTool {
|
15
21
|
private editor;
|
16
22
|
protected builder: ComponentBuilder | null;
|
@@ -42,6 +48,13 @@ export default class Pen extends BaseTool {
|
|
42
48
|
private noteUpdated;
|
43
49
|
setColor(color: Color4): void;
|
44
50
|
setThickness(thickness: number): void;
|
51
|
+
/**
|
52
|
+
* Changes the type of stroke created by the pen. The given `factory` can be one of the built-in
|
53
|
+
* stroke factories (e.g. {@link makeFreehandLineBuilder}) or a custom stroke factory.
|
54
|
+
*
|
55
|
+
* Example:
|
56
|
+
* [[include:doc-pages/inline-examples/changing-pen-types.md]]
|
57
|
+
*/
|
45
58
|
setStrokeFactory(factory: ComponentBuilderFactory): void;
|
46
59
|
setHasStabilization(hasStabilization: boolean): void;
|
47
60
|
setStrokeAutocorrectEnabled(enabled: boolean): void;
|
package/dist/mjs/tools/Pen.mjs
CHANGED
@@ -9,6 +9,12 @@ import { decreaseSizeKeyboardShortcutId, increaseSizeKeyboardShortcutId } from
|
|
9
9
|
import InputStabilizer from './InputFilter/InputStabilizer.mjs';
|
10
10
|
import { ReactiveValue } from '../util/ReactiveValue.mjs';
|
11
11
|
import StationaryPenDetector, { defaultStationaryDetectionConfig, } from './util/StationaryPenDetector.mjs';
|
12
|
+
/**
|
13
|
+
* A tool that allows drawing shapes and freehand lines.
|
14
|
+
*
|
15
|
+
* To change the type of shape drawn by the pen (e.g. to switch to the rectangle
|
16
|
+
* pen type), see {@link setStrokeFactory}.
|
17
|
+
*/
|
12
18
|
export default class Pen extends BaseTool {
|
13
19
|
constructor(editor, description, style) {
|
14
20
|
super(editor.notifier, description);
|
@@ -244,6 +250,13 @@ export default class Pen extends BaseTool {
|
|
244
250
|
});
|
245
251
|
}
|
246
252
|
}
|
253
|
+
/**
|
254
|
+
* Changes the type of stroke created by the pen. The given `factory` can be one of the built-in
|
255
|
+
* stroke factories (e.g. {@link makeFreehandLineBuilder}) or a custom stroke factory.
|
256
|
+
*
|
257
|
+
* Example:
|
258
|
+
* [[include:doc-pages/inline-examples/changing-pen-types.md]]
|
259
|
+
*/
|
247
260
|
setStrokeFactory(factory) {
|
248
261
|
if (factory !== this.style.factory) {
|
249
262
|
this.styleValue.set({
|
package/dist/mjs/tools/lib.d.ts
CHANGED
package/dist/mjs/tools/lib.mjs
CHANGED
@@ -10,7 +10,7 @@ const cloneElementWithStyles = (element) => {
|
|
10
10
|
for (let index = 0; index < originalComputedStyle.length; index++) {
|
11
11
|
const propertyName = originalComputedStyle.item(index);
|
12
12
|
const propertyValue = originalComputedStyle.getPropertyValue(propertyName);
|
13
|
-
clonedElement.style
|
13
|
+
clonedElement.style?.setProperty(propertyName, propertyValue);
|
14
14
|
}
|
15
15
|
for (let i = 0; i < originalElement.children.length; i++) {
|
16
16
|
const originalChild = originalElement.children.item(i);
|
@@ -0,0 +1,62 @@
|
|
1
|
+
type ElementTagNames = keyof HTMLElementTagNameMap | keyof SVGElementTagNameMap;
|
2
|
+
/**
|
3
|
+
* Maps from known elment tag names to options that can be set with .setAttribute.
|
4
|
+
* New elements/properties should be added as necessary.
|
5
|
+
*/
|
6
|
+
interface ElementToPropertiesMap {
|
7
|
+
path: {
|
8
|
+
d: string;
|
9
|
+
fill: string;
|
10
|
+
stroke: string;
|
11
|
+
transform: string;
|
12
|
+
};
|
13
|
+
rect: {
|
14
|
+
stroke: string;
|
15
|
+
fill: string;
|
16
|
+
x: number;
|
17
|
+
y: number;
|
18
|
+
width: number;
|
19
|
+
height: number;
|
20
|
+
transform: string;
|
21
|
+
};
|
22
|
+
pattern: {
|
23
|
+
viewBox: string;
|
24
|
+
width: string;
|
25
|
+
height: string;
|
26
|
+
patternUnits: 'userSpaceOnUse';
|
27
|
+
};
|
28
|
+
stop: {
|
29
|
+
offset: string;
|
30
|
+
'stop-color': string;
|
31
|
+
};
|
32
|
+
svg: {
|
33
|
+
viewBox: `${number} ${number} ${number} ${number}`;
|
34
|
+
};
|
35
|
+
}
|
36
|
+
type EmptyObject = Record<never, never>;
|
37
|
+
type ElementProperties<Tag extends ElementTagNames> = Tag extends keyof ElementToPropertiesMap ? Partial<ElementToPropertiesMap[Tag]> : EmptyObject;
|
38
|
+
/** Contains options for creating an element with tag = `Tag`. */
|
39
|
+
type ElementConfig<Tag extends ElementTagNames> = ElementProperties<Tag> & {
|
40
|
+
id?: string;
|
41
|
+
children?: (HTMLElement | SVGElement)[];
|
42
|
+
};
|
43
|
+
/**
|
44
|
+
* Maps from element tag names (e.g. `Tag='button'`) to the corresponding element type
|
45
|
+
* (e.g. `HTMLButtonElement`).
|
46
|
+
*/
|
47
|
+
type ElementTagToType<Tag extends ElementTagNames> = Tag extends keyof HTMLElementTagNameMap ? HTMLElementTagNameMap[Tag] : Tag extends keyof SVGElementTagNameMap ? SVGElementTagNameMap[Tag] : never;
|
48
|
+
export declare enum ElementNamespace {
|
49
|
+
Html = "html",
|
50
|
+
Svg = "svg"
|
51
|
+
}
|
52
|
+
/**
|
53
|
+
* Shorthand for creating an element with `document.createElement`, then assigning properties.
|
54
|
+
*
|
55
|
+
* Non-HTML elements (e.g. `svg` elements) should use the `elementType` parameter to select
|
56
|
+
* the element namespace.
|
57
|
+
*/
|
58
|
+
declare const createElement: <Tag extends ElementTagNames>(tag: Tag, props: ElementConfig<Tag>, elementType?: ElementNamespace) => ElementTagToType<Tag>;
|
59
|
+
export declare const createSvgElement: <Tag extends keyof SVGElementTagNameMap>(tag: Tag, props: ElementConfig<Tag>) => ElementTagToType<Tag>;
|
60
|
+
export declare const createSvgElements: <Tag extends keyof SVGElementTagNameMap>(tag: Tag, elements: ElementConfig<Tag>[]) => ElementTagToType<Tag>[];
|
61
|
+
export declare const createSvgPaths: (...paths: ElementConfig<"path">[]) => SVGPathElement[];
|
62
|
+
export default createElement;
|
@@ -0,0 +1,47 @@
|
|
1
|
+
export var ElementNamespace;
|
2
|
+
(function (ElementNamespace) {
|
3
|
+
ElementNamespace["Html"] = "html";
|
4
|
+
ElementNamespace["Svg"] = "svg";
|
5
|
+
})(ElementNamespace || (ElementNamespace = {}));
|
6
|
+
/**
|
7
|
+
* Shorthand for creating an element with `document.createElement`, then assigning properties.
|
8
|
+
*
|
9
|
+
* Non-HTML elements (e.g. `svg` elements) should use the `elementType` parameter to select
|
10
|
+
* the element namespace.
|
11
|
+
*/
|
12
|
+
const createElement = (tag, props, elementType = ElementNamespace.Html) => {
|
13
|
+
let elem;
|
14
|
+
if (elementType === ElementNamespace.Html) {
|
15
|
+
elem = document.createElement(tag);
|
16
|
+
}
|
17
|
+
else if (elementType === ElementNamespace.Svg) {
|
18
|
+
elem = document.createElementNS('http://www.w3.org/2000/svg', tag);
|
19
|
+
}
|
20
|
+
else {
|
21
|
+
throw new Error(`Unknown element type ${elementType}`);
|
22
|
+
}
|
23
|
+
for (const [key, value] of Object.entries(props)) {
|
24
|
+
if (key === 'children')
|
25
|
+
continue;
|
26
|
+
if (typeof value !== 'string' && typeof value !== 'number') {
|
27
|
+
throw new Error(`Unsupported value type ${typeof value}`);
|
28
|
+
}
|
29
|
+
elem.setAttribute(key, value.toString());
|
30
|
+
}
|
31
|
+
if (props.children) {
|
32
|
+
for (const item of props.children) {
|
33
|
+
elem.appendChild(item);
|
34
|
+
}
|
35
|
+
}
|
36
|
+
return elem;
|
37
|
+
};
|
38
|
+
export const createSvgElement = (tag, props) => {
|
39
|
+
return createElement(tag, props, ElementNamespace.Svg);
|
40
|
+
};
|
41
|
+
export const createSvgElements = (tag, elements) => {
|
42
|
+
return elements.map((props) => createSvgElement(tag, props));
|
43
|
+
};
|
44
|
+
export const createSvgPaths = (...paths) => {
|
45
|
+
return createSvgElements('path', paths);
|
46
|
+
};
|
47
|
+
export default createElement;
|
package/dist/mjs/version.mjs
CHANGED
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "js-draw",
|
3
|
-
"version": "1.
|
3
|
+
"version": "1.23.1",
|
4
4
|
"description": "Draw pictures using a pen, touchscreen, or mouse! JS-draw is a drawing library for JavaScript and TypeScript. ",
|
5
5
|
"types": "./dist/mjs/lib.d.ts",
|
6
6
|
"main": "./dist/cjs/lib.js",
|
@@ -64,11 +64,11 @@
|
|
64
64
|
"postpack": "ts-node tools/copyREADME.ts revert"
|
65
65
|
},
|
66
66
|
"dependencies": {
|
67
|
-
"@js-draw/math": "^1.
|
67
|
+
"@js-draw/math": "^1.23.1",
|
68
68
|
"@melloware/coloris": "0.22.0"
|
69
69
|
},
|
70
70
|
"devDependencies": {
|
71
|
-
"@js-draw/build-tool": "^1.
|
71
|
+
"@js-draw/build-tool": "^1.23.1",
|
72
72
|
"@types/jest": "29.5.5",
|
73
73
|
"@types/jsdom": "21.1.3"
|
74
74
|
},
|
@@ -86,5 +86,5 @@
|
|
86
86
|
"freehand",
|
87
87
|
"svg"
|
88
88
|
],
|
89
|
-
"gitHead": "
|
89
|
+
"gitHead": "e0bb3336d5f3a94533c823906778d39a4880f4cf"
|
90
90
|
}
|