/* WARNING: This is not (yet) a complete implementation, the following * features are missing: * - Binding on events does not work as expected. * - These events are not implemented at all: create, start, change and stop. * - The value and values method do not yet return the calculated values. * All other features should work as expected: * - All options the jQuery slider accepts with the exception of step. * - The additional non-linear specific options: mid, curve and granularity. * - The slide event when given as an option. * - All methods the jQuery slider has with the exception of value and values. * - Theming works the same as with the standard slider. */ /* Containing the scope is good practice in jQuery code, * this has the added bennefit of being able to use $ even when the user of * the plugin has disabled this. */ (function($, undefined) { /* jQuery-ui has this nice function for defining widget plugins */ $.widget( "ui.nlslider", $.ui.slider, { /* We largely inherit the ui.slider functionality, but the extra options * and default values are here: */ options: { /* If defined, the value of the mid option will be at the center of the * slider. A nice value would be the median of your dataset, that way the * slider slides about linear with the percentiles (for most datasets) */ mid: null, /* The raw value from the slider is used to find a value between min and * max, by taking the position to the n-th power, n is calculated using * the mid option. If the mid option is not given, the the curve option * is used to get a specific value for n directly. */ curve: Math.E, /* The granularity specifies the number of raw positions the jQuery * slider returns, the desired value depends mostly on the size of the * widget */ granularity: 100, }, /* The _create function is the entry point of the widget creation, we use * it to mangle the normal jQuery-ui slider, so this is rather long */ _create: function() { /* First place some variables in the scope */ var self = this, o = this.options, out_min = o.min, range = o.max - o.min, slide_callback = o.slide; /* Calculate to curve value if the mid option is used, or fall back to * the curve option */ var curve = (o.mid != null && (o.mid >= o.min || o.mid <= o.max)) ? (Math.log((o.mid - o.min) / range) / Math.log(0.5)) : o.curve; /* The calculations from/to the value/position */ var calculate_value = function( position ) { return out_min + Math.pow(position / o.granularity, curve) * range; }; var calculate_position = function( value ) { return Math.pow((value - out_min) / range, 1 / curve) * o.granularity; }; /* Update the options */ var newOptions = { /* the step option does not make sense with this slider, the min and * max values are used for the granularity, and the other options are * left as-is */ step: undefined, min: 0, max: o.granularity, /* The new callback, here we calculate the new values, and call the * original callback */ slide: function(event, ui) { var newVal = calculate_value(ui.value); var newUi = {handle: ui.handle, value: newVal}; /* ui.values is available if we are a range slider */ if (ui.values) { newUi.values = [calculate_value(ui.values[0]), calculate_value(ui.values[1])]; }; /* We are done calcutating the new values, the user might still want * to cancel the slide, so we pass their return value along to the * slider code */ if (slide_callback) return slide_callback.call(this, event, newUi); } }; /* Calculate the original positions */ if(o.value) newOptions.value = calculate_position(o.value); if(o.values) newOptions.values = [calculate_position(o.values[0]), calculate_position(o.values[1])]; $.extend(this.options, newOptions); /* We have updated the options, so we can go ahead and instantiate the * slider using the jQuery UI implementation */ return $.ui.slider.prototype._create.call(self); } }); })(jQuery);