July 07, 2023
Have you ever needed to translate one range to the another? Usually we have a range 0 - 100. Then we do all calculations for that range. But what if we need the range narrowed?
Let’s say you have a range of values (700 - 15000) that you
need to map to l
value of hsl
which are 0 - 100. But, 0 is black
and 100 is white. What about, let’s say 10-90?
Here are the requirements. We want to:
l
and max value to 90% of l
Let’s explore this topic:
As a result, we’ll provide appropriate output value within output range for given input value.
PS: Don’t mind the snippet format, this only demonstrates the math. You can (re)write it to your own implementation (class or whatever)
// Define the format of our argumentsinterface TranslatorOptions {minInput: number;maxInput: number;lowOutput: number;highOutput: number;steps: number;}// Set the default argument valuesconst defaults: TranslatorOptions = {minInput: 111,maxInput: 531,lowOutput: 10,highOutput: 90,steps: 5,}/*** Translate one range to another* @param value { number } Value in range of `options.minInput`* and `options.maxInput`* @param options [defaults] { TranslatorOptions }*/function translate(value: number,options: Partial<TranslatorOptions> = defaults) {const mergedOptions = {...defaults,...options } as TranslatorOptions;// Calculate the the "available" difference between extreme valuesconst range = mergedOptions.highOutput - mergedOptions.lowOutput;/*** Set the "inversed" steps. Best to explain by example:* We define 5 steps, i.e. 1, 2, 3, 4, 5. This means that* if we have max value of 100, we need to divide by 20.* Otherwise we'd have 20 steps...*/const step = mergedOptions.steps ? range / mergedOptions.steps : 0;/*** Subtract minInput value from provided `value` and `maxInput`* to reset calculation to zero, so we can get correct* math result.*/const valuePercentage = Math.round(((value - mergedOptions.minInput) /(mergedOptions.maxInput - mergedOptions.minInput)) * range);/*** Here we get the final result ranging from `lowOutput` to* `highOutput` for given range of `minInput`/`maxInput`*/const lightness = valuePercentage + mergedOptions.lowOutput;// And last, we add stepping for provided `value` if correctreturn step? mergedOptions.lowOutput + Math.floor(step * Math.floor(lightness / step)): lightness;}
Here are some examples with the defaults from above:
translate(231, { steps: 3 })// 36translate(423, { steps: 10 })// 74translate(423)// 69
Written by Milan Miljkovic — a tech enthusiast and design system practitioner.