0
# Value Control Functions
1
2
Utilities for clamping values within bounds and controlling numerical precision with configurable rounding methods. These functions provide fine-grained control over numeric values with reactive behavior.
3
4
## Capabilities
5
6
### useClamp
7
8
Reactively clamps a value between minimum and maximum bounds. Returns different ref types based on the input type to optimize for readonly vs writable scenarios.
9
10
```typescript { .api }
11
/**
12
* Clamp a readonly value between min and max bounds
13
* @param value - Readonly reactive number or getter
14
* @param min - Minimum bound (reactive)
15
* @param max - Maximum bound (reactive)
16
* @returns ComputedRef with clamped value
17
*/
18
function useClamp(
19
value: ReadonlyRefOrGetter<number>,
20
min: MaybeRefOrGetter<number>,
21
max: MaybeRefOrGetter<number>
22
): ComputedRef<number>;
23
24
/**
25
* Clamp a writable value between min and max bounds
26
* @param value - Writable reactive number
27
* @param min - Minimum bound (reactive)
28
* @param max - Maximum bound (reactive)
29
* @returns Writable Ref that clamps on both get and set
30
*/
31
function useClamp(
32
value: MaybeRefOrGetter<number>,
33
min: MaybeRefOrGetter<number>,
34
max: MaybeRefOrGetter<number>
35
): Ref<number>;
36
```
37
38
**Usage Examples:**
39
40
```typescript
41
import { ref } from "vue";
42
import { useClamp } from "@vueuse/math";
43
44
// Basic clamping with writable ref
45
const value = ref(15);
46
const clamped = useClamp(value, 0, 10);
47
48
console.log(clamped.value); // 10 (clamped from 15)
49
50
// Setting the clamped value also clamps
51
clamped.value = 20;
52
console.log(clamped.value); // 10 (clamped)
53
console.log(value.value); // 10 (original ref is updated)
54
55
clamped.value = 5;
56
console.log(clamped.value); // 5 (within bounds)
57
58
// Reactive bounds
59
const minBound = ref(0);
60
const maxBound = ref(100);
61
const input = ref(150);
62
const boundedValue = useClamp(input, minBound, maxBound);
63
64
console.log(boundedValue.value); // 100
65
66
// Changing bounds affects the result
67
maxBound.value = 200;
68
console.log(boundedValue.value); // 150 (now within new bounds)
69
70
// Readonly usage (computed or getter)
71
const readonlyValue = useClamp(() => Math.random() * 200, 50, 100);
72
console.log(readonlyValue.value); // Between 50-100
73
```
74
75
### usePrecision
76
77
Reactively sets the precision of a number using configurable rounding methods.
78
79
```typescript { .api }
80
/**
81
* Set the precision of a number with configurable rounding
82
* @param value - The number to set precision for
83
* @param digits - Number of decimal digits to preserve
84
* @param options - Optional configuration for rounding method
85
* @returns ComputedRef containing the precision-controlled number
86
*/
87
function usePrecision(
88
value: MaybeRefOrGetter<number>,
89
digits: MaybeRefOrGetter<number>,
90
options?: MaybeRefOrGetter<UsePrecisionOptions>
91
): ComputedRef<number>;
92
93
/**
94
* Configuration options for precision control
95
*/
96
interface UsePrecisionOptions {
97
/**
98
* Method to use for rounding
99
* @default 'round'
100
*/
101
math?: 'floor' | 'ceil' | 'round';
102
}
103
```
104
105
**Usage Examples:**
106
107
```typescript
108
import { ref } from "vue";
109
import { usePrecision } from "@vueuse/math";
110
111
// Basic precision control
112
const value = ref(3.14159265);
113
const precise = usePrecision(value, 2);
114
115
console.log(precise.value); // 3.14
116
117
// Different rounding methods
118
const number = ref(3.7869);
119
120
const rounded = usePrecision(number, 2, { math: 'round' });
121
const floored = usePrecision(number, 2, { math: 'floor' });
122
const ceiled = usePrecision(number, 2, { math: 'ceil' });
123
124
console.log(rounded.value); // 3.79 (default rounding)
125
console.log(floored.value); // 3.78 (always round down)
126
console.log(ceiled.value); // 3.79 (always round up)
127
128
// Reactive precision
129
const price = ref(19.99567);
130
const decimalPlaces = ref(2);
131
const formattedPrice = usePrecision(price, decimalPlaces);
132
133
console.log(formattedPrice.value); // 20.00
134
135
decimalPlaces.value = 3;
136
console.log(formattedPrice.value); // 19.996
137
138
// Different rounding methods with negative numbers
139
const negative = ref(-2.456);
140
const roundedNeg = usePrecision(negative, 1, { math: 'round' });
141
const flooredNeg = usePrecision(negative, 1, { math: 'floor' });
142
const ceiledNeg = usePrecision(negative, 1, { math: 'ceil' });
143
144
console.log(roundedNeg.value); // -2.5
145
console.log(flooredNeg.value); // -2.5 (floor toward negative infinity)
146
console.log(ceiledNeg.value); // -2.4 (ceil toward positive infinity)
147
```
148
149
## Advanced Usage Patterns
150
151
### Dynamic Bounds and Precision
152
153
```typescript
154
import { ref, computed } from "vue";
155
import { useClamp, usePrecision } from "@vueuse/math";
156
157
// Create a controlled input with dynamic bounds and precision
158
const rawInput = ref(0);
159
const minValue = ref(0);
160
const maxValue = ref(100);
161
const precision = ref(1);
162
163
// Clamp first, then apply precision
164
const clampedInput = useClamp(rawInput, minValue, maxValue);
165
const preciseInput = usePrecision(clampedInput, precision);
166
167
// UI control that updates all values
168
const slider = computed({
169
get: () => preciseInput.value,
170
set: (val: number) => {
171
rawInput.value = val;
172
}
173
});
174
175
// Example usage
176
rawInput.value = 123.456789;
177
console.log(slider.value); // 100.0 (clamped to max, then precision applied)
178
179
maxValue.value = 150;
180
console.log(slider.value); // 123.5 (now within bounds, precision applied)
181
```
182
183
### Financial Calculations
184
185
```typescript
186
import { ref, computed } from "vue";
187
import { useClamp, usePrecision } from "@vueuse/math";
188
189
// Financial calculation with proper precision
190
const principal = ref(10000);
191
const interestRate = ref(0.05); // 5%
192
const years = ref(10);
193
194
// Ensure reasonable bounds for financial inputs
195
const clampedPrincipal = useClamp(principal, 0, 1000000);
196
const clampedRate = useClamp(interestRate, 0, 1); // 0-100%
197
const clampedYears = useClamp(years, 1, 50);
198
199
// Calculate compound interest
200
const futureValue = computed(() => {
201
const p = clampedPrincipal.value;
202
const r = clampedRate.value;
203
const t = clampedYears.value;
204
return p * Math.pow(1 + r, t);
205
});
206
207
// Format for display with proper precision
208
const formattedFutureValue = usePrecision(futureValue, 2);
209
210
console.log(formattedFutureValue.value); // 16288.95
211
212
// Interest calculation stays within bounds even with extreme inputs
213
principal.value = -5000; // Invalid negative
214
interestRate.value = 2.5; // Invalid > 100%
215
console.log(formattedFutureValue.value); // Still gives valid result due to clamping
216
```
217
218
### Animation Value Control
219
220
```typescript
221
import { ref, computed } from "vue";
222
import { useClamp, usePrecision } from "@vueuse/math";
223
224
// Animation progress control
225
const animationProgress = ref(0);
226
const duration = ref(1000); // ms
227
const currentTime = ref(0);
228
229
// Calculate normalized progress (0-1)
230
const rawProgress = computed(() => currentTime.value / duration.value);
231
const clampedProgress = useClamp(rawProgress, 0, 1);
232
const preciseProgress = usePrecision(clampedProgress, 3);
233
234
// Convert to percentage for display
235
const percentProgress = computed(() => preciseProgress.value * 100);
236
const displayPercent = usePrecision(percentProgress, 1);
237
238
// Simulate animation frames
239
function animate() {
240
currentTime.value += 16; // ~60fps
241
242
console.log(`Progress: ${displayPercent.value}%`);
243
244
if (preciseProgress.value < 1) {
245
requestAnimationFrame(animate);
246
}
247
}
248
249
animate();
250
```