The general (unclamped) equation you want is:
var unclamped = (x-minX) * (maxY-minY)/(maxX-minX) + minY;
For clamping, you can either clamp the output after you calculate the result:
var clamped = Math.max( minY, Math.min( maxY, unclamped ) );
Or you can clamp the input before you use it:
x = Math.max( minX, Math.min( maxX, x ) )
var clamped = (x-minX) * (maxY-minY)/(maxX-minX) + minY;
If the slope of the line does not change, and your clamping desires do not change, you can improve performance by pre-calculating it once and generating a function tailored to your input and needs:
// Generate a lerp function for a specific set of input/output,
// with or without clamping to the output range.
function lerp(minX, maxX, minY, maxY, clampFlag) {
var slope = (maxY-minY)/(maxX-minX);
return clampFlag ?
function(x){ return ((x<minX?minX:x>maxX?maxX:x) - minX) * slope + minY }
:
function(x){ return (x-minX)*slope + minY }
}
In action:
prepPlotter(); // Get ready to draw a pretty graph of the results
// Make a simple input/output function
var zoomForSpeed = lerp(20, 80, 17, 15, true);
for (var speed=0; speed<=99; speed++) {
var zoom = zoomForSpeed(speed); // Bam! Lerp'd!
plot(speed,zoom); // Proof of the goodness
}
// Show the min/max input and output
ctx.fillStyle = 'red';
plot(20,17,2);
plot(80,15,2);
function plot(speed,zoom,scale) {
ctx.fillRect(speed,zoom,0.5*(scale||1),0.03*(scale||1));
}
function prepPlotter() {
ctx = document.querySelector('canvas').getContext('2d');
ctx.translate(0,875);
ctx.scale(3,-50);
}
function lerp(minX, maxX, minY, maxY, clampFlag) {
var slope = (maxY-minY)/(maxX-minX);
return clampFlag ? function(x){ return ((x<minX?minX:x>maxX?maxX:x) - minX) * slope + minY } : function(x){ return (x-minX)*slope + minY }
}
<canvas>Press "Run code snippet" for a graph of zoomForSpeed</canvas>