Scaling between two number ranges
Asked Answered
F

6

26

I remember using an equation to do this at some point – how do you do this in Javascript?

Plugin two number ranges:

rangeX = 1 (through) 10;
rangeY = 300.77 (through) 559.22;

Input a value in the rangeY scale:

inputY = 328.17;

Convert to proportional value in rangeX scale:

outputX = 1.43;
Feasible answered 8/1, 2013 at 21:41 Comment(0)
B
59
function convertRange( value, r1, r2 ) { 
    return ( value - r1[ 0 ] ) * ( r2[ 1 ] - r2[ 0 ] ) / ( r1[ 1 ] - r1[ 0 ] ) + r2[ 0 ];
}

convertRange( 328.17, [ 300.77, 559.22 ], [ 1, 10 ] );

>>> 1.9541497388276272
Bushweller answered 8/1, 2013 at 22:3 Comment(1)
Since this answer is popular I'm just gonna add that this is called Linear interpolation for anyone interested.Bushweller
W
37

Use percentages:

xMax = 10;
xMin = 1;

yMax = 559.22;
yMin = 300.77;

percent = (inputY - yMin) / (yMax - yMin);
outputX = percent * (xMax - xMin) + xMin;
Wilburnwilburt answered 8/1, 2013 at 21:46 Comment(0)
O
7

I turned @Foggzie's answer into a TypeScript function and ES2016 function.

TypeScript:

const scale = (inputY: number, yRange: Array<number>, xRange: Array<number>): number => {
  const [xMin, xMax] = xRange;
  const [yMin, yMax] = yRange;

  const percent = (inputY - yMin) / (yMax - yMin);
  const outputX = percent * (xMax - xMin) + xMin;

  return outputX;
};

ES2016:

const scale = (inputY, yRange, xRange) => {
  const [xMin, xMax] = xRange;
  const [yMin, yMax] = yRange;

  const percent = (inputY - yMin) / (yMax - yMin);
  const outputX = percent * (xMax - xMin) + xMin;

  return outputX;
};
Oran answered 10/10, 2019 at 16:24 Comment(0)
W
7

Here's the linear interpolation, same as @oleq's answer, but explicitly working with min and max variables instead of arrays of ranges

function getScaledValue(value, sourceRangeMin, sourceRangeMax, targetRangeMin, targetRangeMax) {
    var targetRange = targetRangeMax - targetRangeMin;
    var sourceRange = sourceRangeMax - sourceRangeMin;
    return (value - sourceRangeMin) * targetRange / sourceRange + targetRangeMin;
}
Wolof answered 25/1, 2021 at 19:56 Comment(0)
B
0

No guarantees on the math, but I think something like this:

var xLow = 1;
var xHigh = 10:
var yLow = 300.77;
var yHigh = 559.22;

var inputY = 328.17;
var ouputX = xLow;

var scaleYOverX = (yHigh - yLow)/(xHigh - xLow);

if(inputY >= yLow && inputY <= yHigh) {
  outputX = (inputY - yLow)/scaleYOverX + xLow;
  alert(outputX);
} else {
  alert("Invalid input for Y scale");
}
Brass answered 8/1, 2013 at 21:56 Comment(0)
N
0

Swift 3 With Bool for extended range or not

func translate(input : Float, inputMin: Float, inputMax: Float, outputMin: Float, outputMax: Float, extendRange: Bool? = false, log: Bool? = false) -> Float {

    //The actual translation function
    func translationResult(_ inputMinA: Float, _ inputMaxA: Float) -> Float {
        let myResult = outputMin + (outputMax - outputMin) * (input - inputMinA) / (inputMaxA - inputMinA)
        return myResult
    }

    // extendRange true means it'll return a value outside the range of inputMin and inputMax but still follow the ratio
    if extendRange! {
        return result = translationResult(inputMin, inputMax)

        if log! == true && input > inputMax || input < inputMin{
            print("outside range!")
        }
    } else {
        //Doesn't let value go outside range
        let inputMinA = min(inputMin, input)
        let inputMaxA = max(inputMax, input)

        return result = translationResult(inputMinA, inputMaxA)
    }
    }


    translate(input: 50, inputMin: 100, inputMax: 1000.0, outputMin: 1, outputMax: 10, extendRange: false) => 1
    translate(input: 50, inputMin: 100, inputMax: 1000.0, outputMin: 1, outputMax: 10, extendRange: true) => 0.5
Narration answered 19/3, 2017 at 18:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.