I'm trying to build a control like the following:
I have it working when it is unlinked, but I can't figure out how to scale it by whatever value is entered in either the first or second input field.
class OffsetControl extends Component {
constructor(props) {
super(props)
this.state = {
axes: { x: 0, y: 0 },
isLinked: false
}
this._handleAxisChange = this._handleAxisChange.bind(this)
}
_scale(axes) {
const { axes: { x, y } } = this.state
let ratio = [axes.x / x, axes.y / y ]
ratio = Math.min(ratio[0], ratio[1])
this.setState({
axes: {
x: x * ratio,
y: y * ratio
}
})
}
_handleAxisChange({ target: { name, value } }) {
const { isLinked, axes } = this.state
const newAxes = { ...axes, [name]: +value }
if (isLinked) {
this._scale(newAxes)
} else {
this.setState(newAxes)
}
}
render() {
const { axes: { x, y }, isLinked } = this.state
return (
<div>
<input type="number" name="x" value={x} onChange={this._handleAxisChange}/>
<button onClick={() => this.setState({ isLinked: !isLinked })}>
{ isLinked ? 'Unlink' : 'Link' }
</button>
<input type="number" name="y" value={y} onChange={this._handleAxisChange}/>
</div>
)
}
}
You can find a live version here. Any help is greatly appreciated.
It is basically the straight line formula:
y = mx + c
In the general case (like converting cm to inches) c
is zero. So the formula is merely:
y = mx
You only need the c
in cases where you have an offset (like converting celsius to fahrenheit).
Just find out the m
(or if you're more familiar with calculus, dy/dx - which is the terminology I'll be using in the following code):
var current_input = 5;
var current_output = 9;
var dy_dx = current_output/current_input;
var new_output = dy_dx * new_input;
So, a concrete example:
current_input = 5;
current_output = 9;
// change 5 to 11, what should 9 change to?
new_output = (9/5) * 11; // result is 19.8
You can flip the equation around if you need to calculate the first value if you change the second value:
current_input = 9;
current_output = 5;
// change 9 to 15, what should 5 change to?
new_output = (5/9) * 15; // result is 8.333
In general you can implement it as:
function scale (old_input, old_output, new_input) {
return (old_output/old_input) * new_input;
}
Although numerically it is better to store the value of m
so that you don't lose accuracy after doing lots of calculations:
function Scaler (x,y) {
this.m = y/x;
}
Scaler.prototype.calculate_y (new_x) {
return this.m * new_x;
}
Scaler.prototype.calculate_x (new_y) {
return (1/this.m) * new_y;
}
// so you can do:
var scaler = new Scaler(5,9);
var new_output = scaler.calculate_y(11);
Highschool math is useful after all.