对数滑块


77

我有一个滑块,其值的范围从0到100。

我想将它们映射到100到10,000,000的范围内。

我已经看到一些分散在网络上的函数,但是它们全都在C ++中。我需要用Javascript。

有任何想法吗?

Answers:


182

您可以使用如下函数:

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));
}

结果值与对数刻度匹配:

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

反向功能将,与相同的定义minpmaxpminvmaxvscale,计算从这样的值的滑块位置:

function logposition(value) {
   // set minv, ... like above
   // ...
   return (Math.log(value)-minv) / scale + minp;
}


总而言之,包裹在一个类中并作为功能代码片段,它看起来像这样:

// 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" />


5
您是否有相反的功能?给定对数值,输出滑块位于什么位置。
GeekyMonkey 2011年

辉煌不能说声谢谢!我拥有数学学位,但是自从获得学位以来已经很久了,以至于这样的事情都会导致挫败感。感谢SO(和您)可以绕开!
Gaz 2012年

1
这不是指数滑块吗?有没有一种方法可以使曲线反转以使其为对数?这样,值快速上升,然后逐渐下降到终点?
尼克·胡克

2
@NickH:取决于您如何看待它。当前,当滑块位置上升时,关联值上升的速度越来越快,因此从这个角度来看,它是指数的。如果您反过来需要它,请切换valueposition以获得相反的效果。
sth

@sth谢谢,我总是对指数和对数感到困惑。有没有办法使您的解决方案中的曲线上升速度较慢(线性度更高,但仍呈指数形式)?在50的输入值是某处大约550
尼克带钩

9

为了获得所需的分布,我认为您可以使用以下公式:

var value = Math.floor(-900 + 1000*Math.exp(i/10.857255959));

这是一个自包含的页面,该页面将打印您通过0-100滑块获得的值,并通过该公式传递它们:

<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>

在我看来对数学不满意的地方,这个数字从100到10,000,000不等。8)


4
从Math.exp(i)开始并手动调整,直到数字合适为止。我的数学能力很弱,但我可以为英格兰砍二进制。8
RichieHindle

这两个答案代表了数学知识的力量。这应该向任何程序员表达对学习数学的要求。
2009年

9

不是很回答这个问题,但是对于感兴趣的人,反向映射最后一行是

return (Math.log(value)-minv)/scale + min;

只是为了记录。

注意该值必须> 0。


5

真正的对数滑块的问题在低端,滑块上的多个点可能会导致值重复。

从纯UI的角度来看,它也没有为用户输入提供非常直观的输出。

我认为一个更好的选择是使用均匀分布的“阶梯式”变换。

在此处输入图片说明

换句话说,我们指定了一系列要使用的增量(例如:1、10、100、1000)。然后,根据定义的增量数将滑块分成相等的部分。当我们在不同部分中滑动时,滑块输出将以各自的增量递增。

工作演示

反应码

在上面的例子中,我们定义minmaxintervals阵列。

<ExpoStepSlider
  intervals={[1, 2, 5, 10, 100, 1000]}
  min={1}
  max={50000}
/>

然后,我们必须找到滑块必须具有的离散值的数量,以使其根据定义的间隔分布正确地从最小值变为最大值。

let sliderPoints = Math.ceil(
  (max - min) / 
  intervals.reduce((total, interval) => total + interval / intervals.length, 0)
);

在这种情况下535

注意:您的滑块点不得超过滑块中的像素数

最后,我们仅使用上述算法转换输出。该代码示例也做了一些工作,因此对于当前步长间隔,输出始终是舍入的。


2
太棒了,谢谢分享代码!我没有那么👍甚至意识到反应滑块
查克·伯杰龙

太棒了!您的评论是正确的,这种方法比对数函数更好地实现了我的目标
Alex

1

我一直在寻找Angular的对数滑块,但找不到任何滑块,然后遇到了这个答案,

我为Angular 2+(Demo在Angular 6中)创建了它:工作示例

感谢@sth的摘要

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;
   }
};
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.