web-dev-qa-db-fra.com

Curseur logarithmique

J'ai un curseur avec des valeurs allant de 0 à 100.

Je veux les mapper sur une plage de 100 à 10 000 000.

J'ai vu quelques fonctions dispersées sur le net mais elles sont toutes en C++. J'en ai besoin en Javascript.

Des idées?

69
user103773

Vous pouvez utiliser une fonction comme celle-ci:

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

Les valeurs résultantes correspondent à une échelle logarithmique:

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

La fonction inverse, avec les mêmes définitions pour minp, maxp, minv, maxv et scale, calculerait la position d'un curseur à partir de une valeur comme celle-ci:

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


Tous ensemble, enveloppés dans une classe et en tant qu'extrait de code fonctionnel, cela ressemblerait à ceci:

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

Pour obtenir la distribution que vous souhaitez, je pense que vous pouvez utiliser cette formule:

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

Voici une page autonome qui imprimera les valeurs que vous obtiendrez pour votre curseur 0-100, après les avoir passées par cette formule:

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

Les chiffres vont de 100 à 10 000 000 dans ce qui me semble mathématiquement rouillé comme la distribution que vous voulez. 8-)

9
RichieHindle

Ne répondant pas tout à fait à la question, mais pour les personnes intéressées, le mappage inverse de la dernière ligne est

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

juste pour documenter.

REMARQUE, la valeur doit être> 0.

9
siliconeagle

Le problème avec un vrai curseur logarithmique est à l'extrémité inférieure, plusieurs points sur le curseur entraîneront probablement des valeurs en double.

Du point de vue purement de l'interface utilisateur, il ne fournit pas non plus une sortie très intuitive pour l'entrée des utilisateurs.

Je pense qu'une meilleure option est d'utiliser une transformation "par étapes" à distribution uniforme.

enter image description here

En d'autres termes, nous spécifions une série d'incréments que nous voulons utiliser (ex: 1, 10, 100, 1000). Ensuite, nous divisons le curseur en parties égales en fonction du nombre d'incréments que nous avons définis. Lorsque nous glissons dans nos différentes sections, la sortie du curseur augmentera de l'incrément respectif.

DEMO DE TRAVAIL

RÉAGIR LE CODE

Dans l'exemple ci-dessus, nous définissons notre tableau min, max & intervals.

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

Nous devons ensuite trouver le nombre de valeurs discrètes que notre curseur doit avoir pour qu'il passe correctement de min à max en fonction de nos distributions d'intervalle définies.

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

Dans ce cas 535.

Remarque : Vos points de curseur ne doivent pas dépasser le nombre de pixels en le curseur

Enfin, nous transformons simplement notre sortie en utilisant l'algorithme décrit ci-dessus. L'exemple de code fait également un peu de travail afin que la sortie soit toujours arrondie pour l'intervalle de pas actuel.

2
NSjonas

Je cherchais curseur logarithmique pour angulaire mais je n'en trouve pas et je suis tombé sur cette réponse,

Et je l'ai créé pour Angular 2+ (La démo est en Angular 6): WORKING DEMO

Merci à @ sth , pour l'extrait:

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;
   }
};
1
Vivek Doshi