UNPKG

ratio-lock

Version:

A TypeScript library for managing n numbers with locked ratios. When the ratio is locked, changing one value automatically adjusts all other values to maintain their proportional relationships.

119 lines 3.35 kB
import { RatioLockError } from './ratio-lock-error.js'; /** * A class for managing n numbers with locked ratios. * When the ratio is locked, changing one value automatically adjusts * all other values to maintain their proportional relationships. */ export class RatioLock { _values; _ratios; _locked; _precision; /** * Creates a new RatioLock instance * @param initialValues - Initial values for the ratio lock * @param options - Configuration options */ constructor(initialValues, options) { if (initialValues.length < 2) { throw new RatioLockError('RatioLock requires at least 2 values'); } this._values = [...initialValues]; this._locked = options.locked === true; this._precision = options.precision; this._ratios = this.calculateRatios(initialValues); } calculateRatios(values) { const baseValue = values[0]; if (baseValue === 0) { return values.map(() => 1); } return values.map(v => v / baseValue); } applyPrecision(value) { if (this._precision === undefined) { return value; } return Number(value.toFixed(this._precision)); } /** * Lock the current ratio */ lock() { this._ratios = this.calculateRatios(this._values); this._locked = true; } /** * Unlock the ratio */ unlock() { this._locked = false; } /** * Toggle lock state */ toggle() { if (this._locked) { this.unlock(); } else { this.lock(); } } /** * Set a value at the given index * @param index - Index of the value to set * @param value - New value */ setValue(index, value) { if (index < 0 || index >= this._values.length) { throw new RatioLockError(`Index ${index} is out of bounds`); } if (this._locked) { const ratio = this._ratios[index]; const baseValue = ratio !== 0 ? value / ratio : 0; this._values = this._ratios.map(r => this.applyPrecision(baseValue * r)); } else { const newValues = [...this._values]; newValues[index] = value; this._values = newValues; } } /** * Set all values (recalculates ratio if locked, unless all values are zero) * @param values - New values */ setValues(values) { if (values.length !== this._values.length) { throw new RatioLockError(`Expected ${this._values.length} values, got ${values.length}`); } this._values = [...values]; if (this._locked) { // Don't recalculate ratios if all values are zero - preserve existing ratios const allZero = values.every(v => v === 0); if (!allZero) { this._ratios = this.calculateRatios(values); } } } /** * Get current values */ getValues() { return [...this._values]; } /** * Get current ratios */ getRatios() { return [...this._ratios]; } /** * Check if ratio is locked */ isLocked() { return this._locked; } } //# sourceMappingURL=ratio-lock.js.map