Created
September 21, 2015 16:00
-
-
Save inorganik/cd6da5a79106d17b7c1b to your computer and use it in GitHub Desktop.
Angular scroll spy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function (angular) { | |
'use strict'; | |
// Scroll Spy Directive | |
// =============================== | |
// | |
// * **Author:** Jamie Perkins | |
// | |
// $broadcast an event when an element comes into or goes out of view: | |
// | |
// 'elementFirstScrolledIntoView' is fired once when the element first scrolls into view | |
// 'elementScrolledIntoView' is fired once every time the element scrolls into view | |
// 'elementScrolledOutOfView' is fired once every time the element is scrolled out of view | |
var module = angular.module('scrollSpyModule', []); | |
module.directive('scrollSpy', ['$window', '$rootScope', function ($window, $rootScope) { | |
return { | |
restrict: 'A', | |
link: function ($scope, $el, $attrs) { | |
function ScrollSpy() { | |
var self = this, | |
initialized = false, | |
viewportHeight, | |
elementHeight, | |
topOffset, | |
elementFirstScrolledIntoView = false, | |
elementScrolledIntoView = false, | |
elementScrolledOutOfView = false, | |
doc = document.documentElement, | |
id = $attrs.id || 'unknown element', | |
viewportShorterThanElement = false, | |
percentOfElementNeededInView = .9; | |
// onscroll | |
this.determinePosition = function() { | |
if (initialized) { | |
var pos = (window.pageYOffset || doc.scrollTop); | |
// console.log(pos); | |
// element Scrolled Out Of View | |
if (!elementScrolledOutOfView) { | |
if (pos + viewportHeight < topOffset || pos > topOffset + elementHeight) { | |
// console.log('element Scrolled Out Of View '+id); | |
elementScrolledOutOfView = true; | |
elementScrolledIntoView = false; | |
$rootScope.$broadcast('elementScrolledOutOfView', id); | |
} | |
} | |
if ((pos + viewportHeight >= topOffset + percentOfElementNeededInView * elementHeight && topOffset > pos) || | |
(pos >= topOffset && viewportShorterThanElement)) { | |
// element First Scrolled Into View | |
if (!elementFirstScrolledIntoView) { | |
// console.log('element First Scrolled Into View '+id); | |
elementFirstScrolledIntoView = true; | |
$rootScope.$broadcast('elementFirstScrolledIntoView', id); | |
} | |
// element Scrolled Into View | |
if (!elementScrolledIntoView) { | |
// console.log('element Scrolled Into View '+id); | |
elementScrolledIntoView = true; | |
elementScrolledOutOfView = false; | |
$rootScope.$broadcast('elementScrolledIntoView', id); | |
} | |
} | |
} | |
} | |
this.takeMeasurements = function() { | |
viewportHeight = angular.element($window).height(); | |
elementHeight = angular.element($el).outerHeight(); | |
topOffset = angular.element($el).offset().top; | |
// console.log('take measurements- viewportHeight:'+viewportHeight+', element height: '+elementHeight+', top offset: '+topOffset); | |
if (viewportHeight < elementHeight) viewportShorterThanElement = true; | |
// determine position on page load | |
initialized = true; | |
self.determinePosition(); | |
} | |
// wait for dom to render so correct measurements can be taken | |
var waitForRender = setInterval(function() { | |
if (angular.element($el).outerHeight() > 2) { // IE11 reports 2 at times... | |
clearTimeout(waitForRender); | |
self.takeMeasurements(); | |
} | |
}, 50); | |
} | |
var name = $attrs.id + '-scrollSpy'; | |
$rootScope[name] = new ScrollSpy(); | |
// global onscroll fns array | |
if (!$rootScope.globalOnScrollFunctions) { | |
$rootScope.globalOnScrollFunctions = []; | |
} | |
$rootScope.globalOnScrollFunctions.push($rootScope[name]); | |
// set up global onscroll function that will call each fn in global onscroll fns | |
if (!$rootScope.globalOnScroll) { | |
$rootScope.globalOnScroll = function() { | |
angular.forEach($rootScope.globalOnScrollFunctions, function (val, key) { | |
val.determinePosition(); | |
}); | |
} | |
// on scroll | |
$window.onscroll = $rootScope.globalOnScroll; | |
} | |
} | |
} | |
}]); | |
})(angular); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment