Reactive mathematical utility functions and composables for Vue.js applications
—
Generic reactive wrapper that provides access to any Math method with full type safety and reactive behavior. This allows you to use any JavaScript Math function reactively without needing individual wrapper functions.
Generic function that creates reactive wrappers for any Math method by name, preserving full type safety and function signatures.
/**
* Generic reactive wrapper for Math methods
* @param key - The name of the Math method to use
* @param args - Arguments to pass to the Math method (reactive)
* @returns Reactive result of the Math method call
*/
function useMath<K extends keyof Math>(
key: K,
...args: ArgumentsType<Reactified<Math[K], true>>
): ReturnType<Reactified<Math[K], true>>;
/**
* Type containing all Math method names that are callable functions
*/
type UseMathKeys = keyof {
[K in keyof Math as Math[K] extends (...args: any) => any ? K : never]: unknown
};Usage Examples:
import { ref, computed } from "vue";
import { useMath } from "@vueuse/math";
// Basic trigonometric functions
const angle = ref(Math.PI / 4); // 45 degrees
const sine = useMath('sin', angle);
const cosine = useMath('cos', angle);
const tangent = useMath('tan', angle);
console.log(sine.value); // ~0.707
console.log(cosine.value); // ~0.707
console.log(tangent.value); // ~1.000
// Power and logarithmic functions
const base = ref(2);
const exponent = ref(8);
const power = useMath('pow', base, exponent);
const log = useMath('log2', power);
console.log(power.value); // 256
console.log(log.value); // 8 (log2 of 256)
// Square root and other single-argument functions
const number = ref(16);
const sqrt = useMath('sqrt', number);
const cbrt = useMath('cbrt', number);
console.log(sqrt.value); // 4
console.log(cbrt.value); // ~2.52
// Min/Max with multiple arguments
const a = ref(5);
const b = ref(10);
const c = ref(3);
const min = useMath('min', a, b, c);
const max = useMath('max', a, b, c);
console.log(min.value); // 3
console.log(max.value); // 10All standard JavaScript Math methods are available through useMath:
// Trigonometric functions
useMath('sin', angle);
useMath('cos', angle);
useMath('tan', angle);
useMath('asin', value);
useMath('acos', value);
useMath('atan', value);
useMath('atan2', y, x);
// Hyperbolic functions
useMath('sinh', value);
useMath('cosh', value);
useMath('tanh', value);
useMath('asinh', value);
useMath('acosh', value);
useMath('atanh', value);
// Exponential and logarithmic functions
useMath('exp', value);
useMath('expm1', value);
useMath('log', value);
useMath('log10', value);
useMath('log2', value);
useMath('log1p', value);
useMath('pow', base, exponent);
// Root functions
useMath('sqrt', value);
useMath('cbrt', value);
useMath('hypot', ...values);
// Rounding and integer functions
useMath('ceil', value);
useMath('floor', value);
useMath('round', value);
useMath('trunc', value);
useMath('sign', value);
// Min/Max and comparison
useMath('min', ...values);
useMath('max', ...values);
useMath('abs', value);
// Random (note: no arguments needed)
useMath('random'); // Always returns different ComputedRef
// Other mathematical functions
useMath('fround', value);
useMath('imul', a, b);
useMath('clz32', value);import { ref, computed } from "vue";
import { useMath } from "@vueuse/math";
// Calculate distance between two points
const x1 = ref(0);
const y1 = ref(0);
const x2 = ref(3);
const y2 = ref(4);
// Using Pythagorean theorem: √((x2-x1)² + (y2-y1)²)
const deltaX = computed(() => x2.value - x1.value);
const deltaY = computed(() => y2.value - y1.value);
const deltaXSquared = useMath('pow', deltaX, 2);
const deltaYSquared = useMath('pow', deltaY, 2);
const sumOfSquares = computed(() => deltaXSquared.value + deltaYSquared.value);
const distance = useMath('sqrt', sumOfSquares);
console.log(distance.value); // 5
// Update coordinates - distance updates automatically
x2.value = 6;
y2.value = 8;
console.log(distance.value); // 10import { ref, computed } from "vue";
import { useMath } from "@vueuse/math";
// Create easing functions using Math methods
const progress = ref(0); // 0 to 1
// Ease-in-sine
const easeInSine = computed(() => {
const halfPI = Math.PI / 2;
const progressAngle = computed(() => progress.value * halfPI);
const cos = useMath('cos', progressAngle);
return 1 - cos.value;
});
// Ease-out-expo
const easeOutExpo = computed(() => {
if (progress.value === 1) return 1;
const negativeProgress = computed(() => -10 * progress.value);
const pow = useMath('pow', 2, negativeProgress);
return 1 - pow.value;
});
// Animate through progress values
function animate() {
progress.value += 0.01;
console.log({
linear: progress.value,
easeInSine: easeInSine.value,
easeOutExpo: easeOutExpo.value
});
if (progress.value < 1) {
requestAnimationFrame(animate);
}
}import { ref, computed } from "vue";
import { useMath } from "@vueuse/math";
// Standard deviation calculation
const values = ref([2, 4, 4, 4, 5, 5, 7, 9]);
const mean = computed(() => {
return values.value.reduce((sum, val) => sum + val, 0) / values.value.length;
});
const variance = computed(() => {
const avg = mean.value;
const squaredDiffs = values.value.map(val => {
const diff = val - avg;
return diff * diff;
});
return squaredDiffs.reduce((sum, val) => sum + val, 0) / values.value.length;
});
const standardDeviation = useMath('sqrt', variance);
console.log({
mean: mean.value, // 5
variance: variance.value, // 4
stdDev: standardDeviation.value // 2
});
// Add new value - all statistics update automatically
values.value.push(10);
console.log({
mean: mean.value, // ~5.56
variance: variance.value, // ~5.58
stdDev: standardDeviation.value // ~2.36
});import { ref, computed } from "vue";
import { useMath } from "@vueuse/math";
// Projectile motion calculator
const initialVelocity = ref(50); // m/s
const angle = ref(45); // degrees
const gravity = ref(9.81); // m/s²
// Convert angle to radians
const angleInRadians = computed(() => (angle.value * Math.PI) / 180);
const sinAngle = useMath('sin', angleInRadians);
const cosAngle = useMath('cos', angleInRadians);
// Calculate components
const vx = computed(() => initialVelocity.value * cosAngle.value);
const vy = computed(() => initialVelocity.value * sinAngle.value);
// Time of flight: t = 2 * vy / g
const timeOfFlight = computed(() => (2 * vy.value) / gravity.value);
// Maximum height: h = vy² / (2 * g)
const vySquared = useMath('pow', vy, 2);
const maxHeight = computed(() => vySquared.value / (2 * gravity.value));
// Range: R = vx * t
const range = computed(() => vx.value * timeOfFlight.value);
console.log({
timeOfFlight: timeOfFlight.value, // ~7.21 seconds
maxHeight: maxHeight.value, // ~63.78 meters
range: range.value // ~254.96 meters
});
// Change launch angle to optimize range
angle.value = 30;
console.log(`Range at 30°: ${range.value.toFixed(2)}m`);
angle.value = 45;
console.log(`Range at 45°: ${range.value.toFixed(2)}m`); // Optimal angleInstall with Tessl CLI
npx tessl i tessl/npm-vueuse--math