对数滑块

发布于 2024-07-19 15:00:39 字数 147 浏览 12 评论 0原文

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

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

我在网上看到过一些函数,但它们都是用 C++ 编写的。 我需要它在 JavaScript 中。

有任何想法吗?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

深居我梦 2024-07-26 15:00:39

您可以使用如下函数:

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

反向函数将具有与 minpmaxpminv 相同的定义code>、maxvscale,根据如下值计算滑块位置:

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

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

南风起 2024-07-26 15:00:39

没有完全回答这个问题,但对于感兴趣的人来说,反向映射最后一行

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

只是为了记录。

注意该值必须> 0。

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.

开始看清了 2024-07-26 15:00:39

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

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

我认为更好的选择是使用均匀分布的“步进”变换。

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

工作演示

反应代码

在上面的示例中,我们定义了 minmax间隔数组。

<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

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

最后,我们只需使用上述算法转换输出即可。 该代码示例还做了一些工作,因此输出始终针对当前步骤间隔进行舍入。

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.

enter image description here

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.

虐人心 2024-07-26 15:00:39

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

并且我已经为 Angular 2+ 创建了它(演示位于 Angular 6 中):< a href="https://stackblitz.com/edit/angular-logarithmic-slider" rel="nofollow noreferrer">工作演示

感谢@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;
   }
};

I was searching for Logarithmic slider For Angular but can't find any and then I came across this answer ,

And I have created that for Angular 2+ (Demo is in Angular 6) : WORKING DEMO

Thanks to @sth, for snippet :

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;
   }
};
撞了怀 2024-07-26 15:00:39

POW() 函数

这里的 pow() 函数略有不同。 这允许设置控制输入分布的“偏斜”曲线。 输出曲线。 另一个重构版本允许从对数(指数)输入设置滑块。

$(document).ready(function() {
  $('#test').change(function() {
    this.value = parseFloat(this.value).toFixed(2);
    widthSliderCurve = this.value;
  });
});

var widthSliderCurve = 0.42; // between -1 and 1 - governs the way the range is skewed

widthSlider.oninput = function() {
  var thisSlider = document.getElementById("widthSlider");


  var curve = Math.pow(10, widthSliderCurve); // convert linear scale into lograthimic exponent for other pow function
  var originalMin = 1.0; // these are set in the slider defintion in HTML make sure they match!
  var originalMax = 200.0; // these are set in the slider defintion in HTML
  var mappedOutputMin = 0.05; // this is the desired output min
  var mappedOutputMax = 10; // this is the desired output max
  var originalRange = originalMax - originalMin;
  var newRange = mappedOutputMax - mappedOutputMin;

  var zeroRefCurVal = thisSlider.value - originalMin; // zero referenced
  var normalizedCurVal = zeroRefCurVal / originalRange; // normalized to 0-1 output
  var rangedValue = ((Math.pow(normalizedCurVal, curve) * newRange) + mappedOutputMin).toFixed(2);

  var outbox = document.getElementById("wSliderOutput");
  outbox.innerHTML = rangedValue;
  //paper.tool.LineWidth = rangedValue;
};



