Skip to content

Commit a90cfe6

Browse files
committed
Some improvements to CircleSlider
1 parent 36bac17 commit a90cfe6

1 file changed

Lines changed: 13 additions & 12 deletions

File tree

src/lib/components/ControlModules/impl/CircleSlider.svelte

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,10 @@
2828
import { cubicOut } from 'svelte/easing';
2929
import { Tween } from 'svelte/motion';
3030
31-
// Unique gauge IDs
31+
// Unique IDs
3232
const id = $props.id();
3333
const inputId = id + '-input';
3434
const labelId = id + '-label';
35-
const gaugeId = id + '-gauge';
3635
3736
interface Props {
3837
name: string;
@@ -51,6 +50,10 @@
5150
let lastFraction: number | null = null;
5251
5352
// --- helpers ---
53+
function snapValue(raw: number): number {
54+
return clamp(Math.round((raw - min) / step) * step + min, min, max);
55+
}
56+
5457
function fractionFromEvent(event: PointerEvent) {
5558
const rect = element.getBoundingClientRect();
5659
const cx = rect.left + rect.width / 2;
@@ -95,6 +98,7 @@
9598
isTracking = false;
9699
window.removeEventListener('pointermove', handlePointerMoveDrag);
97100
window.removeEventListener('pointerup', stopTracking);
101+
window.removeEventListener('pointercancel', stopTracking);
98102
lastFraction = null; // reset for next interaction
99103
}
100104
@@ -104,12 +108,11 @@
104108
// Always jump to exact pointer position on start (wrap protection OFF)
105109
updateValueFromFraction(fractionFromEvent(event));
106110
107-
element.setPointerCapture(event.pointerId);
108-
109111
if (!isTracking) {
110112
isTracking = true;
111113
window.addEventListener('pointermove', handlePointerMoveDrag);
112114
window.addEventListener('pointerup', stopTracking);
115+
window.addEventListener('pointercancel', stopTracking);
113116
}
114117
}
115118
@@ -121,12 +124,13 @@
121124
easing: cubicOut,
122125
});
123126
124-
// Update animated value based on value, step, min, and max
127+
// Snap value to step grid and animate
125128
$effect(() => {
126-
const stepped = Math.round((value - min) / step) * step + min;
127-
const rounded = Math.round((stepped + Number.EPSILON) * 100) / 100;
128-
value = clamp(rounded, min, max);
129-
tween.set(value);
129+
const snapped = snapValue(value);
130+
if (snapped !== value) {
131+
value = snapped;
132+
}
133+
tween.set(snapped);
130134
});
131135
132136
// Update visual progress
@@ -146,7 +150,6 @@
146150

147151
<!-- foreground arc -->
148152
<path
149-
id={gaugeId}
150153
d={calcSvgPathData(degrees)}
151154
class="cursor-pointer fill-none stroke-blue-500 stroke-[10] dark:stroke-blue-400"
152155
stroke-linecap="round"
@@ -166,7 +169,6 @@
166169
aria-valuenow={value}
167170
aria-valuemax={max}
168171
aria-labelledby={labelId}
169-
aria-controls={gaugeId}
170172
class="cursor-move fill-white stroke-neutral-400 drop-shadow-md outline-none focus:ring-2 focus:ring-blue-500/60 dark:fill-neutral-900 dark:stroke-neutral-700"
171173
/>
172174
</svg>
@@ -188,7 +190,6 @@
188190
<label
189191
id={labelId}
190192
for={inputId}
191-
aria-label="Name"
192193
class="absolute bottom-0 left-1/2 -translate-x-1/2 translate-y-1/10 text-center text-neutral-600 dark:text-neutral-300"
193194
>
194195
{name}

0 commit comments

Comments
 (0)