MINI Sh3ll
// Value calculation
// Determine the size of a sub-range in relation to a full range.
function subRangeRatio ( pa, pb ) {
return (100 / (pb - pa));
}
// (percentage) How many percent is this value of this range?
function fromPercentage ( range, value ) {
return (value * 100) / ( range[1] - range[0] );
}
// (percentage) Where is this value on this range?
function toPercentage ( range, value ) {
return fromPercentage( range, range[0] < 0 ?
value + Math.abs(range[0]) :
value - range[0] );
}
// (value) How much is this percentage on this range?
function isPercentage ( range, value ) {
return ((value * ( range[1] - range[0] )) / 100) + range[0];
}
// Range conversion
function getJ ( value, arr ) {
var j = 1;
while ( value >= arr[j] ){
j += 1;
}
return j;
}
// (percentage) Input a value, find where, on a scale of 0-100, it applies.
function toStepping ( xVal, xPct, value ) {
if ( value >= xVal.slice(-1)[0] ){
return 100;
}
var j = getJ( value, xVal ), va, vb, pa, pb;
va = xVal[j-1];
vb = xVal[j];
pa = xPct[j-1];
pb = xPct[j];
return pa + (toPercentage([va, vb], value) / subRangeRatio (pa, pb));
}
// (value) Input a percentage, find where it is on the specified range.
function fromStepping ( xVal, xPct, value ) {
// There is no range group that fits 100
if ( value >= 100 ){
return xVal.slice(-1)[0];
}
var j = getJ( value, xPct ), va, vb, pa, pb;
va = xVal[j-1];
vb = xVal[j];
pa = xPct[j-1];
pb = xPct[j];
return isPercentage([va, vb], (value - pa) * subRangeRatio (pa, pb));
}
// (percentage) Get the step that applies at a certain value.
function getStep ( xPct, xSteps, snap, value ) {
if ( value === 100 ) {
return value;
}
var j = getJ( value, xPct ), a, b;
// If 'snap' is set, steps are used as fixed points on the slider.
if ( snap ) {
a = xPct[j-1];
b = xPct[j];
// Find the closest position, a or b.
if ((value - a) > ((b-a)/2)){
return b;
}
return a;
}
if ( !xSteps[j-1] ){
return value;
}
return xPct[j-1] + closest(
value - xPct[j-1],
xSteps[j-1]
);
}
// Entry parsing
function handleEntryPoint ( index, value, that ) {
var percentage;
// Wrap numerical input in an array.
if ( typeof value === "number" ) {
value = [value];
}
// Reject any invalid input, by testing whether value is an array.
if ( Object.prototype.toString.call( value ) !== '[object Array]' ){
throw new Error("noUiSlider: 'range' contains invalid value.");
}
// Covert min/max syntax to 0 and 100.
if ( index === 'min' ) {
percentage = 0;
} else if ( index === 'max' ) {
percentage = 100;
} else {
percentage = parseFloat( index );
}
// Check for correct input.
if ( !isNumeric( percentage ) || !isNumeric( value[0] ) ) {
throw new Error("noUiSlider: 'range' value isn't numeric.");
}
// Store values.
that.xPct.push( percentage );
that.xVal.push( value[0] );
// NaN will evaluate to false too, but to keep
// logging clear, set step explicitly. Make sure
// not to override the 'step' setting with false.
if ( !percentage ) {
if ( !isNaN( value[1] ) ) {
that.xSteps[0] = value[1];
}
} else {
that.xSteps.push( isNaN(value[1]) ? false : value[1] );
}
}
function handleStepPoint ( i, n, that ) {
// Ignore 'false' stepping.
if ( !n ) {
return true;
}
// Factor to range ratio
that.xSteps[i] = fromPercentage([
that.xVal[i]
,that.xVal[i+1]
], n) / subRangeRatio (
that.xPct[i],
that.xPct[i+1] );
}
// Interface
// The interface to Spectrum handles all direction-based
// conversions, so the above values are unaware.
function Spectrum ( entry, snap, direction, singleStep ) {
this.xPct = [];
this.xVal = [];
this.xSteps = [ singleStep || false ];
this.xNumSteps = [ false ];
this.snap = snap;
this.direction = direction;
var index, ordered = [ /* [0, 'min'], [1, '50%'], [2, 'max'] */ ];
// Map the object keys to an array.
for ( index in entry ) {
if ( entry.hasOwnProperty(index) ) {
ordered.push([entry[index], index]);
}
}
// Sort all entries by value (numeric sort).
ordered.sort(function(a, b) { return a[0] - b[0]; });
// Convert all entries to subranges.
for ( index = 0; index < ordered.length; index++ ) {
handleEntryPoint(ordered[index][1], ordered[index][0], this);
}
// Store the actual step values.
// xSteps is sorted in the same order as xPct and xVal.
this.xNumSteps = this.xSteps.slice(0);
// Convert all numeric steps to the percentage of the subrange they represent.
for ( index = 0; index < this.xNumSteps.length; index++ ) {
handleStepPoint(index, this.xNumSteps[index], this);
}
}
Spectrum.prototype.getMargin = function ( value ) {
return this.xPct.length === 2 ? fromPercentage(this.xVal, value) : false;
};
Spectrum.prototype.toStepping = function ( value ) {
value = toStepping( this.xVal, this.xPct, value );
// Invert the value if this is a right-to-left slider.
if ( this.direction ) {
value = 100 - value;
}
return value;
};
Spectrum.prototype.fromStepping = function ( value ) {
// Invert the value if this is a right-to-left slider.
if ( this.direction ) {
value = 100 - value;
}
return accurateNumber(fromStepping( this.xVal, this.xPct, value ));
};
Spectrum.prototype.getStep = function ( value ) {
// Find the proper step for rtl sliders by search in inverse direction.
// Fixes issue #262.
if ( this.direction ) {
value = 100 - value;
}
value = getStep(this.xPct, this.xSteps, this.snap, value );
if ( this.direction ) {
value = 100 - value;
}
return value;
};
Spectrum.prototype.getApplicableStep = function ( value ) {
// If the value is 100%, return the negative step twice.
var j = getJ(value, this.xPct), offset = value === 100 ? 2 : 1;
return [this.xNumSteps[j-2], this.xVal[j-offset], this.xNumSteps[j-offset]];
};
// Outside testing
Spectrum.prototype.convert = function ( value ) {
return this.getStep(this.toStepping(value));
};
OHA YOOOO