You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2009 line
70 KiB

  1. // Ion.RangeSlider
  2. // version 2.0.13 Build: 335
  3. // © Denis Ineshin, 2015
  4. // https://github.com/IonDen
  5. //
  6. // Project page: http://ionden.com/a/plugins/ion.rangeSlider/en.html
  7. // GitHub page: https://github.com/IonDen/ion.rangeSlider
  8. //
  9. // Released under MIT licence:
  10. // http://ionden.com/a/plugins/licence-en.html
  11. // =====================================================================================================================
  12. ;(function ($, document, window, navigator, undefined) {
  13. "use strict";
  14. // =================================================================================================================
  15. // Service
  16. var plugin_count = 0;
  17. // IE8 fix
  18. var is_old_ie = (function () {
  19. var n = navigator.userAgent,
  20. r = /msie\s\d+/i,
  21. v;
  22. if (n.search(r) > 0) {
  23. v = r.exec(n).toString();
  24. v = v.split(" ")[1];
  25. if (v < 9) {
  26. $("html").addClass("lt-ie9");
  27. return true;
  28. }
  29. }
  30. return false;
  31. } ());
  32. if (!Function.prototype.bind) {
  33. Function.prototype.bind = function bind(that) {
  34. var target = this;
  35. var slice = [].slice;
  36. if (typeof target != "function") {
  37. throw new TypeError();
  38. }
  39. var args = slice.call(arguments, 1),
  40. bound = function () {
  41. if (this instanceof bound) {
  42. var F = function(){};
  43. F.prototype = target.prototype;
  44. var self = new F();
  45. var result = target.apply(
  46. self,
  47. args.concat(slice.call(arguments))
  48. );
  49. if (Object(result) === result) {
  50. return result;
  51. }
  52. return self;
  53. } else {
  54. return target.apply(
  55. that,
  56. args.concat(slice.call(arguments))
  57. );
  58. }
  59. };
  60. return bound;
  61. };
  62. }
  63. if (!Array.prototype.indexOf) {
  64. Array.prototype.indexOf = function(searchElement, fromIndex) {
  65. var k;
  66. if (this == null) {
  67. throw new TypeError('"this" is null or not defined');
  68. }
  69. var O = Object(this);
  70. var len = O.length >>> 0;
  71. if (len === 0) {
  72. return -1;
  73. }
  74. var n = +fromIndex || 0;
  75. if (Math.abs(n) === Infinity) {
  76. n = 0;
  77. }
  78. if (n >= len) {
  79. return -1;
  80. }
  81. k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);
  82. while (k < len) {
  83. if (k in O && O[k] === searchElement) {
  84. return k;
  85. }
  86. k++;
  87. }
  88. return -1;
  89. };
  90. }
  91. // =================================================================================================================
  92. // Template
  93. var base_html =
  94. '<span class="irs">' +
  95. '<span class="irs-line" tabindex="-1"><span class="irs-line-left"></span><span class="irs-line-mid"></span><span class="irs-line-right"></span></span>' +
  96. '<span class="irs-min">0</span><span class="irs-max">1</span>' +
  97. '<span class="irs-from">0</span><span class="irs-to">0</span><span class="irs-single">0</span>' +
  98. '</span>' +
  99. '<span class="irs-grid"></span>' +
  100. '<span class="irs-bar"></span>';
  101. var single_html =
  102. '<span class="irs-bar-edge"></span>' +
  103. '<span class="irs-shadow shadow-single"></span>' +
  104. '<span class="irs-slider single"></span>';
  105. var double_html =
  106. '<span class="irs-shadow shadow-from"></span>' +
  107. '<span class="irs-shadow shadow-to"></span>' +
  108. '<span class="irs-slider from"></span>' +
  109. '<span class="irs-slider to"></span>';
  110. var disable_html =
  111. '<span class="irs-disable-mask"></span>';
  112. // =================================================================================================================
  113. // Core
  114. /**
  115. * Main plugin constructor
  116. *
  117. * @param input {object}
  118. * @param options {object}
  119. * @param plugin_count {number}
  120. * @constructor
  121. */
  122. var IonRangeSlider = function (input, options, plugin_count) {
  123. this.VERSION = "2.0.13";
  124. this.input = input;
  125. this.plugin_count = plugin_count;
  126. this.current_plugin = 0;
  127. this.calc_count = 0;
  128. this.update_tm = 0;
  129. this.old_from = 0;
  130. this.old_to = 0;
  131. this.raf_id = null;
  132. this.dragging = false;
  133. this.force_redraw = false;
  134. this.is_key = false;
  135. this.is_update = false;
  136. this.is_start = true;
  137. this.is_finish = false;
  138. this.is_active = false;
  139. this.is_resize = false;
  140. this.is_click = false;
  141. this.$cache = {
  142. win: $(window),
  143. body: $(document.body),
  144. input: $(input),
  145. cont: null,
  146. rs: null,
  147. min: null,
  148. max: null,
  149. from: null,
  150. to: null,
  151. single: null,
  152. bar: null,
  153. line: null,
  154. s_single: null,
  155. s_from: null,
  156. s_to: null,
  157. shad_single: null,
  158. shad_from: null,
  159. shad_to: null,
  160. edge: null,
  161. grid: null,
  162. grid_labels: []
  163. };
  164. // get config data attributes
  165. var $inp = this.$cache.input;
  166. var data = {
  167. type: $inp.data("type"),
  168. min: $inp.data("min"),
  169. max: $inp.data("max"),
  170. from: $inp.data("from"),
  171. to: $inp.data("to"),
  172. step: $inp.data("step"),
  173. min_interval: $inp.data("minInterval"),
  174. max_interval: $inp.data("maxInterval"),
  175. drag_interval: $inp.data("dragInterval"),
  176. values: $inp.data("values"),
  177. from_fixed: $inp.data("fromFixed"),
  178. from_min: $inp.data("fromMin"),
  179. from_max: $inp.data("fromMax"),
  180. from_shadow: $inp.data("fromShadow"),
  181. to_fixed: $inp.data("toFixed"),
  182. to_min: $inp.data("toMin"),
  183. to_max: $inp.data("toMax"),
  184. to_shadow: $inp.data("toShadow"),
  185. prettify_enabled: $inp.data("prettifyEnabled"),
  186. prettify_separator: $inp.data("prettifySeparator"),
  187. force_edges: $inp.data("forceEdges"),
  188. keyboard: $inp.data("keyboard"),
  189. keyboard_step: $inp.data("keyboardStep"),
  190. grid: $inp.data("grid"),
  191. grid_margin: $inp.data("gridMargin"),
  192. grid_num: $inp.data("gridNum"),
  193. grid_snap: $inp.data("gridSnap"),
  194. hide_min_max: $inp.data("hideMinMax"),
  195. hide_from_to: $inp.data("hideFromTo"),
  196. prefix: $inp.data("prefix"),
  197. postfix: $inp.data("postfix"),
  198. max_postfix: $inp.data("maxPostfix"),
  199. decorate_both: $inp.data("decorateBoth"),
  200. values_separator: $inp.data("valuesSeparator"),
  201. disable: $inp.data("disable")
  202. };
  203. data.values = data.values && data.values.split(",");
  204. // get from and to out of input
  205. var val = $inp.prop("value");
  206. if (val) {
  207. val = val.split(";");
  208. if (val[0] && val[0] == +val[0]) {
  209. val[0] = +val[0];
  210. }
  211. if (val[1] && val[1] == +val[1]) {
  212. val[1] = +val[1];
  213. }
  214. if (options && options.values && options.values.length) {
  215. data.from = val[0] && options.values.indexOf(val[0]);
  216. data.to = val[1] && options.values.indexOf(val[1]);
  217. } else {
  218. data.from = val[0] && +val[0];
  219. data.to = val[1] && +val[1];
  220. }
  221. }
  222. // JS config has a priority
  223. options = $.extend(data, options);
  224. // get config from options
  225. this.options = $.extend({
  226. type: "single",
  227. min: 10,
  228. max: 100,
  229. from: null,
  230. to: null,
  231. step: 1,
  232. min_interval: 0,
  233. max_interval: 0,
  234. drag_interval: false,
  235. values: [],
  236. p_values: [],
  237. from_fixed: false,
  238. from_min: null,
  239. from_max: null,
  240. from_shadow: false,
  241. to_fixed: false,
  242. to_min: null,
  243. to_max: null,
  244. to_shadow: false,
  245. prettify_enabled: true,
  246. prettify_separator: " ",
  247. prettify: null,
  248. force_edges: false,
  249. keyboard: false,
  250. keyboard_step: 5,
  251. grid: false,
  252. grid_margin: true,
  253. grid_num: 4,
  254. grid_snap: false,
  255. hide_min_max: false,
  256. hide_from_to: false,
  257. prefix: "",
  258. postfix: "",
  259. max_postfix: "",
  260. decorate_both: true,
  261. values_separator: " — ",
  262. disable: false,
  263. onStart: null,
  264. onChange: null,
  265. onFinish: null,
  266. onUpdate: null
  267. }, options);
  268. this.validate();
  269. this.result = {
  270. input: this.$cache.input,
  271. slider: null,
  272. min: this.options.min,
  273. max: this.options.max,
  274. from: this.options.from,
  275. from_percent: 0,
  276. from_value: null,
  277. to: this.options.to,
  278. to_percent: 0,
  279. to_value: null
  280. };
  281. this.coords = {
  282. // left
  283. x_gap: 0,
  284. x_pointer: 0,
  285. // width
  286. w_rs: 0,
  287. w_rs_old: 0,
  288. w_handle: 0,
  289. // percents
  290. p_gap: 0,
  291. p_gap_left: 0,
  292. p_gap_right: 0,
  293. p_step: 0,
  294. p_pointer: 0,
  295. p_handle: 0,
  296. p_single: 0,
  297. p_single_real: 0,
  298. p_from: 0,
  299. p_from_real: 0,
  300. p_to: 0,
  301. p_to_real: 0,
  302. p_bar_x: 0,
  303. p_bar_w: 0,
  304. // grid
  305. grid_gap: 0,
  306. big_num: 0,
  307. big: [],
  308. big_w: [],
  309. big_p: [],
  310. big_x: []
  311. };
  312. this.labels = {
  313. // width
  314. w_min: 0,
  315. w_max: 0,
  316. w_from: 0,
  317. w_to: 0,
  318. w_single: 0,
  319. // percents
  320. p_min: 0,
  321. p_max: 0,
  322. p_from: 0,
  323. p_from_left: 0,
  324. p_to: 0,
  325. p_to_left: 0,
  326. p_single: 0,
  327. p_single_left: 0
  328. };
  329. this.init();
  330. };
  331. IonRangeSlider.prototype = {
  332. init: function (is_update) {
  333. this.coords.p_step = this.options.step / ((this.options.max - this.options.min) / 100);
  334. this.target = "base";
  335. this.toggleInput();
  336. this.append();
  337. this.setMinMax();
  338. if (is_update) {
  339. this.force_redraw = true;
  340. this.calc(true);
  341. // callbacks called
  342. this.callOnUpdate();
  343. } else {
  344. this.force_redraw = true;
  345. this.calc(true);
  346. // callbacks called
  347. this.callOnStart();
  348. }
  349. this.updateScene();
  350. },
  351. append: function () {
  352. var container_html = '<span class="irs js-irs-' + this.plugin_count + '"></span>';
  353. this.$cache.input.before(container_html);
  354. this.$cache.input.prop("readonly", true);
  355. this.$cache.cont = this.$cache.input.prev();
  356. this.result.slider = this.$cache.cont;
  357. this.$cache.cont.html(base_html);
  358. this.$cache.rs = this.$cache.cont.find(".irs");
  359. this.$cache.min = this.$cache.cont.find(".irs-min");
  360. this.$cache.max = this.$cache.cont.find(".irs-max");
  361. this.$cache.from = this.$cache.cont.find(".irs-from");
  362. this.$cache.to = this.$cache.cont.find(".irs-to");
  363. this.$cache.single = this.$cache.cont.find(".irs-single");
  364. this.$cache.bar = this.$cache.cont.find(".irs-bar");
  365. this.$cache.line = this.$cache.cont.find(".irs-line");
  366. this.$cache.grid = this.$cache.cont.find(".irs-grid");
  367. if (this.options.type === "single") {
  368. this.$cache.cont.append(single_html);
  369. this.$cache.edge = this.$cache.cont.find(".irs-bar-edge");
  370. this.$cache.s_single = this.$cache.cont.find(".single");
  371. this.$cache.from[0].style.visibility = "hidden";
  372. this.$cache.to[0].style.visibility = "hidden";
  373. this.$cache.shad_single = this.$cache.cont.find(".shadow-single");
  374. } else {
  375. this.$cache.cont.append(double_html);
  376. this.$cache.s_from = this.$cache.cont.find(".from");
  377. this.$cache.s_to = this.$cache.cont.find(".to");
  378. this.$cache.shad_from = this.$cache.cont.find(".shadow-from");
  379. this.$cache.shad_to = this.$cache.cont.find(".shadow-to");
  380. this.setTopHandler();
  381. }
  382. if (this.options.hide_from_to) {
  383. this.$cache.from[0].style.display = "none";
  384. this.$cache.to[0].style.display = "none";
  385. this.$cache.single[0].style.display = "none";
  386. }
  387. this.appendGrid();
  388. if (this.options.disable) {
  389. this.appendDisableMask();
  390. this.$cache.input[0].disabled = true;
  391. } else {
  392. this.$cache.cont.removeClass("irs-disabled");
  393. this.$cache.input[0].disabled = false;
  394. this.bindEvents();
  395. }
  396. },
  397. setTopHandler: function () {
  398. var min = this.options.min,
  399. max = this.options.max,
  400. from = this.options.from,
  401. to = this.options.to;
  402. if (from > min && to === max) {
  403. this.$cache.s_from.addClass("type_last");
  404. } else if (to < max) {
  405. this.$cache.s_to.addClass("type_last");
  406. }
  407. },
  408. appendDisableMask: function () {
  409. this.$cache.cont.append(disable_html);
  410. this.$cache.cont.addClass("irs-disabled");
  411. },
  412. remove: function () {
  413. this.$cache.cont.remove();
  414. this.$cache.cont = null;
  415. this.$cache.line.off("keydown.irs_" + this.plugin_count);
  416. this.$cache.body.off("touchmove.irs_" + this.plugin_count);
  417. this.$cache.body.off("mousemove.irs_" + this.plugin_count);
  418. this.$cache.win.off("touchend.irs_" + this.plugin_count);
  419. this.$cache.win.off("mouseup.irs_" + this.plugin_count);
  420. if (is_old_ie) {
  421. this.$cache.body.off("mouseup.irs_" + this.plugin_count);
  422. this.$cache.body.off("mouseleave.irs_" + this.plugin_count);
  423. }
  424. this.$cache.grid_labels = [];
  425. this.coords.big = [];
  426. this.coords.big_w = [];
  427. this.coords.big_p = [];
  428. this.coords.big_x = [];
  429. cancelAnimationFrame(this.raf_id);
  430. },
  431. bindEvents: function () {
  432. this.$cache.body.on("touchmove.irs_" + this.plugin_count, this.pointerMove.bind(this));
  433. this.$cache.body.on("mousemove.irs_" + this.plugin_count, this.pointerMove.bind(this));
  434. this.$cache.win.on("touchend.irs_" + this.plugin_count, this.pointerUp.bind(this));
  435. this.$cache.win.on("mouseup.irs_" + this.plugin_count, this.pointerUp.bind(this));
  436. this.$cache.line.on("touchstart.irs_" + this.plugin_count, this.pointerClick.bind(this, "click"));
  437. this.$cache.line.on("mousedown.irs_" + this.plugin_count, this.pointerClick.bind(this, "click"));
  438. if (this.options.drag_interval && this.options.type === "double") {
  439. this.$cache.bar.on("touchstart.irs_" + this.plugin_count, this.pointerDown.bind(this, "both"));
  440. this.$cache.bar.on("mousedown.irs_" + this.plugin_count, this.pointerDown.bind(this, "both"));
  441. } else {
  442. this.$cache.bar.on("touchstart.irs_" + this.plugin_count, this.pointerClick.bind(this, "click"));
  443. this.$cache.bar.on("mousedown.irs_" + this.plugin_count, this.pointerClick.bind(this, "click"));
  444. }
  445. if (this.options.type === "single") {
  446. this.$cache.single.on("touchstart.irs_" + this.plugin_count, this.pointerDown.bind(this, "single"));
  447. this.$cache.s_single.on("touchstart.irs_" + this.plugin_count, this.pointerDown.bind(this, "single"));
  448. this.$cache.shad_single.on("touchstart.irs_" + this.plugin_count, this.pointerClick.bind(this, "click"));
  449. this.$cache.single.on("mousedown.irs_" + this.plugin_count, this.pointerDown.bind(this, "single"));
  450. this.$cache.s_single.on("mousedown.irs_" + this.plugin_count, this.pointerDown.bind(this, "single"));
  451. this.$cache.edge.on("mousedown.irs_" + this.plugin_count, this.pointerClick.bind(this, "click"));
  452. this.$cache.shad_single.on("mousedown.irs_" + this.plugin_count, this.pointerClick.bind(this, "click"));
  453. } else {
  454. this.$cache.single.on("touchstart.irs_" + this.plugin_count, this.pointerDown.bind(this, "from"));
  455. this.$cache.single.on("mousedown.irs_" + this.plugin_count, this.pointerDown.bind(this, "from"));
  456. this.$cache.from.on("touchstart.irs_" + this.plugin_count, this.pointerDown.bind(this, "from"));
  457. this.$cache.s_from.on("touchstart.irs_" + this.plugin_count, this.pointerDown.bind(this, "from"));
  458. this.$cache.to.on("touchstart.irs_" + this.plugin_count, this.pointerDown.bind(this, "to"));
  459. this.$cache.s_to.on("touchstart.irs_" + this.plugin_count, this.pointerDown.bind(this, "to"));
  460. this.$cache.shad_from.on("touchstart.irs_" + this.plugin_count, this.pointerClick.bind(this, "click"));
  461. this.$cache.shad_to.on("touchstart.irs_" + this.plugin_count, this.pointerClick.bind(this, "click"));
  462. this.$cache.from.on("mousedown.irs_" + this.plugin_count, this.pointerDown.bind(this, "from"));
  463. this.$cache.s_from.on("mousedown.irs_" + this.plugin_count, this.pointerDown.bind(this, "from"));
  464. this.$cache.to.on("mousedown.irs_" + this.plugin_count, this.pointerDown.bind(this, "to"));
  465. this.$cache.s_to.on("mousedown.irs_" + this.plugin_count, this.pointerDown.bind(this, "to"));
  466. this.$cache.shad_from.on("mousedown.irs_" + this.plugin_count, this.pointerClick.bind(this, "click"));
  467. this.$cache.shad_to.on("mousedown.irs_" + this.plugin_count, this.pointerClick.bind(this, "click"));
  468. }
  469. if (this.options.keyboard) {
  470. this.$cache.line.on("keydown.irs_" + this.plugin_count, this.key.bind(this, "keyboard"));
  471. }
  472. if (is_old_ie) {
  473. this.$cache.body.on("mouseup.irs_" + this.plugin_count, this.pointerUp.bind(this));
  474. this.$cache.body.on("mouseleave.irs_" + this.plugin_count, this.pointerUp.bind(this));
  475. }
  476. },
  477. pointerMove: function (e) {
  478. if (!this.dragging) {
  479. return;
  480. }
  481. var x = e.pageX || e.originalEvent.touches && e.originalEvent.touches[0].pageX;
  482. this.coords.x_pointer = x - this.coords.x_gap;
  483. this.calc();
  484. },
  485. pointerUp: function (e) {
  486. if (this.current_plugin !== this.plugin_count) {
  487. return;
  488. }
  489. if (this.is_active) {
  490. this.is_active = false;
  491. } else {
  492. return;
  493. }
  494. // callbacks call
  495. if ($.contains(this.$cache.cont[0], e.target) || this.dragging) {
  496. this.is_finish = true;
  497. this.callOnFinish();
  498. }
  499. this.$cache.cont.find(".state_hover").removeClass("state_hover");
  500. this.force_redraw = true;
  501. this.dragging = false;
  502. if (is_old_ie) {
  503. $("*").prop("unselectable", false);
  504. }
  505. this.updateScene();
  506. },
  507. changeLevel: function (target) {
  508. switch (target) {
  509. case "single":
  510. this.coords.p_gap = this.toFixed(this.coords.p_pointer - this.coords.p_single);
  511. break;
  512. case "from":
  513. this.coords.p_gap = this.toFixed(this.coords.p_pointer - this.coords.p_from);
  514. this.$cache.s_from.addClass("state_hover");
  515. this.$cache.s_from.addClass("type_last");
  516. this.$cache.s_to.removeClass("type_last");
  517. break;
  518. case "to":
  519. this.coords.p_gap = this.toFixed(this.coords.p_pointer - this.coords.p_to);
  520. this.$cache.s_to.addClass("state_hover");
  521. this.$cache.s_to.addClass("type_last");
  522. this.$cache.s_from.removeClass("type_last");
  523. break;
  524. case "both":
  525. this.coords.p_gap_left = this.toFixed(this.coords.p_pointer - this.coords.p_from);
  526. this.coords.p_gap_right = this.toFixed(this.coords.p_to - this.coords.p_pointer);
  527. this.$cache.s_to.removeClass("type_last");
  528. this.$cache.s_from.removeClass("type_last");
  529. break;
  530. }
  531. },
  532. pointerDown: function (target, e) {
  533. e.preventDefault();
  534. var x = e.pageX || e.originalEvent.touches && e.originalEvent.touches[0].pageX;
  535. if (e.button === 2) {
  536. return;
  537. }
  538. this.current_plugin = this.plugin_count;
  539. this.target = target;
  540. this.is_active = true;
  541. this.dragging = true;
  542. this.coords.x_gap = this.$cache.rs.offset().left;
  543. this.coords.x_pointer = x - this.coords.x_gap;
  544. this.calcPointer();
  545. this.changeLevel(target);
  546. if (is_old_ie) {
  547. $("*").prop("unselectable", true);
  548. }
  549. this.$cache.line.trigger("focus");
  550. this.updateScene();
  551. },
  552. pointerClick: function (target, e) {
  553. e.preventDefault();
  554. var x = e.pageX || e.originalEvent.touches && e.originalEvent.touches[0].pageX;
  555. if (e.button === 2) {
  556. return;
  557. }
  558. this.current_plugin = this.plugin_count;
  559. this.target = target;
  560. this.is_click = true;
  561. this.coords.x_gap = this.$cache.rs.offset().left;
  562. this.coords.x_pointer = +(x - this.coords.x_gap).toFixed();
  563. this.force_redraw = true;
  564. this.calc();
  565. this.$cache.line.trigger("focus");
  566. },
  567. key: function (target, e) {
  568. if (this.current_plugin !== this.plugin_count || e.altKey || e.ctrlKey || e.shiftKey || e.metaKey) {
  569. return;
  570. }
  571. switch (e.which) {
  572. case 83: // W
  573. case 65: // A
  574. case 40: // DOWN
  575. case 37: // LEFT
  576. e.preventDefault();
  577. this.moveByKey(false);
  578. break;
  579. case 87: // S
  580. case 68: // D
  581. case 38: // UP
  582. case 39: // RIGHT
  583. e.preventDefault();
  584. this.moveByKey(true);
  585. break;
  586. }
  587. return true;
  588. },
  589. // Move by key. Beta
  590. // TODO: refactor than have plenty of time
  591. moveByKey: function (right) {
  592. var p = this.coords.p_pointer;
  593. if (right) {
  594. p += this.options.keyboard_step;
  595. } else {
  596. p -= this.options.keyboard_step;
  597. }
  598. this.coords.x_pointer = this.toFixed(this.coords.w_rs / 100 * p);
  599. this.is_key = true;
  600. this.calc();
  601. },
  602. setMinMax: function () {
  603. if (!this.options) {
  604. return;
  605. }
  606. if (this.options.hide_min_max) {
  607. this.$cache.min[0].style.display = "none";
  608. this.$cache.max[0].style.display = "none";
  609. return;
  610. }
  611. if (this.options.values.length) {
  612. this.$cache.min.html(this.decorate(this.options.p_values[this.options.min]));
  613. this.$cache.max.html(this.decorate(this.options.p_values[this.options.max]));
  614. } else {
  615. this.$cache.min.html(this.decorate(this._prettify(this.options.min), this.options.min));
  616. this.$cache.max.html(this.decorate(this._prettify(this.options.max), this.options.max));
  617. }
  618. this.labels.w_min = this.$cache.min.outerWidth(false);
  619. this.labels.w_max = this.$cache.max.outerWidth(false);
  620. },
  621. // =============================================================================================================
  622. // Calculations
  623. calc: function (update) {
  624. if (!this.options) {
  625. return;
  626. }
  627. this.calc_count++;
  628. if (this.calc_count === 10 || update) {
  629. this.calc_count = 0;
  630. this.coords.w_rs = this.$cache.rs.outerWidth(false);
  631. if (this.options.type === "single") {
  632. this.coords.w_handle = this.$cache.s_single.outerWidth(false);
  633. } else {
  634. this.coords.w_handle = this.$cache.s_from.outerWidth(false);
  635. }
  636. }
  637. if (!this.coords.w_rs) {
  638. return;
  639. }
  640. this.calcPointer();
  641. this.coords.p_handle = this.toFixed(this.coords.w_handle / this.coords.w_rs * 100);
  642. var real_width = 100 - this.coords.p_handle,
  643. real_x = this.toFixed(this.coords.p_pointer - this.coords.p_gap);
  644. if (this.target === "click") {
  645. this.coords.p_gap = this.coords.p_handle / 2;
  646. real_x = this.toFixed(this.coords.p_pointer - this.coords.p_gap);
  647. this.target = this.chooseHandle(real_x);
  648. }
  649. if (real_x < 0) {
  650. real_x = 0;
  651. } else if (real_x > real_width) {
  652. real_x = real_width;
  653. }
  654. switch (this.target) {
  655. case "base":
  656. var w = (this.options.max - this.options.min) / 100,
  657. f = (this.result.from - this.options.min) / w,
  658. t = (this.result.to - this.options.min) / w;
  659. this.coords.p_single_real = this.toFixed(f);
  660. this.coords.p_from_real = this.toFixed(f);
  661. this.coords.p_to_real = this.toFixed(t);
  662. this.coords.p_single_real = this.checkDiapason(this.coords.p_single_real, this.options.from_min, this.options.from_max);
  663. this.coords.p_from_real = this.checkDiapason(this.coords.p_from_real, this.options.from_min, this.options.from_max);
  664. this.coords.p_to_real = this.checkDiapason(this.coords.p_to_real, this.options.to_min, this.options.to_max);
  665. this.coords.p_single = this.toFixed(f - (this.coords.p_handle / 100 * f));
  666. this.coords.p_from = this.toFixed(f - (this.coords.p_handle / 100 * f));
  667. this.coords.p_to = this.toFixed(t - (this.coords.p_handle / 100 * t));
  668. this.target = null;
  669. break;
  670. case "single":
  671. if (this.options.from_fixed) {
  672. break;
  673. }
  674. this.coords.p_single_real = this.calcWithStep(real_x / real_width * 100);
  675. this.coords.p_single_real = this.checkDiapason(this.coords.p_single_real, this.options.from_min, this.options.from_max);
  676. this.coords.p_single = this.toFixed(this.coords.p_single_real / 100 * real_width);
  677. break;
  678. case "from":
  679. if (this.options.from_fixed) {
  680. break;
  681. }
  682. this.coords.p_from_real = this.calcWithStep(real_x / real_width * 100);
  683. if (this.coords.p_from_real > this.coords.p_to_real) {
  684. this.coords.p_from_real = this.coords.p_to_real;
  685. }
  686. this.coords.p_from_real = this.checkDiapason(this.coords.p_from_real, this.options.from_min, this.options.from_max);
  687. this.coords.p_from_real = this.checkMinInterval(this.coords.p_from_real, this.coords.p_to_real, "from");
  688. this.coords.p_from_real = this.checkMaxInterval(this.coords.p_from_real, this.coords.p_to_real, "from");
  689. this.coords.p_from = this.toFixed(this.coords.p_from_real / 100 * real_width);
  690. break;
  691. case "to":
  692. if (this.options.to_fixed) {
  693. break;
  694. }
  695. this.coords.p_to_real = this.calcWithStep(real_x / real_width * 100);
  696. if (this.coords.p_to_real < this.coords.p_from_real) {
  697. this.coords.p_to_real = this.coords.p_from_real;
  698. }
  699. this.coords.p_to_real = this.checkDiapason(this.coords.p_to_real, this.options.to_min, this.options.to_max);
  700. this.coords.p_to_real = this.checkMinInterval(this.coords.p_to_real, this.coords.p_from_real, "to");
  701. this.coords.p_to_real = this.checkMaxInterval(this.coords.p_to_real, this.coords.p_from_real, "to");
  702. this.coords.p_to = this.toFixed(this.coords.p_to_real / 100 * real_width);
  703. break;
  704. case "both":
  705. if (this.options.from_fixed || this.options.to_fixed) {
  706. break;
  707. }
  708. real_x = this.toFixed(real_x + (this.coords.p_handle * 0.1));
  709. this.coords.p_from_real = this.calcWithStep((real_x - this.coords.p_gap_left) / real_width * 100);
  710. this.coords.p_from_real = this.checkDiapason(this.coords.p_from_real, this.options.from_min, this.options.from_max);
  711. this.coords.p_from_real = this.checkMinInterval(this.coords.p_from_real, this.coords.p_to_real, "from");
  712. this.coords.p_from = this.toFixed(this.coords.p_from_real / 100 * real_width);
  713. this.coords.p_to_real = this.calcWithStep((real_x + this.coords.p_gap_right) / real_width * 100);
  714. this.coords.p_to_real = this.checkDiapason(this.coords.p_to_real, this.options.to_min, this.options.to_max);
  715. this.coords.p_to_real = this.checkMinInterval(this.coords.p_to_real, this.coords.p_from_real, "to");
  716. this.coords.p_to = this.toFixed(this.coords.p_to_real / 100 * real_width);
  717. break;
  718. }
  719. if (this.options.type === "single") {
  720. this.coords.p_bar_x = (this.coords.p_handle / 2);
  721. this.coords.p_bar_w = this.coords.p_single;
  722. this.result.from_percent = this.coords.p_single_real;
  723. this.result.from = this.calcReal(this.coords.p_single_real);
  724. if (this.options.values.length) {
  725. this.result.from_value = this.options.values[this.result.from];
  726. }
  727. } else {
  728. this.coords.p_bar_x = this.toFixed(this.coords.p_from + (this.coords.p_handle / 2));
  729. this.coords.p_bar_w = this.toFixed(this.coords.p_to - this.coords.p_from);
  730. this.result.from_percent = this.coords.p_from_real;
  731. this.result.from = this.calcReal(this.coords.p_from_real);
  732. this.result.to_percent = this.coords.p_to_real;
  733. this.result.to = this.calcReal(this.coords.p_to_real);
  734. if (this.options.values.length) {
  735. this.result.from_value = this.options.values[this.result.from];
  736. this.result.to_value = this.options.values[this.result.to];
  737. }
  738. }
  739. this.calcMinMax();
  740. this.calcLabels();
  741. },
  742. calcPointer: function () {
  743. if (!this.coords.w_rs) {
  744. this.coords.p_pointer = 0;
  745. return;
  746. }
  747. if (this.coords.x_pointer < 0 || isNaN(this.coords.x_pointer) ) {
  748. this.coords.x_pointer = 0;
  749. } else if (this.coords.x_pointer > this.coords.w_rs) {
  750. this.coords.x_pointer = this.coords.w_rs;
  751. }
  752. this.coords.p_pointer = this.toFixed(this.coords.x_pointer / this.coords.w_rs * 100);
  753. },
  754. chooseHandle: function (real_x) {
  755. if (this.options.type === "single") {
  756. return "single";
  757. } else {
  758. var m_point = this.coords.p_from_real + ((this.coords.p_to_real - this.coords.p_from_real) / 2);
  759. if (real_x >= m_point) {
  760. return this.options.to_fixed ? "from" : "to";
  761. } else {
  762. return this.options.from_fixed ? "to" : "from";
  763. }
  764. }
  765. },
  766. calcMinMax: function () {
  767. if (!this.coords.w_rs) {
  768. return;
  769. }
  770. this.labels.p_min = this.labels.w_min / this.coords.w_rs * 100;
  771. this.labels.p_max = this.labels.w_max / this.coords.w_rs * 100;
  772. },
  773. calcLabels: function () {
  774. if (!this.coords.w_rs || this.options.hide_from_to) {
  775. return;
  776. }
  777. if (this.options.type === "single") {
  778. this.labels.w_single = this.$cache.single.outerWidth(false);
  779. this.labels.p_single = this.labels.w_single / this.coords.w_rs * 100;
  780. this.labels.p_single_left = this.coords.p_single + (this.coords.p_handle / 2) - (this.labels.p_single / 2);
  781. this.labels.p_single_left = this.checkEdges(this.labels.p_single_left, this.labels.p_single);
  782. } else {
  783. this.labels.w_from = this.$cache.from.outerWidth(false);
  784. this.labels.p_from = this.labels.w_from / this.coords.w_rs * 100;
  785. this.labels.p_from_left = this.coords.p_from + (this.coords.p_handle / 2) - (this.labels.p_from / 2);
  786. this.labels.p_from_left = this.toFixed(this.labels.p_from_left);
  787. this.labels.p_from_left = this.checkEdges(this.labels.p_from_left, this.labels.p_from);
  788. this.labels.w_to = this.$cache.to.outerWidth(false);
  789. this.labels.p_to = this.labels.w_to / this.coords.w_rs * 100;
  790. this.labels.p_to_left = this.coords.p_to + (this.coords.p_handle / 2) - (this.labels.p_to / 2);
  791. this.labels.p_to_left = this.toFixed(this.labels.p_to_left);
  792. this.labels.p_to_left = this.checkEdges(this.labels.p_to_left, this.labels.p_to);
  793. this.labels.w_single = this.$cache.single.outerWidth(false);
  794. this.labels.p_single = this.labels.w_single / this.coords.w_rs * 100;
  795. this.labels.p_single_left = ((this.labels.p_from_left + this.labels.p_to_left + this.labels.p_to) / 2) - (this.labels.p_single / 2);
  796. this.labels.p_single_left = this.toFixed(this.labels.p_single_left);
  797. this.labels.p_single_left = this.checkEdges(this.labels.p_single_left, this.labels.p_single);
  798. }
  799. },
  800. // =============================================================================================================
  801. // Drawings
  802. updateScene: function () {
  803. if (this.raf_id) {
  804. cancelAnimationFrame(this.raf_id);
  805. this.raf_id = null;
  806. }
  807. clearTimeout(this.update_tm);
  808. this.update_tm = null;
  809. if (!this.options) {
  810. return;
  811. }
  812. this.drawHandles();
  813. if (this.is_active) {
  814. this.raf_id = requestAnimationFrame(this.updateScene.bind(this));
  815. } else {
  816. this.update_tm = setTimeout(this.updateScene.bind(this), 300);
  817. }
  818. },
  819. drawHandles: function () {
  820. this.coords.w_rs = this.$cache.rs.outerWidth(false);
  821. if (!this.coords.w_rs) {
  822. return;
  823. }
  824. if (this.coords.w_rs !== this.coords.w_rs_old) {
  825. this.target = "base";
  826. this.is_resize = true;
  827. }
  828. if (this.coords.w_rs !== this.coords.w_rs_old || this.force_redraw) {
  829. this.setMinMax();
  830. this.calc(true);
  831. this.drawLabels();
  832. if (this.options.grid) {
  833. this.calcGridMargin();
  834. this.calcGridLabels();
  835. }
  836. this.force_redraw = true;
  837. this.coords.w_rs_old = this.coords.w_rs;
  838. this.drawShadow();
  839. }
  840. if (!this.coords.w_rs) {
  841. return;
  842. }
  843. if (!this.dragging && !this.force_redraw && !this.is_key) {
  844. return;
  845. }
  846. if (this.old_from !== this.result.from || this.old_to !== this.result.to || this.force_redraw || this.is_key) {
  847. this.drawLabels();
  848. this.$cache.bar[0].style.left = this.coords.p_bar_x + "%";
  849. this.$cache.bar[0].style.width = this.coords.p_bar_w + "%";
  850. if (this.options.type === "single") {
  851. this.$cache.s_single[0].style.left = this.coords.p_single + "%";
  852. this.$cache.single[0].style.left = this.labels.p_single_left + "%";
  853. if (this.options.values.length) {
  854. this.$cache.input.prop("value", this.result.from_value);
  855. this.$cache.input.data("from", this.result.from_value);
  856. } else {
  857. this.$cache.input.prop("value", this.result.from);
  858. this.$cache.input.data("from", this.result.from);
  859. }
  860. } else {
  861. this.$cache.s_from[0].style.left = this.coords.p_from + "%";
  862. this.$cache.s_to[0].style.left = this.coords.p_to + "%";
  863. if (this.old_from !== this.result.from || this.force_redraw) {
  864. this.$cache.from[0].style.left = this.labels.p_from_left + "%";
  865. }
  866. if (this.old_to !== this.result.to || this.force_redraw) {
  867. this.$cache.to[0].style.left = this.labels.p_to_left + "%";
  868. }
  869. this.$cache.single[0].style.left = this.labels.p_single_left + "%";
  870. if (this.options.values.length) {
  871. this.$cache.input.prop("value", this.result.from_value + ";" + this.result.to_value);
  872. this.$cache.input.data("from", this.result.from_value);
  873. this.$cache.input.data("to", this.result.to_value);
  874. } else {
  875. this.$cache.input.prop("value", this.result.from + ";" + this.result.to);
  876. this.$cache.input.data("from", this.result.from);
  877. this.$cache.input.data("to", this.result.to);
  878. }
  879. }
  880. if ((this.old_from !== this.result.from || this.old_to !== this.result.to) && !this.is_start) {
  881. this.$cache.input.trigger("change");
  882. }
  883. this.old_from = this.result.from;
  884. this.old_to = this.result.to;
  885. // callbacks call
  886. if (!this.is_resize && !this.is_update && !this.is_start && !this.is_finish) {
  887. this.callOnChange();
  888. }
  889. if (this.is_key || this.is_click) {
  890. this.callOnFinish();
  891. }
  892. this.is_update = false;
  893. this.is_resize = false;
  894. this.is_finish = false;
  895. }
  896. this.is_start = false;
  897. this.is_key = false;
  898. this.is_click = false;
  899. this.force_redraw = false;
  900. },
  901. // callbacks
  902. callOnStart: function () {
  903. if (this.options.onStart && typeof this.options.onStart === "function") {
  904. this.options.onStart(this.result);
  905. }
  906. },
  907. callOnChange: function () {
  908. if (this.options.onChange && typeof this.options.onChange === "function") {
  909. this.options.onChange(this.result);
  910. }
  911. },
  912. callOnFinish: function () {
  913. if (this.options.onFinish && typeof this.options.onFinish === "function") {
  914. this.options.onFinish(this.result);
  915. }
  916. },
  917. callOnUpdate: function () {
  918. if (this.options.onUpdate && typeof this.options.onUpdate === "function") {
  919. this.options.onUpdate(this.result);
  920. }
  921. },
  922. drawLabels: function () {
  923. if (!this.options) {
  924. return;
  925. }
  926. var values_num = this.options.values.length,
  927. p_values = this.options.p_values,
  928. text_single,
  929. text_from,
  930. text_to;
  931. if (this.options.hide_from_to) {
  932. return;
  933. }
  934. if (this.options.type === "single") {
  935. if (values_num) {
  936. text_single = this.decorate(p_values[this.result.from]);
  937. this.$cache.single.html(text_single);
  938. } else {
  939. text_single = this.decorate(this._prettify(this.result.from), this.result.from);
  940. this.$cache.single.html(text_single);
  941. }
  942. this.calcLabels();
  943. if (this.labels.p_single_left < this.labels.p_min + 1) {
  944. this.$cache.min[0].style.visibility = "hidden";
  945. } else {
  946. this.$cache.min[0].style.visibility = "visible";
  947. }
  948. if (this.labels.p_single_left + this.labels.p_single > 100 - this.labels.p_max - 1) {
  949. this.$cache.max[0].style.visibility = "hidden";
  950. } else {
  951. this.$cache.max[0].style.visibility = "visible";
  952. }
  953. } else {
  954. if (values_num) {
  955. if (this.options.decorate_both) {
  956. text_single = this.decorate(p_values[this.result.from]);
  957. text_single += this.options.values_separator;
  958. text_single += this.decorate(p_values[this.result.to]);
  959. } else {
  960. text_single = this.decorate(p_values[this.result.from] + this.options.values_separator + p_values[this.result.to]);
  961. }
  962. text_from = this.decorate(p_values[this.result.from]);
  963. text_to = this.decorate(p_values[this.result.to]);
  964. this.$cache.single.html(text_single);
  965. this.$cache.from.html(text_from);
  966. this.$cache.to.html(text_to);
  967. } else {
  968. if (this.options.decorate_both) {
  969. text_single = this.decorate(this._prettify(this.result.from), this.result.from);
  970. text_single += this.options.values_separator;
  971. text_single += this.decorate(this._prettify(this.result.to), this.result.to);
  972. } else {
  973. text_single = this.decorate(this._prettify(this.result.from) + this.options.values_separator + this._prettify(this.result.to), this.result.to);
  974. }
  975. text_from = this.decorate(this._prettify(this.result.from), this.result.from);
  976. text_to = this.decorate(this._prettify(this.result.to), this.result.to);
  977. this.$cache.single.html(text_single);
  978. this.$cache.from.html(text_from);
  979. this.$cache.to.html(text_to);
  980. }
  981. this.calcLabels();
  982. var min = Math.min(this.labels.p_single_left, this.labels.p_from_left),
  983. single_left = this.labels.p_single_left + this.labels.p_single,
  984. to_left = this.labels.p_to_left + this.labels.p_to,
  985. max = Math.max(single_left, to_left);
  986. if (this.labels.p_from_left + this.labels.p_from >= this.labels.p_to_left) {
  987. this.$cache.from[0].style.visibility = "hidden";
  988. this.$cache.to[0].style.visibility = "hidden";
  989. this.$cache.single[0].style.visibility = "visible";
  990. if (this.result.from === this.result.to) {
  991. this.$cache.from[0].style.visibility = "visible";
  992. this.$cache.single[0].style.visibility = "hidden";
  993. max = to_left;
  994. } else {
  995. this.$cache.from[0].style.visibility = "hidden";
  996. this.$cache.single[0].style.visibility = "visible";
  997. max = Math.max(single_left, to_left);
  998. }
  999. } else {
  1000. this.$cache.from[0].style.visibility = "visible";
  1001. this.$cache.to[0].style.visibility = "visible";
  1002. this.$cache.single[0].style.visibility = "hidden";
  1003. }
  1004. if (min < this.labels.p_min + 1) {
  1005. this.$cache.min[0].style.visibility = "hidden";
  1006. } else {
  1007. this.$cache.min[0].style.visibility = "visible";
  1008. }
  1009. if (max > 100 - this.labels.p_max - 1) {
  1010. this.$cache.max[0].style.visibility = "hidden";
  1011. } else {
  1012. this.$cache.max[0].style.visibility = "visible";
  1013. }
  1014. }
  1015. },
  1016. drawShadow: function () {
  1017. var o = this.options,
  1018. c = this.$cache,
  1019. is_from_min = typeof o.from_min === "number" && !isNaN(o.from_min),
  1020. is_from_max = typeof o.from_max === "number" && !isNaN(o.from_max),
  1021. is_to_min = typeof o.to_min === "number" && !isNaN(o.to_min),
  1022. is_to_max = typeof o.to_max === "number" && !isNaN(o.to_max),
  1023. from_min,
  1024. from_max,
  1025. to_min,
  1026. to_max;
  1027. if (o.type === "single") {
  1028. if (o.from_shadow && (is_from_min || is_from_max)) {
  1029. from_min = this.calcPercent(is_from_min ? o.from_min : o.min);
  1030. from_max = this.calcPercent(is_from_max ? o.from_max : o.max) - from_min;
  1031. from_min = this.toFixed(from_min - (this.coords.p_handle / 100 * from_min));
  1032. from_max = this.toFixed(from_max - (this.coords.p_handle / 100 * from_max));
  1033. from_min = from_min + (this.coords.p_handle / 2);
  1034. c.shad_single[0].style.display = "block";
  1035. c.shad_single[0].style.left = from_min + "%";
  1036. c.shad_single[0].style.width = from_max + "%";
  1037. } else {
  1038. c.shad_single[0].style.display = "none";
  1039. }
  1040. } else {
  1041. if (o.from_shadow && (is_from_min || is_from_max)) {
  1042. from_min = this.calcPercent(is_from_min ? o.from_min : o.min);
  1043. from_max = this.calcPercent(is_from_max ? o.from_max : o.max) - from_min;
  1044. from_min = this.toFixed(from_min - (this.coords.p_handle / 100 * from_min));
  1045. from_max = this.toFixed(from_max - (this.coords.p_handle / 100 * from_max));
  1046. from_min = from_min + (this.coords.p_handle / 2);
  1047. c.shad_from[0].style.display = "block";
  1048. c.shad_from[0].style.left = from_min + "%";
  1049. c.shad_from[0].style.width = from_max + "%";
  1050. } else {
  1051. c.shad_from[0].style.display = "none";
  1052. }
  1053. if (o.to_shadow && (is_to_min || is_to_max)) {
  1054. to_min = this.calcPercent(is_to_min ? o.to_min : o.min);
  1055. to_max = this.calcPercent(is_to_max ? o.to_max : o.max) - to_min;
  1056. to_min = this.toFixed(to_min - (this.coords.p_handle / 100 * to_min));
  1057. to_max = this.toFixed(to_max - (this.coords.p_handle / 100 * to_max));
  1058. to_min = to_min + (this.coords.p_handle / 2);
  1059. c.shad_to[0].style.display = "block";
  1060. c.shad_to[0].style.left = to_min + "%";
  1061. c.shad_to[0].style.width = to_max + "%";
  1062. } else {
  1063. c.shad_to[0].style.display = "none";
  1064. }
  1065. }
  1066. },
  1067. // =============================================================================================================
  1068. // Service methods
  1069. toggleInput: function () {
  1070. this.$cache.input.toggleClass("irs-hidden-input");
  1071. },
  1072. calcPercent: function (num) {
  1073. var w = (this.options.max - this.options.min) / 100,
  1074. percent = (num - this.options.min) / w;
  1075. return this.toFixed(percent);
  1076. },
  1077. calcReal: function (percent) {
  1078. var min = this.options.min,
  1079. max = this.options.max,
  1080. min_decimals = min.toString().split(".")[1],
  1081. max_decimals = max.toString().split(".")[1],
  1082. min_length, max_length,
  1083. avg_decimals = 0,
  1084. abs = 0;
  1085. if (percent === 0) {
  1086. return this.options.min;
  1087. }
  1088. if (percent === 100) {
  1089. return this.options.max;
  1090. }
  1091. if (min_decimals) {
  1092. min_length = min_decimals.length;
  1093. avg_decimals = min_length;
  1094. }
  1095. if (max_decimals) {
  1096. max_length = max_decimals.length;
  1097. avg_decimals = max_length;
  1098. }
  1099. if (min_length && max_length) {
  1100. avg_decimals = (min_length >= max_length) ? min_length : max_length;
  1101. }
  1102. if (min < 0) {
  1103. abs = Math.abs(min);
  1104. min = +(min + abs).toFixed(avg_decimals);
  1105. max = +(max + abs).toFixed(avg_decimals);
  1106. }
  1107. var number = ((max - min) / 100 * percent) + min,
  1108. string = this.options.step.toString().split(".")[1],
  1109. result;
  1110. if (string) {
  1111. number = +number.toFixed(string.length);
  1112. } else {
  1113. number = number / this.options.step;
  1114. number = number * this.options.step;
  1115. number = +number.toFixed(0);
  1116. }
  1117. if (abs) {
  1118. number -= abs;
  1119. }
  1120. if (string) {
  1121. result = +number.toFixed(string.length);
  1122. } else {
  1123. result = this.toFixed(number);
  1124. }
  1125. if (result < this.options.min) {
  1126. result = this.options.min;
  1127. } else if (result > this.options.max) {
  1128. result = this.options.max;
  1129. }
  1130. return result;
  1131. },
  1132. calcWithStep: function (percent) {
  1133. var rounded = Math.round(percent / this.coords.p_step) * this.coords.p_step;
  1134. if (rounded > 100) {
  1135. rounded = 100;
  1136. }
  1137. if (percent === 100) {
  1138. rounded = 100;
  1139. }
  1140. return this.toFixed(rounded);
  1141. },
  1142. checkMinInterval: function (p_current, p_next, type) {
  1143. var o = this.options,
  1144. current,
  1145. next;
  1146. if (!o.min_interval) {
  1147. return p_current;
  1148. }
  1149. current = this.calcReal(p_current);
  1150. next = this.calcReal(p_next);
  1151. if (type === "from") {
  1152. if (next - current < o.min_interval) {
  1153. current = next - o.min_interval;
  1154. }
  1155. } else {
  1156. if (current - next < o.min_interval) {
  1157. current = next + o.min_interval;
  1158. }
  1159. }
  1160. return this.calcPercent(current);
  1161. },
  1162. checkMaxInterval: function (p_current, p_next, type) {
  1163. var o = this.options,
  1164. current,
  1165. next;
  1166. if (!o.max_interval) {
  1167. return p_current;
  1168. }
  1169. current = this.calcReal(p_current);
  1170. next = this.calcReal(p_next);
  1171. if (type === "from") {
  1172. if (next - current > o.max_interval) {
  1173. current = next - o.max_interval;
  1174. }
  1175. } else {
  1176. if (current - next > o.max_interval) {
  1177. current = next + o.max_interval;
  1178. }
  1179. }
  1180. return this.calcPercent(current);
  1181. },
  1182. checkDiapason: function (p_num, min, max) {
  1183. var num = this.calcReal(p_num),
  1184. o = this.options;
  1185. if (typeof min !== "number") {
  1186. min = o.min;
  1187. }
  1188. if (typeof max !== "number") {
  1189. max = o.max;
  1190. }
  1191. if (num < min) {
  1192. num = min;
  1193. }
  1194. if (num > max) {
  1195. num = max;
  1196. }
  1197. return this.calcPercent(num);
  1198. },
  1199. toFixed: function (num) {
  1200. num = num.toFixed(9);
  1201. return +num;
  1202. },
  1203. _prettify: function (num) {
  1204. if (!this.options.prettify_enabled) {
  1205. return num;
  1206. }
  1207. if (this.options.prettify && typeof this.options.prettify === "function") {
  1208. return this.options.prettify(num);
  1209. } else {
  1210. return this.prettify(num);
  1211. }
  1212. },
  1213. prettify: function (num) {
  1214. var n = num.toString();
  1215. return n.replace(/(\d{1,3}(?=(?:\d\d\d)+(?!\d)))/g, "$1" + this.options.prettify_separator);
  1216. },
  1217. checkEdges: function (left, width) {
  1218. if (!this.options.force_edges) {
  1219. return this.toFixed(left);
  1220. }
  1221. if (left < 0) {
  1222. left = 0;
  1223. } else if (left > 100 - width) {
  1224. left = 100 - width;
  1225. }
  1226. return this.toFixed(left);
  1227. },
  1228. validate: function () {
  1229. var o = this.options,
  1230. r = this.result,
  1231. v = o.values,
  1232. vl = v.length,
  1233. value,
  1234. i;
  1235. if (typeof o.min === "string") o.min = +o.min;
  1236. if (typeof o.max === "string") o.max = +o.max;
  1237. if (typeof o.from === "string") o.from = +o.from;
  1238. if (typeof o.to === "string") o.to = +o.to;
  1239. if (typeof o.step === "string") o.step = +o.step;
  1240. if (typeof o.from_min === "string") o.from_min = +o.from_min;
  1241. if (typeof o.from_max === "string") o.from_max = +o.from_max;
  1242. if (typeof o.to_min === "string") o.to_min = +o.to_min;
  1243. if (typeof o.to_max === "string") o.to_max = +o.to_max;
  1244. if (typeof o.keyboard_step === "string") o.keyboard_step = +o.keyboard_step;
  1245. if (typeof o.grid_num === "string") o.grid_num = +o.grid_num;
  1246. if (o.max <= o.min) {
  1247. if (o.min) {
  1248. o.max = o.min * 2;
  1249. } else {
  1250. o.max = o.min + 1;
  1251. }
  1252. o.step = 1;
  1253. }
  1254. if (vl) {
  1255. o.p_values = [];
  1256. o.min = 0;
  1257. o.max = vl - 1;
  1258. o.step = 1;
  1259. o.grid_num = o.max;
  1260. o.grid_snap = true;
  1261. for (i = 0; i < vl; i++) {
  1262. value = +v[i];
  1263. if (!isNaN(value)) {
  1264. v[i] = value;
  1265. value = this._prettify(value);
  1266. } else {
  1267. value = v[i];
  1268. }
  1269. o.p_values.push(value);
  1270. }
  1271. }
  1272. if (typeof o.from !== "number" || isNaN(o.from)) {
  1273. o.from = o.min;
  1274. }
  1275. if (typeof o.to !== "number" || isNaN(o.from)) {
  1276. o.to = o.max;
  1277. }
  1278. if (o.type === "single") {
  1279. if (o.from < o.min) {
  1280. o.from = o.min;
  1281. }
  1282. if (o.from > o.max) {
  1283. o.from = o.max;
  1284. }
  1285. } else {
  1286. if (o.from < o.min || o.from > o.max) {
  1287. o.from = o.min;
  1288. }
  1289. if (o.to > o.max || o.to < o.min) {
  1290. o.to = o.max;
  1291. }
  1292. if (o.from > o.to) {
  1293. o.from = o.to;
  1294. }
  1295. }
  1296. if (typeof o.step !== "number" || isNaN(o.step) || !o.step || o.step < 0) {
  1297. o.step = 1;
  1298. }
  1299. if (typeof o.keyboard_step !== "number" || isNaN(o.keyboard_step) || !o.keyboard_step || o.keyboard_step < 0) {
  1300. o.keyboard_step = 5;
  1301. }
  1302. if (typeof o.from_min === "number" && o.from < o.from_min) {
  1303. o.from = o.from_min;
  1304. }
  1305. if (typeof o.from_max === "number" && o.from > o.from_max) {
  1306. o.from = o.from_max;
  1307. }
  1308. if (typeof o.to_min === "number" && o.to < o.to_min) {
  1309. o.to = o.to_min;
  1310. }
  1311. if (typeof o.to_max === "number" && o.from > o.to_max) {
  1312. o.to = o.to_max;
  1313. }
  1314. if (r) {
  1315. if (r.min !== o.min) {
  1316. r.min = o.min;
  1317. }
  1318. if (r.max !== o.max) {
  1319. r.max = o.max;
  1320. }
  1321. if (r.from < r.min || r.from > r.max) {
  1322. r.from = o.from;
  1323. }
  1324. if (r.to < r.min || r.to > r.max) {
  1325. r.to = o.to;
  1326. }
  1327. }
  1328. if (typeof o.min_interval !== "number" || isNaN(o.min_interval) || !o.min_interval || o.min_interval < 0) {
  1329. o.min_interval = 0;
  1330. }
  1331. if (typeof o.max_interval !== "number" || isNaN(o.max_interval) || !o.max_interval || o.max_interval < 0) {
  1332. o.max_interval = 0;
  1333. }
  1334. if (o.min_interval && o.min_interval > o.max - o.min) {
  1335. o.min_interval = o.max - o.min;
  1336. }
  1337. if (o.max_interval && o.max_interval > o.max - o.min) {
  1338. o.max_interval = o.max - o.min;
  1339. }
  1340. },
  1341. decorate: function (num, original) {
  1342. var decorated = "",
  1343. o = this.options;
  1344. if (o.prefix) {
  1345. decorated += o.prefix;
  1346. }
  1347. decorated += num;
  1348. if (o.max_postfix) {
  1349. if (o.values.length && num === o.p_values[o.max]) {
  1350. decorated += o.max_postfix;
  1351. if (o.postfix) {
  1352. decorated += " ";
  1353. }
  1354. } else if (original === o.max) {
  1355. decorated += o.max_postfix;
  1356. if (o.postfix) {
  1357. decorated += " ";
  1358. }
  1359. }
  1360. }
  1361. if (o.postfix) {
  1362. decorated += o.postfix;
  1363. }
  1364. return decorated;
  1365. },
  1366. updateFrom: function () {
  1367. this.result.from = this.options.from;
  1368. this.result.from_percent = this.calcPercent(this.result.from);
  1369. if (this.options.values) {
  1370. this.result.from_value = this.options.values[this.result.from];
  1371. }
  1372. },
  1373. updateTo: function () {
  1374. this.result.to = this.options.to;
  1375. this.result.to_percent = this.calcPercent(this.result.to);
  1376. if (this.options.values) {
  1377. this.result.to_value = this.options.values[this.result.to];
  1378. }
  1379. },
  1380. updateResult: function () {
  1381. this.result.min = this.options.min;
  1382. this.result.max = this.options.max;
  1383. this.updateFrom();
  1384. this.updateTo();
  1385. },
  1386. // =============================================================================================================
  1387. // Grid
  1388. appendGrid: function () {
  1389. if (!this.options.grid) {
  1390. return;
  1391. }
  1392. var o = this.options,
  1393. i, z,
  1394. total = o.max - o.min,
  1395. big_num = o.grid_num,
  1396. big_p = 0,
  1397. big_w = 0,
  1398. small_max = 4,
  1399. local_small_max,
  1400. small_p,
  1401. small_w = 0,
  1402. result,
  1403. html = '';
  1404. this.calcGridMargin();
  1405. if (o.grid_snap) {
  1406. big_num = total / o.step;
  1407. big_p = this.toFixed(o.step / (total / 100));
  1408. } else {
  1409. big_p = this.toFixed(100 / big_num);
  1410. }
  1411. if (big_num > 4) {
  1412. small_max = 3;
  1413. }
  1414. if (big_num > 7) {
  1415. small_max = 2;
  1416. }
  1417. if (big_num > 14) {
  1418. small_max = 1;
  1419. }
  1420. if (big_num > 28) {
  1421. small_max = 0;
  1422. }
  1423. for (i = 0; i < big_num + 1; i++) {
  1424. local_small_max = small_max;
  1425. big_w = this.toFixed(big_p * i);
  1426. if (big_w > 100) {
  1427. big_w = 100;
  1428. local_small_max -= 2;
  1429. if (local_small_max < 0) {
  1430. local_small_max = 0;
  1431. }
  1432. }
  1433. this.coords.big[i] = big_w;
  1434. small_p = (big_w - (big_p * (i - 1))) / (local_small_max + 1);
  1435. for (z = 1; z <= local_small_max; z++) {
  1436. if (big_w === 0) {
  1437. break;
  1438. }
  1439. small_w = this.toFixed(big_w - (small_p * z));
  1440. html += '<span class="irs-grid-pol small" style="left: ' + small_w + '%"></span>';
  1441. }
  1442. html += '<span class="irs-grid-pol" style="left: ' + big_w + '%"></span>';
  1443. result = this.calcReal(big_w);
  1444. if (o.values.length) {
  1445. result = o.p_values[result];
  1446. } else {
  1447. result = this._prettify(result);
  1448. }
  1449. html += '<span class="irs-grid-text js-grid-text-' + i + '" style="left: ' + big_w + '%">' + result + '</span>';
  1450. }
  1451. this.coords.big_num = Math.ceil(big_num + 1);
  1452. this.$cache.cont.addClass("irs-with-grid");
  1453. this.$cache.grid.html(html);
  1454. this.cacheGridLabels();
  1455. },
  1456. cacheGridLabels: function () {
  1457. var $label, i,
  1458. num = this.coords.big_num;
  1459. for (i = 0; i < num; i++) {
  1460. $label = this.$cache.grid.find(".js-grid-text-" + i);
  1461. this.$cache.grid_labels.push($label);
  1462. }
  1463. this.calcGridLabels();
  1464. },
  1465. calcGridLabels: function () {
  1466. var i, label, start = [], finish = [],
  1467. num = this.coords.big_num;
  1468. for (i = 0; i < num; i++) {
  1469. this.coords.big_w[i] = this.$cache.grid_labels[i].outerWidth(false);
  1470. this.coords.big_p[i] = this.toFixed(this.coords.big_w[i] / this.coords.w_rs * 100);
  1471. this.coords.big_x[i] = this.toFixed(this.coords.big_p[i] / 2);
  1472. start[i] = this.toFixed(this.coords.big[i] - this.coords.big_x[i]);
  1473. finish[i] = this.toFixed(start[i] + this.coords.big_p[i]);
  1474. }
  1475. if (this.options.force_edges) {
  1476. if (start[0] < -this.coords.grid_gap) {
  1477. start[0] = -this.coords.grid_gap;
  1478. finish[0] = this.toFixed(start[0] + this.coords.big_p[0]);
  1479. this.coords.big_x[0] = this.coords.grid_gap;
  1480. }
  1481. if (finish[num - 1] > 100 + this.coords.grid_gap) {
  1482. finish[num - 1] = 100 + this.coords.grid_gap;
  1483. start[num - 1] = this.toFixed(finish[num - 1] - this.coords.big_p[num - 1]);
  1484. this.coords.big_x[num - 1] = this.toFixed(this.coords.big_p[num - 1] - this.coords.grid_gap);
  1485. }
  1486. }
  1487. this.calcGridCollision(2, start, finish);
  1488. this.calcGridCollision(4, start, finish);
  1489. for (i = 0; i < num; i++) {
  1490. label = this.$cache.grid_labels[i][0];
  1491. label.style.marginLeft = -this.coords.big_x[i] + "%";
  1492. }
  1493. },
  1494. // Collisions Calc Beta
  1495. // TODO: Refactor then have plenty of time
  1496. calcGridCollision: function (step, start, finish) {
  1497. var i, next_i, label,
  1498. num = this.coords.big_num;
  1499. for (i = 0; i < num; i += step) {
  1500. next_i = i + (step / 2);
  1501. if (next_i >= num) {
  1502. break;
  1503. }
  1504. label = this.$cache.grid_labels[next_i][0];
  1505. if (finish[i] <= start[next_i]) {
  1506. label.style.visibility = "visible";
  1507. } else {
  1508. label.style.visibility = "hidden";
  1509. }
  1510. }
  1511. },
  1512. calcGridMargin: function () {
  1513. if (!this.options.grid_margin) {
  1514. return;
  1515. }
  1516. this.coords.w_rs = this.$cache.rs.outerWidth(false);
  1517. if (!this.coords.w_rs) {
  1518. return;
  1519. }
  1520. if (this.options.type === "single") {
  1521. this.coords.w_handle = this.$cache.s_single.outerWidth(false);
  1522. } else {
  1523. this.coords.w_handle = this.$cache.s_from.outerWidth(false);
  1524. }
  1525. this.coords.p_handle = this.toFixed(this.coords.w_handle / this.coords.w_rs * 100);
  1526. this.coords.grid_gap = this.toFixed((this.coords.p_handle / 2) - 0.1);
  1527. this.$cache.grid[0].style.width = this.toFixed(100 - this.coords.p_handle) + "%";
  1528. this.$cache.grid[0].style.left = this.coords.grid_gap + "%";
  1529. },
  1530. // =============================================================================================================
  1531. // Public methods
  1532. update: function (options) {
  1533. if (!this.input) {
  1534. return;
  1535. }
  1536. this.is_update = true;
  1537. this.options.from = this.result.from;
  1538. this.options.to = this.result.to;
  1539. this.options = $.extend(this.options, options);
  1540. this.validate();
  1541. this.updateResult(options);
  1542. this.toggleInput();
  1543. this.remove();
  1544. this.init(true);
  1545. },
  1546. reset: function () {
  1547. if (!this.input) {
  1548. return;
  1549. }
  1550. this.updateResult();
  1551. this.update();
  1552. },
  1553. destroy: function () {
  1554. if (!this.input) {
  1555. return;
  1556. }
  1557. this.toggleInput();
  1558. this.$cache.input.prop("readonly", false);
  1559. $.data(this.input, "ionRangeSlider", null);
  1560. this.remove();
  1561. this.input = null;
  1562. this.options = null;
  1563. }
  1564. };
  1565. $.fn.ionRangeSlider = function (options) {
  1566. return this.each(function() {
  1567. if (!$.data(this, "ionRangeSlider")) {
  1568. $.data(this, "ionRangeSlider", new IonRangeSlider(this, options, plugin_count++));
  1569. }
  1570. });
  1571. };
  1572. // =================================================================================================================
  1573. // http://paulirish.com/2011/requestanimationframe-for-smart-animating/
  1574. // http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
  1575. // requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel
  1576. // MIT license
  1577. (function() {
  1578. var lastTime = 0;
  1579. var vendors = ['ms', 'moz', 'webkit', 'o'];
  1580. for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
  1581. window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
  1582. window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame']
  1583. || window[vendors[x]+'CancelRequestAnimationFrame'];
  1584. }
  1585. if (!window.requestAnimationFrame)
  1586. window.requestAnimationFrame = function(callback, element) {
  1587. var currTime = new Date().getTime();
  1588. var timeToCall = Math.max(0, 16 - (currTime - lastTime));
  1589. var id = window.setTimeout(function() { callback(currTime + timeToCall); },
  1590. timeToCall);
  1591. lastTime = currTime + timeToCall;
  1592. return id;
  1593. };
  1594. if (!window.cancelAnimationFrame)
  1595. window.cancelAnimationFrame = function(id) {
  1596. clearTimeout(id);
  1597. };
  1598. }());
  1599. } (jQuery, document, window, navigator));