@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,107 @@
|
|
|
1
|
+
import { BUILT_IN_AUTHOR } from "../../authors/index.js";
|
|
2
|
+
import { SmoothingType } from "../../types/index.js";
|
|
3
|
+
// src/lib/brushes/presets/sketching/index.ts
|
|
4
|
+
/** Settings shared by the sketching presets */
|
|
5
|
+
var DEFAULT_CONFIG = {
|
|
6
|
+
version: "1.0.0",
|
|
7
|
+
author: BUILT_IN_AUTHOR,
|
|
8
|
+
group: "Sketching"
|
|
9
|
+
};
|
|
10
|
+
/** Thin pencil that gets wider and darker with pen pressure */
|
|
11
|
+
var pencil = {
|
|
12
|
+
...DEFAULT_CONFIG,
|
|
13
|
+
id: "pencil",
|
|
14
|
+
name: "Pencil 4px (pressure)",
|
|
15
|
+
width: 4,
|
|
16
|
+
height: 4,
|
|
17
|
+
constrainProportions: true,
|
|
18
|
+
alpha: .9,
|
|
19
|
+
spacing: 1,
|
|
20
|
+
sampleRate: 10,
|
|
21
|
+
smoothingType: SmoothingType.BezierCubic,
|
|
22
|
+
widthConfig: {
|
|
23
|
+
usePressure: true,
|
|
24
|
+
minPressure: .3,
|
|
25
|
+
maxPressure: 1
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
/** Ink pen with strong pressure taper */
|
|
29
|
+
var inkPen = {
|
|
30
|
+
...DEFAULT_CONFIG,
|
|
31
|
+
id: "inkPen",
|
|
32
|
+
name: "Ink pen 10px (pressure)",
|
|
33
|
+
width: 10,
|
|
34
|
+
height: 10,
|
|
35
|
+
constrainProportions: true,
|
|
36
|
+
spacing: 1,
|
|
37
|
+
sampleRate: 10,
|
|
38
|
+
smoothingType: SmoothingType.BezierCubic,
|
|
39
|
+
widthConfig: {
|
|
40
|
+
usePressure: true,
|
|
41
|
+
minPressure: .1,
|
|
42
|
+
maxPressure: 1
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
/** Scattered dots of varying size, for texture */
|
|
46
|
+
var stipple = {
|
|
47
|
+
...DEFAULT_CONFIG,
|
|
48
|
+
id: "stipple",
|
|
49
|
+
name: "Stipple 8px",
|
|
50
|
+
width: 8,
|
|
51
|
+
height: 8,
|
|
52
|
+
constrainProportions: true,
|
|
53
|
+
spacing: 14,
|
|
54
|
+
sampleRate: 10,
|
|
55
|
+
smoothingType: SmoothingType.Linear,
|
|
56
|
+
widthConfig: {
|
|
57
|
+
useRandomise: true,
|
|
58
|
+
minRandomise: .3,
|
|
59
|
+
maxRandomise: 1
|
|
60
|
+
},
|
|
61
|
+
offsetXConfig: {
|
|
62
|
+
useRandomise: true,
|
|
63
|
+
minRandomise: 0,
|
|
64
|
+
maxRandomise: 1
|
|
65
|
+
},
|
|
66
|
+
offsetYConfig: {
|
|
67
|
+
useRandomise: true,
|
|
68
|
+
minRandomise: 0,
|
|
69
|
+
maxRandomise: 1
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
/** Flat angled nib; with a pen, the angle follows the pen's tilt */
|
|
73
|
+
var calligraphy = {
|
|
74
|
+
...DEFAULT_CONFIG,
|
|
75
|
+
id: "calligraphy",
|
|
76
|
+
name: "Calligraphy 24px (tilt)",
|
|
77
|
+
width: 24,
|
|
78
|
+
height: 5,
|
|
79
|
+
constrainProportions: true,
|
|
80
|
+
rotation: 45,
|
|
81
|
+
spacing: 1,
|
|
82
|
+
sampleRate: 10,
|
|
83
|
+
smoothingType: SmoothingType.BezierCubic,
|
|
84
|
+
rotationConfig: { useTilt: true }
|
|
85
|
+
};
|
|
86
|
+
/** Semi-transparent marker: overlapping parts of one stroke stay even, separate strokes build up */
|
|
87
|
+
var marker = {
|
|
88
|
+
...DEFAULT_CONFIG,
|
|
89
|
+
id: "marker",
|
|
90
|
+
name: "Marker 30px 40%",
|
|
91
|
+
width: 30,
|
|
92
|
+
height: 30,
|
|
93
|
+
constrainProportions: true,
|
|
94
|
+
alpha: .4,
|
|
95
|
+
spacing: 2,
|
|
96
|
+
sampleRate: 10,
|
|
97
|
+
smoothingType: SmoothingType.BezierQuad
|
|
98
|
+
};
|
|
99
|
+
/** Presets for sketching and for testing how drawing feels */
|
|
100
|
+
var sketching = {
|
|
101
|
+
pencil,
|
|
102
|
+
inkPen,
|
|
103
|
+
stipple,
|
|
104
|
+
calligraphy,
|
|
105
|
+
marker
|
|
106
|
+
};
|
|
107
|
+
export { calligraphy, sketching as default, sketching, inkPen, marker, pencil, stipple };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { BUILT_IN_AUTHOR } from "../../authors/index.js";
|
|
2
|
+
import { sizedPresets } from "../sized/index.js";
|
|
3
|
+
import square_default$1 from "./square.js";
|
|
4
|
+
/** Hard square brushes, snapped to the pixel grid */
|
|
5
|
+
var square = sizedPresets("square", "Square", [
|
|
6
|
+
1,
|
|
7
|
+
5,
|
|
8
|
+
10,
|
|
9
|
+
20,
|
|
10
|
+
30,
|
|
11
|
+
40,
|
|
12
|
+
50
|
|
13
|
+
], {
|
|
14
|
+
version: "1.0.0",
|
|
15
|
+
author: BUILT_IN_AUTHOR,
|
|
16
|
+
constrainProportions: true,
|
|
17
|
+
image: square_default$1,
|
|
18
|
+
sampleRate: 50,
|
|
19
|
+
snapToPixelGrid: true
|
|
20
|
+
}, (size) => ({ spacing: Math.max(1, Math.round(size / 10)) }));
|
|
21
|
+
var square_default = { ...square };
|
|
22
|
+
export { square_default as default, square };
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
// src/lib/brushes/presets/square/square.png?inline
|
|
2
|
+
var square_default = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAQAAADa613fAAAAa0lEQVR42u3PQREAAAjDsN38ewYVfLi0CtLMj5sngYCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgNy1qlZkZS7/ScAAAAAASUVORK5CYII=";
|
|
3
|
+
export { square_default as default };
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { type CanvasFactory } from "../../classes/Layer";
|
|
2
|
+
/** Largest brush shape file, in bytes */
|
|
3
|
+
export declare const MAX_SHAPE_FILE_BYTES: number;
|
|
4
|
+
/** Largest brush shape width or height, in pixels; larger images are shrunk */
|
|
5
|
+
export declare const MAX_SHAPE_SIZE = 512;
|
|
6
|
+
/** Messages shown when a brush shape can't be used */
|
|
7
|
+
export declare const SHAPE_ERRORS: {
|
|
8
|
+
readonly type: "Brush shapes must be PNG images";
|
|
9
|
+
readonly size: "Brush shape images can be up to 2 MB";
|
|
10
|
+
readonly decode: "Couldn't read the brush shape image";
|
|
11
|
+
readonly noImage: "There is no PNG image to paste";
|
|
12
|
+
};
|
|
13
|
+
/** A brush shape image can't be used, with a message for the user */
|
|
14
|
+
export declare class ShapeImageError extends Error {
|
|
15
|
+
}
|
|
16
|
+
/** A brush shape ready to use in a preset */
|
|
17
|
+
export interface ShapeImage {
|
|
18
|
+
/** PNG data URL */
|
|
19
|
+
image: string;
|
|
20
|
+
width: number;
|
|
21
|
+
height: number;
|
|
22
|
+
}
|
|
23
|
+
/** What reading a shape needs (replaceable for tests) */
|
|
24
|
+
export interface ShapeImageDependencies {
|
|
25
|
+
decode?: (blob: Blob) => Promise<ImageBitmap>;
|
|
26
|
+
createCanvas?: CanvasFactory;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Turn a PNG file into a brush shape: at most 2 MB, shrunk to at most 512 pixels on its longest side, as a PNG data
|
|
30
|
+
* URL. Its alpha is used as is. Throws a `ShapeImageError` if it can't be used.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* const shape = await readShapeImage(input.files[0]); // { image: "data:image/png;base64,…", width: 120, height: 80 }
|
|
34
|
+
*/
|
|
35
|
+
export declare const readShapeImage: (blob: Blob, { decode, createCanvas, }?: ShapeImageDependencies) => Promise<ShapeImage>;
|
|
36
|
+
/**
|
|
37
|
+
* Read a brush shape from a PNG image on the clipboard. Throws a `ShapeImageError` if there is none or it can't be
|
|
38
|
+
* used.
|
|
39
|
+
*/
|
|
40
|
+
export declare const readClipboardShape: (clipboard?: Pick<Clipboard, "read">, deps?: ShapeImageDependencies) => Promise<ShapeImage>;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { bytesToBase64 } from "../../image/index.js";
|
|
2
|
+
import { createOffscreenCanvas } from "../../classes/Layer/index.js";
|
|
3
|
+
// src/lib/brushes/shapeImage/index.ts
|
|
4
|
+
/** Largest brush shape file, in bytes */
|
|
5
|
+
var MAX_SHAPE_FILE_BYTES = 2097152;
|
|
6
|
+
/** Largest brush shape width or height, in pixels; larger images are shrunk */
|
|
7
|
+
var MAX_SHAPE_SIZE = 512;
|
|
8
|
+
/** Messages shown when a brush shape can't be used */
|
|
9
|
+
var SHAPE_ERRORS = {
|
|
10
|
+
type: "Brush shapes must be PNG images",
|
|
11
|
+
size: "Brush shape images can be up to 2 MB",
|
|
12
|
+
decode: "Couldn't read the brush shape image",
|
|
13
|
+
noImage: "There is no PNG image to paste"
|
|
14
|
+
};
|
|
15
|
+
/** A brush shape image can't be used, with a message for the user */
|
|
16
|
+
var ShapeImageError = class extends Error {};
|
|
17
|
+
/**
|
|
18
|
+
* Turn a PNG file into a brush shape: at most 2 MB, shrunk to at most 512 pixels on its longest side, as a PNG data
|
|
19
|
+
* URL. Its alpha is used as is. Throws a `ShapeImageError` if it can't be used.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* const shape = await readShapeImage(input.files[0]); // { image: "data:image/png;base64,…", width: 120, height: 80 }
|
|
23
|
+
*/
|
|
24
|
+
var readShapeImage = async (blob, { decode = (file) => createImageBitmap(file), createCanvas = createOffscreenCanvas } = {}) => {
|
|
25
|
+
if (blob.type !== "image/png") throw new ShapeImageError(SHAPE_ERRORS.type);
|
|
26
|
+
if (blob.size > 2097152) throw new ShapeImageError(SHAPE_ERRORS.size);
|
|
27
|
+
let bitmap;
|
|
28
|
+
try {
|
|
29
|
+
bitmap = await decode(blob);
|
|
30
|
+
} catch {
|
|
31
|
+
throw new ShapeImageError(SHAPE_ERRORS.decode);
|
|
32
|
+
}
|
|
33
|
+
const scale = Math.min(1, 512 / Math.max(bitmap.width, bitmap.height));
|
|
34
|
+
const width = Math.max(1, Math.round(bitmap.width * scale));
|
|
35
|
+
const height = Math.max(1, Math.round(bitmap.height * scale));
|
|
36
|
+
const canvas = createCanvas(width, height);
|
|
37
|
+
canvas.getContext("2d").drawImage(bitmap, 0, 0, width, height);
|
|
38
|
+
const png = await canvas.convertToBlob({ type: "image/png" });
|
|
39
|
+
const bytes = new Uint8Array(await png.arrayBuffer());
|
|
40
|
+
return {
|
|
41
|
+
image: `data:image/png;base64,${bytesToBase64(bytes)}`,
|
|
42
|
+
width,
|
|
43
|
+
height
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Read a brush shape from a PNG image on the clipboard. Throws a `ShapeImageError` if there is none or it can't be
|
|
48
|
+
* used.
|
|
49
|
+
*/
|
|
50
|
+
var readClipboardShape = async (clipboard = navigator.clipboard, deps = {}) => {
|
|
51
|
+
let items;
|
|
52
|
+
try {
|
|
53
|
+
items = await clipboard.read();
|
|
54
|
+
} catch {
|
|
55
|
+
throw new ShapeImageError(SHAPE_ERRORS.noImage);
|
|
56
|
+
}
|
|
57
|
+
const item = items.find((entry) => entry.types.includes("image/png"));
|
|
58
|
+
if (!item) throw new ShapeImageError(SHAPE_ERRORS.noImage);
|
|
59
|
+
return readShapeImage(await item.getType("image/png"), deps);
|
|
60
|
+
};
|
|
61
|
+
export { MAX_SHAPE_FILE_BYTES, MAX_SHAPE_SIZE, SHAPE_ERRORS, ShapeImageError, readClipboardShape, readShapeImage };
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
export interface AssetAuthorDetails {
|
|
2
|
+
/** Author's name */
|
|
3
|
+
name: string;
|
|
4
|
+
/** Author's handle or username, which tells their presets apart from others with the same name */
|
|
5
|
+
handle?: string;
|
|
6
|
+
/** Author's email */
|
|
7
|
+
email?: string;
|
|
8
|
+
/** Author's website */
|
|
9
|
+
website?: string;
|
|
10
|
+
}
|
|
11
|
+
export type AssetAuthor = string | AssetAuthorDetails;
|
|
12
|
+
/** Which colour settings a brush varies */
|
|
13
|
+
export declare enum ColourMode {
|
|
14
|
+
HSL = 0,
|
|
15
|
+
RGB = 1
|
|
16
|
+
}
|
|
17
|
+
/** How the line between a stroke's recorded points is drawn */
|
|
18
|
+
export declare enum SmoothingType {
|
|
19
|
+
/** Same as Linear (kept for older presets) */
|
|
20
|
+
None = 0,
|
|
21
|
+
/** Straight lines between points */
|
|
22
|
+
Linear = 1,
|
|
23
|
+
/** Quadratic curves through the midpoints between points (smooth, no lag) */
|
|
24
|
+
BezierQuad = 2,
|
|
25
|
+
/** Cubic curves whose handles follow the direction of movement before and after each point (smoothest; lags one point) */
|
|
26
|
+
BezierCubic = 3
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Controls how a brush parameter varies for each stamp along a stroke. All ranges are fractions from 0 to 1.
|
|
30
|
+
*
|
|
31
|
+
* Each enabled source produces a factor:
|
|
32
|
+
*
|
|
33
|
+
* - Randomise: `minRandomise + (maxRandomise - minRandomise) * Math.random()`
|
|
34
|
+
* - Pressure: `minPressure + (maxPressure - minPressure) * pressure` (pressure 0–1 from the pen)
|
|
35
|
+
* - Tilt: `minTilt + (maxTilt - minTilt) * tilt` (tilt 0 = pen upright, 1 = pen flat)
|
|
36
|
+
*
|
|
37
|
+
* The factors are multiplied together and applied according to the kind of parameter:
|
|
38
|
+
*
|
|
39
|
+
* - Scale parameters (width, height, alpha, saturation, lightness, red, green, blue): `value * factor`
|
|
40
|
+
* - Angle parameters (rotation, hue): `value + factor * 360` degrees. For rotation, tilt instead sets the
|
|
41
|
+
* angle from the direction the pen leans (like a calligraphy nib).
|
|
42
|
+
* - Offset parameters (offsetX, offsetY): `value ± factor * brush size`, in a random direction (scatter)
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* // Width varies randomly between 50% and 100% and follows pen pressure from 20% to 100%
|
|
46
|
+
* const widthConfig: BrushParamConfig = {
|
|
47
|
+
* useRandomise: true, minRandomise: 0.5, maxRandomise: 1,
|
|
48
|
+
* usePressure: true, minPressure: 0.2, maxPressure: 1,
|
|
49
|
+
* };
|
|
50
|
+
*/
|
|
51
|
+
export interface BrushParamConfig {
|
|
52
|
+
/**
|
|
53
|
+
* Vary the parameter randomly for each stamp, between `minRandomise` and `maxRandomise`
|
|
54
|
+
* @default false
|
|
55
|
+
*/
|
|
56
|
+
useRandomise?: boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Lowest random factor (0–1)
|
|
59
|
+
* @default 1
|
|
60
|
+
*/
|
|
61
|
+
minRandomise?: number;
|
|
62
|
+
/**
|
|
63
|
+
* Highest random factor (0–1)
|
|
64
|
+
* @default 1
|
|
65
|
+
*/
|
|
66
|
+
maxRandomise?: number;
|
|
67
|
+
/**
|
|
68
|
+
* Vary the parameter with pen pressure, when the device provides it
|
|
69
|
+
* @default false
|
|
70
|
+
*/
|
|
71
|
+
usePressure?: boolean;
|
|
72
|
+
/**
|
|
73
|
+
* Factor at the lightest pressure (0–1)
|
|
74
|
+
* @default 0
|
|
75
|
+
*/
|
|
76
|
+
minPressure?: number;
|
|
77
|
+
/**
|
|
78
|
+
* Factor at full pressure (0–1)
|
|
79
|
+
* @default 1
|
|
80
|
+
*/
|
|
81
|
+
maxPressure?: number;
|
|
82
|
+
/**
|
|
83
|
+
* Vary the parameter with pen tilt, when the device provides it
|
|
84
|
+
* @default false
|
|
85
|
+
*/
|
|
86
|
+
useTilt?: boolean;
|
|
87
|
+
/**
|
|
88
|
+
* Factor when the pen is upright (0–1)
|
|
89
|
+
* @default 0
|
|
90
|
+
*/
|
|
91
|
+
minTilt?: number;
|
|
92
|
+
/**
|
|
93
|
+
* Factor when the pen is flat (0–1)
|
|
94
|
+
* @default 1
|
|
95
|
+
*/
|
|
96
|
+
maxTilt?: number;
|
|
97
|
+
}
|
|
98
|
+
export interface BrushConfig {
|
|
99
|
+
/** Unique ID */
|
|
100
|
+
id: string;
|
|
101
|
+
/** Brush name */
|
|
102
|
+
name?: string;
|
|
103
|
+
/** The family the preset belongs to (presets of the same group are listed together, e.g. "Round") */
|
|
104
|
+
group?: string;
|
|
105
|
+
/** Brush version */
|
|
106
|
+
version?: string;
|
|
107
|
+
/** Brush author */
|
|
108
|
+
author?: AssetAuthor;
|
|
109
|
+
/**
|
|
110
|
+
* Brush shape: an image whose alpha values define the shape (its colours are ignored).
|
|
111
|
+
* A data URL string, or raw image file bytes. Defaults to a hard round shape.
|
|
112
|
+
*/
|
|
113
|
+
image?: string | Uint8Array;
|
|
114
|
+
/**
|
|
115
|
+
* Brush colour mode affects how colour settings are applied.
|
|
116
|
+
* @default ColourMode.HSL
|
|
117
|
+
*/
|
|
118
|
+
colourMode?: ColourMode;
|
|
119
|
+
/**
|
|
120
|
+
* Initial colour hue value (0–359)
|
|
121
|
+
* @default 0
|
|
122
|
+
*/
|
|
123
|
+
hue?: string | number;
|
|
124
|
+
/** How hue varies per stamp (angle: adds up to 360°; see {@link BrushParamConfig}) */
|
|
125
|
+
hueConfig?: BrushParamConfig;
|
|
126
|
+
/**
|
|
127
|
+
* Initial colour saturation value (0–100)
|
|
128
|
+
* @default 100
|
|
129
|
+
*/
|
|
130
|
+
saturation?: string | number;
|
|
131
|
+
/** How saturation varies per stamp (scale; see {@link BrushParamConfig}) */
|
|
132
|
+
saturationConfig?: BrushParamConfig;
|
|
133
|
+
/**
|
|
134
|
+
* Initial colour lightness value (0–100)
|
|
135
|
+
* @default 50
|
|
136
|
+
*/
|
|
137
|
+
lightness?: string | number;
|
|
138
|
+
/** How lightness varies per stamp (scale; see {@link BrushParamConfig}) */
|
|
139
|
+
lightnessConfig?: BrushParamConfig;
|
|
140
|
+
/**
|
|
141
|
+
* Initial colour red value (0–255)
|
|
142
|
+
* @default 0
|
|
143
|
+
*/
|
|
144
|
+
red?: string | number;
|
|
145
|
+
/** How red varies per stamp (scale; see {@link BrushParamConfig}) */
|
|
146
|
+
redConfig?: BrushParamConfig;
|
|
147
|
+
/**
|
|
148
|
+
* Initial colour green value (0–255)
|
|
149
|
+
* @default 0
|
|
150
|
+
*/
|
|
151
|
+
green?: string | number;
|
|
152
|
+
/** How green varies per stamp (scale; see {@link BrushParamConfig}) */
|
|
153
|
+
greenConfig?: BrushParamConfig;
|
|
154
|
+
/**
|
|
155
|
+
* Initial colour blue value (0–255)
|
|
156
|
+
* @default 0
|
|
157
|
+
*/
|
|
158
|
+
blue?: string | number;
|
|
159
|
+
/** How blue varies per stamp (scale; see {@link BrushParamConfig}) */
|
|
160
|
+
blueConfig?: BrushParamConfig;
|
|
161
|
+
/**
|
|
162
|
+
* Initial alpha value (0–1)
|
|
163
|
+
* @default 1
|
|
164
|
+
*/
|
|
165
|
+
alpha?: number;
|
|
166
|
+
/** How alpha varies per stamp (scale; see {@link BrushParamConfig}) */
|
|
167
|
+
alphaConfig?: BrushParamConfig;
|
|
168
|
+
/**
|
|
169
|
+
* Default width in pixels (the user can change it from 1 to 256)
|
|
170
|
+
* @default 1
|
|
171
|
+
*/
|
|
172
|
+
width?: number;
|
|
173
|
+
/** How width varies per stamp (scale; see {@link BrushParamConfig}) */
|
|
174
|
+
widthConfig?: BrushParamConfig;
|
|
175
|
+
/**
|
|
176
|
+
* Default height in pixels (the user can change it from 1 to 256)
|
|
177
|
+
* @default 1
|
|
178
|
+
*/
|
|
179
|
+
height?: number;
|
|
180
|
+
/** How height varies per stamp (scale; see {@link BrushParamConfig}) */
|
|
181
|
+
heightConfig?: BrushParamConfig;
|
|
182
|
+
/** Keep the width-to-height ratio when the size changes */
|
|
183
|
+
constrainProportions?: boolean;
|
|
184
|
+
/**
|
|
185
|
+
* Rotation in degrees
|
|
186
|
+
* @default 0
|
|
187
|
+
*/
|
|
188
|
+
rotation?: number;
|
|
189
|
+
/** How rotation varies per stamp (angle: adds up to 360°; tilt sets the angle from the pen's lean direction; see {@link BrushParamConfig}) */
|
|
190
|
+
rotationConfig?: BrushParamConfig;
|
|
191
|
+
/**
|
|
192
|
+
* Horizontal offset of each stamp from the pointer, in pixels
|
|
193
|
+
* @default 0
|
|
194
|
+
*/
|
|
195
|
+
offsetX?: number;
|
|
196
|
+
/** How offsetX varies per stamp (offset: scatters up to the factor × brush width either way; see {@link BrushParamConfig}) */
|
|
197
|
+
offsetXConfig?: BrushParamConfig;
|
|
198
|
+
/**
|
|
199
|
+
* Vertical offset of each stamp from the pointer, in pixels
|
|
200
|
+
* @default 0
|
|
201
|
+
*/
|
|
202
|
+
offsetY?: number;
|
|
203
|
+
/** How offsetY varies per stamp (offset: scatters up to the factor × brush height either way; see {@link BrushParamConfig}) */
|
|
204
|
+
offsetYConfig?: BrushParamConfig;
|
|
205
|
+
/**
|
|
206
|
+
* How often (in milliseconds, 5–400) a new point is recorded while the pointer moves. Higher values record fewer points.
|
|
207
|
+
* No points are recorded while the pointer is still.
|
|
208
|
+
* @default 10
|
|
209
|
+
*/
|
|
210
|
+
sampleRate?: number;
|
|
211
|
+
/**
|
|
212
|
+
* How the line between recorded points is drawn
|
|
213
|
+
* @default SmoothingType.Linear
|
|
214
|
+
*/
|
|
215
|
+
smoothingType?: SmoothingType;
|
|
216
|
+
/**
|
|
217
|
+
* Distance in pixels (0–200) between stamps of the brush shape along the line. 0 stamps at every pixel.
|
|
218
|
+
* @default 5
|
|
219
|
+
*/
|
|
220
|
+
spacing?: number;
|
|
221
|
+
/**
|
|
222
|
+
* Draw each stamp on whole pixels: its size is rounded to whole pixels and its top-left corner is rounded down
|
|
223
|
+
* (`Math.floor`), so it never covers part of a pixel. Rotation other than a multiple of 90° still leaves the grid.
|
|
224
|
+
* @default false
|
|
225
|
+
*/
|
|
226
|
+
snapToPixelGrid?: boolean;
|
|
227
|
+
}
|
|
228
|
+
export type BrushesConfig = Record<string, BrushConfig>;
|
|
229
|
+
export interface BrushStrokePoint {
|
|
230
|
+
/** The X coordinate of the brush stroke point */
|
|
231
|
+
x: number;
|
|
232
|
+
/** The Y coordinate of the brush stroke point */
|
|
233
|
+
y: number;
|
|
234
|
+
/** The rotation (in radians) of the brush stroke point */
|
|
235
|
+
rotation?: number;
|
|
236
|
+
/** The pressure (0–1) of the brush stroke point, from `PointerEvent.pressure` */
|
|
237
|
+
pressure?: number;
|
|
238
|
+
/** The pen tilt (-90–90 degrees) along the X axis, from `PointerEvent.tiltX` */
|
|
239
|
+
tiltX?: number;
|
|
240
|
+
/** The pen tilt (-90–90 degrees) along the Y axis, from `PointerEvent.tiltY` */
|
|
241
|
+
tiltY?: number;
|
|
242
|
+
}
|
|
243
|
+
export type BrushStroke = BrushStrokePoint[];
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// src/lib/brushes/types/index.ts
|
|
2
|
+
/** Which colour settings a brush varies */
|
|
3
|
+
var ColourMode = /* @__PURE__ */ function(ColourMode) {
|
|
4
|
+
ColourMode[ColourMode["HSL"] = 0] = "HSL";
|
|
5
|
+
ColourMode[ColourMode["RGB"] = 1] = "RGB";
|
|
6
|
+
return ColourMode;
|
|
7
|
+
}({});
|
|
8
|
+
/** How the line between a stroke's recorded points is drawn */
|
|
9
|
+
var SmoothingType = /* @__PURE__ */ function(SmoothingType) {
|
|
10
|
+
/** Same as Linear (kept for older presets) */
|
|
11
|
+
SmoothingType[SmoothingType["None"] = 0] = "None";
|
|
12
|
+
/** Straight lines between points */
|
|
13
|
+
SmoothingType[SmoothingType["Linear"] = 1] = "Linear";
|
|
14
|
+
/** Quadratic curves through the midpoints between points (smooth, no lag) */
|
|
15
|
+
SmoothingType[SmoothingType["BezierQuad"] = 2] = "BezierQuad";
|
|
16
|
+
/** Cubic curves whose handles follow the direction of movement before and after each point (smoothest; lags one point) */
|
|
17
|
+
SmoothingType[SmoothingType["BezierCubic"] = 3] = "BezierCubic";
|
|
18
|
+
return SmoothingType;
|
|
19
|
+
}({});
|
|
20
|
+
export { ColourMode, SmoothingType };
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type StrokeLog from "../StrokeLog";
|
|
2
|
+
/** How long drawing must pause after a stroke before background work runs (milliseconds) */
|
|
3
|
+
export declare const DRAWING_PAUSE_MS = 300;
|
|
4
|
+
/** Longest background work waits while drawing continues (milliseconds); it still only runs between strokes */
|
|
5
|
+
export declare const MAX_WAIT_MS = 1000;
|
|
6
|
+
/**
|
|
7
|
+
* Holds slow work that isn't urgent (syncing the drawing, redrawing the canvas map and layer thumbnails, saving) until
|
|
8
|
+
* drawing pauses, so it doesn't keep the page busy while the user is drawing or about to draw the next stroke.
|
|
9
|
+
*
|
|
10
|
+
* Work never runs during a stroke. Between strokes, it runs once `DRAWING_PAUSE_MS` has passed since the last stroke
|
|
11
|
+
* ended, or once it has waited `MAX_WAIT_MS` (so a long run of strokes doesn't hold it up forever).
|
|
12
|
+
* When nobody is drawing, it runs straight away (during `run`); work due when a stroke ends runs just after it. Work
|
|
13
|
+
* asked for again under the same name before it runs replaces the earlier request (keeping its place in the wait). With
|
|
14
|
+
* a stroke log, how long each piece of work took is logged.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* const work = new BackgroundWork(app.strokeLog);
|
|
18
|
+
* work.strokeStarted();
|
|
19
|
+
* work.run("map", () => map.drawThumbnail()); // waits
|
|
20
|
+
* work.strokeEnded(); // the map is redrawn 300ms later, unless another stroke starts first
|
|
21
|
+
*/
|
|
22
|
+
export default class BackgroundWork {
|
|
23
|
+
/** Current time in milliseconds (replaceable for tests) */
|
|
24
|
+
now: () => number;
|
|
25
|
+
private readonly log?;
|
|
26
|
+
private readonly tasks;
|
|
27
|
+
private drawing;
|
|
28
|
+
/** When the last stroke ended */
|
|
29
|
+
private lastStroke;
|
|
30
|
+
private timer?;
|
|
31
|
+
constructor(log?: StrokeLog);
|
|
32
|
+
/** Names of the work waiting to run */
|
|
33
|
+
get pending(): readonly string[];
|
|
34
|
+
/**
|
|
35
|
+
* Run some work once drawing pauses (see the class description).
|
|
36
|
+
*/
|
|
37
|
+
run(name: string, run: () => unknown): void;
|
|
38
|
+
/**
|
|
39
|
+
* Forget work that hasn't run yet.
|
|
40
|
+
*/
|
|
41
|
+
cancel(name: string): void;
|
|
42
|
+
/** A stroke started: hold all work until it ends */
|
|
43
|
+
strokeStarted(): void;
|
|
44
|
+
/** A stroke ended (or was cancelled): run the work once drawing pauses */
|
|
45
|
+
strokeEnded(): void;
|
|
46
|
+
/**
|
|
47
|
+
* Run the waiting work now if it's due (and `now` allows), or set a timer for when it will be (unless drawing).
|
|
48
|
+
*/
|
|
49
|
+
private plan;
|
|
50
|
+
/**
|
|
51
|
+
* Run all waiting work, logging how long each took. If any throws, the rest still runs, then the first error is
|
|
52
|
+
* thrown.
|
|
53
|
+
*/
|
|
54
|
+
private flush;
|
|
55
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// src/lib/classes/BackgroundWork/index.ts
|
|
2
|
+
/** How long drawing must pause after a stroke before background work runs (milliseconds) */
|
|
3
|
+
var DRAWING_PAUSE_MS = 300;
|
|
4
|
+
/** Longest background work waits while drawing continues (milliseconds); it still only runs between strokes */
|
|
5
|
+
var MAX_WAIT_MS = 1e3;
|
|
6
|
+
/**
|
|
7
|
+
* Holds slow work that isn't urgent (syncing the drawing, redrawing the canvas map and layer thumbnails, saving) until
|
|
8
|
+
* drawing pauses, so it doesn't keep the page busy while the user is drawing or about to draw the next stroke.
|
|
9
|
+
*
|
|
10
|
+
* Work never runs during a stroke. Between strokes, it runs once `DRAWING_PAUSE_MS` has passed since the last stroke
|
|
11
|
+
* ended, or once it has waited `MAX_WAIT_MS` (so a long run of strokes doesn't hold it up forever).
|
|
12
|
+
* When nobody is drawing, it runs straight away (during `run`); work due when a stroke ends runs just after it. Work
|
|
13
|
+
* asked for again under the same name before it runs replaces the earlier request (keeping its place in the wait). With
|
|
14
|
+
* a stroke log, how long each piece of work took is logged.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* const work = new BackgroundWork(app.strokeLog);
|
|
18
|
+
* work.strokeStarted();
|
|
19
|
+
* work.run("map", () => map.drawThumbnail()); // waits
|
|
20
|
+
* work.strokeEnded(); // the map is redrawn 300ms later, unless another stroke starts first
|
|
21
|
+
*/
|
|
22
|
+
var BackgroundWork = class {
|
|
23
|
+
/** Current time in milliseconds (replaceable for tests) */
|
|
24
|
+
now = () => performance.now();
|
|
25
|
+
log;
|
|
26
|
+
tasks = /* @__PURE__ */ new Map();
|
|
27
|
+
drawing = false;
|
|
28
|
+
/** When the last stroke ended */
|
|
29
|
+
lastStroke = -Infinity;
|
|
30
|
+
timer;
|
|
31
|
+
constructor(log) {
|
|
32
|
+
this.log = log;
|
|
33
|
+
}
|
|
34
|
+
/** Names of the work waiting to run */
|
|
35
|
+
get pending() {
|
|
36
|
+
return [...this.tasks.keys()];
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Run some work once drawing pauses (see the class description).
|
|
40
|
+
*/
|
|
41
|
+
run(name, run) {
|
|
42
|
+
const since = this.tasks.get(name)?.since ?? this.now();
|
|
43
|
+
this.tasks.set(name, {
|
|
44
|
+
run,
|
|
45
|
+
since
|
|
46
|
+
});
|
|
47
|
+
this.plan();
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Forget work that hasn't run yet.
|
|
51
|
+
*/
|
|
52
|
+
cancel(name) {
|
|
53
|
+
this.tasks.delete(name);
|
|
54
|
+
this.plan();
|
|
55
|
+
}
|
|
56
|
+
/** A stroke started: hold all work until it ends */
|
|
57
|
+
strokeStarted() {
|
|
58
|
+
this.drawing = true;
|
|
59
|
+
this.plan();
|
|
60
|
+
}
|
|
61
|
+
/** A stroke ended (or was cancelled): run the work once drawing pauses */
|
|
62
|
+
strokeEnded() {
|
|
63
|
+
this.drawing = false;
|
|
64
|
+
this.lastStroke = this.now();
|
|
65
|
+
this.plan(false);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Run the waiting work now if it's due (and `now` allows), or set a timer for when it will be (unless drawing).
|
|
69
|
+
*/
|
|
70
|
+
plan(now = true) {
|
|
71
|
+
clearTimeout(this.timer);
|
|
72
|
+
this.timer = void 0;
|
|
73
|
+
if (this.drawing || this.tasks.size === 0) return;
|
|
74
|
+
const oldest = Math.min(...[...this.tasks.values()].map((t) => t.since));
|
|
75
|
+
const wait = Math.min(this.lastStroke + 300, oldest + MAX_WAIT_MS) - this.now();
|
|
76
|
+
if (wait <= 0 && now) this.flush();
|
|
77
|
+
else this.timer = setTimeout(() => this.flush(), Math.max(0, wait));
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Run all waiting work, logging how long each took. If any throws, the rest still runs, then the first error is
|
|
81
|
+
* thrown.
|
|
82
|
+
*/
|
|
83
|
+
flush() {
|
|
84
|
+
this.timer = void 0;
|
|
85
|
+
const tasks = [...this.tasks];
|
|
86
|
+
this.tasks.clear();
|
|
87
|
+
const errors = [];
|
|
88
|
+
for (const [name, { run }] of tasks) try {
|
|
89
|
+
if (this.log) this.log.measure(name, run);
|
|
90
|
+
else run();
|
|
91
|
+
} catch (error) {
|
|
92
|
+
errors.push(error);
|
|
93
|
+
}
|
|
94
|
+
if (errors.length > 0) throw errors[0];
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
export { DRAWING_PAUSE_MS, MAX_WAIT_MS, BackgroundWork as default };
|