bootstrap-slider.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  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.element = $(element);
  22. this.picker = $('<div class="slider">'+
  23. '<div class="slider-track">'+
  24. '<div class="slider-selection"></div>'+
  25. '<div class="slider-handle"></div>'+
  26. '<div class="slider-handle"></div>'+
  27. '</div>'+
  28. '<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>'+
  29. '</div>')
  30. .insertBefore(this.element)
  31. .append(this.element);
  32. this.id = this.element.data('slider-id')||options.id;
  33. if (this.id) {
  34. this.picker[0].id = this.id;
  35. }
  36. if (typeof Modernizr !== 'undefined' && Modernizr.touch) {
  37. this.touchCapable = true;
  38. }
  39. var tooltip = this.element.data('slider-tooltip')||options.tooltip;
  40. this.tooltip = this.picker.find('.tooltip');
  41. this.tooltipInner = this.tooltip.find('div.tooltip-inner');
  42. this.orientation = this.element.data('slider-orientation')||options.orientation;
  43. switch(this.orientation) {
  44. case 'vertical':
  45. this.picker.addClass('slider-vertical');
  46. this.stylePos = 'top';
  47. this.mousePos = 'pageY';
  48. this.sizePos = 'offsetHeight';
  49. this.tooltip.addClass('right')[0].style.left = '100%';
  50. break;
  51. default:
  52. this.picker
  53. .addClass('slider-horizontal')
  54. .css('width', this.element.outerWidth());
  55. this.orientation = 'horizontal';
  56. this.stylePos = 'left';
  57. this.mousePos = 'pageX';
  58. this.sizePos = 'offsetWidth';
  59. this.tooltip.addClass('top')[0].style.top = -this.tooltip.outerHeight() - 14 + 'px';
  60. break;
  61. }
  62. this.min = this.element.data('slider-min')||options.min;
  63. this.max = this.element.data('slider-max')||options.max;
  64. this.step = this.element.data('slider-step')||options.step;
  65. this.value = this.element.data('slider-value')||options.value;
  66. if (this.value[1]) {
  67. this.range = true;
  68. }
  69. this.selection = this.element.data('slider-selection')||options.selection;
  70. this.selectionEl = this.picker.find('.slider-selection');
  71. if (this.selection === 'none') {
  72. this.selectionEl.addClass('hide');
  73. }
  74. this.selectionElStyle = this.selectionEl[0].style;
  75. this.handle1 = this.picker.find('.slider-handle:first');
  76. this.handle1Stype = this.handle1[0].style;
  77. this.handle2 = this.picker.find('.slider-handle:last');
  78. this.handle2Stype = this.handle2[0].style;
  79. var handle = this.element.data('slider-handle')||options.handle;
  80. switch(handle) {
  81. case 'round':
  82. this.handle1.addClass('round');
  83. this.handle2.addClass('round');
  84. break
  85. case 'triangle':
  86. this.handle1.addClass('triangle');
  87. this.handle2.addClass('triangle');
  88. break
  89. }
  90. if (this.range) {
  91. this.value[0] = Math.max(this.min, Math.min(this.max, this.value[0]));
  92. this.value[1] = Math.max(this.min, Math.min(this.max, this.value[1]));
  93. } else {
  94. this.value = [ Math.max(this.min, Math.min(this.max, this.value))];
  95. this.handle2.addClass('hide');
  96. if (this.selection == 'after') {
  97. this.value[1] = this.max;
  98. } else {
  99. this.value[1] = this.min;
  100. }
  101. }
  102. this.diff = this.max - this.min;
  103. this.percentage = [
  104. (this.value[0]-this.min)*100/this.diff,
  105. (this.value[1]-this.min)*100/this.diff,
  106. this.step*100/this.diff
  107. ];
  108. this.offset = this.picker.offset();
  109. this.size = this.picker[0][this.sizePos];
  110. this.formater = options.formater;
  111. this.layout();
  112. if (this.touchCapable) {
  113. // Touch: Bind touch events:
  114. this.picker.on({
  115. touchstart: $.proxy(this.mousedown, this)
  116. });
  117. } else {
  118. this.picker.on({
  119. mousedown: $.proxy(this.mousedown, this)
  120. });
  121. }
  122. if (tooltip === 'show') {
  123. this.picker.on({
  124. mouseenter: $.proxy(this.showTooltip, this),
  125. mouseleave: $.proxy(this.hideTooltip, this)
  126. });
  127. } else {
  128. this.tooltip.addClass('hide');
  129. }
  130. };
  131. Slider.prototype = {
  132. constructor: Slider,
  133. over: false,
  134. inDrag: false,
  135. showTooltip: function(){
  136. this.tooltip.addClass('in');
  137. //var left = Math.round(this.percent*this.width);
  138. //this.tooltip.css('left', left - this.tooltip.outerWidth()/2);
  139. this.over = true;
  140. },
  141. hideTooltip: function(){
  142. if (this.inDrag === false) {
  143. this.tooltip.removeClass('in');
  144. }
  145. this.over = false;
  146. },
  147. layout: function(){
  148. this.handle1Stype[this.stylePos] = this.percentage[0]+'%';
  149. this.handle2Stype[this.stylePos] = this.percentage[1]+'%';
  150. if (this.orientation == 'vertical') {
  151. this.selectionElStyle.top = Math.min(this.percentage[0], this.percentage[1]) +'%';
  152. this.selectionElStyle.height = Math.abs(this.percentage[0] - this.percentage[1]) +'%';
  153. } else {
  154. this.selectionElStyle.left = Math.min(this.percentage[0], this.percentage[1]) +'%';
  155. this.selectionElStyle.width = Math.abs(this.percentage[0] - this.percentage[1]) +'%';
  156. }
  157. if (this.range) {
  158. this.tooltipInner.text(
  159. this.formater(this.value[0]) +
  160. ' : ' +
  161. this.formater(this.value[1])
  162. );
  163. this.tooltip[0].style[this.stylePos] = this.size * (this.percentage[0] + (this.percentage[1] - this.percentage[0])/2)/100 - (this.orientation === 'vertical' ? this.tooltip.outerHeight()/2 : this.tooltip.outerWidth()/2) +'px';
  164. } else {
  165. this.tooltipInner.text(
  166. this.formater(this.value[0])
  167. );
  168. this.tooltip[0].style[this.stylePos] = this.size * this.percentage[0]/100 - (this.orientation === 'vertical' ? this.tooltip.outerHeight()/2 : this.tooltip.outerWidth()/2) +'px';
  169. }
  170. },
  171. mousedown: function(ev) {
  172. // Touch: Get the original event:
  173. if (this.touchCapable && ev.type === 'touchstart') {
  174. ev = ev.originalEvent;
  175. }
  176. this.offset = this.picker.offset();
  177. this.size = this.picker[0][this.sizePos];
  178. var percentage = this.getPercentage(ev);
  179. if (this.range) {
  180. var diff1 = Math.abs(this.percentage[0] - percentage);
  181. var diff2 = Math.abs(this.percentage[1] - percentage);
  182. this.dragged = (diff1 < diff2) ? 0 : 1;
  183. } else {
  184. this.dragged = 0;
  185. }
  186. this.percentage[this.dragged] = percentage;
  187. this.layout();
  188. if (this.touchCapable) {
  189. // Touch: Bind touch events:
  190. $(document).on({
  191. touchmove: $.proxy(this.mousemove, this),
  192. touchend: $.proxy(this.mouseup, this)
  193. });
  194. } else {
  195. $(document).on({
  196. mousemove: $.proxy(this.mousemove, this),
  197. mouseup: $.proxy(this.mouseup, this)
  198. });
  199. }
  200. this.inDrag = true;
  201. var val = this.calculateValue();
  202. this.element.trigger({
  203. type: 'slideStart',
  204. value: val
  205. }).trigger({
  206. type: 'slide',
  207. value: val
  208. });
  209. return false;
  210. },
  211. mousemove: function(ev) {
  212. // Touch: Get the original event:
  213. if (this.touchCapable && ev.type === 'touchmove') {
  214. ev = ev.originalEvent;
  215. }
  216. var percentage = this.getPercentage(ev);
  217. if (this.range) {
  218. if (this.dragged === 0 && this.percentage[1] < percentage) {
  219. this.percentage[0] = this.percentage[1];
  220. this.dragged = 1;
  221. } else if (this.dragged === 1 && this.percentage[0] > percentage) {
  222. this.percentage[1] = this.percentage[0];
  223. this.dragged = 0;
  224. }
  225. }
  226. this.percentage[this.dragged] = percentage;
  227. this.layout();
  228. var val = this.calculateValue();
  229. this.element
  230. .trigger({
  231. type: 'slide',
  232. value: val
  233. })
  234. .data('value', val)
  235. .prop('value', val);
  236. return false;
  237. },
  238. mouseup: function(ev) {
  239. if (this.touchCapable) {
  240. // Touch: Bind touch events:
  241. $(document).off({
  242. touchmove: this.mousemove,
  243. touchend: this.mouseup
  244. });
  245. } else {
  246. $(document).off({
  247. mousemove: this.mousemove,
  248. mouseup: this.mouseup
  249. });
  250. }
  251. this.inDrag = false;
  252. if (this.over == false) {
  253. this.hideTooltip();
  254. }
  255. this.element;
  256. var val = this.calculateValue();
  257. this.element
  258. .trigger({
  259. type: 'slideStop',
  260. value: val
  261. })
  262. .data('value', val)
  263. .prop('value', val);
  264. return false;
  265. },
  266. calculateValue: function() {
  267. var val;
  268. if (this.range) {
  269. val = [
  270. (this.min + Math.round((this.diff * this.percentage[0]/100)/this.step)*this.step),
  271. (this.min + Math.round((this.diff * this.percentage[1]/100)/this.step)*this.step)
  272. ];
  273. this.value = val;
  274. } else {
  275. val = (this.min + Math.round((this.diff * this.percentage[0]/100)/this.step)*this.step);
  276. this.value = [val, this.value[1]];
  277. }
  278. return val;
  279. },
  280. getPercentage: function(ev) {
  281. if (this.touchCapable) {
  282. ev = ev.touches[0];
  283. }
  284. var percentage = (ev[this.mousePos] - this.offset[this.stylePos])*100/this.size;
  285. percentage = Math.round(percentage/this.percentage[2])*this.percentage[2];
  286. return Math.max(0, Math.min(100, percentage));
  287. },
  288. getValue: function() {
  289. if (this.range) {
  290. return this.value;
  291. }
  292. return this.value[0];
  293. },
  294. setValue: function(val) {
  295. this.value = val;
  296. if (this.range) {
  297. this.value[0] = Math.max(this.min, Math.min(this.max, this.value[0]));
  298. this.value[1] = Math.max(this.min, Math.min(this.max, this.value[1]));
  299. } else {
  300. this.value = [ Math.max(this.min, Math.min(this.max, this.value))];
  301. this.handle2.addClass('hide');
  302. if (this.selection == 'after') {
  303. this.value[1] = this.max;
  304. } else {
  305. this.value[1] = this.min;
  306. }
  307. }
  308. this.diff = this.max - this.min;
  309. this.percentage = [
  310. (this.value[0]-this.min)*100/this.diff,
  311. (this.value[1]-this.min)*100/this.diff,
  312. this.step*100/this.diff
  313. ];
  314. this.layout();
  315. }
  316. };
  317. $.fn.slider = function ( option, val ) {
  318. return this.each(function () {
  319. var $this = $(this),
  320. data = $this.data('slider'),
  321. options = typeof option === 'object' && option;
  322. if (!data) {
  323. $this.data('slider', (data = new Slider(this, $.extend({}, $.fn.slider.defaults,options))));
  324. }
  325. if (typeof option == 'string') {
  326. data[option](val);
  327. }
  328. })
  329. };
  330. $.fn.slider.defaults = {
  331. min: 0,
  332. max: 10,
  333. step: 1,
  334. orientation: 'horizontal',
  335. value: 5,
  336. selection: 'before',
  337. tooltip: 'show',
  338. handle: 'round',
  339. formater: function(value) {
  340. return value;
  341. }
  342. };
  343. $.fn.slider.Constructor = Slider;
  344. }( window.jQuery );