@lvl99dotcom/paintcanvas 0.0.0-stage → 0.2.0
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/LICENSE +201 -0
- package/README.md +131 -2
- package/dist/index.d.ts +2 -0
- package/dist/index.js +5 -0
- package/dist/lib/brushes/BrushTipCache/index.d.ts +32 -0
- package/dist/lib/brushes/BrushTipCache/index.js +60 -0
- package/dist/lib/brushes/StrokeEngine/index.d.ts +171 -0
- package/dist/lib/brushes/StrokeEngine/index.js +324 -0
- package/dist/lib/brushes/StrokePath/index.d.ts +53 -0
- package/dist/lib/brushes/StrokePath/index.js +161 -0
- package/dist/lib/brushes/StrokeSampler/index.d.ts +55 -0
- package/dist/lib/brushes/StrokeSampler/index.js +75 -0
- package/dist/lib/brushes/authors/index.d.ts +55 -0
- package/dist/lib/brushes/authors/index.js +60 -0
- package/dist/lib/brushes/configRanges/index.d.ts +52 -0
- package/dist/lib/brushes/configRanges/index.js +206 -0
- package/dist/lib/brushes/index.d.ts +5 -0
- package/dist/lib/brushes/index.js +19 -0
- package/dist/lib/brushes/params/index.d.ts +108 -0
- package/dist/lib/brushes/params/index.js +139 -0
- package/dist/lib/brushes/presetFile/index.d.ts +32 -0
- package/dist/lib/brushes/presetFile/index.js +55 -0
- package/dist/lib/brushes/presets/drawing/brush-pen.js +3 -0
- package/dist/lib/brushes/presets/drawing/felt-pen.js +3 -0
- package/dist/lib/brushes/presets/drawing/index.d.ts +13 -0
- package/dist/lib/brushes/presets/drawing/index.js +88 -0
- package/dist/lib/brushes/presets/drawing/pencil-2b.js +3 -0
- package/dist/lib/brushes/presets/drawing/pencil-hb.js +3 -0
- package/dist/lib/brushes/presets/painting/grass.js +3 -0
- package/dist/lib/brushes/presets/painting/hair.js +3 -0
- package/dist/lib/brushes/presets/painting/index.d.ts +18 -0
- package/dist/lib/brushes/presets/painting/index.js +118 -0
- package/dist/lib/brushes/presets/painting/splatter.js +3 -0
- package/dist/lib/brushes/presets/painting/textured-paint.js +3 -0
- package/dist/lib/brushes/presets/painting/watery-paint.js +3 -0
- package/dist/lib/brushes/presets/round/index.d.ts +9 -0
- package/dist/lib/brushes/presets/round/index.js +44 -0
- package/dist/lib/brushes/presets/round/round.js +3 -0
- package/dist/lib/brushes/presets/round/soft-round.js +3 -0
- package/dist/lib/brushes/presets/sized/index.d.ts +20 -0
- package/dist/lib/brushes/presets/sized/index.js +30 -0
- package/dist/lib/brushes/presets/sketching/index.d.ts +14 -0
- package/dist/lib/brushes/presets/sketching/index.js +107 -0
- package/dist/lib/brushes/presets/square/index.d.ts +7 -0
- package/dist/lib/brushes/presets/square/index.js +22 -0
- package/dist/lib/brushes/presets/square/square.js +3 -0
- package/dist/lib/brushes/shapeImage/index.d.ts +40 -0
- package/dist/lib/brushes/shapeImage/index.js +61 -0
- package/dist/lib/brushes/types/index.d.ts +243 -0
- package/dist/lib/brushes/types/index.js +20 -0
- package/dist/lib/classes/BackgroundWork/index.d.ts +55 -0
- package/dist/lib/classes/BackgroundWork/index.js +97 -0
- package/dist/lib/classes/BrushSettings/index.d.ts +91 -0
- package/dist/lib/classes/BrushSettings/index.js +152 -0
- package/dist/lib/classes/CustomPresets/index.d.ts +53 -0
- package/dist/lib/classes/CustomPresets/index.js +71 -0
- package/dist/lib/classes/ExternalSheets/index.d.ts +64 -0
- package/dist/lib/classes/ExternalSheets/index.js +112 -0
- package/dist/lib/classes/GestureTracker/index.d.ts +62 -0
- package/dist/lib/classes/GestureTracker/index.js +122 -0
- package/dist/lib/classes/History/index.d.ts +83 -0
- package/dist/lib/classes/History/index.js +126 -0
- package/dist/lib/classes/HistoryGuard/index.d.ts +58 -0
- package/dist/lib/classes/HistoryGuard/index.js +97 -0
- package/dist/lib/classes/InputSettings/index.d.ts +74 -0
- package/dist/lib/classes/InputSettings/index.js +101 -0
- package/dist/lib/classes/KeyboardShortcuts/index.d.ts +48 -0
- package/dist/lib/classes/KeyboardShortcuts/index.js +137 -0
- package/dist/lib/classes/Layer/index.d.ts +86 -0
- package/dist/lib/classes/Layer/index.js +111 -0
- package/dist/lib/classes/LayerAutosave/index.d.ts +180 -0
- package/dist/lib/classes/LayerAutosave/index.js +346 -0
- package/dist/lib/classes/LayerStack/index.d.ts +177 -0
- package/dist/lib/classes/LayerStack/index.js +394 -0
- package/dist/lib/classes/PaintCanvas/index.d.ts +537 -0
- package/dist/lib/classes/PaintCanvas/index.js +965 -0
- package/dist/lib/classes/StrokeLog/index.d.ts +149 -0
- package/dist/lib/classes/StrokeLog/index.js +257 -0
- package/dist/lib/classes/Viewport/index.d.ts +108 -0
- package/dist/lib/classes/Viewport/index.js +194 -0
- package/dist/lib/document/index.d.ts +17 -0
- package/dist/lib/document/index.js +25 -0
- package/dist/lib/document/schema.d.ts +132 -0
- package/dist/lib/document/schema.js +110 -0
- package/dist/lib/i18n/index.d.ts +94 -0
- package/dist/lib/i18n/index.js +182 -0
- package/dist/lib/image/index.d.ts +90 -0
- package/dist/lib/image/index.js +147 -0
- package/dist/lib/messages/PatchSender/index.d.ts +75 -0
- package/dist/lib/messages/PatchSender/index.js +125 -0
- package/dist/lib/messages/index.d.ts +26 -0
- package/dist/lib/messages/index.js +59 -0
- package/dist/lib/messages/schema.d.ts +1775 -0
- package/dist/lib/messages/schema.js +192 -0
- package/dist/lib/presets/index.d.ts +32 -0
- package/dist/lib/presets/index.js +35 -0
- package/dist/lib/presets/schema.d.ts +753 -0
- package/dist/lib/presets/schema.js +181 -0
- package/dist/lib/rendering/BrushTip/index.d.ts +63 -0
- package/dist/lib/rendering/BrushTip/index.js +112 -0
- package/dist/lib/rendering/checkerboard/index.d.ts +22 -0
- package/dist/lib/rendering/checkerboard/index.js +31 -0
- package/dist/lib/rendering/compositing/index.d.ts +64 -0
- package/dist/lib/rendering/compositing/index.js +124 -0
- package/dist/lib/rendering/cursor/index.d.ts +14 -0
- package/dist/lib/rendering/cursor/index.js +39 -0
- package/dist/lib/rendering/cursors/index.d.ts +18 -0
- package/dist/lib/rendering/cursors/index.js +23 -0
- package/dist/lib/rendering/maskOutline/index.d.ts +22 -0
- package/dist/lib/rendering/maskOutline/index.js +78 -0
- package/dist/lib/rendering/outline/index.d.ts +36 -0
- package/dist/lib/rendering/outline/index.js +120 -0
- package/dist/lib/rendering/sample/index.d.ts +55 -0
- package/dist/lib/rendering/sample/index.js +83 -0
- package/dist/lib/rendering/screenshot/index.d.ts +67 -0
- package/dist/lib/rendering/screenshot/index.js +96 -0
- package/dist/lib/rendering/transformBox/index.d.ts +10 -0
- package/dist/lib/rendering/transformBox/index.js +57 -0
- package/dist/lib/selection/Lasso/index.d.ts +70 -0
- package/dist/lib/selection/Lasso/index.js +156 -0
- package/dist/lib/selection/Selection/index.d.ts +86 -0
- package/dist/lib/selection/Selection/index.js +228 -0
- package/dist/lib/selection/geometry/index.d.ts +37 -0
- package/dist/lib/selection/geometry/index.js +57 -0
- package/dist/lib/storage/index.d.ts +63 -0
- package/dist/lib/storage/index.js +114 -0
- package/dist/lib/transform/Transformer/index.d.ts +124 -0
- package/dist/lib/transform/Transformer/index.js +286 -0
- package/dist/lib/transform/geometry/index.d.ts +95 -0
- package/dist/lib/transform/geometry/index.js +258 -0
- package/dist/lib/utils/array/index.d.ts +10 -0
- package/dist/lib/utils/array/index.js +21 -0
- package/dist/lib/utils/gestures/index.d.ts +35 -0
- package/dist/lib/utils/gestures/index.js +81 -0
- package/dist/lib/utils/navigation/index.d.ts +51 -0
- package/dist/lib/utils/navigation/index.js +59 -0
- package/dist/lib/utils/random/index.d.ts +18 -0
- package/dist/lib/utils/random/index.js +27 -0
- package/dist/lib/utils/shortcuts/index.d.ts +74 -0
- package/dist/lib/utils/shortcuts/index.js +189 -0
- package/dist/lib/validation/validators.generated.d.ts +27 -0
- package/dist/lib/validation/validators.generated.js +19826 -0
- package/dist/locales/en-GB.js +188 -0
- package/dist/locales/en-US.js +188 -0
- package/dist/locales/fr.js +188 -0
- package/dist/locales/ja.js +188 -0
- package/dist/locales/ko.js +188 -0
- package/dist/locales/zh-Hans.js +188 -0
- package/dist/locales/zh-Hant.js +188 -0
- package/dist/package.js +3 -0
- package/dist/testing/app.d.ts +7 -0
- package/dist/testing/app.js +16 -0
- package/dist/testing/elements.d.ts +42 -0
- package/dist/testing/elements.js +58 -0
- package/dist/testing/fakeCanvas.d.ts +21 -0
- package/dist/testing/fakeCanvas.js +26 -0
- package/dist/testing/layerStore.d.ts +26 -0
- package/dist/testing/layerStore.js +43 -0
- package/dist/testing/locks.d.ts +15 -0
- package/dist/testing/locks.js +41 -0
- package/dist/testing/recordingCanvas.d.ts +14 -0
- package/dist/testing/recordingCanvas.js +28 -0
- package/dist/testing/recordingContext.d.ts +10 -0
- package/dist/testing/recordingContext.js +19 -0
- package/dist/ui/ChangeController/index.d.ts +40 -0
- package/dist/ui/ChangeController/index.js +62 -0
- package/dist/ui/base/index.d.ts +69 -0
- package/dist/ui/base/index.js +94 -0
- package/dist/ui/elements/PaintCanvas/index.d.ts +249 -0
- package/dist/ui/elements/PaintCanvas/index.js +584 -0
- package/dist/ui/elements/PaintCanvas/style.js +3 -0
- package/dist/ui/elements/PcBrushConfig/index.d.ts +130 -0
- package/dist/ui/elements/PcBrushConfig/index.js +463 -0
- package/dist/ui/elements/PcBrushConfig/style.js +3 -0
- package/dist/ui/elements/PcBrushMenu/index.d.ts +121 -0
- package/dist/ui/elements/PcBrushMenu/index.js +362 -0
- package/dist/ui/elements/PcBrushMenu/style.js +3 -0
- package/dist/ui/elements/PcBrushTest/index.d.ts +71 -0
- package/dist/ui/elements/PcBrushTest/index.js +136 -0
- package/dist/ui/elements/PcBrushTest/style.js +3 -0
- package/dist/ui/elements/PcButton/index.d.ts +57 -0
- package/dist/ui/elements/PcButton/index.js +124 -0
- package/dist/ui/elements/PcButtonGroup/index.d.ts +44 -0
- package/dist/ui/elements/PcButtonGroup/index.js +93 -0
- package/dist/ui/elements/PcCanvas/index.d.ts +356 -0
- package/dist/ui/elements/PcCanvas/index.js +1004 -0
- package/dist/ui/elements/PcCanvas/style.js +3 -0
- package/dist/ui/elements/PcCanvasMap/index.d.ts +96 -0
- package/dist/ui/elements/PcCanvasMap/index.js +187 -0
- package/dist/ui/elements/PcCanvasMap/style.js +3 -0
- package/dist/ui/elements/PcContextMenu/index.d.ts +72 -0
- package/dist/ui/elements/PcContextMenu/index.js +148 -0
- package/dist/ui/elements/PcDialog/index.d.ts +63 -0
- package/dist/ui/elements/PcDialog/index.js +114 -0
- package/dist/ui/elements/PcIcon/index.d.ts +36 -0
- package/dist/ui/elements/PcIcon/index.js +43 -0
- package/dist/ui/elements/PcIconToggle/index.d.ts +46 -0
- package/dist/ui/elements/PcIconToggle/index.js +87 -0
- package/dist/ui/elements/PcInfoTip/index.d.ts +40 -0
- package/dist/ui/elements/PcInfoTip/index.js +95 -0
- package/dist/ui/elements/PcInputSettings/index.d.ts +69 -0
- package/dist/ui/elements/PcInputSettings/index.js +150 -0
- package/dist/ui/elements/PcLayerItem/index.d.ts +221 -0
- package/dist/ui/elements/PcLayerItem/index.js +561 -0
- package/dist/ui/elements/PcLayerItem/style.js +3 -0
- package/dist/ui/elements/PcLayersMenu/index.d.ts +108 -0
- package/dist/ui/elements/PcLayersMenu/index.js +208 -0
- package/dist/ui/elements/PcLayersMenu/style.js +3 -0
- package/dist/ui/elements/PcMatch/index.d.ts +31 -0
- package/dist/ui/elements/PcMatch/index.js +58 -0
- package/dist/ui/elements/PcPanel/index.d.ts +43 -0
- package/dist/ui/elements/PcPanel/index.js +51 -0
- package/dist/ui/elements/PcPopover/index.d.ts +48 -0
- package/dist/ui/elements/PcPopover/index.js +86 -0
- package/dist/ui/elements/PcSlider/index.d.ts +57 -0
- package/dist/ui/elements/PcSlider/index.js +88 -0
- package/dist/ui/elements/PcStats/index.d.ts +54 -0
- package/dist/ui/elements/PcStats/index.js +141 -0
- package/dist/ui/elements/PcThemePicker/index.d.ts +56 -0
- package/dist/ui/elements/PcThemePicker/index.js +134 -0
- package/dist/ui/elements/PcToast/index.d.ts +58 -0
- package/dist/ui/elements/PcToast/index.js +110 -0
- package/dist/ui/elements/PcToggleCheckbox/index.d.ts +37 -0
- package/dist/ui/elements/PcToggleCheckbox/index.js +105 -0
- package/dist/ui/elements/PcToolSettings/index.d.ts +128 -0
- package/dist/ui/elements/PcToolSettings/index.js +543 -0
- package/dist/ui/elements/PcToolSettings/style.js +3 -0
- package/dist/ui/elements/PcToolbar/index.d.ts +71 -0
- package/dist/ui/elements/PcToolbar/index.js +190 -0
- package/dist/ui/elements/PcToolbar/style.js +3 -0
- package/dist/ui/icons/images/brush.js +3 -0
- package/dist/ui/icons/images/circle-mask.js +3 -0
- package/dist/ui/icons/images/clipboard.js +3 -0
- package/dist/ui/icons/images/cursor.js +3 -0
- package/dist/ui/icons/images/eraser.js +3 -0
- package/dist/ui/icons/images/eyedropper.js +3 -0
- package/dist/ui/icons/images/flip-horizontal.js +3 -0
- package/dist/ui/icons/images/flip-vertical.js +3 -0
- package/dist/ui/icons/images/focus-pen.js +3 -0
- package/dist/ui/icons/images/freehand-mask.js +3 -0
- package/dist/ui/icons/images/hidden.js +3 -0
- package/dist/ui/icons/images/layers.js +3 -0
- package/dist/ui/icons/images/linked.js +3 -0
- package/dist/ui/icons/images/locked.js +3 -0
- package/dist/ui/icons/images/moon.js +3 -0
- package/dist/ui/icons/images/pan.js +3 -0
- package/dist/ui/icons/images/polygon-mask.js +3 -0
- package/dist/ui/icons/images/pressure.js +3 -0
- package/dist/ui/icons/images/randomise.js +3 -0
- package/dist/ui/icons/images/rectangle-mask.js +3 -0
- package/dist/ui/icons/images/redo.js +3 -0
- package/dist/ui/icons/images/rotate-90-left.js +3 -0
- package/dist/ui/icons/images/rotate-90-right.js +3 -0
- package/dist/ui/icons/images/smoothing-bezier-cubic.js +3 -0
- package/dist/ui/icons/images/smoothing-bezier-quad.js +3 -0
- package/dist/ui/icons/images/smoothing-linear.js +3 -0
- package/dist/ui/icons/images/star.js +3 -0
- package/dist/ui/icons/images/sun.js +3 -0
- package/dist/ui/icons/images/tilt.js +3 -0
- package/dist/ui/icons/images/undo.js +3 -0
- package/dist/ui/icons/images/unlinked.js +3 -0
- package/dist/ui/icons/images/unlocked.js +3 -0
- package/dist/ui/icons/images/visible.js +3 -0
- package/dist/ui/icons/images/zoom-in.js +3 -0
- package/dist/ui/icons/images/zoom-out.js +3 -0
- package/dist/ui/icons/images/zoom.js +3 -0
- package/dist/ui/icons/index.d.ts +42 -0
- package/dist/ui/icons/index.js +130 -0
- package/dist/ui/index.d.ts +21 -0
- package/dist/ui/index.js +22 -0
- package/dist/ui/layout/index.d.ts +88 -0
- package/dist/ui/layout/index.js +96 -0
- package/dist/ui/styles/index.d.ts +13 -0
- package/dist/ui/styles/index.js +195 -0
- package/dist/ui/tokens/index.d.ts +29 -0
- package/dist/ui/tokens/index.js +114 -0
- package/locales/en-GB.json +186 -0
- package/locales/en-US.json +186 -0
- package/locales/fr.json +186 -0
- package/locales/ja.json +186 -0
- package/locales/ko.json +186 -0
- package/locales/zh-Hans.json +186 -0
- package/locales/zh-Hant.json +186 -0
- package/package.json +97 -3
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import type { BrushConfig, BrushesConfig } from "../../brushes/types";
|
|
2
|
+
/** Smallest brush size in pixels */
|
|
3
|
+
export declare const MIN_BRUSH_SIZE = 1;
|
|
4
|
+
/** Largest brush size in pixels */
|
|
5
|
+
export declare const MAX_BRUSH_SIZE = 256;
|
|
6
|
+
/** Fraction of the current size added or removed by `grow` and `shrink` ("]" and "[" keys) */
|
|
7
|
+
export declare const BRUSH_SIZE_STEP = 0.1;
|
|
8
|
+
/**
|
|
9
|
+
* Clamp a value between min and max.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* clamp(300, 1, 256); // 256
|
|
13
|
+
*/
|
|
14
|
+
export declare const clamp: (value: number, min: number, max: number) => number;
|
|
15
|
+
/**
|
|
16
|
+
* The settings of a brush or eraser: the selected preset, an editable copy of its settings (changed from the tool
|
|
17
|
+
* settings bar or the configuration window, without changing the preset) and the size. The brush and eraser each have
|
|
18
|
+
* their own instance.
|
|
19
|
+
*
|
|
20
|
+
* Dispatches a `change` event whenever the presets, settings or size change.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* const brush = new BrushSettings(standardBrushes);
|
|
24
|
+
* brush.grow(); // "]" key
|
|
25
|
+
* brush.update({ alpha: 0.5 }); // half opacity, until another preset is selected
|
|
26
|
+
*/
|
|
27
|
+
export default class BrushSettings extends EventTarget {
|
|
28
|
+
/** Available presets */
|
|
29
|
+
presets: BrushesConfig;
|
|
30
|
+
/** Current width in pixels */
|
|
31
|
+
width: number;
|
|
32
|
+
/** Current height in pixels */
|
|
33
|
+
height: number;
|
|
34
|
+
/** ID of the selected preset */
|
|
35
|
+
presetId: string;
|
|
36
|
+
/** The current settings: a copy of the selected preset, with any changes */
|
|
37
|
+
private current;
|
|
38
|
+
constructor(presets: BrushesConfig);
|
|
39
|
+
/** The current settings: the selected preset's, with any changes made since selecting it */
|
|
40
|
+
get preset(): BrushConfig;
|
|
41
|
+
/** The selected preset as saved, or undefined if it no longer exists */
|
|
42
|
+
get selectedPreset(): BrushConfig | undefined;
|
|
43
|
+
/**
|
|
44
|
+
* Select a preset: use a fresh copy of its settings and its default size.
|
|
45
|
+
*/
|
|
46
|
+
select(id: string): void;
|
|
47
|
+
/**
|
|
48
|
+
* Change the current settings (not the preset). The size is changed with `setSize`.
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* brush.update({ alpha: 0.5, widthConfig: { usePressure: true } });
|
|
52
|
+
*/
|
|
53
|
+
update(changes: Partial<BrushConfig>): void;
|
|
54
|
+
/**
|
|
55
|
+
* Replace the current settings and size with a whole configuration (the configuration window's "Save").
|
|
56
|
+
*/
|
|
57
|
+
apply(config: BrushConfig): void;
|
|
58
|
+
/**
|
|
59
|
+
* Replace the available presets (e.g. when custom presets are added or removed). If the selected preset is gone, the
|
|
60
|
+
* current settings stay until another preset is selected.
|
|
61
|
+
*/
|
|
62
|
+
setPresets(presets: BrushesConfig): void;
|
|
63
|
+
/**
|
|
64
|
+
* Set the height, clamped to 1–256 pixels. If the settings constrain proportions, width follows height.
|
|
65
|
+
*/
|
|
66
|
+
setHeight(height: number): void;
|
|
67
|
+
/**
|
|
68
|
+
* Set the size, clamped to 1–256 pixels. If the settings constrain proportions, height follows width.
|
|
69
|
+
*/
|
|
70
|
+
setSize(width: number, height?: number): void;
|
|
71
|
+
/**
|
|
72
|
+
* Change the size by a number of pixels (positive = bigger). Used when dragging up/right (bigger) or down/left (smaller).
|
|
73
|
+
*/
|
|
74
|
+
resize(delta: number): void;
|
|
75
|
+
/**
|
|
76
|
+
* Increase the size by one step (at least 1 pixel).
|
|
77
|
+
*/
|
|
78
|
+
grow(): void;
|
|
79
|
+
/**
|
|
80
|
+
* Decrease the size by one step (at least 1 pixel).
|
|
81
|
+
*/
|
|
82
|
+
shrink(): void;
|
|
83
|
+
/**
|
|
84
|
+
* Use a preset's (or configuration's) default size.
|
|
85
|
+
*/
|
|
86
|
+
private applyPresetSize;
|
|
87
|
+
/**
|
|
88
|
+
* Dispatch a `change` event.
|
|
89
|
+
*/
|
|
90
|
+
private notify;
|
|
91
|
+
}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
// src/lib/classes/BrushSettings/index.ts
|
|
2
|
+
/** Smallest brush size in pixels */
|
|
3
|
+
var MIN_BRUSH_SIZE = 1;
|
|
4
|
+
/** Largest brush size in pixels */
|
|
5
|
+
var MAX_BRUSH_SIZE = 256;
|
|
6
|
+
/** Fraction of the current size added or removed by `grow` and `shrink` ("]" and "[" keys) */
|
|
7
|
+
var BRUSH_SIZE_STEP = .1;
|
|
8
|
+
/**
|
|
9
|
+
* Clamp a value between min and max.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* clamp(300, 1, 256); // 256
|
|
13
|
+
*/
|
|
14
|
+
var clamp = (value, min, max) => Math.max(min, Math.min(max, value));
|
|
15
|
+
/**
|
|
16
|
+
* The settings of a brush or eraser: the selected preset, an editable copy of its settings (changed from the tool
|
|
17
|
+
* settings bar or the configuration window, without changing the preset) and the size. The brush and eraser each have
|
|
18
|
+
* their own instance.
|
|
19
|
+
*
|
|
20
|
+
* Dispatches a `change` event whenever the presets, settings or size change.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* const brush = new BrushSettings(standardBrushes);
|
|
24
|
+
* brush.grow(); // "]" key
|
|
25
|
+
* brush.update({ alpha: 0.5 }); // half opacity, until another preset is selected
|
|
26
|
+
*/
|
|
27
|
+
var BrushSettings = class extends EventTarget {
|
|
28
|
+
/** Available presets */
|
|
29
|
+
presets;
|
|
30
|
+
/** Current width in pixels */
|
|
31
|
+
width = 1;
|
|
32
|
+
/** Current height in pixels */
|
|
33
|
+
height = 1;
|
|
34
|
+
/** ID of the selected preset */
|
|
35
|
+
presetId;
|
|
36
|
+
/** The current settings: a copy of the selected preset, with any changes */
|
|
37
|
+
current;
|
|
38
|
+
constructor(presets) {
|
|
39
|
+
super();
|
|
40
|
+
const first = Object.values(presets)[0];
|
|
41
|
+
if (!first) throw new Error("At least one brush preset is required");
|
|
42
|
+
this.presets = presets;
|
|
43
|
+
this.presetId = first.id;
|
|
44
|
+
this.current = structuredClone(first);
|
|
45
|
+
this.applyPresetSize(first);
|
|
46
|
+
}
|
|
47
|
+
/** The current settings: the selected preset's, with any changes made since selecting it */
|
|
48
|
+
get preset() {
|
|
49
|
+
return this.current;
|
|
50
|
+
}
|
|
51
|
+
/** The selected preset as saved, or undefined if it no longer exists */
|
|
52
|
+
get selectedPreset() {
|
|
53
|
+
return this.presets[this.presetId];
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Select a preset: use a fresh copy of its settings and its default size.
|
|
57
|
+
*/
|
|
58
|
+
select(id) {
|
|
59
|
+
const preset = this.presets[id];
|
|
60
|
+
if (!preset) throw new Error(`Brush preset ${id} not found`);
|
|
61
|
+
this.presetId = id;
|
|
62
|
+
this.current = structuredClone(preset);
|
|
63
|
+
this.applyPresetSize(preset);
|
|
64
|
+
this.notify();
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Change the current settings (not the preset). The size is changed with `setSize`.
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* brush.update({ alpha: 0.5, widthConfig: { usePressure: true } });
|
|
71
|
+
*/
|
|
72
|
+
update(changes) {
|
|
73
|
+
this.current = {
|
|
74
|
+
...this.current,
|
|
75
|
+
...changes,
|
|
76
|
+
id: this.current.id
|
|
77
|
+
};
|
|
78
|
+
this.notify();
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Replace the current settings and size with a whole configuration (the configuration window's "Save").
|
|
82
|
+
*/
|
|
83
|
+
apply(config) {
|
|
84
|
+
this.current = {
|
|
85
|
+
...structuredClone(config),
|
|
86
|
+
id: this.current.id
|
|
87
|
+
};
|
|
88
|
+
this.applyPresetSize(config);
|
|
89
|
+
this.notify();
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Replace the available presets (e.g. when custom presets are added or removed). If the selected preset is gone, the
|
|
93
|
+
* current settings stay until another preset is selected.
|
|
94
|
+
*/
|
|
95
|
+
setPresets(presets) {
|
|
96
|
+
if (Object.keys(presets).length === 0) throw new Error("At least one brush preset is required");
|
|
97
|
+
this.presets = presets;
|
|
98
|
+
this.notify();
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Set the height, clamped to 1–256 pixels. If the settings constrain proportions, width follows height.
|
|
102
|
+
*/
|
|
103
|
+
setHeight(height) {
|
|
104
|
+
if (!this.current.constrainProportions) {
|
|
105
|
+
this.setSize(this.width, height);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
const ratio = this.width / this.height;
|
|
109
|
+
this.setSize(clamp(height, 1, 256) * ratio);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Set the size, clamped to 1–256 pixels. If the settings constrain proportions, height follows width.
|
|
113
|
+
*/
|
|
114
|
+
setSize(width, height = width) {
|
|
115
|
+
const ratio = this.height / this.width;
|
|
116
|
+
this.width = Math.round(clamp(width, 1, 256));
|
|
117
|
+
this.height = Math.round(clamp(this.preset.constrainProportions ? this.width * ratio : height, 1, 256));
|
|
118
|
+
this.notify();
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Change the size by a number of pixels (positive = bigger). Used when dragging up/right (bigger) or down/left (smaller).
|
|
122
|
+
*/
|
|
123
|
+
resize(delta) {
|
|
124
|
+
this.setSize(this.width + delta, this.height + delta);
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Increase the size by one step (at least 1 pixel).
|
|
128
|
+
*/
|
|
129
|
+
grow() {
|
|
130
|
+
this.resize(Math.max(1, Math.round(this.width * BRUSH_SIZE_STEP)));
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Decrease the size by one step (at least 1 pixel).
|
|
134
|
+
*/
|
|
135
|
+
shrink() {
|
|
136
|
+
this.resize(-Math.max(1, Math.round(this.width * BRUSH_SIZE_STEP)));
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Use a preset's (or configuration's) default size.
|
|
140
|
+
*/
|
|
141
|
+
applyPresetSize(preset) {
|
|
142
|
+
this.width = preset.width ?? 1;
|
|
143
|
+
this.height = preset.height ?? this.width;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Dispatch a `change` event.
|
|
147
|
+
*/
|
|
148
|
+
notify() {
|
|
149
|
+
this.dispatchEvent(new Event("change"));
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
export { BRUSH_SIZE_STEP, MAX_BRUSH_SIZE, MIN_BRUSH_SIZE, clamp, BrushSettings as default };
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { BrushConfig } from "../../brushes/types";
|
|
2
|
+
/** Where custom presets are kept (see `PresetStore`) */
|
|
3
|
+
export interface PresetStoreLike {
|
|
4
|
+
/** The owner's presets, in the order they were saved */
|
|
5
|
+
list(ownerId: string): Promise<BrushConfig[]>;
|
|
6
|
+
/** Save one of the owner's presets (replacing one with the same ID) */
|
|
7
|
+
put(ownerId: string, preset: BrushConfig): Promise<void>;
|
|
8
|
+
/** Delete one of the owner's presets */
|
|
9
|
+
remove(ownerId: string, id: string): Promise<void>;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* The user's own and imported brush presets, shared by the brush and eraser. They are kept in a store when one is
|
|
13
|
+
* given (otherwise only until the page closes).
|
|
14
|
+
*
|
|
15
|
+
* Dispatches a `change` event when presets are loaded, saved or removed.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* const custom = new CustomPresets("user-1", myPresetStore);
|
|
19
|
+
* await custom.load();
|
|
20
|
+
* await custom.save({ id: crypto.randomUUID(), name: "My brush", author: { name: "Ada", handle } });
|
|
21
|
+
*/
|
|
22
|
+
export default class CustomPresets extends EventTarget {
|
|
23
|
+
/** Presets, in the order they were added */
|
|
24
|
+
presets: BrushConfig[];
|
|
25
|
+
private readonly ownerId;
|
|
26
|
+
private readonly store?;
|
|
27
|
+
constructor(ownerId: string, store?: PresetStoreLike);
|
|
28
|
+
/**
|
|
29
|
+
* Load the user's presets from the store.
|
|
30
|
+
*/
|
|
31
|
+
load(): Promise<void>;
|
|
32
|
+
/**
|
|
33
|
+
* A preset by ID.
|
|
34
|
+
*/
|
|
35
|
+
get(id: string): BrushConfig | undefined;
|
|
36
|
+
/**
|
|
37
|
+
* One of the user's own presets with a name (ignoring case), to ask before replacing it.
|
|
38
|
+
*
|
|
39
|
+
* @param handle - the user's handle (empty if they have none)
|
|
40
|
+
* @param unknownName - the author name of presets made by a user without a handle (see `isOwnAuthor`)
|
|
41
|
+
*/
|
|
42
|
+
findOwn(name: string, handle: string, unknownName?: string): BrushConfig | undefined;
|
|
43
|
+
/**
|
|
44
|
+
* Add presets, replacing any with the same ID, and keep them.
|
|
45
|
+
*/
|
|
46
|
+
save(...presets: BrushConfig[]): Promise<void>;
|
|
47
|
+
/**
|
|
48
|
+
* Delete a preset.
|
|
49
|
+
*/
|
|
50
|
+
remove(id: string): Promise<void>;
|
|
51
|
+
/** Dispatch a `change` event */
|
|
52
|
+
private notify;
|
|
53
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { isOwnAuthor } from "../../brushes/authors/index.js";
|
|
2
|
+
// src/lib/classes/CustomPresets/index.ts
|
|
3
|
+
/**
|
|
4
|
+
* The user's own and imported brush presets, shared by the brush and eraser. They are kept in a store when one is
|
|
5
|
+
* given (otherwise only until the page closes).
|
|
6
|
+
*
|
|
7
|
+
* Dispatches a `change` event when presets are loaded, saved or removed.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* const custom = new CustomPresets("user-1", myPresetStore);
|
|
11
|
+
* await custom.load();
|
|
12
|
+
* await custom.save({ id: crypto.randomUUID(), name: "My brush", author: { name: "Ada", handle } });
|
|
13
|
+
*/
|
|
14
|
+
var CustomPresets = class extends EventTarget {
|
|
15
|
+
/** Presets, in the order they were added */
|
|
16
|
+
presets = [];
|
|
17
|
+
ownerId;
|
|
18
|
+
store;
|
|
19
|
+
constructor(ownerId, store) {
|
|
20
|
+
super();
|
|
21
|
+
this.ownerId = ownerId;
|
|
22
|
+
this.store = store;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Load the user's presets from the store.
|
|
26
|
+
*/
|
|
27
|
+
async load() {
|
|
28
|
+
if (!this.store) return;
|
|
29
|
+
this.presets = await this.store.list(this.ownerId);
|
|
30
|
+
this.notify();
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* A preset by ID.
|
|
34
|
+
*/
|
|
35
|
+
get(id) {
|
|
36
|
+
return this.presets.find((preset) => preset.id === id);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* One of the user's own presets with a name (ignoring case), to ask before replacing it.
|
|
40
|
+
*
|
|
41
|
+
* @param handle - the user's handle (empty if they have none)
|
|
42
|
+
* @param unknownName - the author name of presets made by a user without a handle (see `isOwnAuthor`)
|
|
43
|
+
*/
|
|
44
|
+
findOwn(name, handle, unknownName) {
|
|
45
|
+
const wanted = name.trim().toLowerCase();
|
|
46
|
+
return this.presets.find((preset) => isOwnAuthor(preset.author, handle, unknownName) && preset.name?.trim().toLowerCase() === wanted);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Add presets, replacing any with the same ID, and keep them.
|
|
50
|
+
*/
|
|
51
|
+
async save(...presets) {
|
|
52
|
+
for (const preset of presets) await this.store?.put(this.ownerId, preset);
|
|
53
|
+
const kept = this.presets.map((existing) => presets.find((preset) => preset.id === existing.id) ?? existing);
|
|
54
|
+
const added = presets.filter((preset) => !this.presets.some((existing) => existing.id === preset.id));
|
|
55
|
+
this.presets = [...kept, ...added];
|
|
56
|
+
if (presets.length > 0) this.notify();
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Delete a preset.
|
|
60
|
+
*/
|
|
61
|
+
async remove(id) {
|
|
62
|
+
await this.store?.remove(this.ownerId, id);
|
|
63
|
+
this.presets = this.presets.filter((preset) => preset.id !== id);
|
|
64
|
+
this.notify();
|
|
65
|
+
}
|
|
66
|
+
/** Dispatch a `change` event */
|
|
67
|
+
notify() {
|
|
68
|
+
this.dispatchEvent(new Event("change"));
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
export { CustomPresets as default };
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { type CanvasFactory } from "../Layer";
|
|
2
|
+
import type { DrawableLayer } from "../../rendering/compositing";
|
|
3
|
+
import type { PatchMessage } from "../../messages";
|
|
4
|
+
/** A drawing from elsewhere (e.g. another person's), flattened into one sheet */
|
|
5
|
+
export interface ExternalSheet extends DrawableLayer {
|
|
6
|
+
/** Where the drawing comes from: an ID the implementer chooses (e.g. a user ID), which PaintCanvas doesn't interpret */
|
|
7
|
+
source: string;
|
|
8
|
+
canvas: OffscreenCanvas;
|
|
9
|
+
}
|
|
10
|
+
/** Decodes a PNG into pixels (replaceable for tests) */
|
|
11
|
+
export type DecodePng = (bytes: Uint8Array<ArrayBuffer>) => Promise<ImageBitmap>;
|
|
12
|
+
/**
|
|
13
|
+
* Drawings from elsewhere (e.g. other people's), one flattened sheet per source. They are drawn under the user's own
|
|
14
|
+
* layers, so their own work is always in focus; the sheets are ordered by when each source's first drawing arrived
|
|
15
|
+
* (newest on top).
|
|
16
|
+
*
|
|
17
|
+
* Dispatches a `change` event when a sheet changes.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* const external = new ExternalSheets(2000, 2000);
|
|
21
|
+
* await external.apply("user-2", patchMessage);
|
|
22
|
+
* drawLayers(ctx, [...ownLayers, ...external.sheets]);
|
|
23
|
+
*/
|
|
24
|
+
export default class ExternalSheets extends EventTarget {
|
|
25
|
+
private width;
|
|
26
|
+
private height;
|
|
27
|
+
private readonly createCanvas;
|
|
28
|
+
private readonly decodePng;
|
|
29
|
+
/** Sheets from top to bottom, as layer lists are ordered */
|
|
30
|
+
private list;
|
|
31
|
+
/** Updates are applied one at a time, in the order they arrive */
|
|
32
|
+
private queue;
|
|
33
|
+
constructor(width: number, height: number, createCanvas?: CanvasFactory, decodePng?: DecodePng);
|
|
34
|
+
/** Sheets from top to bottom */
|
|
35
|
+
get sheets(): readonly ExternalSheet[];
|
|
36
|
+
/**
|
|
37
|
+
* A source's sheet, created (on top of the others) if it doesn't exist yet.
|
|
38
|
+
*/
|
|
39
|
+
private sheetOf;
|
|
40
|
+
/**
|
|
41
|
+
* Draw a patch's pixels onto a source's sheet, replacing what was there. Updates are applied in order. Returns once
|
|
42
|
+
* this update is applied; a patch whose data can't be decoded is skipped.
|
|
43
|
+
*/
|
|
44
|
+
apply(source: string, message: PatchMessage): Promise<void>;
|
|
45
|
+
/**
|
|
46
|
+
* Draw onto a source's sheet with a drawing function (e.g. a received stroke), after any updates before it. Returns
|
|
47
|
+
* once drawn; a drawing that throws is skipped.
|
|
48
|
+
*/
|
|
49
|
+
paint(source: string, draw: (canvas: OffscreenCanvas) => void | Promise<void>): Promise<void>;
|
|
50
|
+
/** Decode and draw one patch */
|
|
51
|
+
private draw;
|
|
52
|
+
/**
|
|
53
|
+
* Put a saved drawing back onto a source's sheet (e.g. other people's drawing in a saved drawing).
|
|
54
|
+
*/
|
|
55
|
+
restore(source: string, image: CanvasImageSource): void;
|
|
56
|
+
/**
|
|
57
|
+
* Change the canvas size, removing all sheets.
|
|
58
|
+
*/
|
|
59
|
+
resize(width: number, height: number): void;
|
|
60
|
+
/**
|
|
61
|
+
* Remove all sheets (e.g. when a shared drawing ends).
|
|
62
|
+
*/
|
|
63
|
+
clear(): void;
|
|
64
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { ImageEncoding, base64ToBytes, boundingBoxSize, decodeRgbaDeflate } from "../../image/index.js";
|
|
2
|
+
import { BlendMode, createOffscreenCanvas } from "../Layer/index.js";
|
|
3
|
+
// src/lib/classes/ExternalSheets/index.ts
|
|
4
|
+
/**
|
|
5
|
+
* Drawings from elsewhere (e.g. other people's), one flattened sheet per source. They are drawn under the user's own
|
|
6
|
+
* layers, so their own work is always in focus; the sheets are ordered by when each source's first drawing arrived
|
|
7
|
+
* (newest on top).
|
|
8
|
+
*
|
|
9
|
+
* Dispatches a `change` event when a sheet changes.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* const external = new ExternalSheets(2000, 2000);
|
|
13
|
+
* await external.apply("user-2", patchMessage);
|
|
14
|
+
* drawLayers(ctx, [...ownLayers, ...external.sheets]);
|
|
15
|
+
*/
|
|
16
|
+
var ExternalSheets = class extends EventTarget {
|
|
17
|
+
width;
|
|
18
|
+
height;
|
|
19
|
+
createCanvas;
|
|
20
|
+
decodePng;
|
|
21
|
+
/** Sheets from top to bottom, as layer lists are ordered */
|
|
22
|
+
list = [];
|
|
23
|
+
/** Updates are applied one at a time, in the order they arrive */
|
|
24
|
+
queue = Promise.resolve();
|
|
25
|
+
constructor(width, height, createCanvas = createOffscreenCanvas, decodePng = (bytes) => createImageBitmap(new Blob([bytes], { type: "image/png" }))) {
|
|
26
|
+
super();
|
|
27
|
+
this.width = width;
|
|
28
|
+
this.height = height;
|
|
29
|
+
this.createCanvas = createCanvas;
|
|
30
|
+
this.decodePng = decodePng;
|
|
31
|
+
}
|
|
32
|
+
/** Sheets from top to bottom */
|
|
33
|
+
get sheets() {
|
|
34
|
+
return this.list;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* A source's sheet, created (on top of the others) if it doesn't exist yet.
|
|
38
|
+
*/
|
|
39
|
+
sheetOf(source) {
|
|
40
|
+
let sheet = this.list.find((existing) => existing.source === source);
|
|
41
|
+
if (!sheet) {
|
|
42
|
+
sheet = {
|
|
43
|
+
source,
|
|
44
|
+
canvas: this.createCanvas(this.width, this.height),
|
|
45
|
+
visible: true,
|
|
46
|
+
opacity: 1,
|
|
47
|
+
blendMode: BlendMode.Normal
|
|
48
|
+
};
|
|
49
|
+
this.list = [sheet, ...this.list];
|
|
50
|
+
}
|
|
51
|
+
return sheet;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Draw a patch's pixels onto a source's sheet, replacing what was there. Updates are applied in order. Returns once
|
|
55
|
+
* this update is applied; a patch whose data can't be decoded is skipped.
|
|
56
|
+
*/
|
|
57
|
+
apply(source, message) {
|
|
58
|
+
this.queue = this.queue.then(() => this.draw(source, message)).catch(() => void 0);
|
|
59
|
+
return this.queue;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Draw onto a source's sheet with a drawing function (e.g. a received stroke), after any updates before it. Returns
|
|
63
|
+
* once drawn; a drawing that throws is skipped.
|
|
64
|
+
*/
|
|
65
|
+
paint(source, draw) {
|
|
66
|
+
this.queue = this.queue.then(async () => {
|
|
67
|
+
await draw(this.sheetOf(source).canvas);
|
|
68
|
+
this.dispatchEvent(new Event("change"));
|
|
69
|
+
}).catch(() => void 0);
|
|
70
|
+
return this.queue;
|
|
71
|
+
}
|
|
72
|
+
/** Decode and draw one patch */
|
|
73
|
+
async draw(source, message) {
|
|
74
|
+
const [x, y] = message.coords;
|
|
75
|
+
const { width, height } = boundingBoxSize(message.coords);
|
|
76
|
+
const context = this.sheetOf(source).canvas.getContext("2d");
|
|
77
|
+
if (message.encoding === ImageEncoding.Png) {
|
|
78
|
+
const image = await this.decodePng(base64ToBytes(message.data));
|
|
79
|
+
context.clearRect(x, y, width, height);
|
|
80
|
+
context.drawImage(image, x, y);
|
|
81
|
+
} else {
|
|
82
|
+
const rgba = await decodeRgbaDeflate(message.data, message.coords);
|
|
83
|
+
context.putImageData(new ImageData(rgba, width, height), x, y);
|
|
84
|
+
}
|
|
85
|
+
this.dispatchEvent(new Event("change"));
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Put a saved drawing back onto a source's sheet (e.g. other people's drawing in a saved drawing).
|
|
89
|
+
*/
|
|
90
|
+
restore(source, image) {
|
|
91
|
+
const context = this.sheetOf(source).canvas.getContext("2d");
|
|
92
|
+
context.clearRect(0, 0, this.width, this.height);
|
|
93
|
+
context.drawImage(image, 0, 0);
|
|
94
|
+
this.dispatchEvent(new Event("change"));
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Change the canvas size, removing all sheets.
|
|
98
|
+
*/
|
|
99
|
+
resize(width, height) {
|
|
100
|
+
this.width = width;
|
|
101
|
+
this.height = height;
|
|
102
|
+
this.clear();
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Remove all sheets (e.g. when a shared drawing ends).
|
|
106
|
+
*/
|
|
107
|
+
clear() {
|
|
108
|
+
this.list = [];
|
|
109
|
+
this.dispatchEvent(new Event("change"));
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
export { ExternalSheets as default };
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { Point } from "../Viewport";
|
|
2
|
+
import type { TouchGesture } from "../../utils/gestures";
|
|
3
|
+
/** A tap's fingers must all lift within this long of the first touching down */
|
|
4
|
+
export declare const TAP_MAX_MS = 300;
|
|
5
|
+
/** How far a finger can move and still be tapping (screen pixels); two-finger pan and pinch wait until a finger moves further */
|
|
6
|
+
export declare const TAP_SLOP_PX = 10;
|
|
7
|
+
/** How far three fingers must move together, or spread apart or close together, to swipe (screen pixels) */
|
|
8
|
+
export declare const SWIPE_MIN_PX = 40;
|
|
9
|
+
/**
|
|
10
|
+
* The swipe three fingers made from where they were to where they are: in or out if their spread changed more than
|
|
11
|
+
* they moved together, otherwise left, right, up or down (whichever way they moved most). Undefined if they moved less
|
|
12
|
+
* than `SWIPE_MIN_PX`.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* swipeOf([{ x: 0, y: 0 }, { x: 10, y: 0 }, { x: 20, y: 0 }], [{ x: 50, y: 0 }, { x: 60, y: 0 }, { x: 70, y: 0 }]); // "swipeRight3"
|
|
16
|
+
*/
|
|
17
|
+
export declare const swipeOf: (from: readonly Point[], to: readonly Point[]) => TouchGesture | undefined;
|
|
18
|
+
/**
|
|
19
|
+
* Recognises touch gestures from the fingers on the canvas, from the first finger down to the last one up: a tap with
|
|
20
|
+
* two or three fingers (all lifted within `TAP_MAX_MS`, none moving more than `TAP_SLOP_PX`), or a swipe with three
|
|
21
|
+
* fingers (see `swipeOf`, measured from when the third finger touched down to when the first of them lifted). Four or
|
|
22
|
+
* more fingers, or a cancelled touch (e.g. taken by a system gesture), make no gesture.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* const tracker = new GestureTracker();
|
|
26
|
+
* tracker.down(1, { x: 0, y: 0 }, 0);
|
|
27
|
+
* tracker.down(2, { x: 50, y: 0 }, 10);
|
|
28
|
+
* tracker.up(1, 100);
|
|
29
|
+
* tracker.up(2, 120); // "tap2"
|
|
30
|
+
*/
|
|
31
|
+
export default class GestureTracker {
|
|
32
|
+
/** Where each finger on the screen touched down, and where it is now */
|
|
33
|
+
private readonly fingers;
|
|
34
|
+
/** When the first finger touched down */
|
|
35
|
+
private startTime;
|
|
36
|
+
/** Most fingers down at once */
|
|
37
|
+
private most;
|
|
38
|
+
/** Whether any finger moved too far to tap */
|
|
39
|
+
private moved;
|
|
40
|
+
/** Whether a touch was cancelled */
|
|
41
|
+
private cancelled;
|
|
42
|
+
/** The three fingers' positions when the third touched down, and when the first of them lifted */
|
|
43
|
+
private swipe?;
|
|
44
|
+
/** How many fingers are on the screen */
|
|
45
|
+
get count(): number;
|
|
46
|
+
/**
|
|
47
|
+
* Whether any finger moved further than a tap allows since touching down.
|
|
48
|
+
*/
|
|
49
|
+
get dragging(): boolean;
|
|
50
|
+
/** A finger touched down */
|
|
51
|
+
down(id: number, point: Point, time: number): void;
|
|
52
|
+
/** A finger moved */
|
|
53
|
+
move(id: number, point: Point): void;
|
|
54
|
+
/**
|
|
55
|
+
* A finger lifted. Returns the gesture made once the last finger lifts, if any.
|
|
56
|
+
*/
|
|
57
|
+
up(id: number, time: number): TouchGesture | undefined;
|
|
58
|
+
/** A touch was cancelled: no gesture until all fingers have lifted */
|
|
59
|
+
cancel(id: number): void;
|
|
60
|
+
/** Start tracking a new gesture */
|
|
61
|
+
private reset;
|
|
62
|
+
}
|