bootstrap-slider.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  1. /* =========================================================
  2. * bootstrap-slider.js v2.0.0
  3. * http://www.eyecon.ro/bootstrap-slider
  4. * =========================================================
  5. * Copyright 2012 Stefan Petre
  6. *
  7. * Licensed under the Apache License, Version 2.0 (the "License");
  8. * you may not use this file except in compliance with the License.
  9. * You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS,
  15. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. * See the License for the specific language governing permissions and
  17. * limitations under the License.
  18. * ========================================================= */
  19. !function( $ ) {
  20. var Slider = function(element, options) {
  21. this.dragLocked = false;
  22. this.limit = 100000;
  23. this.element = $(element).hide();
  24. this.picker = $('<div class="slider">'+
  25. '<div class="slider-track">'+
  26. '<div class="slider-selection"></div>'+
  27. '<div class="slider-handle"></div>'+
  28. '<div class="slider-handle"></div>'+
  29. '</div>'+
  30. '<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>'+
  31. '</div>')
  32. .insertBefore(this.element)
  33. .append(this.element);
  34. this.id = this.element.data('slider-id')||options.id;
  35. if (this.id) {
  36. this.picker[0].id = this.id;
  37. }
  38. if (typeof Modernizr !== 'undefined' && Modernizr.touch) {
  39. this.touchCapable = true;
  40. }
  41. var tooltip = this.element.data('slider-tooltip')||options.tooltip;
  42. this.tooltip = this.picker.find('.tooltip');
  43. this.tooltipInner = this.tooltip.find('div.tooltip-inner');
  44. this.orientation = this.element.data('slider-orientation')||options.orientation;
  45. switch(this.orientation) {
  46. case 'vertical':
  47. this.picker.addClass('slider-vertical');
  48. this.stylePos = 'top';
  49. this.mousePos = 'pageY';
  50. this.sizePos = 'offsetHeight';
  51. this.tooltip.addClass('right')[0].style.left = '100%';
  52. break;
  53. default:
  54. this.picker
  55. .addClass('slider-horizontal')
  56. .css('width', this.element.outerWidth());
  57. this.orientation = 'horizontal';
  58. this.stylePos = 'left';
  59. this.mousePos = 'pageX';
  60. this.sizePos = 'offsetWidth';
  61. this.tooltip.addClass('top')[0].style.top = -this.tooltip.outerHeight() - 14 + 'px';
  62. break;
  63. }
  64. this.min = this.element.data('slider-min')||options.min;
  65. this.max = this.element.data('slider-max')||options.max;
  66. this.step = this.element.data('slider-step')||options.step;
  67. this.value = this.element.data('slider-value')||options.value;
  68. if (this.value[1]) {
  69. this.range = true;
  70. }
  71. this.selection = this.element.data('slider-selection')||options.selection;
  72. this.selectionEl = this.picker.find('.slider-selection');
  73. if (this.selection === 'none') {
  74. this.selectionEl.addClass('hide');
  75. }
  76. this.selectionElStyle = this.selectionEl[0].style;
  77. this.handle1 = this.picker.find('.slider-handle:first');
  78. this.handle1Stype = this.handle1[0].style;
  79. this.handle2 = this.picker.find('.slider-handle:last');
  80. this.handle2Stype = this.handle2[0].style;
  81. var handle = this.element.data('slider-handle')||options.handle;
  82. switch(handle) {
  83. case 'round':
  84. this.handle1.addClass('round');
  85. this.handle2.addClass('round');
  86. break
  87. case 'triangle':
  88. this.handle1.addClass('triangle');
  89. this.handle2.addClass('triangle');
  90. break
  91. }
  92. if (this.range) {
  93. this.value[0] = Math.max(this.min, Math.min(this.max, this.value[0]));
  94. this.value[1] = Math.max(this.min, Math.min(this.max, this.value[1]));
  95. } else {
  96. this.value = [ Math.max(this.min, Math.min(this.max, this.value))];
  97. this.handle2.addClass('hide');
  98. if (this.selection == 'after') {
  99. this.value[1] = this.max;
  100. } else {
  101. this.value[1] = this.min;
  102. }
  103. }
  104. this.diff = this.max - this.min;
  105. this.percentage = [
  106. (this.value[0]-this.min)*100/this.diff,
  107. (this.value[1]-this.min)*100/this.diff,
  108. this.step*100/this.diff
  109. ];
  110. this.offset = this.picker.offset();
  111. this.size = this.picker[0][this.sizePos];
  112. this.formater = options.formater;
  113. this.reversed = this.element.data('slider-reversed')||options.reversed;
  114. this.layout();
  115. if (this.touchCapable) {
  116. // Touch: Bind touch events:
  117. this.picker.on({
  118. touchstart: $.proxy(this.mousedown, this)
  119. });
  120. } else {
  121. this.picker.on({
  122. mousedown: $.proxy(this.mousedown, this)
  123. });
  124. }
  125. if (tooltip === 'show') {
  126. this.picker.on({
  127. mouseenter: $.proxy(this.showTooltip, this),
  128. mouseleave: $.proxy(this.hideTooltip, this)
  129. });
  130. } else {
  131. this.tooltip.addClass('hide');
  132. }
  133. };
  134. Slider.prototype = {
  135. constructor: Slider,
  136. over: false,
  137. inDrag: false,
  138. showTooltip: function(){
  139. this.tooltip.addClass('in');
  140. //var left = Math.round(this.percent*this.width);
  141. //this.tooltip.css('left', left - this.tooltip.outerWidth()/2);
  142. this.over = true;
  143. },
  144. hideTooltip: function(){
  145. if (this.inDrag === false) {
  146. this.tooltip.removeClass('in');
  147. }
  148. this.over = false;
  149. },
  150. layout: function(){
  151. var positionPercentages;
  152. if(this.reversed) {
  153. positionPercentages = [ this.percentage[1] - this.percentage[0], this.percentage[1] ];
  154. } else {
  155. positionPercentages = [ this.percentage[0], this.percentage[1] ];
  156. }
  157. this.handle1Stype[this.stylePos] = positionPercentages[0]+'%';
  158. this.handle2Stype[this.stylePos] = positionPercentages[1]+'%';
  159. if (this.orientation == 'vertical') {
  160. this.selectionElStyle.top = Math.min(positionPercentages[0], positionPercentages[1]) +'%';
  161. this.selectionElStyle.height = Math.abs(positionPercentages[0] - positionPercentages[1]) +'%';
  162. } else {
  163. this.selectionElStyle.left = Math.min(positionPercentages[0], positionPercentages[1]) +'%';
  164. this.selectionElStyle.width = Math.abs(positionPercentages[0] - positionPercentages[1]) +'%';
  165. }
  166. if (this.range) {
  167. this.tooltipInner.text(
  168. this.formater(this.value[0]) +
  169. ' : ' +
  170. this.formater(this.value[1])
  171. );
  172. this.tooltip[0].style[this.stylePos] = this.size * (positionPercentages[0] + (positionPercentages[1] - positionPercentages[0])/2)/100 - (this.orientation === 'vertical' ? this.tooltip.outerHeight()/2 : this.tooltip.outerWidth()/2) +'px';
  173. } else {
  174. this.tooltipInner.text(
  175. this.formater(this.value[0])
  176. );
  177. this.tooltip[0].style[this.stylePos] = this.size * positionPercentages[0]/100 - (this.orientation === 'vertical' ? this.tooltip.outerHeight()/2 : this.tooltip.outerWidth()/2) +'px';
  178. }
  179. },
  180. mousedown: function(ev) {
  181. if (!this.dragLocked){
  182. // Touch: Get the original event:
  183. if (this.touchCapable && ev.type === 'touchstart') {
  184. ev = ev.originalEvent;
  185. }
  186. this.offset = this.picker.offset();
  187. this.size = this.picker[0][this.sizePos];
  188. var percentage = this.getPercentage(ev);
  189. if (this.range) {
  190. var diff1 = Math.abs(this.percentage[0] - percentage);
  191. var diff2 = Math.abs(this.percentage[1] - percentage);
  192. this.dragged = (diff1 < diff2) ? 0 : 1;
  193. } else {
  194. this.dragged = 0;
  195. }
  196. this.percentage[this.dragged] = this.reversed ? this.percentage[1] - percentage : percentage;
  197. this.layout();
  198. if (this.touchCapable) {
  199. // Touch: Bind touch events:
  200. $(document).on({
  201. touchmove: $.proxy(this.mousemove, this),
  202. touchend: $.proxy(this.mouseup, this)
  203. });
  204. } else {
  205. $(document).on({
  206. mousemove: $.proxy(this.mousemove, this),
  207. mouseup: $.proxy(this.mouseup, this)
  208. });
  209. }
  210. this.inDrag = true;
  211. var val = this.calculateValue();
  212. this.setValue(val);
  213. this.element.trigger({
  214. type: 'slideStart',
  215. value: val
  216. }).trigger({
  217. type: 'slide',
  218. value: val
  219. });
  220. return false;
  221. }
  222. },
  223. mousemove: function(ev) {
  224. // Touch: Get the original event:
  225. if (!this.dragLocked){
  226. if (this.touchCapable && ev.type === 'touchmove') {
  227. ev = ev.originalEvent;
  228. }
  229. var percentage = this.getPercentage(ev);
  230. if (this.range) {
  231. if (this.dragged === 0 && this.percentage[1] < percentage) {
  232. this.percentage[0] = this.percentage[1];
  233. this.dragged = 1;
  234. } else if (this.dragged === 1 && this.percentage[0] > percentage) {
  235. this.percentage[1] = this.percentage[0];
  236. this.dragged = 0;
  237. }
  238. }
  239. x = this.reversed ? this.percentage[1] - percentage : percentage;
  240. if (x > this.limit) {
  241. return ;
  242. }
  243. this.percentage[this.dragged] = x;
  244. this.layout();
  245. var val = this.calculateValue();
  246. this.setValue(val);
  247. this.element
  248. .trigger({
  249. type: 'slide',
  250. value: val
  251. })
  252. .data('value', val)
  253. .prop('value', val);
  254. return false;
  255. }
  256. },
  257. mouseup: function(ev) {
  258. if (this.touchCapable) {
  259. // Touch: Bind touch events:
  260. $(document).off({
  261. touchmove: this.mousemove,
  262. touchend: this.mouseup
  263. });
  264. } else {
  265. $(document).off({
  266. mousemove: this.mousemove,
  267. mouseup: this.mouseup
  268. });
  269. }
  270. this.inDrag = false;
  271. if (this.over == false) {
  272. this.hideTooltip();
  273. }
  274. this.element;
  275. var val = this.calculateValue();
  276. this.layout();
  277. this.element
  278. .trigger({
  279. type: 'slideStop',
  280. value: val
  281. })
  282. .data('value', val)
  283. .prop('value', val);
  284. return false;
  285. },
  286. calculateValue: function() {
  287. var val;
  288. if (this.range) {
  289. val = [
  290. (this.min + Math.round((this.diff * this.percentage[0]/100)/this.step)*this.step),
  291. (this.min + Math.round((this.diff * this.percentage[1]/100)/this.step)*this.step)
  292. ];
  293. this.value = val;
  294. } else {
  295. val = (this.min + Math.round((this.diff * this.percentage[0]/100)/this.step)*this.step);
  296. this.value = [val, this.value[1]];
  297. }
  298. return val;
  299. },
  300. getPercentage: function(ev) {
  301. if (this.touchCapable) {
  302. ev = ev.touches[0];
  303. }
  304. var percentage = (ev[this.mousePos] - this.offset[this.stylePos])*100/this.size;
  305. percentage = Math.round(percentage/this.percentage[2])*this.percentage[2];
  306. return Math.max(0, Math.min(100, percentage));
  307. },
  308. getValue: function() {
  309. if (this.range) {
  310. return this.value;
  311. }
  312. return this.value[0];
  313. },
  314. setLimit: function(val) {
  315. this.limit = val;
  316. },
  317. setDragLocked: function(val) {
  318. this.dragLocked = val;
  319. },
  320. getDragLocked: function(val) {
  321. return this.dragLocked;
  322. },
  323. setValue: function(val) {
  324. this.value = val;
  325. if (this.range) {
  326. this.value[0] = Math.max(this.min, Math.min(this.max, this.value[0]));
  327. this.value[1] = Math.max(this.min, Math.min(this.max, this.value[1]));
  328. } else {
  329. this.value = [ Math.max(this.min, Math.min(this.max, this.value))];
  330. this.handle2.addClass('hide');
  331. if (this.selection == 'after') {
  332. this.value[1] = this.max;
  333. } else {
  334. this.value[1] = this.min;
  335. }
  336. }
  337. this.diff = this.max - this.min;
  338. this.percentage = [
  339. (this.value[0]-this.min)*100/this.diff,
  340. (this.value[1]-this.min)*100/this.diff,
  341. this.step*100/this.diff
  342. ];
  343. this.layout();
  344. },
  345. destroy: function(){
  346. this.element.show().insertBefore(this.picker);
  347. this.picker.remove();
  348. },
  349. };
  350. $.fn.slider = function ( option, val ) {
  351. return this.each(function () {
  352. var $this = $(this),
  353. data = $this.data('slider'),
  354. options = typeof option === 'object' && option;
  355. if (!data) {
  356. $this.data('slider', (data = new Slider(this, $.extend({}, $.fn.slider.defaults,options))));
  357. }
  358. if (typeof option == 'string') {
  359. data[option](val);
  360. }
  361. })
  362. };
  363. $.fn.slider.defaults = {
  364. min: 0,
  365. max: 10,
  366. step: 1,
  367. orientation: 'horizontal',
  368. value: 5,
  369. selection: 'before',
  370. tooltip: 'show',
  371. handle: 'round',
  372. reversed : false,
  373. limit: 100000,
  374. dragLocked: false,
  375. formater: function(value) {
  376. return value;
  377. }
  378. };
  379. $.fn.slider.Constructor = Slider;
  380. }( window.jQuery );