1/** 2 * Touch List Control 3 * version 1.1.2 4 * 5 * Copyright (C) 2014, Averta Ltd. All rights reserved. 6 */ 7 8;(function(){ 9 10 "use strict"; 11 12 var _options = { 13 bouncing : true, 14 snapping : false, 15 snapsize : null, 16 friction : 0.05, 17 outFriction : 0.05, 18 outAcceleration : 0.09, 19 minValidDist : 0.3, 20 snappingMinSpeed : 2, 21 paging : false, 22 endless : false, 23 maxSpeed : 160 24 }; 25 26 27 var Controller = function(min , max , options){ 28 29 if(max === null || min === null) { 30 throw new Error('Max and Min values are required.'); 31 } 32 33 this.options = options || {}; 34 35 for(var key in _options){ 36 if(!(key in this.options)) 37 this.options[key] = _options[key]; 38 } 39 40 this._max_value = max; 41 this._min_value = min; 42 43 this.value = min; 44 this.end_loc = min; 45 46 this.current_snap = this.getSnapNum(min); 47 48 this.__extrStep = 0; 49 this.__extraMove = 0; 50 51 this.__animID = -1; 52 53 }; 54 55 var p = Controller.prototype; 56 57 /* 58 --------------------------------------------------- 59 PUBLIC METHODS 60 ---------------------------------------------------- 61 */ 62 63 64 p.changeTo = function(value , animate , speed , snap_num , dispatch) { 65 this.stopped = false; 66 this._internalStop(); 67 value = this._checkLimits(value); 68 speed = Math.abs(speed || 0); 69 70 if(this.options.snapping){ 71 snap_num = snap_num || this.getSnapNum(value);
72 if( dispatch !== false )this._callsnapChange(snap_num); 73 this.current_snap = snap_num; 74 } 75 76 if(animate){ 77 this.animating = true; 78 79 var self = this, 80 active_id = ++self.__animID, 81 amplitude = value - self.value, 82 timeStep = 0, 83 targetPosition = value, 84 animFrict = 1 - self.options.friction, 85 timeconst = animFrict + (speed - 20) * animFrict * 1.3 / self.options.maxSpeed; 86 87 var tick = function(){ 88 89 if(active_id !== self.__animID) return; 90 91 var dis = value - self.value; 92 93 if( Math.abs(dis) > self.options.minValidDist && self.animating ){ 94 window.requestAnimationFrame(tick); 95 } else { 96 97 if( self.animating ){ 98 self.value = value; 99 self._callrenderer(); 100 } 101 102 self.animating = false; 103 104 if( active_id !== self.__animID ){ 105 self.__animID = -1; 106 } 107 108 self._callonComplete('anim'); 109 110 return; 111 } 112 113 //self.value += dis * timeconst 114 self.value = targetPosition - amplitude * Math.exp(-++timeStep * timeconst); 115 116 self._callrenderer(); 117 }; 118 119 tick(); 120 121 return; 122 } 123 124 this.value = value; 125 this._callrenderer(); 126 }; 127 128 p.drag = function(move){ 129 130 if(this.start_drag){ 131 this.drag_start_loc = this.value; 132 this.start_drag = false; 133 } 134 135 this.animating = false; 136 this._deceleration = false; 137 138 this.value -= move; 139 140 if ( !this.options.endless && (this.value > this._max_value || this.value < 0)) { 141 if (this.options.bouncing) { 142 this.__isout = true; 143 this.value += move * 0.6; 144 } else if (this.value > this._max_value) { 145 this.value = this._max_value; 146 } else { 147 this.value = 0; 148 } 149 }else if(!this.options.endless && this.options.bouncing){ 150 this.__isout = false; 151 } 152 153 this._callrenderer(); 154 155 }; 156 157 p.push = function(speed){ 158 this.stopped = false; 159 if(this.options.snapping && Math.abs(speed) <= this.options.snappingMinSpeed){ 160 this.cancel(); 161 return; 162 } 163 164 this.__speed = speed; 165 this.__startSpeed = speed; 166 167 this.end_loc = this._calculateEnd(); 168 169 if(this.options.snapping){ 170 171 var snap_loc = this.getSnapNum(this.value), 172 end_snap = this.getSnapNum(this.end_loc); 173 174 if(this.options.paging){ 175 snap_loc = this.getSnapNum(this.drag_start_loc); 176 177 this.__isout = false; 178 if(speed > 0){ 179 this.gotoSnap(snap_loc + 1 , true , speed); 180 }else{ 181 this.gotoSnap(snap_loc - 1 , true , speed); 182 } 183 return; 184 }else if(snap_loc === end_snap){ 185 this.cancel(); 186 return; 187 } 188 189 this._callsnapChange(end_snap); 190 this.current_snap = end_snap; 191 192 } 193 194 this.animating = false; 195 196 this.__needsSnap = this.options.endless || (this.end_loc > this._min_value && this.end_loc < this._max_value) ; 197 198 if(this.options.snapping && this.__needsSnap) 199 this.__extraMove = this._calculateExtraMove(this.end_loc); 200 201 202 this._startDecelaration(); 203 }; 204 205 p.bounce = function(speed){ 206 if(this.animating) return; 207 this.stopped = false; 208 this.animating = false; 209 210 this.__speed = speed; 211 this.__startSpeed = speed; 212 213 this.end_loc = this._calculateEnd(); 214 215 //if(this.options.paging){} 216 217 this._startDecelaration(); 218 }; 219 220 p.stop = function(){ 221 this.stopped = true; 222 this._internalStop(); 223 }; 224 225 p.cancel = function(){ 226 this.start_drag = true; // reset flag for next drag 227 if(this.__isout){ 228 this.__speed = 0.0004; 229 this._startDecelaration(); 230 }else if(this.options.snapping){ 231 this.gotoSnap(this.getSnapNum(this.value) , true); 232 } 233 234 }; 235 236 p.renderCallback = function(listener , ref){ 237 this.__renderHook = {fun:listener , ref:ref}; 238 }; 239 240 p.snappingCallback = function(listener , ref){ 241 this.__snapHook = {fun:listener , ref:ref}; 242 }; 243 244 p.snapCompleteCallback = function(listener , ref){ 245 this.__compHook = {fun:listener , ref:ref}; 246 }; 247 248 p.getSnapNum = function(value){ 249 return Math.floor(( value + this.options.snapsize / 2 ) / this.options.snapsize); 250 }; 251 252 p.nextSnap = function(){ 253 this._internalStop(); 254
255 var curr_snap = this.getSnapNum(this.value); 256 257 if(!this.options.endless && (curr_snap + 1) * this.options.snapsize > this._max_value){ 258 this.__speed = 8; 259 this.__needsSnap = false; 260 this._startDecelaration(); 261 }else{ 262 this.gotoSnap(curr_snap + 1 , true); 263 } 264 265 }; 266 267 p.prevSnap = function(){ 268 this._internalStop(); 269 270 var curr_snap = this.getSnapNum(this.value); 271 272 if(!this.options.endless && (curr_snap - 1) * this.options.snapsize < this._min_value){ 273 this.__speed = -8; 274 this.__needsSnap = false; 275 this._startDecelaration(); 276 }else{ 277 this.gotoSnap(curr_snap - 1 , true); 278 } 279 280 }; 281 282 p.gotoSnap = function(snap_num , animate , speed){ 283 this.changeTo(snap_num * this.options.snapsize , animate , speed , snap_num); 284 }; 285 286 p.destroy = function(){ 287 this._internalStop(); 288 this.__renderHook = null; 289 this.__snapHook = null; 290 this.__compHook = null; 291 }; 292 293 /* 294 --------------------------------------------------- 295 PRIVATE METHODS 296 ---------------------------------------------------- 297 */ 298 299 p._internalStop = function(){ 300 this.start_drag = true; // reset flag for next drag 301 this.animating = false; 302 this._deceleration = false; 303 this.__extrStep = 0; 304 }; 305 306 p._calculateExtraMove = function(value){ 307 var m = value % this.options.snapsize; 308 return m < this.options.snapsize / 2 ? -m : this.options.snapsize - m; 309 }; 310 311 p._calculateEnd = function(step){ 312 var temp_speed = this.__speed; 313 var temp_value = this.value; 314 var i = 0; 315 while(Math.abs(temp_speed) > this.options.minValidDist){ 316 temp_value += temp_speed; 317 temp_speed *= this.options.friction; 318 i++; 319 } 320 if(step) return i; 321 return temp_value; 322 }; 323 324 p._checkLimits = function(value){ 325 if(this.options.endless) return value; 326 if(value < this._min_value) return this._min_value; 327 if(value > this._max_value) return this._max_value; 328 return value; 329 }; 330 331 p._callrenderer = function(){ 332 if(this.__renderHook) this.__renderHook.fun.call(this.__renderHook.ref , this , this.value); 333 }; 334 335 p._callsnapChange = function(targetSnap){ 336 if(!this.__snapHook || targetSnap === this.current_snap) return; 337 this.__snapHook.fun.call(this.__snapHook.ref , this , targetSnap , targetSnap - this.current_snap); 338 }; 339 340 p._callonComplete = function(type){ 341 if(this.__compHook && !this.stopped){ 342 this.__compHook.fun.call(this.__compHook.ref , this , this.current_snap , type); 343 } 344 345 }; 346 347 p._computeDeceleration = function(){ 348 349 if(this.options.snapping && this.__needsSnap){ 350 var xtr_move = (this.__startSpeed - this.__speed) / this.__startSpeed * this.__extraMove; 351 this.value += this.__speed + xtr_move - this.__extrStep; 352 this.__extrStep = xtr_move; 353 }else{ 354 this.value += this.__speed; 355 } 356 357 this.__speed *= this.options.friction; //* 10; 358 359 if(!this.options.endless && !this.options.bouncing){ 360 if(this.value <= this._min_value){ 361 this.value = this._min_value; 362 this.__speed = 0; 363 }else if(this.value >= this._max_value){ 364 this.value = this._max_value; 365 this.__speed = 0; 366 } 367 } 368 369 this._callrenderer(); 370 371 if(!this.options.endless && this.options.bouncing){ 372 373 var out_value = 0; 374 375 if(this.value < this._min_value){ 376 out_value = this._min_value - this.value; 377 }else if(this.value > this._max_value){ 378 out_value = this._max_value - this.value; 379 } 380 381 this.__isout = Math.abs(out_value) >= this.options.minValidDist; 382 383 if(this.__isout){ 384 if(this.__speed * out_value <= 0){ 385 this.__speed += out_value * this.options.outFriction; 386 }else { 387 this.__speed = out_value * this.options.outAcceleration; 388 } 389 } 390 } 391 }; 392 393 p._startDecelaration = function(){ 394 if(this._deceleration) return; 395 this._deceleration = true; 396 397 var self = this; 398 399 var tick = function (){ 400 401 if(!self._deceleration) return; 402 403 self._computeDeceleration(); 404 405 if(Math.abs(self.__speed) > self.options.minValidDist || self.__isout){ 406 window.requestAnimationFrame(tick); 407 }else{ 408 self._deceleration = false; 409 self.__isout = false; 410 411 if(self.__needsSnap && self.options.snapping && !self.options.paging){ 412 self.value = self._checkLimits(self.end_loc + self.__extraMove); 413 }else{ 414 self.value = Math.round(self.value); 415 } 416 417 self._callrenderer(); 418 self._callonComplete('decel'); 419 } 420 }; 421 422 tick(); 423 }; 424 425 window.Controller = Controller; 426 427})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.