简体   繁体   中英

Logarithmic Range Input Slider - Increasing Steps in Thresholds

Summary
I need a range input with numbers from 1,000 to 10,000,000. Due to the large range it can't be linear. So each time the decimal length increases (eg from 1000 to 10000) the steps should also increase.

#--------------------#--------------------#--------------------#--------------------#
0  1000   5000  9000 10,000    56,498  100,000    500,000   1,000,000          10,000,000

Failed attempts
I already tried to create a slider range from 1 to 5 (to have 4 steps) and interpolate the values but I couldn't get it to work so the steps increased at the same time when the decimal increased.

Also I tried this solution: Logarithmic slider It's better than a linear behavior but still the steps in the beginning (left) are too small and too large in the end (right end of range slider).

Additional requirement
This range slider also has to be connected to an input field. So the input value also has to be written back to the slider (so some kind of inverse calculation input <-> range slider).

Adjusted version of the Logarithmic Slider solution linked above:

 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: 300, minval: 1000, maxval: 10000000}); $('#slider').on('change input', function() { var val = logsl.value(+$(this).val()); // console.log(val); var rounded = Math.round(val / 1000) * 1000; var localized = rounded.toLocaleString('DE'); $('#value').val(localized); }); $('#value').on('keyup', function() { var val = +($(this).val().toString().replace(/[\D]/g,'')); //console.log(this.value, val); var pos = logsl.position(val); //console.log(pos); $('#slider').val(pos); }); $('#value').val("10000").trigger("keyup");
 #slider { width: 300px; }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> Input value or use slider: <input id="value" /> <input id="slider" type="range" min="0" max="300" />

The smallest steps are 1,000. Here you can see, between 1,000 and 2,000 there are around 20 px space. But on very high numbers, the steps are up to over 300,000. So not the best user experience. You should at least be able to input in steps of 100,000 as illustrated above.

To get you started, you could get the right base for the slider.

 function updateSlider() { let value = +document.getElementById('value').value, adjusted = Math.max(Math.min(value, max), min); document.getElementById('slider').value = Math.log(adjusted / min) / Math.log(base); updateValue(); } function updateValue() { const value = document.getElementById('slider').value; document.getElementById('value').value = (min * base ** value).toFixed(0); } const min = 1_000, max = 10_000_000, steps = +document.getElementById('slider').max, base = Math.pow(max / min, 1 / steps); document.getElementById('value').addEventListener('change', updateSlider); document.getElementById('slider').addEventListener('click', updateValue);
 <input id="value" /> <input id="slider" type="range" min="0" max="20" />

Not a Javascript coder so I will not touch any of the stuff however you can use linear slide and use conversion between linear and logarithmic scales:

// linear x to logarithmic xx
if (x>=xmin) xx=log(x/xmin)/log(xmax/xmin)
 else        xx=0.0;

// logarithmic xx to linear x
x=exp(xx*log(xmax/xmin))*xmin; 

Where xmin,xmax is your range. Beware it can not include zero !!! so for example:

xmin=1.0;
xmax=10000000.0;

the xmin can be anything bigger than 0 for example 0.001 and xmax must be bigger than xmin usually xmin*pow(10,?) ...

So x is the slider linear position from xmin to xmax and xx is logarithmic position in range <0.0,1.0>

So you just simply multiply the xx by your resolution in pixels of your view/slider what ever to get [pixels] ...

I use conversions like this time to time here an example:

分光镜

where xmin=100; xmax=22050; xmin=100; xmax=22050; from my spectroscope app.

Here 3D interpolation between curves another example with C++ code

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM