I have a slider with a minimum value of 0 and maximum of 500.
I want to when the slider goes to 100, the thumb be in the middle of the slider.
I know it seems wierd, but some programs do it with zoom slider, and I believe it's better.
A good formula for the displayed value is a monotonous function such as a power curve, in the following form:
DisplayValue = A + B * Math.Exp(C * SliderValue);
The internal slider value (from 0 to 1 for instance) is obtained by inverting the formula:
SliderValue = Math.Log((DisplayValue - A) / B) / C;
Now how to obtain A, B and C? By using the three constraints you gave:
f(0.0) = 0
f(0.5) = 100
f(1.0) = 500
Three equations, three unknowns, this is solved using basic maths:
A + B = 0
A + B exp(C * 0.5) = 100
A + B exp(C) = 500
B (exp(C * 0.5) - 1) = 100
B (exp(C) - 1) = 500
exp(C) - 5 exp(C * 0.5) + 4 = 0 // this is a quadratic equation
exp(C * 0.5) = 4
C = log(16)
B = 100/3
A = -100/3
Yielding the following code:
double B = 100.0 / 3;
double C = Math.Log(16.0);
DisplayValue = B * (Math.Exp(C * SliderValue) - 1.0);
You can see that the display value is at 100 when the internal value is in the middle:
Edit: since a generic formula was requested, here it is. Given:
f(0.0) = x
f(0.5) = y
f(1.0) = z
The values for A, B and C are:
A = (xz - y²) / (x - 2y + z)
B = (y - x)² / (x - 2y + z)
C = 2 * log((z-y) / (y-x))
Note that if x - 2y + z
or y - x
is zero, there is no solution and you’ll get a division by zero. That’s because in this case, the scale is actually linear. You need to take care of that special case.
let the slider as it is and use a ValueConverter for your bindings. In the ValueConverter use the non-linear scaling to scale the value as you wish.
Just as a further reference; if you are not interested on exact positions for your slider to correspond to specific values in your scale but still want a behavior where the slider is more sensitive to values on the beginning of the scale than on the end, then perhaps using a simple log scale may suffice.
public class LogScaleConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
double x = (int)value;
return Math.Log(x);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
double x = (double)value;
return (int)Math.Exp(x);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With