|
1 | 1 | <script lang="ts" module> |
2 | 2 | import type { DraggableProps } from './Draggable.svelte'; |
3 | | - import { Spring, type Tween } from 'svelte/motion'; |
4 | | -
|
5 | | - type Motion<T> = Spring<T> | Tween<T>; |
6 | 3 |
|
7 | 4 | export type SvgKnobProps = DraggableProps & { |
8 | 5 | /** |
|
17 | 14 |
|
18 | 15 | pointerLength?: number; |
19 | 16 |
|
20 | | - /** |
21 | | - * "svelte/motion" class instance used to animate the knob. |
22 | | - * Default motion in Spring with stiffness of 0.5 |
23 | | - */ |
24 | | - motion?: Motion<number>; |
25 | | -
|
26 | 17 | /** |
27 | 18 | * Background color of the knob. |
28 | 19 | * Default color is #333 |
|
50 | 41 | </script> |
51 | 42 |
|
52 | 43 | <script lang="ts"> |
| 44 | + import { describeArc, polarToCartesian, valueToAngle } from './helpers/arc.js'; |
53 | 45 | import Draggable from './Draggable.svelte'; |
54 | 46 | import type { SvelteHTMLElements } from 'svelte/elements'; |
55 | | - import { describeArc, polarToCartesian, valueToAngle } from './helpers/arc.js'; |
56 | 47 |
|
57 | 48 | type Props = SvelteHTMLElements['svg'] & SvgKnobProps; |
58 | 49 | let { |
59 | | - value = $bindable(0), |
| 50 | + value = $bindable(0.5), |
| 51 | + valueSmoothed = $bindable(0.5), |
60 | 52 | size = 80, |
61 | | - motion = new Spring(0.0, { stiffness: 0.5 }), |
| 53 | + motion, |
62 | 54 | bgColor = '#333', |
63 | 55 | disabledColor = '#777', |
64 | 56 | minAngle = -135, |
65 | 57 | maxAngle = 135, |
66 | 58 | snapPointLength = 0.44, |
| 59 | + invertWheel, |
67 | 60 | circleRadius: cr = 0.32, |
68 | 61 | arcRadius: ar = 0.4, |
69 | 62 | pointerLength = 0, |
|
76 | 69 | ...svgProps |
77 | 70 | }: Props = $props(); |
78 | 71 |
|
79 | | - let draggableProps = $derived({ step, defaultValue, snapPoints, snapThreshold, weight }); |
| 72 | + let draggableProps = $derived({ |
| 73 | + defaultValue, |
| 74 | + invertWheel, |
| 75 | + motion, |
| 76 | + snapPoints, |
| 77 | + snapThreshold, |
| 78 | + step, |
| 79 | + weight |
| 80 | + }); |
80 | 81 |
|
81 | 82 | let c = $derived(size / 2); |
82 | 83 | let arcRadius = $derived(size * ar); |
83 | 84 | let circleRadius = $derived(size * cr); |
84 | 85 | let snapRadius = $derived(size * snapPointLength); |
85 | | -
|
86 | | - $effect(() => { |
87 | | - motion.set(value); |
88 | | - }); |
89 | 86 | </script> |
90 | 87 |
|
91 | | -<Draggable bind:value {...draggableProps} disabled={isDisabled}> |
| 88 | +<Draggable bind:value bind:valueSmoothed {...draggableProps} disabled={isDisabled}> |
92 | 89 | <svg |
93 | 90 | width="{size}px" |
94 | 91 | height="{size}px" |
|
108 | 105 | /> |
109 | 106 | <path |
110 | 107 | class="knob_line" |
111 | | - d={describeArc(c, c, arcRadius, motion.current, minAngle, maxAngle)} |
| 108 | + d={describeArc(c, c, arcRadius, valueSmoothed, minAngle, maxAngle)} |
112 | 109 | stroke={isDisabled ? disabledColor : 'currentColor'} |
113 | 110 | fill="none" |
114 | 111 | /> |
|
118 | 115 | {#each snapPoints ?? [] as p} |
119 | 116 | {@const [x1, y1] = polarToCartesian(c, c, arcRadius, valueToAngle(p, minAngle, maxAngle))} |
120 | 117 | {@const [x2, y2] = polarToCartesian(c, c, snapRadius, valueToAngle(p, minAngle, maxAngle))} |
121 | | - {@const stroke = value >= p ? 'currentColor' : bgColor} |
| 118 | + {@const stroke = valueSmoothed >= p ? 'currentColor' : bgColor} |
122 | 119 |
|
123 | 120 | <line class="knob_line" {x1} {y1} {x2} {y2} {stroke} /> |
124 | 121 | {/each} |
|
130 | 127 | c, |
131 | 128 | c, |
132 | 129 | circleRadius * 0.8, |
133 | | - valueToAngle(motion.current, minAngle, maxAngle) |
| 130 | + valueToAngle(valueSmoothed, minAngle, maxAngle) |
134 | 131 | )} |
135 | 132 | {@const [x2, y2] = polarToCartesian( |
136 | 133 | c, |
137 | 134 | c, |
138 | 135 | circleRadius * 0.8 - pointerLength * size * 0.52, |
139 | | - valueToAngle(motion.current, minAngle, maxAngle) |
| 136 | + valueToAngle(valueSmoothed, minAngle, maxAngle) |
140 | 137 | )} |
141 | 138 | <line |
142 | 139 | class="knob_line" |
|
0 commit comments