From a365debd03e7fafcc2fe83bc34d0fbdaebbe4074 Mon Sep 17 00:00:00 2001 From: Andy Joslin Date: Mon, 29 Jul 2013 10:11:50 -0400 Subject: [PATCH] feat(scroller): support mousewheel, keys --- Gruntfile.js | 2 +- src/services/desktop.js | 53 ++++++++++++++++++++++++++++++++++++++++ src/services/dragger.js | 5 ++-- src/services/scroller.js | 44 ++++++++++++++++++++++++--------- 4 files changed, 90 insertions(+), 14 deletions(-) create mode 100644 src/services/desktop.js diff --git a/Gruntfile.js b/Gruntfile.js index c6c34f0..a6a89cd 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -151,7 +151,7 @@ module.exports = function(grunt) { grunt.registerTask('build', function() { if (!grunt.file.exists('.git/hooks/commit-msg')) { - sh.cp('scripts/validate-commit-msg.js', '.git/hooks/commit-msg'); + grunt.file.copy('scripts/validate-commit-msg.js', '.git/hooks/commit-msg'); require('fs').chmodSync('.git/hooks/commit-msg', '0755'); } grunt.task.run(['ngmin', 'concat', 'uglify']); diff --git a/src/services/desktop.js b/src/services/desktop.js new file mode 100644 index 0000000..d7a407b --- /dev/null +++ b/src/services/desktop.js @@ -0,0 +1,53 @@ + +angular.module('ajoslin.scrolly.desktop', []) + +.factory('$desktopScroller', function($document) { + + return function $desktopScroller(elm, scroller) { + + elm.bind('$destroy', function() { + $document.unbind('mousewheel', onMousewheel); + }); + $document.bind('mousewheel', onMousewheel); + $document.bind('keydown', onKey); + + function onMousewheel(e) { + var delta = e.wheelDeltaY / 2; + scroller.calculateHeight(); + + var newPos = scroller.transformer.pos + delta; + scroller.transformer.setTo(clamp(-scroller.scrollHeight, newPos, 0)); + e.preventDefault(); + } + + //{keycode: amountToEase} map + var KEYS = { + 38: 150, //up + 40: -150, //down + 32: -600 //down + }; + function onKey(e) { + var delta = KEYS[e.keyCode || e.which]; + if (delta) { + e.preventDefault(); + if (scroller.transformer.changing) return; + scroller.calculateHeight(); + + var newPos = scroller.transformer.pos + delta; + newPos = clamp(-scroller.scrollHeight, newPos, 0); + + if (newPos !== scroller.transformer.pos) { + var newDelta = newPos - scroller.transformer.pos; + var time = Math.abs(delta / 1.5) * (newDelta / delta); + + scroller.transformer.easeTo( + newPos, time + ); + } + } + } + }; + function clamp(a, b, c) { + return Math.min( Math.max(a, b), c ); + } +}); diff --git a/src/services/dragger.js b/src/services/dragger.js index 7f18476..934dd71 100644 --- a/src/services/dragger.js +++ b/src/services/dragger.js @@ -270,8 +270,9 @@ angular.module('ajoslin.scrolly.dragger', []) if (state.dragging) { state.dragging = false; - var duration = Date.now() - state.startTime; - var inactiveDrag = (duration > _maxTimeMotionless); + var now = Date.now(); + var duration = now - state.startTime; + var inactiveDrag = ((now - state.lastMoveTime) > _maxTimeMotionless); dispatchEvent({ type: 'end', diff --git a/src/services/scroller.js b/src/services/scroller.js index 4a4076c..05bebc2 100644 --- a/src/services/scroller.js +++ b/src/services/scroller.js @@ -8,7 +8,8 @@ angular.module('ajoslin.scrolly.scroller', [ 'ajoslin.scrolly.dragger', - 'ajoslin.scrolly.transformer' + 'ajoslin.scrolly.transformer', + 'ajoslin.scrolly.desktop' ]) .provider('$scroller', function() { @@ -18,6 +19,24 @@ angular.module('ajoslin.scrolly.scroller', [ return _decelerationRate; }; + /** + * @ngdoc method + * @name ajoslin.scrolly.$scrollerProvider#supportDesktop + * @methodOf ajoslin.scrolly.$scrollerProvider + * + * @description + * Sets/gets whether the scroller should support desktop events (mousewheel, + * arrow keys, etc). Default true. + * + * @param {boolean=} newSupport New value to set for desktop support. + * @returns {boolean} support Current desktop support. + */ + var _supportDesktop = true; + this.supportDesktop = function(newSupport) { + _supportDesktop = !!newSupport; + return _supportDesktop; + }; + /** * @ngdoc method * @name ajoslin.scrolly.$scrollerProvider#pastBoundaryScrollRate @@ -114,23 +133,22 @@ angular.module('ajoslin.scrolly.scroller', [ //http://jsperf.com/math-floor-vs-math-round-vs-parseint/69 function floor(n) { return n | 0; } - this.$get = function($dragger, $transformer, $window, $document) { + this.$get = function($dragger, $transformer, $window, $document, $desktopScroller) { $scroller.getContentRect = function(raw) { - var top, bottom; var style = window.getComputedStyle(raw); var offTop = parseInt(style['margin-top'], 10) + - parseInt(style['padding-top'], 10) + - isNaN( (top = parseInt(style.top, 10)) ) ? 0 : top; - + parseInt(style['padding-top'], 10); var offBottom = parseInt(style['margin-bottom'], 10) + - parseInt(style['padding-bottom'], 10) + - isNaN( (bottom = parseInt(style.bottom, 10)) ) ? 0 : bottom; + parseInt(style['padding-bottom'], 10); + + var top = parseInt(style.top, 10); + var bottom = parseInt(style.bottom, 10); var height = parseInt(style.height, 10); return { - top: offTop, - bottom: offBottom, + top: offTop + (isNaN(top) ? 0 : top), + bottom: offBottom + (isNaN(bottom) ? 0 : bottom), height: height }; }; @@ -161,6 +179,9 @@ angular.module('ajoslin.scrolly.scroller', [ var transformer = self.transformer = new $transformer(elm); var dragger = self.dragger = new $dragger(elm); + if (_supportDesktop) { + var desktopScroller = new $desktopScroller(elm, self); + } self.calculateHeight = function() { var rect = $scroller.getContentRect(raw); @@ -208,12 +229,13 @@ angular.module('ajoslin.scrolly.scroller', [ if (self.outOfBounds(transformer.pos) || dragData.inactiveDrag) { self.checkBoundaries(); } else { + console.log('momentum'); var momentum = self.momentum(dragData); if (momentum.position !== transformer.pos) { transformer.easeTo( momentum.position, momentum.time, - checkBoundaries + self.checkBoundaries ); } }