foundation.slider.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725
  1. 'use strict';
  2. import $ from 'jquery';
  3. import { Keyboard } from './foundation.util.keyboard';
  4. import { Move } from './foundation.util.motion';
  5. import { GetYoDigits, rtl as Rtl } from './foundation.core.utils';
  6. import { Plugin } from './foundation.core.plugin';
  7. import { Touch } from './foundation.util.touch';
  8. import { Triggers } from './foundation.util.triggers';
  9. /**
  10. * Slider module.
  11. * @module foundation.slider
  12. * @requires foundation.util.motion
  13. * @requires foundation.util.triggers
  14. * @requires foundation.util.keyboard
  15. * @requires foundation.util.touch
  16. */
  17. class Slider extends Plugin {
  18. /**
  19. * Creates a new instance of a slider control.
  20. * @class
  21. * @name Slider
  22. * @param {jQuery} element - jQuery object to make into a slider control.
  23. * @param {Object} options - Overrides to the default plugin settings.
  24. */
  25. _setup(element, options) {
  26. this.$element = element;
  27. this.options = $.extend({}, Slider.defaults, this.$element.data(), options);
  28. this.className = 'Slider'; // ie9 back compat
  29. // Touch and Triggers inits are idempotent, we just need to make sure it's initialied.
  30. Touch.init($);
  31. Triggers.init($);
  32. this._init();
  33. Keyboard.register('Slider', {
  34. 'ltr': {
  35. 'ARROW_RIGHT': 'increase',
  36. 'ARROW_UP': 'increase',
  37. 'ARROW_DOWN': 'decrease',
  38. 'ARROW_LEFT': 'decrease',
  39. 'SHIFT_ARROW_RIGHT': 'increase_fast',
  40. 'SHIFT_ARROW_UP': 'increase_fast',
  41. 'SHIFT_ARROW_DOWN': 'decrease_fast',
  42. 'SHIFT_ARROW_LEFT': 'decrease_fast',
  43. 'HOME': 'min',
  44. 'END': 'max'
  45. },
  46. 'rtl': {
  47. 'ARROW_LEFT': 'increase',
  48. 'ARROW_RIGHT': 'decrease',
  49. 'SHIFT_ARROW_LEFT': 'increase_fast',
  50. 'SHIFT_ARROW_RIGHT': 'decrease_fast'
  51. }
  52. });
  53. }
  54. /**
  55. * Initilizes the plugin by reading/setting attributes, creating collections and setting the initial position of the handle(s).
  56. * @function
  57. * @private
  58. */
  59. _init() {
  60. this.inputs = this.$element.find('input');
  61. this.handles = this.$element.find('[data-slider-handle]');
  62. this.$handle = this.handles.eq(0);
  63. this.$input = this.inputs.length ? this.inputs.eq(0) : $(`#${this.$handle.attr('aria-controls')}`);
  64. this.$fill = this.$element.find('[data-slider-fill]').css(this.options.vertical ? 'height' : 'width', 0);
  65. var isDbl = false,
  66. _this = this;
  67. if (this.options.disabled || this.$element.hasClass(this.options.disabledClass)) {
  68. this.options.disabled = true;
  69. this.$element.addClass(this.options.disabledClass);
  70. }
  71. if (!this.inputs.length) {
  72. this.inputs = $().add(this.$input);
  73. this.options.binding = true;
  74. }
  75. this._setInitAttr(0);
  76. if (this.handles[1]) {
  77. this.options.doubleSided = true;
  78. this.$handle2 = this.handles.eq(1);
  79. this.$input2 = this.inputs.length > 1 ? this.inputs.eq(1) : $(`#${this.$handle2.attr('aria-controls')}`);
  80. if (!this.inputs[1]) {
  81. this.inputs = this.inputs.add(this.$input2);
  82. }
  83. isDbl = true;
  84. // this.$handle.triggerHandler('click.zf.slider');
  85. this._setInitAttr(1);
  86. }
  87. // Set handle positions
  88. this.setHandles();
  89. this._events();
  90. }
  91. setHandles() {
  92. if(this.handles[1]) {
  93. this._setHandlePos(this.$handle, this.inputs.eq(0).val(), true, () => {
  94. this._setHandlePos(this.$handle2, this.inputs.eq(1).val(), true);
  95. });
  96. } else {
  97. this._setHandlePos(this.$handle, this.inputs.eq(0).val(), true);
  98. }
  99. }
  100. _reflow() {
  101. this.setHandles();
  102. }
  103. /**
  104. * @function
  105. * @private
  106. * @param {Number} value - floating point (the value) to be transformed using to a relative position on the slider (the inverse of _value)
  107. */
  108. _pctOfBar(value) {
  109. var pctOfBar = percent(value - this.options.start, this.options.end - this.options.start)
  110. switch(this.options.positionValueFunction) {
  111. case "pow":
  112. pctOfBar = this._logTransform(pctOfBar);
  113. break;
  114. case "log":
  115. pctOfBar = this._powTransform(pctOfBar);
  116. break;
  117. }
  118. return pctOfBar.toFixed(2)
  119. }
  120. /**
  121. * @function
  122. * @private
  123. * @param {Number} pctOfBar - floating point, the relative position of the slider (typically between 0-1) to be transformed to a value
  124. */
  125. _value(pctOfBar) {
  126. switch(this.options.positionValueFunction) {
  127. case "pow":
  128. pctOfBar = this._powTransform(pctOfBar);
  129. break;
  130. case "log":
  131. pctOfBar = this._logTransform(pctOfBar);
  132. break;
  133. }
  134. var value = (this.options.end - this.options.start) * pctOfBar + parseFloat(this.options.start);
  135. return value
  136. }
  137. /**
  138. * @function
  139. * @private
  140. * @param {Number} value - floating point (typically between 0-1) to be transformed using the log function
  141. */
  142. _logTransform(value) {
  143. return baseLog(this.options.nonLinearBase, ((value*(this.options.nonLinearBase-1))+1))
  144. }
  145. /**
  146. * @function
  147. * @private
  148. * @param {Number} value - floating point (typically between 0-1) to be transformed using the power function
  149. */
  150. _powTransform(value) {
  151. return (Math.pow(this.options.nonLinearBase, value) - 1) / (this.options.nonLinearBase - 1)
  152. }
  153. /**
  154. * Sets the position of the selected handle and fill bar.
  155. * @function
  156. * @private
  157. * @param {jQuery} $hndl - the selected handle to move.
  158. * @param {Number} location - floating point between the start and end values of the slider bar.
  159. * @param {Function} cb - callback function to fire on completion.
  160. * @fires Slider#moved
  161. * @fires Slider#changed
  162. */
  163. _setHandlePos($hndl, location, noInvert, cb) {
  164. // don't move if the slider has been disabled since its initialization
  165. if (this.$element.hasClass(this.options.disabledClass)) {
  166. return;
  167. }
  168. //might need to alter that slightly for bars that will have odd number selections.
  169. location = parseFloat(location);//on input change events, convert string to number...grumble.
  170. // prevent slider from running out of bounds, if value exceeds the limits set through options, override the value to min/max
  171. if (location < this.options.start) { location = this.options.start; }
  172. else if (location > this.options.end) { location = this.options.end; }
  173. var isDbl = this.options.doubleSided;
  174. //this is for single-handled vertical sliders, it adjusts the value to account for the slider being "upside-down"
  175. //for click and drag events, it's weird due to the scale(-1, 1) css property
  176. if (this.options.vertical && !noInvert) {
  177. location = this.options.end - location;
  178. }
  179. if (isDbl) { //this block is to prevent 2 handles from crossing eachother. Could/should be improved.
  180. if (this.handles.index($hndl) === 0) {
  181. var h2Val = parseFloat(this.$handle2.attr('aria-valuenow'));
  182. location = location >= h2Val ? h2Val - this.options.step : location;
  183. } else {
  184. var h1Val = parseFloat(this.$handle.attr('aria-valuenow'));
  185. location = location <= h1Val ? h1Val + this.options.step : location;
  186. }
  187. }
  188. var _this = this,
  189. vert = this.options.vertical,
  190. hOrW = vert ? 'height' : 'width',
  191. lOrT = vert ? 'top' : 'left',
  192. handleDim = $hndl[0].getBoundingClientRect()[hOrW],
  193. elemDim = this.$element[0].getBoundingClientRect()[hOrW],
  194. //percentage of bar min/max value based on click or drag point
  195. pctOfBar = this._pctOfBar(location),
  196. //number of actual pixels to shift the handle, based on the percentage obtained above
  197. pxToMove = (elemDim - handleDim) * pctOfBar,
  198. //percentage of bar to shift the handle
  199. movement = (percent(pxToMove, elemDim) * 100).toFixed(this.options.decimal);
  200. //fixing the decimal value for the location number, is passed to other methods as a fixed floating-point value
  201. location = parseFloat(location.toFixed(this.options.decimal));
  202. // declare empty object for css adjustments, only used with 2 handled-sliders
  203. var css = {};
  204. this._setValues($hndl, location);
  205. // TODO update to calculate based on values set to respective inputs??
  206. if (isDbl) {
  207. var isLeftHndl = this.handles.index($hndl) === 0,
  208. //empty variable, will be used for min-height/width for fill bar
  209. dim,
  210. //percentage w/h of the handle compared to the slider bar
  211. handlePct = ~~(percent(handleDim, elemDim) * 100);
  212. //if left handle, the math is slightly different than if it's the right handle, and the left/top property needs to be changed for the fill bar
  213. if (isLeftHndl) {
  214. //left or top percentage value to apply to the fill bar.
  215. css[lOrT] = `${movement}%`;
  216. //calculate the new min-height/width for the fill bar.
  217. dim = parseFloat(this.$handle2[0].style[lOrT]) - movement + handlePct;
  218. //this callback is necessary to prevent errors and allow the proper placement and initialization of a 2-handled slider
  219. //plus, it means we don't care if 'dim' isNaN on init, it won't be in the future.
  220. if (cb && typeof cb === 'function') { cb(); }//this is only needed for the initialization of 2 handled sliders
  221. } else {
  222. //just caching the value of the left/bottom handle's left/top property
  223. var handlePos = parseFloat(this.$handle[0].style[lOrT]);
  224. //calculate the new min-height/width for the fill bar. Use isNaN to prevent false positives for numbers <= 0
  225. //based on the percentage of movement of the handle being manipulated, less the opposing handle's left/top position, plus the percentage w/h of the handle itself
  226. dim = movement - (isNaN(handlePos) ? (this.options.initialStart - this.options.start)/((this.options.end-this.options.start)/100) : handlePos) + handlePct;
  227. }
  228. // assign the min-height/width to our css object
  229. css[`min-${hOrW}`] = `${dim}%`;
  230. }
  231. this.$element.one('finished.zf.animate', function() {
  232. /**
  233. * Fires when the handle is done moving.
  234. * @event Slider#moved
  235. */
  236. _this.$element.trigger('moved.zf.slider', [$hndl]);
  237. });
  238. //because we don't know exactly how the handle will be moved, check the amount of time it should take to move.
  239. var moveTime = this.$element.data('dragging') ? 1000/60 : this.options.moveTime;
  240. Move(moveTime, $hndl, function() {
  241. // adjusting the left/top property of the handle, based on the percentage calculated above
  242. // if movement isNaN, that is because the slider is hidden and we cannot determine handle width,
  243. // fall back to next best guess.
  244. if (isNaN(movement)) {
  245. $hndl.css(lOrT, `${pctOfBar * 100}%`);
  246. }
  247. else {
  248. $hndl.css(lOrT, `${movement}%`);
  249. }
  250. if (!_this.options.doubleSided) {
  251. //if single-handled, a simple method to expand the fill bar
  252. _this.$fill.css(hOrW, `${pctOfBar * 100}%`);
  253. } else {
  254. //otherwise, use the css object we created above
  255. _this.$fill.css(css);
  256. }
  257. });
  258. /**
  259. * Fires when the value has not been change for a given time.
  260. * @event Slider#changed
  261. */
  262. clearTimeout(_this.timeout);
  263. _this.timeout = setTimeout(function(){
  264. _this.$element.trigger('changed.zf.slider', [$hndl]);
  265. }, _this.options.changedDelay);
  266. }
  267. /**
  268. * Sets the initial attribute for the slider element.
  269. * @function
  270. * @private
  271. * @param {Number} idx - index of the current handle/input to use.
  272. */
  273. _setInitAttr(idx) {
  274. var initVal = (idx === 0 ? this.options.initialStart : this.options.initialEnd)
  275. var id = this.inputs.eq(idx).attr('id') || GetYoDigits(6, 'slider');
  276. this.inputs.eq(idx).attr({
  277. 'id': id,
  278. 'max': this.options.end,
  279. 'min': this.options.start,
  280. 'step': this.options.step
  281. });
  282. this.inputs.eq(idx).val(initVal);
  283. this.handles.eq(idx).attr({
  284. 'role': 'slider',
  285. 'aria-controls': id,
  286. 'aria-valuemax': this.options.end,
  287. 'aria-valuemin': this.options.start,
  288. 'aria-valuenow': initVal,
  289. 'aria-orientation': this.options.vertical ? 'vertical' : 'horizontal',
  290. 'tabindex': 0
  291. });
  292. }
  293. /**
  294. * Sets the input and `aria-valuenow` values for the slider element.
  295. * @function
  296. * @private
  297. * @param {jQuery} $handle - the currently selected handle.
  298. * @param {Number} val - floating point of the new value.
  299. */
  300. _setValues($handle, val) {
  301. var idx = this.options.doubleSided ? this.handles.index($handle) : 0;
  302. this.inputs.eq(idx).val(val);
  303. $handle.attr('aria-valuenow', val);
  304. }
  305. /**
  306. * Handles events on the slider element.
  307. * Calculates the new location of the current handle.
  308. * If there are two handles and the bar was clicked, it determines which handle to move.
  309. * @function
  310. * @private
  311. * @param {Object} e - the `event` object passed from the listener.
  312. * @param {jQuery} $handle - the current handle to calculate for, if selected.
  313. * @param {Number} val - floating point number for the new value of the slider.
  314. * TODO clean this up, there's a lot of repeated code between this and the _setHandlePos fn.
  315. */
  316. _handleEvent(e, $handle, val) {
  317. var value, hasVal;
  318. if (!val) {//click or drag events
  319. e.preventDefault();
  320. var _this = this,
  321. vertical = this.options.vertical,
  322. param = vertical ? 'height' : 'width',
  323. direction = vertical ? 'top' : 'left',
  324. eventOffset = vertical ? e.pageY : e.pageX,
  325. halfOfHandle = this.$handle[0].getBoundingClientRect()[param] / 2,
  326. barDim = this.$element[0].getBoundingClientRect()[param],
  327. windowScroll = vertical ? $(window).scrollTop() : $(window).scrollLeft();
  328. var elemOffset = this.$element.offset()[direction];
  329. // touch events emulated by the touch util give position relative to screen, add window.scroll to event coordinates...
  330. // best way to guess this is simulated is if clientY == pageY
  331. if (e.clientY === e.pageY) { eventOffset = eventOffset + windowScroll; }
  332. var eventFromBar = eventOffset - elemOffset;
  333. var barXY;
  334. if (eventFromBar < 0) {
  335. barXY = 0;
  336. } else if (eventFromBar > barDim) {
  337. barXY = barDim;
  338. } else {
  339. barXY = eventFromBar;
  340. }
  341. var offsetPct = percent(barXY, barDim);
  342. value = this._value(offsetPct);
  343. // turn everything around for RTL, yay math!
  344. if (Rtl() && !this.options.vertical) {value = this.options.end - value;}
  345. value = _this._adjustValue(null, value);
  346. //boolean flag for the setHandlePos fn, specifically for vertical sliders
  347. hasVal = false;
  348. if (!$handle) {//figure out which handle it is, pass it to the next function.
  349. var firstHndlPos = absPosition(this.$handle, direction, barXY, param),
  350. secndHndlPos = absPosition(this.$handle2, direction, barXY, param);
  351. $handle = firstHndlPos <= secndHndlPos ? this.$handle : this.$handle2;
  352. }
  353. } else {//change event on input
  354. value = this._adjustValue(null, val);
  355. hasVal = true;
  356. }
  357. this._setHandlePos($handle, value, hasVal);
  358. }
  359. /**
  360. * Adjustes value for handle in regard to step value. returns adjusted value
  361. * @function
  362. * @private
  363. * @param {jQuery} $handle - the selected handle.
  364. * @param {Number} value - value to adjust. used if $handle is falsy
  365. */
  366. _adjustValue($handle, value) {
  367. var val,
  368. step = this.options.step,
  369. div = parseFloat(step/2),
  370. left, prev_val, next_val;
  371. if (!!$handle) {
  372. val = parseFloat($handle.attr('aria-valuenow'));
  373. }
  374. else {
  375. val = value;
  376. }
  377. if (val >= 0) {
  378. left = val % step;
  379. } else {
  380. left = step + (val % step);
  381. }
  382. prev_val = val - left;
  383. next_val = prev_val + step;
  384. if (left === 0) {
  385. return val;
  386. }
  387. val = val >= prev_val + div ? next_val : prev_val;
  388. return val;
  389. }
  390. /**
  391. * Adds event listeners to the slider elements.
  392. * @function
  393. * @private
  394. */
  395. _events() {
  396. this._eventsForHandle(this.$handle);
  397. if(this.handles[1]) {
  398. this._eventsForHandle(this.$handle2);
  399. }
  400. }
  401. /**
  402. * Adds event listeners a particular handle
  403. * @function
  404. * @private
  405. * @param {jQuery} $handle - the current handle to apply listeners to.
  406. */
  407. _eventsForHandle($handle) {
  408. var _this = this,
  409. curHandle,
  410. timer;
  411. const handleChangeEvent = function(e) {
  412. const idx = _this.inputs.index($(this));
  413. _this._handleEvent(e, _this.handles.eq(idx), $(this).val());
  414. };
  415. // IE only triggers the change event when the input loses focus which strictly follows the HTML specification
  416. // listen for the enter key and trigger a change
  417. // @see https://html.spec.whatwg.org/multipage/input.html#common-input-element-events
  418. this.inputs.off('keyup.zf.slider').on('keyup.zf.slider', function (e) {
  419. if(e.keyCode == 13) handleChangeEvent.call(this, e);
  420. });
  421. this.inputs.off('change.zf.slider').on('change.zf.slider', handleChangeEvent);
  422. if (this.options.clickSelect) {
  423. this.$element.off('click.zf.slider').on('click.zf.slider', function(e) {
  424. if (_this.$element.data('dragging')) { return false; }
  425. if (!$(e.target).is('[data-slider-handle]')) {
  426. if (_this.options.doubleSided) {
  427. _this._handleEvent(e);
  428. } else {
  429. _this._handleEvent(e, _this.$handle);
  430. }
  431. }
  432. });
  433. }
  434. if (this.options.draggable) {
  435. this.handles.addTouch();
  436. var $body = $('body');
  437. $handle
  438. .off('mousedown.zf.slider')
  439. .on('mousedown.zf.slider', function(e) {
  440. $handle.addClass('is-dragging');
  441. _this.$fill.addClass('is-dragging');//
  442. _this.$element.data('dragging', true);
  443. curHandle = $(e.currentTarget);
  444. $body.on('mousemove.zf.slider', function(e) {
  445. e.preventDefault();
  446. _this._handleEvent(e, curHandle);
  447. }).on('mouseup.zf.slider', function(e) {
  448. _this._handleEvent(e, curHandle);
  449. $handle.removeClass('is-dragging');
  450. _this.$fill.removeClass('is-dragging');
  451. _this.$element.data('dragging', false);
  452. $body.off('mousemove.zf.slider mouseup.zf.slider');
  453. });
  454. })
  455. // prevent events triggered by touch
  456. .on('selectstart.zf.slider touchmove.zf.slider', function(e) {
  457. e.preventDefault();
  458. });
  459. }
  460. $handle.off('keydown.zf.slider').on('keydown.zf.slider', function(e) {
  461. var _$handle = $(this),
  462. idx = _this.options.doubleSided ? _this.handles.index(_$handle) : 0,
  463. oldValue = parseFloat(_this.inputs.eq(idx).val()),
  464. newValue;
  465. // handle keyboard event with keyboard util
  466. Keyboard.handleKey(e, 'Slider', {
  467. decrease: function() {
  468. newValue = oldValue - _this.options.step;
  469. },
  470. increase: function() {
  471. newValue = oldValue + _this.options.step;
  472. },
  473. decrease_fast: function() {
  474. newValue = oldValue - _this.options.step * 10;
  475. },
  476. increase_fast: function() {
  477. newValue = oldValue + _this.options.step * 10;
  478. },
  479. min: function() {
  480. newValue = _this.options.start;
  481. },
  482. max: function() {
  483. newValue = _this.options.end;
  484. },
  485. handled: function() { // only set handle pos when event was handled specially
  486. e.preventDefault();
  487. _this._setHandlePos(_$handle, newValue, true);
  488. }
  489. });
  490. /*if (newValue) { // if pressed key has special function, update value
  491. e.preventDefault();
  492. _this._setHandlePos(_$handle, newValue);
  493. }*/
  494. });
  495. }
  496. /**
  497. * Destroys the slider plugin.
  498. */
  499. _destroy() {
  500. this.handles.off('.zf.slider');
  501. this.inputs.off('.zf.slider');
  502. this.$element.off('.zf.slider');
  503. clearTimeout(this.timeout);
  504. }
  505. }
  506. Slider.defaults = {
  507. /**
  508. * Minimum value for the slider scale.
  509. * @option
  510. * @type {number}
  511. * @default 0
  512. */
  513. start: 0,
  514. /**
  515. * Maximum value for the slider scale.
  516. * @option
  517. * @type {number}
  518. * @default 100
  519. */
  520. end: 100,
  521. /**
  522. * Minimum value change per change event.
  523. * @option
  524. * @type {number}
  525. * @default 1
  526. */
  527. step: 1,
  528. /**
  529. * Value at which the handle/input *(left handle/first input)* should be set to on initialization.
  530. * @option
  531. * @type {number}
  532. * @default 0
  533. */
  534. initialStart: 0,
  535. /**
  536. * Value at which the right handle/second input should be set to on initialization.
  537. * @option
  538. * @type {number}
  539. * @default 100
  540. */
  541. initialEnd: 100,
  542. /**
  543. * Allows the input to be located outside the container and visible. Set to by the JS
  544. * @option
  545. * @type {boolean}
  546. * @default false
  547. */
  548. binding: false,
  549. /**
  550. * Allows the user to click/tap on the slider bar to select a value.
  551. * @option
  552. * @type {boolean}
  553. * @default true
  554. */
  555. clickSelect: true,
  556. /**
  557. * Set to true and use the `vertical` class to change alignment to vertical.
  558. * @option
  559. * @type {boolean}
  560. * @default false
  561. */
  562. vertical: false,
  563. /**
  564. * Allows the user to drag the slider handle(s) to select a value.
  565. * @option
  566. * @type {boolean}
  567. * @default true
  568. */
  569. draggable: true,
  570. /**
  571. * Disables the slider and prevents event listeners from being applied. Double checked by JS with `disabledClass`.
  572. * @option
  573. * @type {boolean}
  574. * @default false
  575. */
  576. disabled: false,
  577. /**
  578. * Allows the use of two handles. Double checked by the JS. Changes some logic handling.
  579. * @option
  580. * @type {boolean}
  581. * @default false
  582. */
  583. doubleSided: false,
  584. /**
  585. * Potential future feature.
  586. */
  587. // steps: 100,
  588. /**
  589. * Number of decimal places the plugin should go to for floating point precision.
  590. * @option
  591. * @type {number}
  592. * @default 2
  593. */
  594. decimal: 2,
  595. /**
  596. * Time delay for dragged elements.
  597. */
  598. // dragDelay: 0,
  599. /**
  600. * Time, in ms, to animate the movement of a slider handle if user clicks/taps on the bar. Needs to be manually set if updating the transition time in the Sass settings.
  601. * @option
  602. * @type {number}
  603. * @default 200
  604. */
  605. moveTime: 200,//update this if changing the transition time in the sass
  606. /**
  607. * Class applied to disabled sliders.
  608. * @option
  609. * @type {string}
  610. * @default 'disabled'
  611. */
  612. disabledClass: 'disabled',
  613. /**
  614. * Will invert the default layout for a vertical<span data-tooltip title="who would do this???"> </span>slider.
  615. * @option
  616. * @type {boolean}
  617. * @default false
  618. */
  619. invertVertical: false,
  620. /**
  621. * Milliseconds before the `changed.zf-slider` event is triggered after value change.
  622. * @option
  623. * @type {number}
  624. * @default 500
  625. */
  626. changedDelay: 500,
  627. /**
  628. * Basevalue for non-linear sliders
  629. * @option
  630. * @type {number}
  631. * @default 5
  632. */
  633. nonLinearBase: 5,
  634. /**
  635. * Basevalue for non-linear sliders, possible values are: `'linear'`, `'pow'` & `'log'`. Pow and Log use the nonLinearBase setting.
  636. * @option
  637. * @type {string}
  638. * @default 'linear'
  639. */
  640. positionValueFunction: 'linear',
  641. };
  642. function percent(frac, num) {
  643. return (frac / num);
  644. }
  645. function absPosition($handle, dir, clickPos, param) {
  646. return Math.abs(($handle.position()[dir] + ($handle[param]() / 2)) - clickPos);
  647. }
  648. function baseLog(base, value) {
  649. return Math.log(value)/Math.log(base)
  650. }
  651. export {Slider};