How to Map Values from one Range to Another in JavaScript

Written By idriss douiri profile picture Idriss Douiri

3 min read

range mapping in javascript
Share

Mapping values from one range (e.g.: 0 to 800) to another (e.g.: 10 to 100) is common practice for most applications, especially in creative coding and video games.

It is a technique that transforms a value from a source range to a target range while preserving its relative position.

For a visual explanation, move the first slider and notice how the value is mapped to the second range while it keeps the same position relative to the source range:

source:

target:

50
27
42%

The mapping formula is simple once you understand what each component means:

range mapping formula

The Math Behind Range Mapping

Let’s break down this formula to understand how it works:

percentage = (value - sourceStart) / (sourceEnd - sourceStart)
targetLength = (targetEnd - targetStart)
mapped = percentage * targetLength + targetStart

First we get the value percentage relative to its source range, then we multiply this percentage with the length of the target range, and finally offset it back by the starting value of the target range.

Common Use Cases

  • Normalizing ranges to [0-1] range
  • Scaling ranges up or down
  • UI slider input mapping
  • mouse position mapping
  • Unit Conversion

JavaScript Implementation

Most Math libraries will come with their own mapping function, but if you want to write your own here is how it might look like in JavaScript:

function map(value, sourceStart, sourceEnd, targetStart, targetEnd) {
    return (value - sourceStart) / (sourceEnd - sourceStart) * (targetEnd - targetStart) + targetStart
}
console.log(map(0, -300, 300, 0, 100)) // 50

Edge Cases and Improvements

With the current implementation, if the source range’s min and max values are equal we will get a 0 division issue. We can prevent this by checking the source range in the function and only perform the calculation if the two ends are different, otherwise we can throw an error or return a fallback value.

if (sourceStart === sourceEnd) return targetStart // fallback

Additionally, values outside of the source range will result in values outside of the target range, this might be the desired behavior but if not, we can optionally clamp the result to never exceed the target range like this:

return Math.max(targetStart, Math.min(mappedValue, targetEnd))

This will work only if the targetStart is less than the targetEnd, but we can’t always be sure. what if the ranges where in revere? say [80 - 25] instead of [25 - 80], this could mess the calculation, so let’s constrain the ranges to work safely with any range.

the final function will look like this:

function map(value, sourceStart, sourceEnd, targetStart, targetEnd, clamped = false) {
    if (sourceStart === sourceEnd) return targetStart;
    
    const sourceMin = Math.min(sourceStart, sourceEnd);
    const sourceMax = Math.max(sourceStart, sourceEnd);
    const targetMin = Math.min(targetStart, targetEnd);
    const targetMax = Math.max(targetStart, targetEnd);

    const mappedValue = (value - sourceMin) / (sourceMax - sourceMin) * (targetMax - targetMin) + targetMin;
    
    if (!clamped) return mappedValue;
    return Math.max(targetMin, Math.min(mappedValue, targetMax));
}

Conclusion

Try integrating this mapping logic into your next creative project and see what you can achieve with it.