let setLogSlider = function(value, widthSliderCurve, sliderType, outputName) {
  /*** make sure constants match the oninput function values ***/
  var curve = Math.pow(10, widthSliderCurve);
  var originalMin = 1.0; // these are set in the slider defintion in HTML make sure they match!
  var originalMax = 200.0; // these are set in the slider defintion in HTML
  var mappedOutputMin = 0.05; // this is the desired output min
  var mappedOutputMax = 10; // this is the desired output max
  var originalRange = originalMax - originalMin;
  var newRange = mappedOutputMax - mappedOutputMin;
  var logToLinear = Math.pow((value - mappedOutputMin) / newRange, 1 / curve) * originalRange + originalMin;
  console.log("logToLinear ", logToLinear);
  // set the output box
  var outbox = document.getElementById("wSliderOutput");
  outbox.innerHTML = Number(value).toFixed(2);
  // set the linear scale on the slider
  document.querySelectorAll(".optionSliders").forEach((optSlider) => {
    if (optSlider.getAttribute("data-slider-type") == sliderType) {
      optSlider.value = logToLinear;
    }
    var outBox = document.getElementById(outputName);
    outBox.value = value;
  });
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<html>

<head>
  <title>Pow function for variable skew of data mapping</title>
</head>

<body>
  Enter a float between -1.0 and 1.0, hit return, and cycle the slider.</br>

  <input id="test" type="text" value="0.5" />

  <input id="widthSlider" sliderName="widthSlider" type="range" min="1" value="20" max="200" data-slider-type="linesWidth">
  <label for="widthSlider">L Width <span id="Width">
        <output id="wSliderOutput"></output>
        </span></label>
</body>

</html>

var widthSliderCurve = 0.42; // -1 和 1 之间 - 控制范围倾斜的方式

widthSlider.oninput = function () {
var thisSlider = document.getElementById("widthSlider");

  var curve = Math.pow(10, widthSliderCurve); // convert linear scale into lograthimic exponent for other pow function
  var originalMin = 1.0;     // these are set in the slider defintion in HTML make sure they match!
  var originalMax = 200.0;   // these are set in the slider defintion in HTML
  var mappedOutputMin = 0.05; // this is the desired output min
  var mappedOutputMax = 10;  // this is the desired output max
  var originalRange = originalMax - originalMin;
  var newRange = mappedOutputMax - mappedOutputMin;

  var zeroRefCurVal = thisSlider.value - originalMin;      // zero referenced
  var normalizedCurVal  =  zeroRefCurVal / originalRange;  // normalized to 0-1 output
  var rangedValue =  ((Math.pow(normalizedCurVal, curve) * newRange) + mappedOutputMin).toFixed(2);

  var outbox = document.getElementById("wSliderOutput");
  outbox.innerHTML = rangedValue;
  paper.tool.LineWidth = rangedValue;

 
  

  //setLogSlider(rangedValue, widthSliderCurve, "L_Width", "wSliderOutput2");

};let setLogSlider = 函数(值,widthSliderCurve,sliderType,outputName){
/*** 确保常量与 oninput 函数值匹配 ***/
var curve = Math.pow(10, widthSliderCurve);
var 原始最小值 = 1.0; // 这些是在 HTML 的滑块定义中设置的,确保它们匹配!
var 原始最大值 = 200.0; // 这些是在 HTML 的滑块定义中设置的
var 映射输出最小值 = 0.05; // 这是所需的输出最小值
var 映射输出最大值 = 10; // 这是所需的最大输出
var 原始范围 = 原始最大 - 原始最小;
var newRange=mappedOutputMax-mappedOutputMin;
var logToLinear = Math.pow((值 -mappedOutputMin)/newRange, 1/曲线)*originalRange +originalMin;
console.log("logToLinear", logToLinear);
// 设置输出框
var outbox = document.getElementById("wSliderOutput");
outbox.innerHTML = Number(值).toFixed(2);
// 设置滑块的线性比例
document.querySelectorAll(".optionSliders").forEach((optSlider) => {
if (optSlider.getAttribute("data-slider-type") == sliderType) {
optSlider.value = logToLinear;
}
var outBox = document.getElementById(outputName);
outBox.value = 值;
});
};

var widthSliderCurve = 0.42; // -1 和 1 之间 - 控制范围倾斜的方式

widthSlider.oninput = function () {
var thisSlider = document.getElementById("widthSlider");

  var curve = Math.pow(10, widthSliderCurve); // convert linear scale into lograthimic exponent for other pow function
  var originalMin = 1.0;     // these are set in the slider defintion in HTML make sure they match!
  var originalMax = 200.0;   // these are set in the slider defintion in HTML
  var mappedOutputMin = 0.05; // this is the desired output min
  var mappedOutputMax = 10;  // this is the desired output max
  var originalRange = originalMax - originalMin;
  var newRange = mappedOutputMax - mappedOutputMin;

  var zeroRefCurVal = thisSlider.value - originalMin;      // zero referenced
  var normalizedCurVal  =  zeroRefCurVal / originalRange;  // normalized to 0-1 output
  var rangedValue =  ((Math.pow(normalizedCurVal, curve) * newRange) + mappedOutputMin).toFixed(2);

  var outbox = document.getElementById("wSliderOutput");
  outbox.innerHTML = rangedValue;
  paper.tool.LineWidth = rangedValue;

};

POW() function

Here's a slightly different take with a pow() function. This allows setting a "skew" curve that governs the distribution of the input <-> output curve. Another refactored version allows setting the slider from logarithmic (exponential) input.

$(document).ready(function() {
  $('#test').change(function() {
    this.value = parseFloat(this.value).toFixed(2);
    widthSliderCurve = this.value;
  });
});

var widthSliderCurve = 0.42; // between -1 and 1 - governs the way the range is skewed

widthSlider.oninput = function() {
  var thisSlider = document.getElementById("widthSlider");


  var curve = Math.pow(10, widthSliderCurve); // convert linear scale into lograthimic exponent for other pow function
  var originalMin = 1.0; // these are set in the slider defintion in HTML make sure they match!
  var originalMax = 200.0; // these are set in the slider defintion in HTML
  var mappedOutputMin = 0.05; // this is the desired output min
  var mappedOutputMax = 10; // this is the desired output max
  var originalRange = originalMax - originalMin;
  var newRange = mappedOutputMax - mappedOutputMin;

  var zeroRefCurVal = thisSlider.value - originalMin; // zero referenced
  var normalizedCurVal = zeroRefCurVal / originalRange; // normalized to 0-1 output
  var rangedValue = ((Math.pow(normalizedCurVal, curve) * newRange) + mappedOutputMin).toFixed(2);

  var outbox = document.getElementById("wSliderOutput");
  outbox.innerHTML = rangedValue;
  //paper.tool.LineWidth = rangedValue;
};



let setLogSlider = function(value, widthSliderCurve, sliderType, outputName) {
  /*** make sure constants match the oninput function values ***/
  var curve = Math.pow(10, widthSliderCurve);
  var originalMin = 1.0; // these are set in the slider defintion in HTML make sure they match!
  var originalMax = 200.0; // these are set in the slider defintion in HTML
  var mappedOutputMin = 0.05; // this is the desired output min
  var mappedOutputMax = 10; // this is the desired output max
  var originalRange = originalMax - originalMin;
  var newRange = mappedOutputMax - mappedOutputMin;
  var logToLinear = Math.pow((value - mappedOutputMin) / newRange, 1 / curve) * originalRange + originalMin;
  console.log("logToLinear ", logToLinear);
  // set the output box
  var outbox = document.getElementById("wSliderOutput");
  outbox.innerHTML = Number(value).toFixed(2);
  // set the linear scale on the slider
  document.querySelectorAll(".optionSliders").forEach((optSlider) => {
    if (optSlider.getAttribute("data-slider-type") == sliderType) {
      optSlider.value = logToLinear;
    }
    var outBox = document.getElementById(outputName);
    outBox.value = value;
  });
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<html>

<head>
  <title>Pow function for variable skew of data mapping</title>
</head>

<body>
  Enter a float between -1.0 and 1.0, hit return, and cycle the slider.</br>

  <input id="test" type="text" value="0.5" />

  <input id="widthSlider" sliderName="widthSlider" type="range" min="1" value="20" max="200" data-slider-type="linesWidth">
  <label for="widthSlider">L Width <span id="Width">
        <output id="wSliderOutput"></output>
        </span></label>
</body>

</html>

var widthSliderCurve = 0.42; // between -1 and 1 - governs the way the range is skewed

widthSlider.oninput = function () {
var thisSlider = document.getElementById("widthSlider");

  var curve = Math.pow(10, widthSliderCurve); // convert linear scale into lograthimic exponent for other pow function
  var originalMin = 1.0;     // these are set in the slider defintion in HTML make sure they match!
  var originalMax = 200.0;   // these are set in the slider defintion in HTML
  var mappedOutputMin = 0.05; // this is the desired output min
  var mappedOutputMax = 10;  // this is the desired output max
  var originalRange = originalMax - originalMin;
  var newRange = mappedOutputMax - mappedOutputMin;

  var zeroRefCurVal = thisSlider.value - originalMin;      // zero referenced
  var normalizedCurVal  =  zeroRefCurVal / originalRange;  // normalized to 0-1 output
  var rangedValue =  ((Math.pow(normalizedCurVal, curve) * newRange) + mappedOutputMin).toFixed(2);

  var outbox = document.getElementById("wSliderOutput");
  outbox.innerHTML = rangedValue;
  paper.tool.LineWidth = rangedValue;

 
  

  //setLogSlider(rangedValue, widthSliderCurve, "L_Width", "wSliderOutput2");

};let setLogSlider = function (value, widthSliderCurve, sliderType, outputName){
/*** make sure constants match the oninput function values ***/
var curve = Math.pow(10, widthSliderCurve);
var originalMin = 1.0; // these are set in the slider defintion in HTML make sure they match!
var originalMax = 200.0; // these are set in the slider defintion in HTML
var mappedOutputMin = 0.05; // this is the desired output min
var mappedOutputMax = 10; // this is the desired output max
var originalRange = originalMax - originalMin;
var newRange = mappedOutputMax - mappedOutputMin;
var logToLinear = Math.pow((value - mappedOutputMin) / newRange, 1 / curve) * originalRange + originalMin;
console.log("logToLinear ", logToLinear);
// set the output box
var outbox = document.getElementById("wSliderOutput");
outbox.innerHTML = Number(value).toFixed(2);
// set the linear scale on the slider
document.querySelectorAll(".optionSliders").forEach((optSlider) => {
if (optSlider.getAttribute("data-slider-type") == sliderType) {
optSlider.value = logToLinear;
}
var outBox = document.getElementById(outputName);
outBox.value = value;
});
};

var widthSliderCurve = 0.42; // between -1 and 1 - governs the way the range is skewed

widthSlider.oninput = function () {
var thisSlider = document.getElementById("widthSlider");

  var curve = Math.pow(10, widthSliderCurve); // convert linear scale into lograthimic exponent for other pow function
  var originalMin = 1.0;     // these are set in the slider defintion in HTML make sure they match!
  var originalMax = 200.0;   // these are set in the slider defintion in HTML
  var mappedOutputMin = 0.05; // this is the desired output min
  var mappedOutputMax = 10;  // this is the desired output max
  var originalRange = originalMax - originalMin;
  var newRange = mappedOutputMax - mappedOutputMin;

  var zeroRefCurVal = thisSlider.value - originalMin;      // zero referenced
  var normalizedCurVal  =  zeroRefCurVal / originalRange;  // normalized to 0-1 output
  var rangedValue =  ((Math.pow(normalizedCurVal, curve) * newRange) + mappedOutputMin).toFixed(2);

  var outbox = document.getElementById("wSliderOutput");
  outbox.innerHTML = rangedValue;
  paper.tool.LineWidth = rangedValue;

};

つ可否回来 2024-07-26 15:00:39

为了获得你想要的分布,我认为你可以使用这个公式:

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

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文