js-draw 0.24.1 → 0.25.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/dist/bundle.js +2 -2
- package/dist/bundledStyles.js +1 -1
- package/dist/cjs/Pointer.js +5 -3
- package/dist/cjs/localizations/de.js +1 -1
- package/dist/cjs/localizations/es.js +1 -1
- package/dist/cjs/rendering/renderers/CanvasRenderer.js +2 -0
- package/dist/cjs/rendering/renderers/SVGRenderer.d.ts +1 -1
- package/dist/cjs/rendering/renderers/SVGRenderer.js +4 -2
- package/dist/cjs/testing/getUniquePointerId.d.ts +4 -0
- package/dist/cjs/testing/getUniquePointerId.js +16 -0
- package/dist/cjs/testing/sendPenEvent.d.ts +1 -1
- package/dist/cjs/testing/sendPenEvent.js +4 -1
- package/dist/cjs/testing/sendTouchEvent.js +2 -9
- package/dist/cjs/toolbar/IconProvider.d.ts +1 -1
- package/dist/cjs/toolbar/IconProvider.js +76 -10
- package/dist/cjs/toolbar/localization.d.ts +2 -2
- package/dist/cjs/toolbar/localization.js +2 -2
- package/dist/cjs/toolbar/widgets/BaseToolWidget.d.ts +2 -0
- package/dist/cjs/toolbar/widgets/BaseToolWidget.js +7 -0
- package/dist/cjs/toolbar/widgets/PenToolWidget.d.ts +3 -1
- package/dist/cjs/toolbar/widgets/PenToolWidget.js +125 -41
- package/dist/cjs/toolbar/widgets/SelectionToolWidget.js +4 -0
- package/dist/cjs/tools/BaseTool.d.ts +17 -1
- package/dist/cjs/tools/BaseTool.js +18 -0
- package/dist/cjs/tools/Pen.d.ts +5 -2
- package/dist/cjs/tools/Pen.js +37 -4
- package/dist/cjs/tools/ToolController.js +14 -2
- package/dist/mjs/Pointer.mjs +5 -3
- package/dist/mjs/localizations/de.mjs +1 -1
- package/dist/mjs/localizations/es.mjs +1 -1
- package/dist/mjs/rendering/renderers/CanvasRenderer.mjs +2 -0
- package/dist/mjs/rendering/renderers/SVGRenderer.d.ts +1 -1
- package/dist/mjs/rendering/renderers/SVGRenderer.mjs +4 -2
- package/dist/mjs/testing/getUniquePointerId.d.ts +4 -0
- package/dist/mjs/testing/getUniquePointerId.mjs +14 -0
- package/dist/mjs/testing/sendPenEvent.d.ts +1 -1
- package/dist/mjs/testing/sendPenEvent.mjs +4 -1
- package/dist/mjs/testing/sendTouchEvent.mjs +2 -9
- package/dist/mjs/toolbar/IconProvider.d.ts +1 -1
- package/dist/mjs/toolbar/IconProvider.mjs +76 -10
- package/dist/mjs/toolbar/localization.d.ts +2 -2
- package/dist/mjs/toolbar/localization.mjs +2 -2
- package/dist/mjs/toolbar/widgets/BaseToolWidget.d.ts +2 -0
- package/dist/mjs/toolbar/widgets/BaseToolWidget.mjs +7 -0
- package/dist/mjs/toolbar/widgets/PenToolWidget.d.ts +3 -1
- package/dist/mjs/toolbar/widgets/PenToolWidget.mjs +125 -41
- package/dist/mjs/toolbar/widgets/SelectionToolWidget.mjs +4 -0
- package/dist/mjs/tools/BaseTool.d.ts +17 -1
- package/dist/mjs/tools/BaseTool.mjs +18 -0
- package/dist/mjs/tools/Pen.d.ts +5 -2
- package/dist/mjs/tools/Pen.mjs +37 -4
- package/dist/mjs/tools/ToolController.mjs +14 -2
- package/package.json +2 -2
- package/src/Pointer.ts +5 -2
- package/src/localizations/de.ts +2 -2
- package/src/localizations/es.ts +1 -1
- package/src/rendering/renderers/CanvasRenderer.ts +2 -0
- package/src/rendering/renderers/SVGRenderer.ts +6 -3
- package/src/testing/getUniquePointerId.ts +18 -0
- package/src/testing/sendPenEvent.ts +6 -1
- package/src/testing/sendTouchEvent.ts +2 -9
- package/src/toolbar/IconProvider.ts +92 -23
- package/src/toolbar/localization.ts +4 -4
- package/src/toolbar/toolbar.css +1 -0
- package/src/toolbar/widgets/BaseToolWidget.ts +10 -1
- package/src/toolbar/widgets/PenToolWidget.css +53 -0
- package/src/toolbar/widgets/PenToolWidget.ts +156 -44
- package/src/toolbar/widgets/SelectionToolWidget.ts +4 -0
- package/src/tools/BaseTool.ts +22 -1
- package/src/tools/Pen.test.ts +68 -0
- package/src/tools/Pen.ts +42 -4
- package/src/tools/ToolController.ts +17 -2
@@ -9,6 +9,7 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
9
9
|
};
|
10
10
|
import Pointer, { PointerDevice } from '../Pointer.mjs';
|
11
11
|
import { InputEvtType } from '../types.mjs';
|
12
|
+
import getUniquePointerId from './getUniquePointerId.mjs';
|
12
13
|
/**
|
13
14
|
* Dispatch a touch event to the currently selected tool. Intended for unit tests.
|
14
15
|
*
|
@@ -47,17 +48,9 @@ import { InputEvtType } from '../types.mjs';
|
|
47
48
|
*/
|
48
49
|
var sendTouchEvent = function (editor, eventType, screenPos, allOtherPointers) {
|
49
50
|
var canvasPos = editor.viewport.screenToCanvas(screenPos);
|
50
|
-
var ptrId = 0;
|
51
|
-
var maxPtrId = 0;
|
52
51
|
// Get a unique ID for the main pointer
|
53
52
|
// (try to use id=0, but don't use it if it's already in use).
|
54
|
-
|
55
|
-
var pointer = _a[_i];
|
56
|
-
maxPtrId = Math.max(pointer.id, maxPtrId);
|
57
|
-
if (pointer.id === ptrId) {
|
58
|
-
ptrId = maxPtrId + 1;
|
59
|
-
}
|
60
|
-
}
|
53
|
+
var ptrId = getUniquePointerId(allOtherPointers !== null && allOtherPointers !== void 0 ? allOtherPointers : []);
|
61
54
|
var mainPointer = Pointer.ofCanvasPoint(canvasPos, eventType !== InputEvtType.PointerUpEvt, editor.viewport, ptrId, PointerDevice.Touch);
|
62
55
|
editor.toolController.dispatchInputEvent({
|
63
56
|
kind: eventType,
|
@@ -49,7 +49,7 @@ export default class IconProvider {
|
|
49
49
|
makeInsertImageIcon(): IconType;
|
50
50
|
makeTextIcon(textStyle: TextRenderingStyle): IconType;
|
51
51
|
makePenIcon(strokeSize: number, color: string | Color4, rounded?: boolean): IconType;
|
52
|
-
makeIconFromFactory(pen: Pen, factory: ComponentBuilderFactory): IconType;
|
52
|
+
makeIconFromFactory(pen: Pen, factory: ComponentBuilderFactory, includeTransparencyGrid?: boolean): IconType;
|
53
53
|
makePipetteIcon(color?: Color4): IconType;
|
54
54
|
makeFormatSelectionIcon(): IconType;
|
55
55
|
makeResizeViewportIcon(): IconType;
|
@@ -1,3 +1,18 @@
|
|
1
|
+
var __extends = (this && this.__extends) || (function () {
|
2
|
+
var extendStatics = function (d, b) {
|
3
|
+
extendStatics = Object.setPrototypeOf ||
|
4
|
+
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
5
|
+
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
|
6
|
+
return extendStatics(d, b);
|
7
|
+
};
|
8
|
+
return function (d, b) {
|
9
|
+
if (typeof b !== "function" && b !== null)
|
10
|
+
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
|
11
|
+
extendStatics(d, b);
|
12
|
+
function __() { this.constructor = d; }
|
13
|
+
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
14
|
+
};
|
15
|
+
})();
|
1
16
|
import Color4 from '../Color4.mjs';
|
2
17
|
import { Vec2 } from '../math/Vec2.mjs';
|
3
18
|
import SVGRenderer from '../rendering/renderers/SVGRenderer.mjs';
|
@@ -5,8 +20,13 @@ import Viewport from '../Viewport.mjs';
|
|
5
20
|
var svgNamespace = 'http://www.w3.org/2000/svg';
|
6
21
|
var iconColorFill = "\n\tstyle='fill: var(--icon-color);'\n";
|
7
22
|
var iconColorStrokeFill = "\n\tstyle='fill: var(--icon-color); stroke: var(--icon-color);'\n";
|
8
|
-
var
|
9
|
-
var
|
23
|
+
var checkerboardIdCounter = 0;
|
24
|
+
var makeCheckerboardPattern = function () {
|
25
|
+
var id = "checkerboard-".concat(checkerboardIdCounter++);
|
26
|
+
var patternDef = "\n\t\t<pattern\n\t\t\tid='".concat(id, "'\n\t\t\tviewBox='0,0,10,10'\n\t\t\twidth='20%'\n\t\t\theight='20%'\n\t\t\tpatternUnits='userSpaceOnUse'\n\t\t>\n\t\t\t<rect x=0 y=0 width=10 height=10 fill='white'/>\n\t\t\t<rect x=0 y=0 width=5 height=5 fill='gray'/>\n\t\t\t<rect x=5 y=5 width=5 height=5 fill='gray'/>\n\t\t</pattern>\n\t");
|
27
|
+
var patternRef = "url(#".concat(id, ")");
|
28
|
+
return { patternDef: patternDef, patternRef: patternRef };
|
29
|
+
};
|
10
30
|
/**
|
11
31
|
* Provides icons that can be used in the toolbar, etc.
|
12
32
|
* Extend this class and override methods to customize icons.
|
@@ -176,13 +196,17 @@ var IconProvider = /** @class */ (function () {
|
|
176
196
|
var penTipPath = "M 25,35 ".concat(10 - tipThickness / 4, ",").concat(70 - tipThickness / 2, " 20,75 25,85 60,75 70,55 45,25 Z");
|
177
197
|
var pencilTipColor = Color4.fromHex('#f4d7d7');
|
178
198
|
var tipColor = pencilTipColor.mix(Color4.fromString(color), tipThickness / 40 - 0.1).toHexString();
|
179
|
-
var
|
180
|
-
var
|
181
|
-
var
|
182
|
-
|
199
|
+
var checkerboardPattern = makeCheckerboardPattern();
|
200
|
+
var ink = "\n\t\t\t<path\n\t\t\t\tfill=\"".concat(checkerboardPattern.patternRef, "\"\n\t\t\t\td=\"").concat(inkTipPath, "\"\n\t\t\t/>\n\t\t\t<path\n\t\t\t\tfill=\"").concat(checkerboardPattern.patternRef, "\"\n\t\t\t\td=\"").concat(inkTrailPath, "\"\n\t\t\t/>\n\t\t\t<path\n\t\t\t\tfill=\"").concat(color, "\"\n\t\t\t\td=\"").concat(inkTipPath, "\"\n\t\t\t/>\n\t\t\t<path\n\t\t\t\tfill=\"").concat(color, "\"\n\t\t\t\td=\"").concat(inkTrailPath, "\"\n\t\t\t/>\n\t\t");
|
201
|
+
var penTip = "\n\t\t\t<path\n\t\t\t\tfill=\"".concat(checkerboardPattern.patternRef, "\"\n\t\t\t\td=\"").concat(penTipPath, "\"\n\t\t\t/>\n\t\t\t<path\n\t\t\t\tfill=\"").concat(tipColor, "\"\n\t\t\t\tstroke=\"").concat(color, "\"\n\t\t\t\td=\"").concat(penTipPath, "\"\n\t\t\t/>\n\t\t");
|
202
|
+
var grip = "\n\t\t\t<path\n\t\t\t\t".concat(iconColorStrokeFill, "\n\t\t\t\td=\"").concat(gripMainPath, "\"\n\t\t\t/>\n\n\t\t\t<!-- shadows -->\n\t\t\t<path\n\t\t\t\tfill=\"rgba(150, 150, 150, 0.3)\"\n\t\t\t\td=\"").concat(gripShadow1Path, "\"\n\t\t\t/>\n\t\t\t<path\n\t\t\t\tfill=\"rgba(100, 100, 100, 0.2)\"\n\t\t\t\td=\"").concat(gripShadow2Path, "\"\n\t\t\t/>\n\n\t\t\t<!-- color bubble -->\n\t\t\t<path\n\t\t\t\tfill=\"").concat(checkerboardPattern.patternRef, "\"\n\t\t\t\td=\"").concat(colorBubblePath, "\"\n\t\t\t/>\n\t\t\t<path\n\t\t\t\tfill=\"").concat(color, "\"\n\t\t\t\td=\"").concat(colorBubblePath, "\"\n\t\t\t/>\n\t\t");
|
203
|
+
icon.innerHTML = "\n\t\t<defs>\n\t\t\t".concat(checkerboardPattern.patternDef, "\n\t\t</defs>\n\t\t<g>\n\t\t\t").concat(ink, "\n\t\t\t").concat(penTip, "\n\t\t\t").concat(grip, "\n\t\t</g>\n\t\t");
|
183
204
|
return icon;
|
184
205
|
};
|
185
|
-
IconProvider.prototype.makeIconFromFactory = function (pen, factory
|
206
|
+
IconProvider.prototype.makeIconFromFactory = function (pen, factory,
|
207
|
+
// If true, attempts to guess the location of a transparency grid
|
208
|
+
includeTransparencyGrid) {
|
209
|
+
if (includeTransparencyGrid === void 0) { includeTransparencyGrid = false; }
|
186
210
|
// Increase the thickness we use to generate the icon less with larger actual thicknesses.
|
187
211
|
// We want the icon to be recognisable with a large range of thicknesses.
|
188
212
|
var thickness = Math.sqrt(pen.getThickness()) * 3;
|
@@ -205,8 +229,49 @@ var IconProvider = /** @class */ (function () {
|
|
205
229
|
var icon = document.createElementNS(svgNamespace, 'svg');
|
206
230
|
icon.setAttribute('viewBox', '0 0 100 100');
|
207
231
|
viewport.updateScreenSize(Vec2.of(100, 100));
|
208
|
-
var renderer
|
232
|
+
var renderer;
|
233
|
+
if (includeTransparencyGrid) {
|
234
|
+
var checkerboardPattern_1 = makeCheckerboardPattern();
|
235
|
+
var defs = document.createElementNS(svgNamespace, 'defs');
|
236
|
+
defs.innerHTML = checkerboardPattern_1.patternDef;
|
237
|
+
icon.appendChild(defs);
|
238
|
+
var background_1 = document.createElementNS(svgNamespace, 'g');
|
239
|
+
icon.appendChild(background_1);
|
240
|
+
renderer = new /** @class */ (function (_super) {
|
241
|
+
__extends(class_1, _super);
|
242
|
+
function class_1() {
|
243
|
+
return _super.call(this, icon, viewport) || this;
|
244
|
+
}
|
245
|
+
class_1.prototype.addPathToSVG = function () {
|
246
|
+
var addedPath = _super.prototype.addPathToSVG.call(this);
|
247
|
+
if (addedPath) {
|
248
|
+
// Add a copy of the path on the background
|
249
|
+
var copy = addedPath.cloneNode(true);
|
250
|
+
copy.style.zIndex = '-1';
|
251
|
+
// Make the
|
252
|
+
if (copy.hasAttribute('fill')
|
253
|
+
&& copy.getAttribute('fill') !== 'transparent'
|
254
|
+
&& copy.getAttribute('fill') !== 'none') {
|
255
|
+
copy.setAttribute('fill', checkerboardPattern_1.patternRef);
|
256
|
+
}
|
257
|
+
if (copy.hasAttribute('stroke')) {
|
258
|
+
copy.setAttribute('stroke', checkerboardPattern_1.patternRef);
|
259
|
+
}
|
260
|
+
background_1.appendChild(copy);
|
261
|
+
}
|
262
|
+
return addedPath;
|
263
|
+
};
|
264
|
+
return class_1;
|
265
|
+
}(SVGRenderer))();
|
266
|
+
}
|
267
|
+
else {
|
268
|
+
renderer = new SVGRenderer(icon, viewport);
|
269
|
+
}
|
209
270
|
builder.preview(renderer);
|
271
|
+
// If only a single path was rendered, try to give it a checkerboard background to
|
272
|
+
// emphasize transparency. TODO: This is very fragile
|
273
|
+
var bbox = builder.getBBox();
|
274
|
+
icon.setAttribute('viewBox', "".concat(bbox.x, " ").concat(bbox.y, " ").concat(bbox.w, " ").concat(bbox.h));
|
210
275
|
return icon;
|
211
276
|
};
|
212
277
|
IconProvider.prototype.makePipetteIcon = function (color) {
|
@@ -215,8 +280,9 @@ var IconProvider = /** @class */ (function () {
|
|
215
280
|
pipette.setAttribute('d', "\n\t\t\tM 47,6\n\t\t\tC 35,5 25,15 35,30\n\t\t\tc -9.2,1.3 -15,0 -15,3\n\t\t\t\t0,2 5,5 15,7\n\t\t\tV 81\n\t\t\tL 40,90\n\t\t\th 6\n\t\t\tL 40,80\n\t\t\tV 40\n\t\t\th 15\n\t\t\tv 40\n\t\t\tl -6,10\n\t\t\th 6\n\t\t\tl 5,-9.2\n\t\t\tV 40\n\t\t\tC 70,38 75,35 75,33\n\t\t\t\t75,30 69.2,31.2 60,30\n\t\t\t\t65,15 65,5 47,6\n\t\t\tZ\n\t\t");
|
216
281
|
pipette.style.fill = 'var(--icon-color)';
|
217
282
|
if (color) {
|
283
|
+
var checkerboardPattern = makeCheckerboardPattern();
|
218
284
|
var defs = document.createElementNS(svgNamespace, 'defs');
|
219
|
-
defs.innerHTML =
|
285
|
+
defs.innerHTML = checkerboardPattern.patternDef;
|
220
286
|
icon.appendChild(defs);
|
221
287
|
var fluidBackground = document.createElementNS(svgNamespace, 'path');
|
222
288
|
var fluid = document.createElementNS(svgNamespace, 'path');
|
@@ -224,7 +290,7 @@ var IconProvider = /** @class */ (function () {
|
|
224
290
|
fluid.setAttribute('d', fluidPathData);
|
225
291
|
fluidBackground.setAttribute('d', fluidPathData);
|
226
292
|
fluid.style.fill = color.toHexString();
|
227
|
-
fluidBackground.style.fill =
|
293
|
+
fluidBackground.style.fill = checkerboardPattern.patternRef;
|
228
294
|
icon.appendChild(fluidBackground);
|
229
295
|
icon.appendChild(fluid);
|
230
296
|
}
|
@@ -13,8 +13,8 @@ export interface ToolbarLocalization {
|
|
13
13
|
chooseFile: string;
|
14
14
|
cancel: string;
|
15
15
|
submit: string;
|
16
|
-
|
17
|
-
|
16
|
+
roundedTipPen: string;
|
17
|
+
flatTipPen: string;
|
18
18
|
selectPenType: string;
|
19
19
|
colorLabel: string;
|
20
20
|
pen: string;
|
@@ -32,8 +32,8 @@ export var defaultToolbarLocalization = {
|
|
32
32
|
useGridOption: 'Grid: ',
|
33
33
|
toggleOverflow: 'More',
|
34
34
|
touchPanning: 'Touchscreen panning',
|
35
|
-
|
36
|
-
|
35
|
+
roundedTipPen: 'Rounded Tip',
|
36
|
+
flatTipPen: 'Flat Tip',
|
37
37
|
arrowPen: 'Arrow',
|
38
38
|
linePen: 'Line',
|
39
39
|
outlinedRectanglePen: 'Outlined rectangle',
|
@@ -1,10 +1,12 @@
|
|
1
1
|
import Editor from '../../Editor';
|
2
2
|
import BaseTool from '../../tools/BaseTool';
|
3
|
+
import { KeyPressEvent } from '../../types';
|
3
4
|
import { ToolbarLocalization } from '../localization';
|
4
5
|
import BaseWidget from './BaseWidget';
|
5
6
|
export default abstract class BaseToolWidget extends BaseWidget {
|
6
7
|
protected targetTool: BaseTool;
|
7
8
|
constructor(editor: Editor, targetTool: BaseTool, id: string, localizationTable?: ToolbarLocalization);
|
8
9
|
protected handleClick(): void;
|
10
|
+
protected onKeyPress(event: KeyPressEvent): boolean;
|
9
11
|
addTo(parent: HTMLElement): HTMLElement;
|
10
12
|
}
|
@@ -52,6 +52,13 @@ var BaseToolWidget = /** @class */ (function (_super) {
|
|
52
52
|
this.targetTool.setEnabled(!this.targetTool.isEnabled());
|
53
53
|
}
|
54
54
|
};
|
55
|
+
BaseToolWidget.prototype.onKeyPress = function (event) {
|
56
|
+
if (this.isSelected() && event.key === ' ' && this.hasDropdown) {
|
57
|
+
this.handleClick();
|
58
|
+
return true;
|
59
|
+
}
|
60
|
+
return false;
|
61
|
+
};
|
55
62
|
BaseToolWidget.prototype.addTo = function (parent) {
|
56
63
|
var result = _super.prototype.addTo.call(this, parent);
|
57
64
|
this.setSelected(this.targetTool.isEnabled());
|
@@ -14,12 +14,14 @@ export default class PenToolWidget extends BaseToolWidget {
|
|
14
14
|
private tool;
|
15
15
|
private updateInputs;
|
16
16
|
protected penTypes: PenTypeRecord[];
|
17
|
+
private static idCounter;
|
17
18
|
constructor(editor: Editor, tool: Pen, localization?: ToolbarLocalization);
|
18
19
|
protected getTitle(): string;
|
19
20
|
private getCurrentPenTypeIdx;
|
20
21
|
private getCurrentPenType;
|
22
|
+
private createIconForRecord;
|
21
23
|
protected createIcon(): Element;
|
22
|
-
private
|
24
|
+
private createPenTypeSelector;
|
23
25
|
protected fillDropdown(dropdown: HTMLElement): boolean;
|
24
26
|
protected onKeyPress(event: KeyPressEvent): boolean;
|
25
27
|
serializeState(): SavedToolbuttonState;
|
@@ -45,12 +45,12 @@ var PenToolWidget = /** @class */ (function (_super) {
|
|
45
45
|
// Default pen types
|
46
46
|
_this.penTypes = [
|
47
47
|
{
|
48
|
-
name: _this.localizationTable.
|
48
|
+
name: _this.localizationTable.flatTipPen,
|
49
49
|
id: 'pressure-sensitive-pen',
|
50
50
|
factory: makePressureSensitiveFreehandLineBuilder,
|
51
51
|
},
|
52
52
|
{
|
53
|
-
name: _this.localizationTable.
|
53
|
+
name: _this.localizationTable.roundedTipPen,
|
54
54
|
id: 'freehand-pen',
|
55
55
|
factory: makeFreehandLineBuilder,
|
56
56
|
},
|
@@ -117,38 +117,140 @@ var PenToolWidget = /** @class */ (function (_super) {
|
|
117
117
|
}
|
118
118
|
return null;
|
119
119
|
};
|
120
|
-
PenToolWidget.prototype.
|
121
|
-
var
|
122
|
-
|
120
|
+
PenToolWidget.prototype.createIconForRecord = function (record) {
|
121
|
+
var color = this.tool.getColor();
|
122
|
+
var strokeFactory = record === null || record === void 0 ? void 0 : record.factory;
|
123
|
+
if (!strokeFactory || strokeFactory === makeFreehandLineBuilder || strokeFactory === makePressureSensitiveFreehandLineBuilder) {
|
123
124
|
// Use a square-root scale to prevent the pen's tip from overflowing.
|
124
125
|
var scale = Math.round(Math.sqrt(this.tool.getThickness()) * 4);
|
125
|
-
var color = this.tool.getColor();
|
126
126
|
var roundedTip = strokeFactory === makeFreehandLineBuilder;
|
127
127
|
return this.editor.icons.makePenIcon(scale, color.toHexString(), roundedTip);
|
128
128
|
}
|
129
129
|
else {
|
130
|
-
var
|
131
|
-
return this.editor.icons.makeIconFromFactory(this.tool,
|
130
|
+
var hasTransparency = color.a < 1;
|
131
|
+
return this.editor.icons.makeIconFromFactory(this.tool, strokeFactory, hasTransparency);
|
132
132
|
}
|
133
133
|
};
|
134
|
+
PenToolWidget.prototype.createIcon = function () {
|
135
|
+
return this.createIconForRecord(this.getCurrentPenType());
|
136
|
+
};
|
137
|
+
// Creates a widget that allows selecting different pen types
|
138
|
+
PenToolWidget.prototype.createPenTypeSelector = function () {
|
139
|
+
var _this = this;
|
140
|
+
var outerContainer = document.createElement('div');
|
141
|
+
outerContainer.classList.add("".concat(toolbarCSSPrefix, "pen-type-selector"));
|
142
|
+
var scrollingContainer = document.createElement('div');
|
143
|
+
scrollingContainer.setAttribute('role', 'menu');
|
144
|
+
scrollingContainer.id = "".concat(toolbarCSSPrefix, "-pen-type-selector-id-").concat(PenToolWidget.idCounter++);
|
145
|
+
scrollingContainer.onwheel = function (event) {
|
146
|
+
var hasScroll = scrollingContainer.clientWidth !== scrollingContainer.scrollWidth
|
147
|
+
&& event.deltaX !== 0;
|
148
|
+
var eventScrollsPastLeft = scrollingContainer.scrollLeft + event.deltaX <= 0;
|
149
|
+
var scrollRight = scrollingContainer.scrollLeft + scrollingContainer.clientWidth;
|
150
|
+
var eventScrollsPastRight = scrollRight + event.deltaX > scrollingContainer.scrollWidth;
|
151
|
+
// Stop the editor from receiving the event if it will scroll the pen type selector
|
152
|
+
// instead.
|
153
|
+
if (hasScroll && !eventScrollsPastLeft && !eventScrollsPastRight) {
|
154
|
+
event.stopPropagation();
|
155
|
+
}
|
156
|
+
};
|
157
|
+
var label = document.createElement('label');
|
158
|
+
label.innerText = this.localizationTable.selectPenType;
|
159
|
+
label.htmlFor = scrollingContainer.id;
|
160
|
+
outerContainer.appendChild(label);
|
161
|
+
// All buttons in a radiogroup need the same name attribute.
|
162
|
+
var radiogroupName = "".concat(toolbarCSSPrefix, "-pen-type-selector-").concat(PenToolWidget.idCounter++);
|
163
|
+
var createTypeSelectorButton = function (record) {
|
164
|
+
var buttonContainer = document.createElement('div');
|
165
|
+
buttonContainer.classList.add('pen-type-button');
|
166
|
+
var button = document.createElement('input');
|
167
|
+
button.type = 'radio';
|
168
|
+
button.name = radiogroupName;
|
169
|
+
button.id = "".concat(toolbarCSSPrefix, "-pen-type-button-").concat(PenToolWidget.idCounter++);
|
170
|
+
var labelContainer = document.createElement('label');
|
171
|
+
var rebuildLabel = function () {
|
172
|
+
var labelText = document.createElement('span');
|
173
|
+
var icon = _this.createIconForRecord(record);
|
174
|
+
icon.classList.add('icon');
|
175
|
+
// The title of the record
|
176
|
+
labelText.innerText = record.name;
|
177
|
+
labelContainer.htmlFor = button.id;
|
178
|
+
labelContainer.replaceChildren(icon, labelText);
|
179
|
+
};
|
180
|
+
rebuildLabel();
|
181
|
+
var updateButtonCSS = function () {
|
182
|
+
if (button.checked) {
|
183
|
+
buttonContainer.classList.add('checked');
|
184
|
+
}
|
185
|
+
else {
|
186
|
+
buttonContainer.classList.remove('checked');
|
187
|
+
}
|
188
|
+
};
|
189
|
+
button.oninput = function () {
|
190
|
+
// Setting the stroke factory fires an event that causes the value
|
191
|
+
// of this button to be set.
|
192
|
+
if (button.checked) {
|
193
|
+
_this.tool.setStrokeFactory(record.factory);
|
194
|
+
}
|
195
|
+
updateButtonCSS();
|
196
|
+
};
|
197
|
+
buttonContainer.replaceChildren(button, labelContainer);
|
198
|
+
scrollingContainer.appendChild(buttonContainer);
|
199
|
+
// Set whether the button is checked, assuming the stroke factory associated
|
200
|
+
// with the button was set elsewhere.
|
201
|
+
var setChecked = function (checked) {
|
202
|
+
button.checked = checked;
|
203
|
+
updateButtonCSS();
|
204
|
+
if (checked) {
|
205
|
+
button.scrollIntoView();
|
206
|
+
}
|
207
|
+
};
|
208
|
+
setChecked(false);
|
209
|
+
// Updates the factory's icon based on the current style of the tool.
|
210
|
+
var updateIcon = function () {
|
211
|
+
rebuildLabel();
|
212
|
+
};
|
213
|
+
return { setChecked: setChecked, updateIcon: updateIcon };
|
214
|
+
};
|
215
|
+
var buttons = [];
|
216
|
+
for (var _i = 0, _a = this.penTypes; _i < _a.length; _i++) {
|
217
|
+
var penType = _a[_i];
|
218
|
+
buttons.push(createTypeSelectorButton(penType));
|
219
|
+
}
|
220
|
+
// invariant: buttons.length = this.penTypes.length
|
221
|
+
outerContainer.appendChild(scrollingContainer);
|
222
|
+
return {
|
223
|
+
setValue: function (penTypeIndex) {
|
224
|
+
// Select the value specified
|
225
|
+
if (penTypeIndex < 0 || penTypeIndex >= _this.penTypes.length) {
|
226
|
+
console.error('Invalid pen type index', penTypeIndex);
|
227
|
+
return;
|
228
|
+
}
|
229
|
+
for (var i = 0; i < buttons.length; i++) {
|
230
|
+
buttons[i].setChecked(i === penTypeIndex);
|
231
|
+
}
|
232
|
+
},
|
233
|
+
updateIcons: function () {
|
234
|
+
buttons.forEach(function (button) { return button.updateIcon(); });
|
235
|
+
},
|
236
|
+
addTo: function (parent) {
|
237
|
+
parent.appendChild(outerContainer);
|
238
|
+
},
|
239
|
+
};
|
240
|
+
};
|
134
241
|
PenToolWidget.prototype.fillDropdown = function (dropdown) {
|
135
242
|
var _this = this;
|
136
243
|
var container = document.createElement('div');
|
137
244
|
container.classList.add("".concat(toolbarCSSPrefix, "spacedList"));
|
138
245
|
var thicknessRow = document.createElement('div');
|
139
|
-
var objectTypeRow = document.createElement('div');
|
140
246
|
// Thickness: Value of the input is squared to allow for finer control/larger values.
|
141
247
|
var thicknessLabel = document.createElement('label');
|
142
248
|
var thicknessInput = document.createElement('input');
|
143
|
-
var
|
144
|
-
var objectTypeSelect = document.createElement('select');
|
249
|
+
var penTypeSelect = this.createPenTypeSelector();
|
145
250
|
// Give inputs IDs so we can label them with a <label for=...>Label text</label>
|
146
251
|
thicknessInput.id = "".concat(toolbarCSSPrefix, "penThicknessInput").concat(PenToolWidget.idCounter++);
|
147
|
-
objectTypeSelect.id = "".concat(toolbarCSSPrefix, "penBuilderSelect").concat(PenToolWidget.idCounter++);
|
148
252
|
thicknessLabel.innerText = this.localizationTable.thicknessLabel;
|
149
253
|
thicknessLabel.setAttribute('for', thicknessInput.id);
|
150
|
-
objectSelectLabel.innerText = this.localizationTable.selectPenType;
|
151
|
-
objectSelectLabel.setAttribute('for', objectTypeSelect.id);
|
152
254
|
// Use a logarithmic scale for thicknessInput (finer control over thinner strokewidths.)
|
153
255
|
var inverseThicknessInputFn = function (t) { return Math.log10(t); };
|
154
256
|
var thicknessInputFn = function (t) { return Math.pow(10, t); };
|
@@ -161,16 +263,6 @@ var PenToolWidget = /** @class */ (function (_super) {
|
|
161
263
|
};
|
162
264
|
thicknessRow.appendChild(thicknessLabel);
|
163
265
|
thicknessRow.appendChild(thicknessInput);
|
164
|
-
objectTypeSelect.oninput = function () {
|
165
|
-
var penTypeIdx = parseInt(objectTypeSelect.value);
|
166
|
-
if (penTypeIdx < 0 || penTypeIdx >= _this.penTypes.length) {
|
167
|
-
console.error('Invalid pen type index', penTypeIdx);
|
168
|
-
return;
|
169
|
-
}
|
170
|
-
_this.tool.setStrokeFactory(_this.penTypes[penTypeIdx].factory);
|
171
|
-
};
|
172
|
-
objectTypeRow.appendChild(objectSelectLabel);
|
173
|
-
objectTypeRow.appendChild(objectTypeSelect);
|
174
266
|
var colorRow = document.createElement('div');
|
175
267
|
var colorLabel = document.createElement('label');
|
176
268
|
var _a = makeColorInput(this.editor, function (color) {
|
@@ -184,26 +276,13 @@ var PenToolWidget = /** @class */ (function (_super) {
|
|
184
276
|
this.updateInputs = function () {
|
185
277
|
setColorInputValue(_this.tool.getColor());
|
186
278
|
thicknessInput.value = inverseThicknessInputFn(_this.tool.getThickness()).toString();
|
187
|
-
|
188
|
-
objectTypeSelect.replaceChildren();
|
189
|
-
for (var i = 0; i < _this.penTypes.length; i++) {
|
190
|
-
var penType = _this.penTypes[i];
|
191
|
-
var option = document.createElement('option');
|
192
|
-
option.value = i.toString();
|
193
|
-
option.innerText = penType.name;
|
194
|
-
objectTypeSelect.appendChild(option);
|
195
|
-
}
|
279
|
+
penTypeSelect.updateIcons();
|
196
280
|
// Update the selected stroke factory.
|
197
|
-
|
198
|
-
if (strokeFactoryIdx === -1) {
|
199
|
-
objectTypeSelect.value = '';
|
200
|
-
}
|
201
|
-
else {
|
202
|
-
objectTypeSelect.value = strokeFactoryIdx.toString();
|
203
|
-
}
|
281
|
+
penTypeSelect.setValue(_this.getCurrentPenTypeIdx());
|
204
282
|
};
|
205
283
|
this.updateInputs();
|
206
|
-
container.replaceChildren(colorRow, thicknessRow
|
284
|
+
container.replaceChildren(colorRow, thicknessRow);
|
285
|
+
penTypeSelect.addTo(container);
|
207
286
|
dropdown.replaceChildren(container);
|
208
287
|
return true;
|
209
288
|
};
|
@@ -221,6 +300,10 @@ var PenToolWidget = /** @class */ (function (_super) {
|
|
221
300
|
}
|
222
301
|
}
|
223
302
|
}
|
303
|
+
// Run any default actions registered by the parent class.
|
304
|
+
if (_super.prototype.onKeyPress.call(this, event)) {
|
305
|
+
return true;
|
306
|
+
}
|
224
307
|
return false;
|
225
308
|
};
|
226
309
|
PenToolWidget.prototype.serializeState = function () {
|
@@ -256,6 +339,7 @@ var PenToolWidget = /** @class */ (function (_super) {
|
|
256
339
|
}
|
257
340
|
}
|
258
341
|
};
|
342
|
+
// A counter variable that ensures different HTML elements are given unique names/ids.
|
259
343
|
PenToolWidget.idCounter = 0;
|
260
344
|
return PenToolWidget;
|
261
345
|
}(BaseToolWidget));
|
@@ -198,6 +198,10 @@ var SelectionToolWidget = /** @class */ (function (_super) {
|
|
198
198
|
this.resizeImageToSelection();
|
199
199
|
return true;
|
200
200
|
}
|
201
|
+
// If we didn't handle the event, allow the superclass to handle it.
|
202
|
+
if (_super.prototype.onKeyPress.call(this, event)) {
|
203
|
+
return true;
|
204
|
+
}
|
201
205
|
return false;
|
202
206
|
};
|
203
207
|
SelectionToolWidget.prototype.getTitle = function () {
|
@@ -5,9 +5,19 @@ export default abstract class BaseTool implements PointerEvtListener {
|
|
5
5
|
readonly description: string;
|
6
6
|
private enabled;
|
7
7
|
private group;
|
8
|
+
/**
|
9
|
+
* Returns true iff the tool handled the event and thus should receive additional
|
10
|
+
* events.
|
11
|
+
*/
|
8
12
|
onPointerDown(_event: PointerEvt): boolean;
|
9
13
|
onPointerMove(_event: PointerEvt): void;
|
10
|
-
|
14
|
+
/**
|
15
|
+
* Returns true iff there are additional pointers down and the tool should
|
16
|
+
* remain active to handle the additional events.
|
17
|
+
*
|
18
|
+
* For most purposes, this should return `false` or nothing.
|
19
|
+
*/
|
20
|
+
onPointerUp(_event: PointerEvt): boolean | void;
|
11
21
|
onGestureCancel(): void;
|
12
22
|
protected constructor(notifier: EditorNotifier, description: string);
|
13
23
|
onWheel(_event: WheelEvt): boolean;
|
@@ -15,6 +25,12 @@ export default abstract class BaseTool implements PointerEvtListener {
|
|
15
25
|
onPaste(_event: PasteEvent): boolean;
|
16
26
|
onKeyPress(_event: KeyPressEvent): boolean;
|
17
27
|
onKeyUp(_event: KeyUpEvent): boolean;
|
28
|
+
/**
|
29
|
+
* Return true if, while this tool is active, `_event` can be delivered to
|
30
|
+
* another tool that is higher priority than this.
|
31
|
+
* @internal May be renamed
|
32
|
+
*/
|
33
|
+
eventCanBeDeliveredToNonActiveTool(_event: PointerEvt): boolean;
|
18
34
|
setEnabled(enabled: boolean): void;
|
19
35
|
isEnabled(): boolean;
|
20
36
|
setToolGroup(group: ToolEnabledGroup): void;
|
@@ -6,8 +6,18 @@ var BaseTool = /** @class */ (function () {
|
|
6
6
|
this.enabled = true;
|
7
7
|
this.group = null;
|
8
8
|
}
|
9
|
+
/**
|
10
|
+
* Returns true iff the tool handled the event and thus should receive additional
|
11
|
+
* events.
|
12
|
+
*/
|
9
13
|
BaseTool.prototype.onPointerDown = function (_event) { return false; };
|
10
14
|
BaseTool.prototype.onPointerMove = function (_event) { };
|
15
|
+
/**
|
16
|
+
* Returns true iff there are additional pointers down and the tool should
|
17
|
+
* remain active to handle the additional events.
|
18
|
+
*
|
19
|
+
* For most purposes, this should return `false` or nothing.
|
20
|
+
*/
|
11
21
|
BaseTool.prototype.onPointerUp = function (_event) { };
|
12
22
|
BaseTool.prototype.onGestureCancel = function () { };
|
13
23
|
BaseTool.prototype.onWheel = function (_event) {
|
@@ -25,6 +35,14 @@ var BaseTool = /** @class */ (function () {
|
|
25
35
|
BaseTool.prototype.onKeyUp = function (_event) {
|
26
36
|
return false;
|
27
37
|
};
|
38
|
+
/**
|
39
|
+
* Return true if, while this tool is active, `_event` can be delivered to
|
40
|
+
* another tool that is higher priority than this.
|
41
|
+
* @internal May be renamed
|
42
|
+
*/
|
43
|
+
BaseTool.prototype.eventCanBeDeliveredToNonActiveTool = function (_event) {
|
44
|
+
return true;
|
45
|
+
};
|
28
46
|
BaseTool.prototype.setEnabled = function (enabled) {
|
29
47
|
var _a;
|
30
48
|
this.enabled = enabled;
|
package/dist/mjs/tools/Pen.d.ts
CHANGED
@@ -15,6 +15,7 @@ export default class Pen extends BaseTool {
|
|
15
15
|
protected builder: ComponentBuilder | null;
|
16
16
|
private lastPoint;
|
17
17
|
private startPoint;
|
18
|
+
private currentDeviceType;
|
18
19
|
private snapToGridEnabled;
|
19
20
|
private angleLockEnabled;
|
20
21
|
constructor(editor: Editor, description: string, style: PenStyle, builderFactory?: ComponentBuilderFactory);
|
@@ -23,9 +24,11 @@ export default class Pen extends BaseTool {
|
|
23
24
|
protected toStrokePoint(pointer: Pointer): StrokeDataPoint;
|
24
25
|
protected previewStroke(): void;
|
25
26
|
protected addPointToStroke(point: StrokeDataPoint): void;
|
26
|
-
onPointerDown(
|
27
|
+
onPointerDown(event: PointerEvt): boolean;
|
28
|
+
private eventCanCancelStroke;
|
29
|
+
eventCanBeDeliveredToNonActiveTool(event: PointerEvt): boolean;
|
27
30
|
onPointerMove({ current }: PointerEvt): void;
|
28
|
-
onPointerUp({ current }: PointerEvt):
|
31
|
+
onPointerUp({ current }: PointerEvt): boolean;
|
29
32
|
onGestureCancel(): void;
|
30
33
|
private finalizeStroke;
|
31
34
|
private noteUpdated;
|