I have a slider with values ranging from 0 to 100.
I want to map them to a range from 100 to 10,000,000.
I've seen some functions scattered around the net but they're all in C++. I need it in Javascript.
Any ideas?
You can use a function like this:
function logslider(position) {
// position will be between 0 and 100
var minp = 0;
var maxp = 100;
// The result should be between 100 an 10000000
var minv = Math.log(100);
var maxv = Math.log(10000000);
// calculate adjustment factor
var scale = (maxv-minv) / (maxp-minp);
return Math.exp(minv + scale*(position-minp));
}
The resulting values match a logarithmic scale:
js> logslider(0);
100.00000000000004
js> logslider(10);
316.22776601683825
js> logslider(20);
1000.0000000000007
js> logslider(40);
10000.00000000001
js> logslider(60);
100000.0000000002
js> logslider(100);
10000000.000000006
The reverse function would, with the same definitions for minp
, maxp
, minv
, maxv
and scale
, calculate a slider position from a value like this:
function logposition(value) {
// set minv, ... like above
// ...
return (Math.log(value)-minv) / scale + minp;
}
All together, wrapped in a class and as a functional code snippet, it would look like this:
// Generic class:
function LogSlider(options) {
options = options || {};
this.minpos = options.minpos || 0;
this.maxpos = options.maxpos || 100;
this.minlval = Math.log(options.minval || 1);
this.maxlval = Math.log(options.maxval || 100000);
this.scale = (this.maxlval - this.minlval) / (this.maxpos - this.minpos);
}
LogSlider.prototype = {
// Calculate value from a slider position
value: function(position) {
return Math.exp((position - this.minpos) * this.scale + this.minlval);
},
// Calculate slider position from a value
position: function(value) {
return this.minpos + (Math.log(value) - this.minlval) / this.scale;
}
};
// Usage:
var logsl = new LogSlider({maxpos: 20, minval: 100, maxval: 10000000});
$('#slider').on('change', function() {
var val = logsl.value(+$(this).val());
$('#value').val(val.toFixed(0));
});
$('#value').on('keyup', function() {
var pos = logsl.position(+$(this).val());
$('#slider').val(pos);
});
$('#value').val("1000").trigger("keyup");
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Input value or use slider:
<input id="value" />
<input id="slider" type="range" min="0" max="20" />
To get the distribution you want, I think you can use this formula:
var value = Math.floor(-900 + 1000*Math.exp(i/10.857255959));
Here's a self-contained page that will print the values you'll get for your 0-100 slider, having passed them through that formula:
<html><body><script>
for (var i = 0; i <= 100; i++) {
var value = Math.floor(-900 + 1000*Math.exp(i/10.857255959));
document.write(value + "<br>");
}
</script></body></html>
The numbers go from 100 to 10,000,000 in what looks to my mathematically-rusty eye to be the distribution you want. 8-)
The problem with a true Logarithmic slider is at the low end, multiple points on the slider will likely result in duplicate values.
From purely UI perspective, it also doesn't provide a very intuitive output for the users input.
I think a better option is to use an even-distribution "stepped" transform.
In other words, we specify a series of increments we want to use (ex: 1, 10, 100, 1000). Then we split the slider into equal parts based on the number of increments we defined. When we are sliding through our different sections, the slider output will increment by the respective increment.
WORKING DEMO
REACT CODE
In the above example, we define our min
, max
& intervals
array.
<ExpoStepSlider
intervals={[1, 2, 5, 10, 100, 1000]}
min={1}
max={50000}
/>
We then must find the number of discrete values our slider must have so that it properly goes from min to max based on our defined interval distributions.
let sliderPoints = Math.ceil(
(max - min) /
intervals.reduce((total, interval) => total + interval / intervals.length, 0)
);
In this case 535
.
Note: Your slider points should not exceed the number of pixels in the slider
Finally, we just transform our output using the algorithm described above. The code example also does some work so the output is always round for the the current step interval.
Not quite answering the question, but for people interested, the reverse maping the last line is
return (Math.log(value)-minv)/scale + min;
just to document.
NOTE the value must be > 0.
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