├── LICENSE ├── README.md ├── bower.json ├── build.sh ├── demo ├── index.html └── js │ └── app.js ├── dist ├── angular-slidezilla.min.js └── angular-slidezilla.min.js.map └── src ├── angular-slidezilla.css └── angular-slidezilla.js /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Lenny 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Angular Slidezilla 2 | ======================== 3 | 4 | Angular Slidezilla is a pure angular slider directive which makes it incredibly simple to have reliable sliders in angular. 5 | 6 | Talk is cheap: [See THE DEMO here](http://itslenny.github.io/angular-slidezilla/). 7 | 8 | ##Why Slidezilla? 9 | 10 | There are several other angular slider directives. Most of them depend on jQuery and/or are really glitchy or don't have the features I wanted. So I created my own and I needed a unique name for the plugin and this was the first thing that popped in my head. 11 | 12 | 13 | ##Installation 14 | 15 | Dependencies: Angular 16 | 17 | Download and include angular-slidezilla.js and pretty-slidezilla.css 18 | 19 | Create an angular app and inject angular-slidezilla. That's about it. 20 | 21 | **bower** 22 | ```bash 23 | bower install angular-slidezilla 24 | ``` 25 | 26 | ##Usage 27 | 28 | **basic** 29 | ```html 30 | 31 | ``` 32 | controller: 33 | ```js 34 | //set slider value as a number to have 1 slider 35 | //all properties default values 36 | $scope.slider1 = {val:5}; 37 | ``` 38 | 39 | **static** 40 | ```html 41 | 42 | ``` 43 | controller: 44 | ```js 45 | //set slider value as a number to have 1 slider 46 | // properties defined in html 47 | $scope.slider2 = {val:-7}; 48 | ``` 49 | 50 | **dynamic** 51 | ```html 52 | 53 | ``` 54 | controller: 55 | ```js 56 | //set slider value as a number to have 1 slider 57 | // properties defined below 58 | $scope.slider3 = { 59 | val:5.5, 60 | min: 0, 61 | max: 10, 62 | step: 0.5 63 | }; 64 | ``` 65 | 66 | **range** 67 | ```html 68 | 69 | ``` 70 | controller: 71 | ```js 72 | //set value as an array to have 2 sliders 73 | $scope.slider4 = { val:[5,20] }; 74 | ``` 75 | 76 | ##Configuration 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 |
NameValuesDescriptionDefault
minvariable or number (float)Min value of slider.0
maxvariable or number (float)Max value of slider100
stepvariable or number (float)Step value of slider. Slider will increment by this value.5
106 | 107 | 108 | ##Customization 109 | 110 | Simply modify angular-slidezilla.css 111 | 112 | 113 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-slidezilla", 3 | "main": [ 4 | "dist/angular-slidezilla.min.js", 5 | "dist/angular-slidezilla.min.js.map", 6 | "src/angular-slidezilla.css" 7 | ], 8 | "ignore": [ 9 | "source", 10 | "spec", 11 | ".bowerrc", 12 | ".gitignore", 13 | ".jshintignore", 14 | ".jshintrc", 15 | "bower.json", 16 | "gruntfile.js", 17 | "package.json", 18 | "README.md", 19 | "build.sh" 20 | ], 21 | "dependencies": { 22 | "angular": "~1.2.13" 23 | } 24 | } -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #creates minified version and source map 4 | #requires uglifyjs -- npm install uglifyjs -g 5 | 6 | PROJECT_NAME=angular-slidezilla 7 | 8 | uglifyjs ./src/${PROJECT_NAME}.js --comments --source-map ./dist/${PROJECT_NAME}.min.js.map --source-map-url ${PROJECT_NAME}.min.js.map --output ./dist/${PROJECT_NAME}.min.js 9 | 10 | 11 | -------------------------------------------------------------------------------- /demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Angular Slidezilla 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 |
15 |

Angular Slidezilla Demo

16 |
17 |
18 |
19 | This is the demo of Angular Slidezilla: a simple slider directive. 20 |

21 | View source on this page to see the various options available (also available in the github repo). 22 |

23 | For more information and full documents see Github 24 |
25 |
26 |
27 |

Basic

28 | 29 |

30 | Value: {{slider1.val}} 31 |
32 |
33 |

Static

34 | 35 |

36 | Value: {{slider2.val}} 37 |
38 |
39 |

Dynamic

40 |
41 | Value: {{slider3.val}} 42 |


43 | Min: {{slider3.min}}
44 |

45 | Max: {{slider3.max}}
46 |

47 | Step: {{slider3.step}}
48 | 49 |

50 | 51 |
52 |
53 |

Range

54 | 55 |

56 | Values: {{slider4.val}} 57 |
58 |
59 |
60 |
61 | 62 | -------------------------------------------------------------------------------- /demo/js/app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var myApp = angular.module('myapp', ['angular-slidezilla']) 4 | 5 | myApp.controller('sliderdemo', ['$scope',function($scope){ 6 | 7 | //set slider value as a number to have 1 slider 8 | //all properties default values 9 | $scope.slider1 = {val:5}; 10 | 11 | //set slider value as a number to have 1 slider 12 | // properties defined in html 13 | $scope.slider2 = {val:-7}; 14 | 15 | //set slider value as a number to have 1 slider 16 | // properties defined below 17 | $scope.slider3 = { 18 | val:5.5, 19 | min: 0, 20 | max: 10, 21 | step: 0.5 22 | }; 23 | 24 | //set value as an array to have 2 sliders 25 | $scope.slider4 = { val:[5,20] }; 26 | 27 | }]); 28 | -------------------------------------------------------------------------------- /dist/angular-slidezilla.min.js: -------------------------------------------------------------------------------- 1 | /* @preserve 2 | * 3 | * angular-slidezilla 4 | * https://github.com/itslenny/angular-slidezilla 5 | * 6 | * Version: 0.1.3 - 02/21/2015 7 | * License: MIT 8 | */ 9 | "use strict";angular.module("angular-slidezilla",[]).constant("angularSlidezillaConfig",{min:0,max:100,step:5}).controller("AngularSlidezillaController",["angularSlidezillaConfig","$scope",function(angularSlidezillaConfig,$scope){$scope.min=angularSlidezillaConfig.min||0;$scope.max=angularSlidezillaConfig.max||100;$scope.step=angularSlidezillaConfig.step||5}]).directive("slider",function(){return{scope:{model:"=ngModel"},restrict:"E",require:["ngModel"],controller:"AngularSlidezillaController",link:function(scope,element,attrs,ctrls){if(attrs.min){scope.min=scope.$parent.$eval(attrs.min);scope.$parent.$watch(attrs.min,function(newVal){scope.min=newVal;ctrls[0].$render()})}if(attrs.max){scope.max=scope.$parent.$eval(attrs.max);scope.$parent.$watch(attrs.max,function(newVal){scope.max=newVal;ctrls[0].$render()})}if(attrs.step){scope.step=scope.$parent.$eval(attrs.step);scope.$parent.$watch(attrs.step,function(newVal){scope.step=newVal;ctrls[0].$render()})}var handles=element[0].querySelectorAll(".slider-handle");var track=element[0].querySelector(".slider-track");var selection=element[0].querySelector(".slider-selection");var dragging=false;ctrls[0].$render=function(){var hPos1,hPos2;clampModelValue();ctrls[0].$setViewValue(scope.model);if(typeof scope.model=="number"){hPos1=0;hPos2=100/(scope.max-scope.min)*(scope.model-scope.max)+100;angular.element(handles[0]).css("margin-left",hPos2+"%");angular.element(handles[1]).addClass("hidden")}else{hPos1=100/(scope.max-scope.min)*(scope.model[0]-scope.max)+100;hPos2=100/(scope.max-scope.min)*(scope.model[1]-scope.max)+100;angular.element(handles[0]).css("margin-left",hPos1+"%");angular.element(handles[1]).css("margin-left",hPos2+"%").removeClass("hidden")}angular.element(selection).css("margin-left",hPos1+"%").css("width",hPos2-hPos1+1+"%")};angular.element(track).bind("mousedown",function(e){e.preventDefault();if(dragging)return;var newVal=scope.model;var offsetX=e.offsetX||e.layerX;if(typeof newVal=="number"){if(offsetX>handles[0].offsetLeft){newVal+=scope.step}else{newVal-=scope.step}}else{if(e.target==track&&offsetXhandles[1].offsetLeft){newVal[1]+=scope.step}else{if(e.target==selection&&offsetX>e.target.offsetWidth/2){newVal[1]-=scope.step}else{newVal[0]+=scope.step}}}scope.$apply(function(){scope.model=newVal;ctrls[0].$render()})});angular.element(handles).bind("mousedown",function(e){e.preventDefault();dragging={sx:e.clientX-e.target.offsetLeft,sy:e.clientY-e.target.offsetTop,w:e.target.offsetWidth,h:e.target.offsetHeight,element:e.target,index:e.target==handles[0]?0:1,container:e.target.parentElement.getBoundingClientRect()};angular.element(document).bind("mousemove",mousemove);angular.element(document).bind("mouseup",mouseup)});function mousemove(e){if(!dragging)return;dragging.y=e.clientY-dragging.sy;dragging.x=e.clientX-dragging.sx;if(dragging.x<0){dragging.x=0}else if(dragging.x>dragging.container.right-dragging.container.left){dragging.x=dragging.container.right-dragging.container.left}var percentVal=Math.max(0,Math.min(100,parseInt(dragging.x/(dragging.container.right-dragging.container.left)*100)));var normalizedVal=percentVal/100*(scope.max-scope.min)+scope.min;normalizedVal=parseFloat(normalizedVal.toFixed(3));var rounded=roundToStep(normalizedVal,scope.step);scope.$apply(function(){var setMVal=scope.model;if(typeof setMVal=="number"){setMVal=rounded}else{setMVal[dragging.index]=rounded}scope.model=setMVal;ctrls[0].$render()})}function mouseup(e){angular.element(document).unbind("mousemove",mousemove);angular.element(document).unbind("mouseup",mouseup);dragging=false}function roundToStep(val,step){return val>=0?val+step/2-(val+step/2)%step:val-step/2-(val+step/2)%step}function clampModelValue(){if(typeof scope.model=="number"){if(scope.model>scope.max){scope.model=scope.max}else if(scope.modelscope.model[1]){cv1=scope.model[0];cv0=scope.model[1];scope.model[0]=cv0;scope.model[1]=cv1}if(scope.model[0]>scope.max){cv0=scope.max}else if(scope.model[0]scope.max){cv1=scope.max}else if(scope.model[1]
',replace:true}}); 10 | //# sourceMappingURL=angular-slidezilla.min.js.map -------------------------------------------------------------------------------- /dist/angular-slidezilla.min.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"./dist/angular-slidezilla.min.js","sources":["./src/angular-slidezilla.js"],"names":["angular","module","constant","min","max","step","controller","angularSlidezillaConfig","$scope","directive","scope","model","restrict","require","link","element","attrs","ctrls","$parent","$eval","$watch","newVal","$render","handles","querySelectorAll","track","querySelector","selection","dragging","hPos1","hPos2","clampModelValue","$setViewValue","css","addClass","removeClass","bind","e","preventDefault","offsetX","layerX","offsetLeft","target","offsetWidth","$apply","sx","clientX","sy","clientY","offsetTop","w","h","offsetHeight","index","container","parentElement","getBoundingClientRect","document","mousemove","mouseup","y","x","right","left","percentVal","Math","parseInt","normalizedVal","parseFloat","toFixed","rounded","roundToStep","setMVal","unbind","val","cv0","cv1","template","replace"],"mappings":"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"} -------------------------------------------------------------------------------- /src/angular-slidezilla.css: -------------------------------------------------------------------------------- 1 | .slider { 2 | display: inline-block; 3 | vertical-align: middle; 4 | position: relative; 5 | } 6 | .slider.slider-horizontal { 7 | width: 210px; 8 | height: 20px; 9 | } 10 | .slider.slider-horizontal .slider-track { 11 | height: 10px; 12 | width: 100%; 13 | margin-top: -5px; 14 | top: 50%; 15 | left: 0; 16 | } 17 | .slider.slider-horizontal .slider-selection { 18 | height: 100%; 19 | top: 0; 20 | bottom: 0; 21 | } 22 | .slider.slider-horizontal .slider-handle { 23 | margin-left: -10px; 24 | margin-top: -5px; 25 | } 26 | .slider.slider-horizontal .slider-handle.triangle { 27 | border-width: 0 10px 10px 10px; 28 | width: 0; 29 | height: 0; 30 | border-bottom-color: #0480be; 31 | margin-top: 0; 32 | } 33 | .slider.slider-vertical { 34 | height: 210px; 35 | width: 20px; 36 | } 37 | .slider.slider-vertical .slider-track { 38 | width: 10px; 39 | height: 100%; 40 | margin-left: -5px; 41 | left: 50%; 42 | top: 0; 43 | } 44 | .slider.slider-vertical .slider-selection { 45 | width: 100%; 46 | left: 0; 47 | top: 0; 48 | bottom: 0; 49 | } 50 | .slider.slider-vertical .slider-handle { 51 | margin-left: -5px; 52 | margin-top: -10px; 53 | } 54 | .slider.slider-vertical .slider-handle.triangle { 55 | border-width: 10px 0 10px 10px; 56 | width: 1px; 57 | height: 1px; 58 | border-left-color: #0480be; 59 | margin-left: 0; 60 | } 61 | .slider input { 62 | display: none; 63 | } 64 | .slider .tooltip-inner { 65 | white-space: nowrap; 66 | } 67 | .slider-track { 68 | position: absolute; 69 | cursor: pointer; 70 | background-color: #f7f7f7; 71 | background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9); 72 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9)); 73 | background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9); 74 | background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9); 75 | background-image: linear-gradient(to bottom, #f5f5f5, #f9f9f9); 76 | background-repeat: repeat-x; 77 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#fff9f9f9', GradientType=0); 78 | -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); 79 | -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); 80 | box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); 81 | -webkit-border-radius: 4px; 82 | -moz-border-radius: 4px; 83 | border-radius: 4px; 84 | } 85 | .slider-selection { 86 | position: absolute; 87 | background-color: #f7f7f7; 88 | background-image: -moz-linear-gradient(top, #f9f9f9, #f5f5f5); 89 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f9f9f9), to(#f5f5f5)); 90 | background-image: -webkit-linear-gradient(top, #f9f9f9, #f5f5f5); 91 | background-image: -o-linear-gradient(top, #f9f9f9, #f5f5f5); 92 | background-image: linear-gradient(to bottom, #f9f9f9, #f5f5f5); 93 | background-repeat: repeat-x; 94 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff9f9f9', endColorstr='#fff5f5f5', GradientType=0); 95 | -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); 96 | -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); 97 | box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); 98 | -webkit-box-sizing: border-box; 99 | -moz-box-sizing: border-box; 100 | box-sizing: border-box; 101 | -webkit-border-radius: 4px; 102 | -moz-border-radius: 4px; 103 | border-radius: 4px; 104 | } 105 | .slider-handle { 106 | position: absolute; 107 | width: 20px; 108 | height: 20px; 109 | background-color: #0e90d2; 110 | background-image: -moz-linear-gradient(top, #149bdf, #0480be); 111 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be)); 112 | background-image: -webkit-linear-gradient(top, #149bdf, #0480be); 113 | background-image: -o-linear-gradient(top, #149bdf, #0480be); 114 | background-image: linear-gradient(to bottom, #149bdf, #0480be); 115 | background-repeat: repeat-x; 116 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf', endColorstr='#ff0480be', GradientType=0); 117 | -webkit-box-shadow: inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05); 118 | -moz-box-shadow: inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05); 119 | box-shadow: inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05); 120 | opacity: 0.8; 121 | border: 0px solid transparent; 122 | } 123 | .slider-handle.round { 124 | -webkit-border-radius: 20px; 125 | -moz-border-radius: 20px; 126 | border-radius: 20px; 127 | } 128 | 129 | .slider-handle.hidden{ 130 | display: none; 131 | } -------------------------------------------------------------------------------- /src/angular-slidezilla.js: -------------------------------------------------------------------------------- 1 | /* @preserve 2 | * 3 | * angular-slidezilla 4 | * https://github.com/itslenny/angular-slidezilla 5 | * 6 | * Version: 0.1.3 - 02/21/2015 7 | * License: MIT 8 | */ 9 | 10 | 'use strict'; 11 | 12 | //init module 13 | angular.module('angular-slidezilla', []) 14 | 15 | //config 16 | .constant('angularSlidezillaConfig', { 17 | min:0, 18 | max:100, 19 | step:5 20 | }) 21 | 22 | //controller 23 | .controller('AngularSlidezillaController', ['angularSlidezillaConfig','$scope', function(angularSlidezillaConfig,$scope) { 24 | //set default scope values 25 | $scope.min=angularSlidezillaConfig.min || 0; 26 | $scope.max=angularSlidezillaConfig.max || 100; 27 | $scope.step=angularSlidezillaConfig.step || 5; 28 | }]) 29 | 30 | //slider directive 31 | .directive('slider', function () { 32 | return { 33 | scope: { 34 | 'model':'=ngModel' 35 | }, 36 | restrict: 'E', 37 | require: ['ngModel'], 38 | controller: 'AngularSlidezillaController', 39 | link: function (scope, element, attrs, ctrls) { 40 | //process attributes and watch for changes 41 | if(attrs.min){ 42 | scope.min = scope.$parent.$eval(attrs.min); 43 | scope.$parent.$watch(attrs.min, function(newVal) { 44 | scope.min = newVal; 45 | ctrls[0].$render(); 46 | }); 47 | } 48 | if(attrs.max){ 49 | scope.max = scope.$parent.$eval(attrs.max); 50 | scope.$parent.$watch(attrs.max, function(newVal) { 51 | scope.max = newVal; 52 | ctrls[0].$render(); 53 | }); 54 | } 55 | if(attrs.step){ 56 | scope.step = scope.$parent.$eval(attrs.step); 57 | scope.$parent.$watch(attrs.step, function(newVal) { 58 | scope.step = newVal; 59 | ctrls[0].$render(); 60 | }); 61 | } 62 | 63 | //init dom objects 64 | var handles = element[0].querySelectorAll('.slider-handle'); 65 | var track = element[0].querySelector('.slider-track'); 66 | var selection = element[0].querySelector('.slider-selection'); 67 | 68 | //drag state variable 69 | var dragging=false; 70 | 71 | //// model -> UI //////////////////////////////////// 72 | ctrls[0].$render = function () { 73 | var hPos1,hPos2; 74 | //ensure model value is in range 75 | clampModelValue(); 76 | //update view value 77 | ctrls[0].$setViewValue(scope.model); 78 | //update display to match model value 79 | if(typeof scope.model == 'number'){ // 25/75 = x / 100 80 | hPos1 = 0; 81 | hPos2 = 100 / (scope.max - scope.min) * (scope.model - scope.max) + 100; 82 | angular.element(handles[0]).css('margin-left',hPos2+'%'); 83 | angular.element(handles[1]).addClass('hidden'); 84 | }else{ 85 | hPos1 = 100 / (scope.max - scope.min) * (scope.model[0] - scope.max) + 100; 86 | hPos2 = 100 / (scope.max - scope.min) * (scope.model[1] - scope.max) + 100; 87 | angular.element(handles[0]).css('margin-left',hPos1+'%'); 88 | angular.element(handles[1]).css('margin-left',hPos2+'%').removeClass('hidden'); 89 | } 90 | angular.element(selection).css('margin-left',hPos1+'%').css('width',(hPos2-hPos1+1)+'%'); 91 | }; 92 | 93 | 94 | //// ui->model //////////////////////////////////// 95 | 96 | //bind mouse down event (track) - increment by step 97 | angular.element(track).bind('mousedown', function(e) { 98 | e.preventDefault(); 99 | if(dragging) return; 100 | var newVal=scope.model; 101 | var offsetX = e.offsetX || e.layerX; 102 | 103 | if(typeof newVal == 'number') { 104 | if (offsetX > handles[0].offsetLeft) { 105 | newVal += scope.step; 106 | } else { 107 | newVal -= scope.step; 108 | } 109 | }else{ 110 | if(e.target == track && offsetX < handles[0].offsetLeft) { 111 | newVal[0] -= scope.step; 112 | }else if(e.target == track && offsetX > handles[1].offsetLeft) { 113 | newVal[1] += scope.step; 114 | }else{ 115 | if(e.target == selection && offsetX > e.target.offsetWidth/2){ 116 | newVal[1] -= scope.step; 117 | }else{ 118 | newVal[0] += scope.step; 119 | } 120 | } 121 | } 122 | scope.$apply(function () { 123 | scope.model=newVal; 124 | ctrls[0].$render(); 125 | }); 126 | }); 127 | 128 | // Bind mousedown event (drag handles) -- start drag 129 | angular.element(handles).bind('mousedown', function(e) { 130 | e.preventDefault(); 131 | //store data about currently dragging handle 132 | dragging={ 133 | sx: e.clientX - e.target.offsetLeft, 134 | sy: e.clientY - e.target.offsetTop, 135 | w: e.target.offsetWidth, 136 | h: e.target.offsetHeight, 137 | element: e.target, 138 | index: e.target==handles[0] ? 0 : 1, 139 | container: e.target.parentElement.getBoundingClientRect() 140 | }; 141 | 142 | //listen for movement / mouse up 143 | angular.element(document).bind('mousemove', mousemove); 144 | angular.element(document).bind('mouseup', mouseup); 145 | }); 146 | 147 | // mousemove event (document) -- update drag handle to position 148 | function mousemove(e) { 149 | if(!dragging) return; 150 | dragging.y = e.clientY - dragging.sy; 151 | dragging.x = e.clientX - dragging.sx; 152 | //contain drag within track 153 | if (dragging.x < 0) { 154 | dragging.x = 0; 155 | } else if (dragging.x > dragging.container.right - dragging.container.left) { 156 | dragging.x = dragging.container.right - dragging.container.left; 157 | } 158 | 159 | //compute slider value based on handle position 160 | var percentVal = Math.max(0,Math.min(100,parseInt((dragging.x / (dragging.container.right - dragging.container.left))*100))); 161 | var normalizedVal = ((percentVal/100)*(scope.max - scope.min))+scope.min; 162 | normalizedVal = parseFloat(normalizedVal.toFixed(3)); 163 | var rounded = roundToStep(normalizedVal,scope.step); 164 | //pass value to model 165 | scope.$apply(function () { 166 | var setMVal=scope.model; 167 | if(typeof setMVal == 'number') { 168 | setMVal=rounded; 169 | }else{ 170 | setMVal[dragging.index]=rounded; 171 | } 172 | scope.model=setMVal; 173 | ctrls[0].$render(); 174 | }); 175 | } 176 | 177 | // mouse up event (document) -- stop drag 178 | function mouseup(e) { 179 | angular.element(document).unbind('mousemove', mousemove); 180 | angular.element(document).unbind('mouseup', mouseup); 181 | dragging=false; 182 | } 183 | 184 | 185 | //// helpers //////////////////////////////////// 186 | 187 | //rounds value to step 188 | function roundToStep(val,step){ 189 | return (val >= 0 ) ? val + step/2 - (val+step/2) % step : val - step/2 - (val+step/2) % step; 190 | } 191 | 192 | //clamps model values. Keeps sliders within track and keeps them in index order 193 | function clampModelValue(){ 194 | if(typeof scope.model == 'number'){ 195 | if(scope.model > scope.max){ 196 | scope.model=scope.max; 197 | }else if(scope.model < scope.min){ 198 | scope.model=scope.min; 199 | } 200 | }else{ 201 | var cv0,cv1; 202 | if(scope.model[0] > scope.model[1]){ 203 | cv1 = scope.model[0]; 204 | cv0 = scope.model[1]; 205 | scope.model[0] = cv0; 206 | scope.model[1] = cv1; 207 | } 208 | if(scope.model[0] > scope.max){ 209 | cv0 = scope.max; 210 | }else if(scope.model[0] < scope.min){ 211 | cv0 = scope.min; 212 | } 213 | if(scope.model[1] > scope.max){ 214 | cv1 = scope.max; 215 | }else if(scope.model[1] < scope.min){ 216 | cv1 = scope.min; 217 | } 218 | if(cv0 || cv1){ 219 | scope.model=[cv0 || scope.model[0],cv1 || scope.model[1]]; 220 | } 221 | } 222 | } 223 | }, 224 | template:'
', 225 | replace: true 226 | }; 227 | }); --------------------------------------------------------------------------------