Comparing version 0.5.4 to 0.6.0
@@ -10,21 +10,9 @@ (function (global, factory) { | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* Licensed under the W3C SOFTWARE AND DOCUMENT NOTICE AND LICENSE. | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document | ||
* | ||
*/ | ||
(function(window, document) { | ||
'use strict'; | ||
// Exits early if all IntersectionObserver and IntersectionObserverEntry | ||
// features are natively supported. | ||
if ('IntersectionObserver' in window && | ||
@@ -35,3 +23,3 @@ 'IntersectionObserverEntry' in window && | ||
// Minimal polyfill for Edge 15's lack of `isIntersecting` | ||
// See: https://github.com/WICG/IntersectionObserver/issues/211 | ||
// See: https://github.com/w3c/IntersectionObserver/issues/211 | ||
if (!('isIntersecting' in window.IntersectionObserverEntry.prototype)) { | ||
@@ -60,3 +48,3 @@ Object.defineProperty(window.IntersectionObserverEntry.prototype, | ||
* Creates the global IntersectionObserverEntry constructor. | ||
* https://wicg.github.io/IntersectionObserver/#intersection-observer-entry | ||
* https://w3c.github.io/IntersectionObserver/#intersection-observer-entry | ||
* @param {Object} entry A dictionary of instance properties. | ||
@@ -91,3 +79,3 @@ * @constructor | ||
* Creates the global IntersectionObserver constructor. | ||
* https://wicg.github.io/IntersectionObserver/#intersection-observer-interface | ||
* https://w3c.github.io/IntersectionObserver/#intersection-observer-interface | ||
* @param {Function} callback The function to be invoked after intersection | ||
@@ -370,3 +358,3 @@ * changes have queued. The function is not invoked if the queue has | ||
* TODO(philipwalton): at this time clip-path is not considered. | ||
* https://wicg.github.io/IntersectionObserver/#calculate-intersection-rect-algo | ||
* https://w3c.github.io/IntersectionObserver/#calculate-intersection-rect-algo | ||
* @param {Element} target The target DOM element | ||
@@ -664,3 +652,3 @@ * @param {Object} rootRect The bounding rect of the root after being | ||
// Ignore Windows 7 IE11 "Unspecified error" | ||
// https://github.com/WICG/IntersectionObserver/pull/205 | ||
// https://github.com/w3c/IntersectionObserver/pull/205 | ||
} | ||
@@ -788,22 +776,48 @@ | ||
var stepStates = null; | ||
var previousYOffset = 0; | ||
var direction = 'down'; | ||
function getIndex(element) { | ||
return +element.getAttribute('data-scrollama-index'); | ||
} | ||
function updateDirection() { | ||
if (window.pageYOffset > previousYOffset) { direction = 'down'; } | ||
else if (window.pageYOffset < previousYOffset) { direction = 'up'; } | ||
previousYOffset = window.pageYOffset; | ||
} | ||
// NOTIFY CALLBACKS | ||
function notifyStepEnter(element, direction) { | ||
var index = +element.getAttribute('data-scrollama-index'); | ||
function notifyStepEnter(element) { | ||
var index = getIndex(element); | ||
var resp = { element: element, index: index, direction: direction }; | ||
// store most recent trigger | ||
stepStates[index].direction = direction; | ||
stepStates[index].state = 'enter'; | ||
if (callback.stepEnter && typeof callback.stepEnter === 'function') | ||
{ callback.stepEnter(resp); } | ||
if (progressMode) { | ||
if (direction === 'up') { notifyStepProgress(element, 1); } | ||
else { notifyStepProgress(element, 0); } | ||
if (direction === 'down') { notifyStepProgress(element, 0); } | ||
else { notifyStepProgress(element, 1); } | ||
} | ||
} | ||
function notifyStepExit(element, direction) { | ||
var index = +element.getAttribute('data-scrollama-index'); | ||
function notifyStepExit(element) { | ||
var index = getIndex(element); | ||
var resp = { element: element, index: index, direction: direction }; | ||
// store most recent trigger | ||
stepStates[index].direction = direction; | ||
stepStates[index].state = 'exit'; | ||
if (callback.stepExit && typeof callback.stepExit === 'function') | ||
{ callback.stepExit(resp); } | ||
if (progressMode) { | ||
if (direction === 'up') { notifyStepProgress(element, 0); } | ||
else { notifyStepProgress(element, 1); } | ||
if (direction === 'down') { notifyStepProgress(element, 1); } | ||
else { notifyStepProgress(element, 0); } | ||
} | ||
@@ -813,3 +827,3 @@ } | ||
function notifyStepProgress(element, progress) { | ||
var index = +element.getAttribute('data-scrollama-index'); | ||
var index = getIndex(element); | ||
var resp = { element: element, index: index, progress: progress }; | ||
@@ -820,3 +834,3 @@ if (callback.stepProgress && typeof callback.stepProgress === 'function') | ||
function notifyContainerEnter(direction) { | ||
function notifyContainerEnter() { | ||
var resp = { direction: direction }; | ||
@@ -830,3 +844,3 @@ if ( | ||
function notifyContainerExit(direction) { | ||
function notifyContainerExit() { | ||
var resp = { direction: direction }; | ||
@@ -841,13 +855,23 @@ if (callback.containerExit && typeof callback.containerExit === 'function') | ||
// bottom must be > 0 which means it is on "screen" (shifted by offset) | ||
function intersectStepTop(entries) { | ||
function intersectStepAbove(entries) { | ||
updateDirection(); | ||
entries.forEach(function (entry) { | ||
var isIntersecting = entry.isIntersecting; | ||
var intersectionRatio = entry.intersectionRatio; | ||
var boundingClientRect = entry.boundingClientRect; | ||
var target = entry.target; | ||
// bottom is how far bottom edge of el is from top of viewport | ||
var bottom = boundingClientRect.bottom; | ||
var bottomAdjusted = bottom - offsetMargin; | ||
var index = getIndex(target); | ||
if (bottomAdjusted >= -ZERO_MOE) { | ||
var direction = isIntersecting ? 'down' : 'up'; | ||
if (isIntersecting) { notifyStepEnter(target, direction); } | ||
else { notifyStepExit(target, direction); } | ||
if (isIntersecting && direction === 'down') | ||
{ notifyStepEnter(target, direction); } | ||
else if (direction === 'up') { | ||
// we went from exit to exit, must have skipped an enter | ||
if (stepStates[index].state === 'exit') | ||
{ notifyStepEnter(target, direction); } | ||
notifyStepExit(target, direction); | ||
} | ||
} | ||
@@ -857,5 +881,7 @@ }); | ||
function intersectStepBottom(entries) { | ||
function intersectStepBelow(entries) { | ||
updateDirection(); | ||
entries.forEach(function (entry) { | ||
var isIntersecting = entry.isIntersecting; | ||
var intersectionRatio = entry.intersectionRatio; | ||
var boundingClientRect = entry.boundingClientRect; | ||
@@ -866,12 +892,19 @@ var target = entry.target; | ||
var bottomAdjusted = bottom - offsetMargin; | ||
var index = getIndex(target); | ||
if ( | ||
bottomAdjusted >= -ZERO_MOE && | ||
bottomAdjusted < height && | ||
isIntersecting | ||
isIntersecting && | ||
direction === 'up' | ||
) { | ||
var direction = 'up'; | ||
notifyStepEnter(target, direction); | ||
} else if (bottomAdjusted <= ZERO_MOE && !isIntersecting) { | ||
var direction$1 = 'down'; | ||
notifyStepExit(target, direction$1); | ||
} else if ( | ||
bottomAdjusted <= ZERO_MOE && | ||
!isIntersecting && | ||
direction === 'down' | ||
) { | ||
if (stepStates[index].state === 'exit') | ||
{ notifyStepEnter(target, direction); } | ||
notifyStepExit(target, direction); | ||
} | ||
@@ -881,3 +914,49 @@ }); | ||
// if there is a scroll even that skips the entire enter/exit of a step, | ||
// fallback to trigger the enter/exit if element lands in viewport | ||
function intersectViewportAbove(entries) { | ||
updateDirection(); | ||
entries.forEach(function (entry) { | ||
var isIntersecting = entry.isIntersecting; | ||
var intersectionRatio = entry.intersectionRatio; | ||
var boundingClientRect = entry.boundingClientRect; | ||
var target = entry.target; | ||
var index = getIndex(target); | ||
if (isIntersecting && direction === 'down') { | ||
if ( | ||
stepStates[index].state === 'exit' && | ||
stepStates[index].direction === 'up' | ||
) { | ||
notifyStepEnter(target, 'down'); | ||
notifyStepExit(target, 'down'); | ||
} | ||
} | ||
}); | ||
} | ||
function intersectViewportBelow(entries) { | ||
updateDirection(); | ||
entries.forEach(function (entry) { | ||
var isIntersecting = entry.isIntersecting; | ||
var intersectionRatio = entry.intersectionRatio; | ||
var boundingClientRect = entry.boundingClientRect; | ||
var target = entry.target; | ||
var index = getIndex(target); | ||
if (isIntersecting && direction === 'up') { | ||
if ( | ||
stepStates[index].state === 'exit' && | ||
stepStates[index].direction === 'down' | ||
) { | ||
notifyStepEnter(target, 'up'); | ||
notifyStepExit(target, 'up'); | ||
} | ||
} | ||
}); | ||
} | ||
function intersectStepProgress(entries) { | ||
updateDirection(); | ||
entries.forEach(function (entry) { | ||
@@ -898,8 +977,9 @@ var isIntersecting = entry.isIntersecting; | ||
function intersectTop(entries) { | ||
updateDirection(); | ||
var ref = entries[0]; | ||
var isIntersecting = ref.isIntersecting; | ||
var boundingClientRect = ref.boundingClientRect; | ||
var top = boundingClientRect.top; | ||
var bottom = boundingClientRect.bottom; | ||
if (bottom > -ZERO_MOE) { | ||
var direction = isIntersecting ? 'down' : 'up'; | ||
if (isIntersecting) { notifyContainerEnter(direction); } | ||
@@ -911,2 +991,3 @@ else { notifyContainerExit(direction); } | ||
function intersectBottom(entries) { | ||
updateDirection(); | ||
var ref = entries[0]; | ||
@@ -917,3 +998,2 @@ var isIntersecting = ref.isIntersecting; | ||
if (top < ZERO_MOE) { | ||
var direction = isIntersecting ? 'up' : 'down'; | ||
if (isIntersecting) { notifyContainerEnter(direction); } | ||
@@ -951,9 +1031,10 @@ else { notifyContainerExit(direction); } | ||
// top edge | ||
function updateStepTopIO() { | ||
if (io.stepTop) { io.stepTop.forEach(function (d) { return d.disconnect(); }); } | ||
function updateStepAboveIO() { | ||
if (io.stepAbove) { io.stepAbove.forEach(function (d) { return d.disconnect(); }); } | ||
io.stepTop = stepEl.map(function (el, i) { | ||
io.stepAbove = stepEl.map(function (el, i) { | ||
var marginTop = stepHeights[i] - offsetMargin; | ||
var marginBottom = -vh + offsetMargin; | ||
var rootMargin = marginTop + "px 0px " + marginBottom + "px 0px"; | ||
// addDebugStep({ label: 'above', edge: 'orange', marginTop, marginBottom }); | ||
@@ -966,3 +1047,3 @@ var options = { | ||
var obs = new IntersectionObserver(intersectStepTop, options); | ||
var obs = new IntersectionObserver(intersectStepAbove, options); | ||
obs.observe(el); | ||
@@ -974,10 +1055,30 @@ return obs; | ||
// bottom edge | ||
function updateStepBottomIO() { | ||
if (io.stepBottom) { io.stepBottom.forEach(function (d) { return d.disconnect(); }); } | ||
function updateStepBelowIO() { | ||
if (io.stepBelow) { io.stepBelow.forEach(function (d) { return d.disconnect(); }); } | ||
io.stepBottom = stepEl.map(function (el, i) { | ||
io.stepBelow = stepEl.map(function (el, i) { | ||
var marginTop = -offsetMargin; | ||
var marginBottom = -vh + stepHeights[i] + offsetMargin; | ||
var rootMargin = marginTop + "px 0px " + marginBottom + "px 0px"; | ||
// addDebugStep({ label: 'below', edge: 'blue', marginTop, marginBottom }); | ||
var options = { | ||
root: null, | ||
rootMargin: rootMargin, | ||
threshold: 0 | ||
}; | ||
var obs = new IntersectionObserver(intersectStepBelow, options); | ||
obs.observe(el); | ||
return obs; | ||
}); | ||
} | ||
// jump into viewport | ||
function updateViewportAboveIO() { | ||
if (io.viewportAbove) { io.viewportAbove.forEach(function (d) { return d.disconnect(); }); } | ||
io.viewportAbove = stepEl.map(function (el, i) { | ||
var marginTop = 0; | ||
var marginBottom = -(vh - offsetMargin + stepHeights[i]); | ||
var rootMargin = marginTop + "px 0px " + marginBottom + "px 0px"; | ||
addDebugStep({ label: 'above', edge: 'purple', marginTop: marginTop, marginBottom: marginBottom }); | ||
var options = { | ||
@@ -989,3 +1090,3 @@ root: null, | ||
var obs = new IntersectionObserver(intersectStepBottom, options); | ||
var obs = new IntersectionObserver(intersectViewportAbove, options); | ||
obs.observe(el); | ||
@@ -996,2 +1097,21 @@ return obs; | ||
function updateViewportBelowIO() { | ||
if (io.viewportBelow) { io.viewportBelow.forEach(function (d) { return d.disconnect(); }); } | ||
io.viewportBelow = stepEl.map(function (el, i) { | ||
var marginTop = -(offsetMargin + stepHeights[i]); | ||
var marginBottom = 0; | ||
var rootMargin = marginTop + "px 0px " + marginBottom + "px 0px"; | ||
addDebugStep({ label: 'above', edge: 'purple', marginTop: marginTop, marginBottom: marginBottom }); | ||
var options = { | ||
root: null, | ||
rootMargin: rootMargin, | ||
threshold: 0 | ||
}; | ||
var obs = new IntersectionObserver(intersectViewportBelow, options); | ||
obs.observe(el); | ||
return obs; | ||
}); | ||
} | ||
// progress progress tracker | ||
@@ -1019,4 +1139,6 @@ function updateStepProgressIO() { | ||
function updateIO() { | ||
updateStepTopIO(); | ||
updateStepBottomIO(); | ||
updateStepAboveIO(); | ||
updateStepBelowIO(); | ||
updateViewportAboveIO(); | ||
updateViewportBelowIO(); | ||
@@ -1057,5 +1179,7 @@ if (progressMode) { updateStepProgressIO(); } | ||
if (io.bottom) { io.bottom.disconnect(); } | ||
if (io.stepTop) { io.stepTop.forEach(function (d) { return d.disconnect(); }); } | ||
if (io.stepBottom) { io.stepBottom.forEach(function (d) { return d.disconnect(); }); } | ||
if (io.stepAbove) { io.stepAbove.forEach(function (d) { return d.disconnect(); }); } | ||
if (io.stepBelow) { io.stepBelow.forEach(function (d) { return d.disconnect(); }); } | ||
if (io.stepProgress) { io.stepProgress.forEach(function (d) { return d.disconnect(); }); } | ||
if (io.viewportAbove) { io.viewportAbove.forEach(function (d) { return d.disconnect(); }); } | ||
if (io.viewportBelow) { io.viewportBelow.forEach(function (d) { return d.disconnect(); }); } | ||
isEnabled = false; | ||
@@ -1069,2 +1193,10 @@ } | ||
function setupStepStates() { | ||
stepStates = stepEl.map(function () { return ({ | ||
direction: null, | ||
state: null, | ||
bottom: -1 | ||
}); }); | ||
} | ||
function addDebug() { | ||
@@ -1094,2 +1226,30 @@ if (debugMode) { | ||
function addDebugStep(ref) { | ||
var label = ref.label; | ||
var edge = ref.edge; | ||
var marginTop = ref.marginTop; | ||
var marginBottom = ref.marginBottom; | ||
var el1 = document.createElement('div'); | ||
el1.setAttribute('id', ("scrollama__debug--" + edge + "-a-" + id)); | ||
el1.setAttribute('class', 'scrollama__debug--offset'); | ||
el1.style.position = 'fixed'; | ||
el1.style.top = (-marginTop) + "px"; | ||
el1.style.left = '0'; | ||
el1.style.width = '100%'; | ||
el1.style.height = '1px'; | ||
el1.style.borderBottom = "1px dashed " + edge; | ||
document.body.appendChild(el1); | ||
var el2 = document.createElement('div'); | ||
el2.setAttribute('id', ("scrollama__debug--" + edge + "-b-" + id)); | ||
el2.setAttribute('class', 'scrollama__debug--offset'); | ||
el2.style.position = 'fixed'; | ||
el2.style.bottom = (-marginBottom) + "px"; | ||
el2.style.left = '0'; | ||
el2.style.width = '100%'; | ||
el2.style.height = '1px'; | ||
el2.style.borderBottom = "1px dashed " + edge; | ||
document.body.appendChild(el2); | ||
} | ||
function setThreshold() { | ||
@@ -1125,2 +1285,3 @@ var count = 100; | ||
indexSteps(); | ||
setupStepStates(); | ||
if (progressMode) { setThreshold(); } | ||
@@ -1127,0 +1288,0 @@ handleResize(); |
@@ -1,1 +0,1 @@ | ||
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):t.scrollama=e()}(this,function(){"use strict";function t(t){for(var e=t.length,n=[],o=0;o<e;o+=1)n.push(t[o]);return n}function e(t){return document.querySelector(t)}function n(e,n){return void 0===n&&(n=document),t(n.querySelectorAll(e))}return function(t,e){function n(t){this.time=t.time,this.target=t.target,this.rootBounds=t.rootBounds,this.boundingClientRect=t.boundingClientRect,this.intersectionRect=t.intersectionRect||{top:0,bottom:0,left:0,right:0,width:0,height:0},this.isIntersecting=!!t.intersectionRect;var e=this.boundingClientRect,n=e.width*e.height,o=this.intersectionRect,r=o.width*o.height;this.intersectionRatio=n?r/n:this.isIntersecting?1:0}function o(t,e){var n=e||{};if("function"!=typeof t)throw new Error("callback must be a function");if(n.root&&1!=n.root.nodeType)throw new Error("root must be an Element");this._checkForIntersections=i(this._checkForIntersections.bind(this),this.THROTTLE_TIMEOUT),this._callback=t,this._observationTargets=[],this._queuedEntries=[],this._rootMarginValues=this._parseRootMargin(n.rootMargin),this.thresholds=this._initThresholds(n.threshold),this.root=n.root||null,this.rootMargin=this._rootMarginValues.map(function(t){return t.value+t.unit}).join(" ")}function r(){return t.performance&&performance.now&&performance.now()}function i(t,e){var n=null;return function(){n||(n=setTimeout(function(){t(),n=null},e))}}function s(t,e,n,o){"function"==typeof t.addEventListener?t.addEventListener(e,n,o||!1):"function"==typeof t.attachEvent&&t.attachEvent("on"+e,n)}function c(t,e,n,o){"function"==typeof t.removeEventListener?t.removeEventListener(e,n,o||!1):"function"==typeof t.detatchEvent&&t.detatchEvent("on"+e,n)}function u(t,e){var n=Math.max(t.top,e.top),o=Math.min(t.bottom,e.bottom),r=Math.max(t.left,e.left),i=Math.min(t.right,e.right),s=i-r,c=o-n;return s>=0&&c>=0&&{top:n,bottom:o,left:r,right:i,width:s,height:c}}function a(t){var e;try{e=t.getBoundingClientRect()}catch(t){}return e?(e.width&&e.height||(e={top:e.top,right:e.right,bottom:e.bottom,left:e.left,width:e.right-e.left,height:e.bottom-e.top}),e):{top:0,bottom:0,left:0,right:0,width:0,height:0}}function h(t,e){for(var n=e;n;){if(n==t)return!0;n=p(n)}return!1}function p(t){var e=t.parentNode;return e&&11==e.nodeType&&e.host?e.host:e}if("IntersectionObserver"in t&&"IntersectionObserverEntry"in t&&"intersectionRatio"in t.IntersectionObserverEntry.prototype)"isIntersecting"in t.IntersectionObserverEntry.prototype||Object.defineProperty(t.IntersectionObserverEntry.prototype,"isIntersecting",{get:function(){return this.intersectionRatio>0}});else{var l=[];o.prototype.THROTTLE_TIMEOUT=100,o.prototype.POLL_INTERVAL=null,o.prototype.observe=function(t){if(!this._observationTargets.some(function(e){return e.element==t})){if(!t||1!=t.nodeType)throw new Error("target must be an Element");this._registerInstance(),this._observationTargets.push({element:t,entry:null}),this._monitorIntersections(),this._checkForIntersections()}},o.prototype.unobserve=function(t){this._observationTargets=this._observationTargets.filter(function(e){return e.element!=t}),this._observationTargets.length||(this._unmonitorIntersections(),this._unregisterInstance())},o.prototype.disconnect=function(){this._observationTargets=[],this._unmonitorIntersections(),this._unregisterInstance()},o.prototype.takeRecords=function(){var t=this._queuedEntries.slice();return this._queuedEntries=[],t},o.prototype._initThresholds=function(t){var e=t||[0];return Array.isArray(e)||(e=[e]),e.sort().filter(function(t,e,n){if("number"!=typeof t||isNaN(t)||t<0||t>1)throw new Error("threshold must be a number between 0 and 1 inclusively");return t!==n[e-1]})},o.prototype._parseRootMargin=function(t){var e=(t||"0px").split(/\s+/).map(function(t){var e=/^(-?\d*\.?\d+)(px|%)$/.exec(t);if(!e)throw new Error("rootMargin must be specified in pixels or percent");return{value:parseFloat(e[1]),unit:e[2]}});return e[1]=e[1]||e[0],e[2]=e[2]||e[0],e[3]=e[3]||e[1],e},o.prototype._monitorIntersections=function(){this._monitoringIntersections||(this._monitoringIntersections=!0,this.POLL_INTERVAL?this._monitoringInterval=setInterval(this._checkForIntersections,this.POLL_INTERVAL):(s(t,"resize",this._checkForIntersections,!0),s(e,"scroll",this._checkForIntersections,!0),"MutationObserver"in t&&(this._domObserver=new MutationObserver(this._checkForIntersections),this._domObserver.observe(e,{attributes:!0,childList:!0,characterData:!0,subtree:!0}))))},o.prototype._unmonitorIntersections=function(){this._monitoringIntersections&&(this._monitoringIntersections=!1,clearInterval(this._monitoringInterval),this._monitoringInterval=null,c(t,"resize",this._checkForIntersections,!0),c(e,"scroll",this._checkForIntersections,!0),this._domObserver&&(this._domObserver.disconnect(),this._domObserver=null))},o.prototype._checkForIntersections=function(){var t=this._rootIsInDom(),e=t?this._getRootRect():{top:0,bottom:0,left:0,right:0,width:0,height:0};this._observationTargets.forEach(function(o){var i=o.element,s=a(i),c=this._rootContainsTarget(i),u=o.entry,h=t&&c&&this._computeTargetAndRootIntersection(i,e),p=o.entry=new n({time:r(),target:i,boundingClientRect:s,rootBounds:e,intersectionRect:h});u?t&&c?this._hasCrossedThreshold(u,p)&&this._queuedEntries.push(p):u&&u.isIntersecting&&this._queuedEntries.push(p):this._queuedEntries.push(p)},this),this._queuedEntries.length&&this._callback(this.takeRecords(),this)},o.prototype._computeTargetAndRootIntersection=function(n,o){var r=this;if("none"!=t.getComputedStyle(n).display){for(var i=a(n),s=p(n),c=!1;!c;){var h=null,l=1==s.nodeType?t.getComputedStyle(s):{};if("none"==l.display)return;if(s==r.root||s==e?(c=!0,h=o):s!=e.body&&s!=e.documentElement&&"visible"!=l.overflow&&(h=a(s)),h&&!(i=u(h,i)))break;s=p(s)}return i}},o.prototype._getRootRect=function(){var t;if(this.root)t=a(this.root);else{var n=e.documentElement,o=e.body;t={top:0,left:0,right:n.clientWidth||o.clientWidth,width:n.clientWidth||o.clientWidth,bottom:n.clientHeight||o.clientHeight,height:n.clientHeight||o.clientHeight}}return this._expandRectByRootMargin(t)},o.prototype._expandRectByRootMargin=function(t){var e=this._rootMarginValues.map(function(e,n){return"px"==e.unit?e.value:e.value*(n%2?t.width:t.height)/100}),n={top:t.top-e[0],right:t.right+e[1],bottom:t.bottom+e[2],left:t.left-e[3]};return n.width=n.right-n.left,n.height=n.bottom-n.top,n},o.prototype._hasCrossedThreshold=function(t,e){var n=this,o=t&&t.isIntersecting?t.intersectionRatio||0:-1,r=e.isIntersecting?e.intersectionRatio||0:-1;if(o!==r)for(var i=0;i<this.thresholds.length;i++){var s=n.thresholds[i];if(s==o||s==r||s<o!=s<r)return!0}},o.prototype._rootIsInDom=function(){return!this.root||h(e,this.root)},o.prototype._rootContainsTarget=function(t){return h(this.root||e,t)},o.prototype._registerInstance=function(){l.indexOf(this)<0&&l.push(this)},o.prototype._unregisterInstance=function(){var t=l.indexOf(this);-1!=t&&l.splice(t,1)},t.IntersectionObserver=o,t.IntersectionObserverEntry=n}}(window,document),function(){function t(t,e){var n={element:t,index:+t.getAttribute("data-scrollama-index"),direction:e};T.stepEnter&&"function"==typeof T.stepEnter&&T.stepEnter(n),H&&("up"===e?r(t,1):r(t,0))}function o(t,e){var n={element:t,index:+t.getAttribute("data-scrollama-index"),direction:e};T.stepExit&&"function"==typeof T.stepExit&&T.stepExit(n),H&&("up"===e?r(t,0):r(t,1))}function r(t,e){var n={element:t,index:+t.getAttribute("data-scrollama-index"),progress:e};T.stepProgress&&"function"==typeof T.stepProgress&&T.stepProgress(n)}function i(t){var e={direction:t};T.containerEnter&&"function"==typeof T.containerEnter&&T.containerEnter(e)}function s(t){var e={direction:t};T.containerExit&&"function"==typeof T.containerExit&&T.containerExit(e)}function c(e){e.forEach(function(e){var n=e.isIntersecting,r=e.boundingClientRect,i=e.target;if(r.bottom-L>=-R){var s=n?"down":"up";n?t(i,s):o(i,s)}})}function u(e){e.forEach(function(e){var n=e.isIntersecting,r=e.boundingClientRect,i=e.target,s=r.bottom,c=r.height,u=s-L;u>=-R&&u<c&&n?t(i,"up"):u<=R&&!n&&o(i,"down")})}function a(t){t.forEach(function(t){var e=t.isIntersecting,n=t.intersectionRatio,o=t.boundingClientRect,i=t.target,s=o.bottom-L;e&&s>=-R&&r(i,+n.toFixed(3))})}function h(t){var e=t[0],n=e.isIntersecting;if(e.boundingClientRect.bottom>-R){var o=n?"down":"up";n?i(o):s(o)}}function p(t){var e=t[0],n=e.isIntersecting;if(e.boundingClientRect.top<R){var o=n?"up":"down";n?i(o):s(o)}}function l(){w.top&&w.top.unobserve(O);var t={root:null,rootMargin:A+"px 0px -"+A+"px 0px",threshold:0};w.top=new IntersectionObserver(h,t),w.top.observe(O)}function f(){w.bottom&&w.bottom.unobserve(O);var t={root:null,rootMargin:"-"+P.height+"px 0px "+P.height+"px 0px",threshold:0};w.bottom=new IntersectionObserver(p,t),w.bottom.observe(O)}function d(){w.stepTop&&w.stepTop.forEach(function(t){return t.disconnect()}),w.stepTop=C.map(function(t,e){var n={root:null,rootMargin:B[e]-L+"px 0px "+(-A+L)+"px 0px",threshold:0},o=new IntersectionObserver(c,n);return o.observe(t),o})}function g(){w.stepBottom&&w.stepBottom.forEach(function(t){return t.disconnect()}),w.stepBottom=C.map(function(t,e){var n={root:null,rootMargin:-L+"px 0px "+(-A+B[e]+L)+"px 0px",threshold:0},o=new IntersectionObserver(u,n);return o.observe(t),o})}function m(){w.stepProgress&&w.stepProgress.forEach(function(t){return t.disconnect()}),w.stepProgress=C.map(function(t,e){var n={root:null,rootMargin:B[e]-L+"px 0px "+(-A+L)+"px 0px",threshold:F},o=new IntersectionObserver(a,n);return o.observe(t),o})}function v(){d(),g(),H&&m(),O&&M&&(l(),f())}function b(){A=window.innerHeight,P=M?M.getBoundingClientRect():null,L=k*A,B=C?C.map(function(t){return t.getBoundingClientRect().height}):[],S&&q&&v(),N&&(document.querySelector("#scrollama__debug--offset-"+x).style.top=L+"px")}function _(t){t&&!S?(q&&v(),S=!0):t||(w.top&&w.top.disconnect(),w.bottom&&w.bottom.disconnect(),w.stepTop&&w.stepTop.forEach(function(t){return t.disconnect()}),w.stepBottom&&w.stepBottom.forEach(function(t){return t.disconnect()}),w.stepProgress&&w.stepProgress.forEach(function(t){return t.disconnect()}),S=!1)}function y(){C.forEach(function(t,e){return t.setAttribute("data-scrollama-index",e)})}function E(){if(N){var t=document.createElement("div");t.setAttribute("id","scrollama__debug--offset-"+x),t.setAttribute("class","scrollama__debug--offset"),t.style.position="fixed",t.style.top="0",t.style.left="0",t.style.width="100%",t.style.height="1px",t.style.borderBottom="1px dashed red";var e=document.createElement("p"),n=C[0].getAttribute("class");e.innerText='".'+n+'" trigger: '+k,e.style.fontSize="12px",e.style.fontFamily="monospace",e.style.color="red",e.style.margin="0",e.style.padding="6px",t.appendChild(e),document.body.appendChild(t)}}function I(){F=[];for(var t=0;t<100;t++)F.push(.01*t)}var x=Math.floor(1e5*Math.random()),R=1,T={},w={},O=null,M=null,C=null,k=0,L=0,A=0,B=null,P=null,F=0,q=!1,S=!1,N=!1,H=!1,V={};return V.setup=function(t){var o=t.container,r=t.graphic,i=t.step,s=t.offset;void 0===s&&(s=.5);var c=t.progress;void 0===c&&(c=!1);var u=t.debug;return void 0===u&&(u=!1),i?(C=n(i),O=o?e(o):null,M=r?e(r):null,V.offsetTrigger(s),N=u,H=c,q=!0,E(),y(),H&&I(),b(),_(!0)):console.error("scrollama error: missing step element"),V},V.resize=function(){return b(),V},V.enable=function(){return _(!0),V},V.disable=function(){return _(!1),V},V.offsetTrigger=function(t){return t&&(isNaN(t),!0)?(k=Math.min(Math.max(0,t),1),V):k},V.onStepEnter=function(t){return T.stepEnter=t,V},V.onStepExit=function(t){return T.stepExit=t,V},V.onStepProgress=function(t){return T.stepProgress=t,V},V.onContainerEnter=function(t){return T.containerEnter=t,V},V.onContainerExit=function(t){return T.containerExit=t,V},V}}); | ||
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):t.scrollama=e()}(this,function(){"use strict";function t(t){return document.querySelector(t)}return function(t,e){function n(t){this.time=t.time,this.target=t.target,this.rootBounds=t.rootBounds,this.boundingClientRect=t.boundingClientRect,this.intersectionRect=t.intersectionRect||{top:0,bottom:0,left:0,right:0,width:0,height:0},this.isIntersecting=!!t.intersectionRect;var e=this.boundingClientRect,n=e.width*e.height,o=this.intersectionRect,r=o.width*o.height;this.intersectionRatio=n?r/n:this.isIntersecting?1:0}function o(t,e){var n=e||{};if("function"!=typeof t)throw new Error("callback must be a function");if(n.root&&1!=n.root.nodeType)throw new Error("root must be an Element");this._checkForIntersections=function(t,e){var n=null;return function(){n||(n=setTimeout(function(){t(),n=null},e))}}(this._checkForIntersections.bind(this),this.THROTTLE_TIMEOUT),this._callback=t,this._observationTargets=[],this._queuedEntries=[],this._rootMarginValues=this._parseRootMargin(n.rootMargin),this.thresholds=this._initThresholds(n.threshold),this.root=n.root||null,this.rootMargin=this._rootMarginValues.map(function(t){return t.value+t.unit}).join(" ")}function r(t,e,n,o){"function"==typeof t.addEventListener?t.addEventListener(e,n,o||!1):"function"==typeof t.attachEvent&&t.attachEvent("on"+e,n)}function i(t,e,n,o){"function"==typeof t.removeEventListener?t.removeEventListener(e,n,o||!1):"function"==typeof t.detatchEvent&&t.detatchEvent("on"+e,n)}function s(t){var e;try{e=t.getBoundingClientRect()}catch(t){}return e?(e.width&&e.height||(e={top:e.top,right:e.right,bottom:e.bottom,left:e.left,width:e.right-e.left,height:e.bottom-e.top}),e):{top:0,bottom:0,left:0,right:0,width:0,height:0}}function c(t,e){for(var n=e;n;){if(n==t)return!0;n=u(n)}return!1}function u(t){var e=t.parentNode;return e&&11==e.nodeType&&e.host?e.host:e}if("IntersectionObserver"in t&&"IntersectionObserverEntry"in t&&"intersectionRatio"in t.IntersectionObserverEntry.prototype)"isIntersecting"in t.IntersectionObserverEntry.prototype||Object.defineProperty(t.IntersectionObserverEntry.prototype,"isIntersecting",{get:function(){return this.intersectionRatio>0}});else{var a=[];o.prototype.THROTTLE_TIMEOUT=100,o.prototype.POLL_INTERVAL=null,o.prototype.observe=function(t){if(!this._observationTargets.some(function(e){return e.element==t})){if(!t||1!=t.nodeType)throw new Error("target must be an Element");this._registerInstance(),this._observationTargets.push({element:t,entry:null}),this._monitorIntersections(),this._checkForIntersections()}},o.prototype.unobserve=function(t){this._observationTargets=this._observationTargets.filter(function(e){return e.element!=t}),this._observationTargets.length||(this._unmonitorIntersections(),this._unregisterInstance())},o.prototype.disconnect=function(){this._observationTargets=[],this._unmonitorIntersections(),this._unregisterInstance()},o.prototype.takeRecords=function(){var t=this._queuedEntries.slice();return this._queuedEntries=[],t},o.prototype._initThresholds=function(t){var e=t||[0];return Array.isArray(e)||(e=[e]),e.sort().filter(function(t,e,n){if("number"!=typeof t||isNaN(t)||t<0||t>1)throw new Error("threshold must be a number between 0 and 1 inclusively");return t!==n[e-1]})},o.prototype._parseRootMargin=function(t){var e=(t||"0px").split(/\s+/).map(function(t){var e=/^(-?\d*\.?\d+)(px|%)$/.exec(t);if(!e)throw new Error("rootMargin must be specified in pixels or percent");return{value:parseFloat(e[1]),unit:e[2]}});return e[1]=e[1]||e[0],e[2]=e[2]||e[0],e[3]=e[3]||e[1],e},o.prototype._monitorIntersections=function(){this._monitoringIntersections||(this._monitoringIntersections=!0,this.POLL_INTERVAL?this._monitoringInterval=setInterval(this._checkForIntersections,this.POLL_INTERVAL):(r(t,"resize",this._checkForIntersections,!0),r(e,"scroll",this._checkForIntersections,!0),"MutationObserver"in t&&(this._domObserver=new MutationObserver(this._checkForIntersections),this._domObserver.observe(e,{attributes:!0,childList:!0,characterData:!0,subtree:!0}))))},o.prototype._unmonitorIntersections=function(){this._monitoringIntersections&&(this._monitoringIntersections=!1,clearInterval(this._monitoringInterval),this._monitoringInterval=null,i(t,"resize",this._checkForIntersections,!0),i(e,"scroll",this._checkForIntersections,!0),this._domObserver&&(this._domObserver.disconnect(),this._domObserver=null))},o.prototype._checkForIntersections=function(){var e=this._rootIsInDom(),o=e?this._getRootRect():{top:0,bottom:0,left:0,right:0,width:0,height:0};this._observationTargets.forEach(function(r){var i=r.element,c=s(i),u=this._rootContainsTarget(i),a=r.entry,h=e&&u&&this._computeTargetAndRootIntersection(i,o),p=r.entry=new n({time:t.performance&&performance.now&&performance.now(),target:i,boundingClientRect:c,rootBounds:o,intersectionRect:h});a?e&&u?this._hasCrossedThreshold(a,p)&&this._queuedEntries.push(p):a&&a.isIntersecting&&this._queuedEntries.push(p):this._queuedEntries.push(p)},this),this._queuedEntries.length&&this._callback(this.takeRecords(),this)},o.prototype._computeTargetAndRootIntersection=function(n,o){if("none"!=t.getComputedStyle(n).display){for(var r=s(n),i=u(n),c=!1;!c;){var a=null,h=1==i.nodeType?t.getComputedStyle(i):{};if("none"==h.display)return;if(i==this.root||i==e?(c=!0,a=o):i!=e.body&&i!=e.documentElement&&"visible"!=h.overflow&&(a=s(i)),a&&!(r=function(t,e){var n=Math.max(t.top,e.top),o=Math.min(t.bottom,e.bottom),r=Math.max(t.left,e.left),i=Math.min(t.right,e.right),s=i-r,c=o-n;return s>=0&&c>=0&&{top:n,bottom:o,left:r,right:i,width:s,height:c}}(a,r)))break;i=u(i)}return r}},o.prototype._getRootRect=function(){var t;if(this.root)t=s(this.root);else{var n=e.documentElement,o=e.body;t={top:0,left:0,right:n.clientWidth||o.clientWidth,width:n.clientWidth||o.clientWidth,bottom:n.clientHeight||o.clientHeight,height:n.clientHeight||o.clientHeight}}return this._expandRectByRootMargin(t)},o.prototype._expandRectByRootMargin=function(t){var e=this._rootMarginValues.map(function(e,n){return"px"==e.unit?e.value:e.value*(n%2?t.width:t.height)/100}),n={top:t.top-e[0],right:t.right+e[1],bottom:t.bottom+e[2],left:t.left-e[3]};return n.width=n.right-n.left,n.height=n.bottom-n.top,n},o.prototype._hasCrossedThreshold=function(t,e){var n=t&&t.isIntersecting?t.intersectionRatio||0:-1,o=e.isIntersecting?e.intersectionRatio||0:-1;if(n!==o)for(var r=0;r<this.thresholds.length;r++){var i=this.thresholds[r];if(i==n||i==o||i<n!=i<o)return!0}},o.prototype._rootIsInDom=function(){return!this.root||c(e,this.root)},o.prototype._rootContainsTarget=function(t){return c(this.root||e,t)},o.prototype._registerInstance=function(){a.indexOf(this)<0&&a.push(this)},o.prototype._unregisterInstance=function(){var t=a.indexOf(this);-1!=t&&a.splice(t,1)},t.IntersectionObserver=o,t.IntersectionObserverEntry=n}}(window,document),function(){function e(t){return+t.getAttribute("data-scrollama-index")}function n(){window.pageYOffset>q?S="down":window.pageYOffset<q&&(S="up"),q=window.pageYOffset}function o(t){var n=e(t),o={element:t,index:n,direction:S};F[n].direction=S,F[n].state="enter",y.stepEnter&&"function"==typeof y.stepEnter&&y.stepEnter(o),P&&("down"===S?i(t,0):i(t,1))}function r(t){var n=e(t),o={element:t,index:n,direction:S};F[n].direction=S,F[n].state="exit",y.stepExit&&"function"==typeof y.stepExit&&y.stepExit(o),P&&("down"===S?i(t,1):i(t,0))}function i(t,n){var o={element:t,index:e(t),progress:n};y.stepProgress&&"function"==typeof y.stepProgress&&y.stepProgress(o)}function s(){var t={direction:S};y.containerEnter&&"function"==typeof y.containerEnter&&y.containerEnter(t)}function c(){var t={direction:S};y.containerExit&&"function"==typeof y.containerExit&&y.containerExit(t)}function u(t){n(),t.forEach(function(t){var n=t.isIntersecting,i=(t.intersectionRatio,t.boundingClientRect),s=t.target,c=i.bottom-T,u=e(s);c>=-_&&(n&&"down"===S?o(s):"up"===S&&("exit"===F[u].state&&o(s),r(s)))})}function a(t){n(),t.forEach(function(t){var n=t.isIntersecting,i=(t.intersectionRatio,t.boundingClientRect),s=t.target,c=i.bottom,u=i.height,a=c-T,h=e(s);a>=-_&&a<u&&n&&"up"===S?o(s):a<=_&&!n&&"down"===S&&("exit"===F[h].state&&o(s),r(s))})}function h(t){n(),t.forEach(function(t){var n=t.isIntersecting,i=(t.intersectionRatio,t.boundingClientRect,t.target),s=e(i);n&&"down"===S&&"exit"===F[s].state&&"up"===F[s].direction&&(o(i),r(i))})}function p(t){n(),t.forEach(function(t){var n=t.isIntersecting,i=(t.intersectionRatio,t.boundingClientRect,t.target),s=e(i);n&&"up"===S&&"exit"===F[s].state&&"down"===F[s].direction&&(o(i),r(i))})}function l(t){n(),t.forEach(function(t){var e=t.isIntersecting,n=t.intersectionRatio,o=t.boundingClientRect,r=t.target,s=o.bottom;e&&s-T>=-_&&i(r,+n.toFixed(3))})}function f(t){n();var e=t[0],o=e.isIntersecting,r=e.boundingClientRect;r.top,r.bottom>-_&&(o?s():c())}function d(t){n();var e=t[0],o=e.isIntersecting;e.boundingClientRect.top<_&&(o?s():c())}function g(){E.stepAbove&&E.stepAbove.forEach(function(t){return t.disconnect()}),E.stepAbove=I.map(function(t,e){var n={root:null,rootMargin:M[e]-T+"px 0px "+(-O+T)+"px 0px",threshold:0},o=new IntersectionObserver(u,n);return o.observe(t),o}),E.stepBelow&&E.stepBelow.forEach(function(t){return t.disconnect()}),E.stepBelow=I.map(function(t,e){var n={root:null,rootMargin:-T+"px 0px "+(-O+M[e]+T)+"px 0px",threshold:0},o=new IntersectionObserver(a,n);return o.observe(t),o}),E.viewportAbove&&E.viewportAbove.forEach(function(t){return t.disconnect()}),E.viewportAbove=I.map(function(t,e){var n={root:null,rootMargin:"0px 0px "+-(O-T+M[e])+"px 0px",threshold:0},o=new IntersectionObserver(h,n);return o.observe(t),o}),E.viewportBelow&&E.viewportBelow.forEach(function(t){return t.disconnect()}),E.viewportBelow=I.map(function(t,e){var n={root:null,rootMargin:-(T+M[e])+"px 0px 0px 0px",threshold:0},o=new IntersectionObserver(p,n);return o.observe(t),o}),P&&(E.stepProgress&&E.stepProgress.forEach(function(t){return t.disconnect()}),E.stepProgress=I.map(function(t,e){var n={root:null,rootMargin:M[e]-T+"px 0px "+(-O+T)+"px 0px",threshold:A},o=new IntersectionObserver(l,n);return o.observe(t),o})),w&&x&&(function(){E.top&&E.top.unobserve(w);var t={root:null,rootMargin:O+"px 0px -"+O+"px 0px",threshold:0};E.top=new IntersectionObserver(f,t),E.top.observe(w)}(),function(){E.bottom&&E.bottom.unobserve(w);var t={root:null,rootMargin:"-"+C.height+"px 0px "+C.height+"px 0px",threshold:0};E.bottom=new IntersectionObserver(d,t),E.bottom.observe(w)}())}function v(){O=window.innerHeight,C=x?x.getBoundingClientRect():null,T=R*O,M=I?I.map(function(t){return t.getBoundingClientRect().height}):[],k&&B&&g(),L&&(document.querySelector("#scrollama__debug--offset-"+m).style.top=T+"px")}function b(t){t&&!k?(B&&g(),k=!0):t||(E.top&&E.top.disconnect(),E.bottom&&E.bottom.disconnect(),E.stepAbove&&E.stepAbove.forEach(function(t){return t.disconnect()}),E.stepBelow&&E.stepBelow.forEach(function(t){return t.disconnect()}),E.stepProgress&&E.stepProgress.forEach(function(t){return t.disconnect()}),E.viewportAbove&&E.viewportAbove.forEach(function(t){return t.disconnect()}),E.viewportBelow&&E.viewportBelow.forEach(function(t){return t.disconnect()}),k=!1)}var m=Math.floor(1e5*Math.random()),_=1,y={},E={},w=null,x=null,I=null,R=0,T=0,O=0,M=null,C=null,A=0,B=!1,k=!1,L=!1,P=!1,F=null,q=0,S="up",N={};return N.setup=function(e){var n=e.container,o=e.graphic,r=e.step,i=e.offset;void 0===i&&(i=.5);var s=e.progress;void 0===s&&(s=!1);var c=e.debug;return void 0===c&&(c=!1),r?(I=function(t,e){return void 0===e&&(e=document),function(t){for(var e=t.length,n=[],o=0;o<e;o+=1)n.push(t[o]);return n}(e.querySelectorAll(t))}(r),w=n?t(n):null,x=o?t(o):null,N.offsetTrigger(i),L=c,P=s,B=!0,function(){if(L){var t=document.createElement("div");t.setAttribute("id","scrollama__debug--offset-"+m),t.setAttribute("class","scrollama__debug--offset"),t.style.position="fixed",t.style.top="0",t.style.left="0",t.style.width="100%",t.style.height="1px",t.style.borderBottom="1px dashed red";var e=document.createElement("p"),n=I[0].getAttribute("class");e.innerText='".'+n+'" trigger: '+R,e.style.fontSize="12px",e.style.fontFamily="monospace",e.style.color="red",e.style.margin="0",e.style.padding="6px",t.appendChild(e),document.body.appendChild(t)}}(),I.forEach(function(t,e){return t.setAttribute("data-scrollama-index",e)}),F=I.map(function(){return{direction:null,state:null,bottom:-1}}),P&&function(){A=[];for(var t=0;t<100;t++)A.push(.01*t)}(),v(),b(!0)):console.error("scrollama error: missing step element"),N},N.resize=function(){return v(),N},N.enable=function(){return b(!0),N},N.disable=function(){return b(!1),N},N.offsetTrigger=function(t){return t&&(isNaN(t),!0)?(R=Math.min(Math.max(0,t),1),N):R},N.onStepEnter=function(t){return y.stepEnter=t,N},N.onStepExit=function(t){return y.stepExit=t,N},N.onStepProgress=function(t){return y.stepProgress=t,N},N.onContainerEnter=function(t){return y.containerEnter=t,N},N.onContainerExit=function(t){return y.containerExit=t,N},N}}); |
{ | ||
"name": "scrollama", | ||
"version": "0.5.4", | ||
"version": "0.6.0", | ||
"description": "Lightweight scrollytelling library using IntersectionObserver", | ||
@@ -8,6 +8,6 @@ "main": "build/scrollama.js", | ||
"scripts": { | ||
"dev": "rollup -w --config rollup.config.dev.js", | ||
"pretest": "rm -rf build && mkdir build && rollup --config rollup.config.js", | ||
"build": "npm run pretest && uglifyjs -m -c -- build/scrollama.js > build/scrollama.min.js", | ||
"docs": "cp build/scrollama.js docs" | ||
"dev": "cross-env NODE_ENV=development rollup -w -c", | ||
"build": "cross-env NODE_ENV=production rollup -c && npm run docs", | ||
"pretest": "npm run dev", | ||
"docs": "cp build/scrollama.min.js docs" | ||
}, | ||
@@ -34,12 +34,14 @@ "module": "index", | ||
"devDependencies": { | ||
"rollup": "^0.50.0", | ||
"cross-env": "^5.1.1", | ||
"rollup": "^0.51.8", | ||
"rollup-plugin-babel": "^3.0.2", | ||
"rollup-plugin-buble": "^0.16.0", | ||
"rollup-plugin-commonjs": "^8.2.4", | ||
"rollup-plugin-buble": "^0.18.0", | ||
"rollup-plugin-commonjs": "^8.2.6", | ||
"rollup-plugin-filesize": "^1.5.0", | ||
"rollup-plugin-node-resolve": "^3.0.0", | ||
"uglifyjs": "^2.4.11" | ||
"rollup-plugin-uglify": "^2.0.1" | ||
}, | ||
"dependencies": { | ||
"intersection-observer": "^0.4.2" | ||
"intersection-observer": "^0.4.3" | ||
} | ||
} |
184
README.md
###### scrollama.js | ||
<img src="https://russellgoldenberg.github.io/scrollama/logo.png" width="160" alt="scrollama.js"/> | ||
**Scrollama** is a modern & lightweight JavaScript library for scrollytelling using [IntersectionObserver](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API) in favor of scroll events. | ||
**Scrollama** is a modern & lightweight JavaScript library for scrollytelling | ||
using | ||
[IntersectionObserver](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API) | ||
in favor of scroll events. | ||
As seen on [The Pudding](https://pudding.cool/): | ||
* [What is a Superteam in the NBA?](https://pudding.cool/2017/10/superteams/) | ||
* [What City is the Microbrew Capital of the US?](https://pudding.cool/2017/04/beer/) | ||
<!-- * [2017-18 NBA Top Plays](https://russellgoldenberg.github.io/reddit-nba-top-plays) --> | ||
<!-- * [2017-18 NBA Top Plays](https://russellgoldenberg.github.io/reddit-nba-top-plays) --> | ||
@@ -15,3 +20,11 @@ [Jump to examples.](https://github.com/russellgoldenberg/scrollama#examples) | ||
Scrollytelling can be complicated to implement and difficult to make performant. The goal of this library is to provide a simple interface for creating scroll-driven interactives. Scrollama is focused on perfomance by using [IntersectionObserver](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API) to handle element position detection. It offers an opinionated (but popular) scrollytelling pattern to reduce more involved DOM calculations. The sticky graphic pattern (enter-stick-exit) can be seen below. Check out my [blog post](https://pudding.cool/process/introducing-scrollama) for a deeper introduction. | ||
Scrollytelling can be complicated to implement and difficult to make performant. | ||
The goal of this library is to provide a simple interface for creating | ||
scroll-driven interactives. Scrollama is focused on perfomance by using | ||
[IntersectionObserver](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API) | ||
to handle element position detection. It offers an opinionated (but popular) | ||
scrollytelling pattern to reduce more involved DOM calculations. The sticky | ||
graphic pattern (enter-stick-exit) can be seen below. Check out my | ||
[blog post](https://pudding.cool/process/introducing-scrollama) for a deeper | ||
introduction. | ||
@@ -25,3 +38,3 @@ [![scrollytelling pattern](https://thumbs.gfycat.com/FearfulHotArabianoryx-size_restricted.gif)](https://pudding.cool/process/how-to-implement-scrollytelling) | ||
```html | ||
<script src='scrollama.min.js'></script> | ||
<script src='https://unpkg.com/scrollama'></script> | ||
``` | ||
@@ -38,3 +51,3 @@ | ||
```js | ||
import scrollama from 'scrollama' // or... | ||
import scrollama from 'scrollama'; // or... | ||
const scrollama = require('scrollama'); | ||
@@ -47,5 +60,10 @@ ``` | ||
You can use this library to simply trigger steps, similar to something like [Waypoints](http://imakewebthings.com/waypoints/). This is useful if you need more control over your interactive, or you don't want to follow the sticky scrollytelling pattern. | ||
You can use this library to simply trigger steps, similar to something like | ||
[Waypoints](http://imakewebthings.com/waypoints/). This is useful if you need | ||
more control over your interactive, or you don't want to follow the sticky | ||
scrollytelling pattern. | ||
You can use any id/class naming conventions you want. The HTML structure should look like: | ||
You can use any id/class naming conventions you want. The HTML structure should | ||
look like: | ||
```html | ||
@@ -60,17 +78,20 @@ <!--you don't need the "data-step" attr, but can be useful for storing instructions for JS --> | ||
// instantiate the scrollama | ||
const scroller = Scrollama() | ||
const scroller = Scrollama(); | ||
// setup the instance, pass callback functions | ||
scroller.setup({ | ||
step: '.step', // required | ||
offset: 0.5, // optional, default = 0.5 | ||
debug: false, // optional, default = false | ||
}) | ||
.onStepEnter(handleStepEnter) | ||
.onStepExit(handleStepExit) | ||
scroller | ||
.setup({ | ||
step: '.step', // required | ||
offset: 0.5, // optional, default = 0.5 | ||
debug: false // optional, default = false | ||
}) | ||
.onStepEnter(handleStepEnter) | ||
.onStepExit(handleStepExit); | ||
``` | ||
#### Sticky Graphic | ||
To implement the sticky graphic scrollytelling pattern, you need the following three elements (container, graphic, steps). The structure should look like: | ||
To implement the sticky graphic scrollytelling pattern, you need the following | ||
three elements (container, graphic, steps). The structure should look like: | ||
```html | ||
@@ -94,16 +115,17 @@ <!-- container = ".scroll" --> | ||
// instantiate the scrollama | ||
const scroller = Scrollama() | ||
const scroller = Scrollama(); | ||
// setup the instance, pass callback functions | ||
scroller.setup({ | ||
step: '.scroll__text .step', // required | ||
container: '.scroll', // required (for sticky) | ||
graphic: '.scroll__graphic', // required (for sticky) | ||
offset: 0.5, // optional, default = 0.5 | ||
debug: false, // optional, default = false | ||
}) | ||
.onStepEnter(handleStepEnter) | ||
.onStepExit(handleStepExit) | ||
.onContainerEnter(handleContainerEnter) | ||
.onContainerExit(handleContainerExit) | ||
scroller | ||
.setup({ | ||
step: '.scroll__text .step', // required | ||
container: '.scroll', // required (for sticky) | ||
graphic: '.scroll__graphic', // required (for sticky) | ||
offset: 0.5, // optional, default = 0.5 | ||
debug: false // optional, default = false | ||
}) | ||
.onStepEnter(handleStepEnter) | ||
.onStepExit(handleStepExit) | ||
.onContainerEnter(handleContainerEnter) | ||
.onContainerExit(handleContainerExit); | ||
``` | ||
@@ -115,16 +137,24 @@ | ||
*options:* | ||
* `step` (string): Selector for the step elements that will trigger changes. **required** | ||
* `container` (string): Selector for the element that contains everything for the scroller. **optional** | ||
* `graphic` (string): Selector for the graphic element that will become fixed. **optional** | ||
* `offset` (number, 0 - 1): How far from the top of the viewport to trigger a step. **(default: 0.5)** | ||
* `progress` (boolean): Whether to fire incremental step progress updates or not. **(default: false)** | ||
* `debug` (boolean): Whether to show visual debugging tools or not. **(default: false)** | ||
_options:_ | ||
* `step` (string): Selector for the step elements that will trigger changes. | ||
**required** | ||
* `container` (string): Selector for the element that contains everything for | ||
the scroller. **optional** | ||
* `graphic` (string): Selector for the graphic element that will become fixed. | ||
**optional** | ||
* `offset` (number, 0 - 1): How far from the top of the viewport to trigger a | ||
step. **(default: 0.5)** | ||
* `progress` (boolean): Whether to fire incremental step progress updates or | ||
not. **(default: false)** | ||
* `debug` (boolean): Whether to show visual debugging tools or not. **(default: | ||
false)** | ||
#### scrollama.onStepEnter(callback) | ||
Callback that fires when the top or bottom edge of a step element enters the offset threshold. | ||
Callback that fires when the top or bottom edge of a step element enters the | ||
offset threshold. | ||
The argument of the callback is an object: | ||
`{ element: DOMElement, index: number, direction: string }` | ||
The argument of the callback is an object: `{ element: DOMElement, index: | ||
number, direction: string }` | ||
@@ -139,6 +169,7 @@ `element`: The step element that triggered | ||
Callback that fires when the top or bottom edge of a step element exits the offset threshold. | ||
Callback that fires when the top or bottom edge of a step element exits the | ||
offset threshold. | ||
The argument of the callback is an object: | ||
`{ element: DOMElement, index: number, direction: string }` | ||
The argument of the callback is an object: `{ element: DOMElement, index: | ||
number, direction: string }` | ||
@@ -155,4 +186,4 @@ `element`: The step element that triggered | ||
The argument of the callback is an object: | ||
`{ element: DOMElement, index: number, progress: number }` | ||
The argument of the callback is an object: `{ element: DOMElement, index: | ||
number, progress: number }` | ||
@@ -167,6 +198,6 @@ `element`: The step element that triggered | ||
Callback that fires when the top of container becomes flush with viewport *or* the graphic becomes fully in view coming from the bottom of the container. | ||
Callback that fires when the top of container becomes flush with viewport _or_ | ||
the graphic becomes fully in view coming from the bottom of the container. | ||
The argument of the callback is an object: | ||
`{ direction: string }` | ||
The argument of the callback is an object: `{ direction: string }` | ||
@@ -177,6 +208,6 @@ `direction`: 'up' or 'down' | ||
Callback that fires when the top of container goes below viewport *or* the graphic becomes not full in view leaving the bottom of the container. | ||
Callback that fires when the top of container goes below viewport _or_ the | ||
graphic becomes not full in view leaving the bottom of the container. | ||
The argument of the callback is an object: | ||
`{ direction: string }` | ||
The argument of the callback is an object: `{ direction: string }` | ||
@@ -191,7 +222,10 @@ `direction`: 'up' or 'down' | ||
Tell scrollama to get latest dimensions the browser/DOM. It is best practice to throttle resize in your code, update the DOM elements, then call this function at the end. | ||
Tell scrollama to get latest dimensions the browser/DOM. It is best practice to | ||
throttle resize in your code, update the DOM elements, then call this function | ||
at the end. | ||
#### scrollama.enable() | ||
Tell scrollama to resume observing for trigger changes. Only necessary to call if you have previously disabled. | ||
Tell scrollama to resume observing for trigger changes. Only necessary to call | ||
if you have previously disabled. | ||
@@ -204,15 +238,27 @@ #### scrollama.disable() | ||
*Note: most of these demos use D3 to keep the code concise, but this can be used with any library, or with no library at all.* | ||
_Note: most of these demos use D3 to keep the code concise, but this can be used | ||
with any library, or with no library at all._ | ||
* [Basic](https://russellgoldenberg.github.io/scrollama/basic) - just step triggers | ||
* [Progress](https://russellgoldenberg.github.io/scrollama/progress) - incremental step progress callback | ||
* [Sticky Graphic v1a (CSS, position sticky)](https://russellgoldenberg.github.io/scrollama/sticky-css) - using CSS vertically center chart, and position sticky (+ polyfill) for sticking. | ||
* [Sticky Graphic v1b (JS, position sticky)](https://russellgoldenberg.github.io/scrollama/sticky-js) - using JS vertically center chart, and position sticky (+ polyfill) for sticking. Added bonus ability to start chart at top of steps then vertically. | ||
* [Sticky Graphic v2a (CSS, position fixed)](https://russellgoldenberg.github.io/scrollama/fixed-css) - using CSS vertically center chart, and position fixed and absolute for sticking. | ||
* [Sticky Graphic v2b (JS, position fixed)](https://russellgoldenberg.github.io/scrollama/fixed-js) - using read position fixed and absolute for sticking. | ||
* [Basic](https://russellgoldenberg.github.io/scrollama/basic) - just step | ||
triggers | ||
* [Progress](https://russellgoldenberg.github.io/scrollama/progress) - | ||
incremental step progress callback | ||
* [Sticky Graphic v1a (CSS, position sticky)](https://russellgoldenberg.github.io/scrollama/sticky-css) - | ||
using CSS vertically center chart, and position sticky (+ polyfill) for | ||
sticking. | ||
* [Sticky Graphic v1b (JS, position sticky)](https://russellgoldenberg.github.io/scrollama/sticky-js) - | ||
using JS vertically center chart, and position sticky (+ polyfill) for | ||
sticking. Added bonus ability to start chart at top of steps then vertically. | ||
* [Sticky Graphic v2a (CSS, position fixed)](https://russellgoldenberg.github.io/scrollama/fixed-css) - | ||
using CSS vertically center chart, and position fixed and absolute for | ||
sticking. | ||
* [Sticky Graphic v2b (JS, position fixed)](https://russellgoldenberg.github.io/scrollama/fixed-js) - | ||
using read position fixed and absolute for sticking. | ||
### Tips | ||
* Always call `scrollama.resize()` after a window resize event to ensure scroll triggers update with new dimensions. | ||
* Avoid using `viewport height` (vh) in your CSS because scrolling up and down constantly triggers vh to change, which will also trigger a window resize. | ||
* Always call `scrollama.resize()` after a window resize event to ensure scroll | ||
triggers update with new dimensions. | ||
* Avoid using `viewport height` (vh) in your CSS because scrolling up and down | ||
constantly triggers vh to change, which will also trigger a window resize. | ||
@@ -231,2 +277,3 @@ ### To do | ||
### Logo | ||
Logo by the awesome [Elaina Natario](https://twitter.com/elainanatario) | ||
@@ -240,6 +287,17 @@ | ||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: | ||
Permission is hereby granted, free of charge, to any person obtaining a copy of | ||
this software and associated documentation files (the "Software"), to deal in | ||
the Software without restriction, including without limitation the rights to | ||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of | ||
the Software, and to permit persons to whom the Software is furnished to do so, | ||
subject to the following conditions: | ||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. | ||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS | ||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR | ||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | ||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
import commonjs from 'rollup-plugin-commonjs'; | ||
import resolve from 'rollup-plugin-node-resolve'; | ||
import buble from 'rollup-plugin-buble'; | ||
import uglify from 'rollup-plugin-uglify'; | ||
import filesize from 'rollup-plugin-filesize'; | ||
const isProd = process.env.NODE_ENV === 'production'; | ||
const file = `build/scrollama${isProd ? '.min' : ''}.js`; | ||
const plugins = [ | ||
resolve({ | ||
jsnext: true, | ||
main: true, | ||
}), | ||
commonjs({ | ||
sourceMap: false, | ||
}), | ||
buble(), | ||
filesize(), | ||
]; | ||
isProd && plugins.push(uglify()); | ||
export default { | ||
input: 'index.js', | ||
output: { | ||
file: 'build/scrollama.js', | ||
file, | ||
format: 'umd', | ||
}, | ||
name: 'scrollama', | ||
plugins: [ | ||
resolve({ | ||
jsnext: true, | ||
main: true, | ||
}), | ||
commonjs({ | ||
sourceMap: false, | ||
}), | ||
buble(), | ||
], | ||
plugins, | ||
}; |
213
src/init.js
@@ -27,22 +27,48 @@ import { select, selectAll } from './dom'; | ||
let stepStates = null; | ||
let previousYOffset = 0; | ||
let direction = 'up'; | ||
function getIndex(element) { | ||
return +element.getAttribute('data-scrollama-index'); | ||
} | ||
function updateDirection() { | ||
if (window.pageYOffset > previousYOffset) direction = 'down'; | ||
else if (window.pageYOffset < previousYOffset) direction = 'up'; | ||
previousYOffset = window.pageYOffset; | ||
} | ||
// NOTIFY CALLBACKS | ||
function notifyStepEnter(element, direction) { | ||
const index = +element.getAttribute('data-scrollama-index'); | ||
function notifyStepEnter(element) { | ||
const index = getIndex(element); | ||
const resp = { element, index, direction }; | ||
// store most recent trigger | ||
stepStates[index].direction = direction; | ||
stepStates[index].state = 'enter'; | ||
if (callback.stepEnter && typeof callback.stepEnter === 'function') | ||
callback.stepEnter(resp); | ||
if (progressMode) { | ||
if (direction === 'up') notifyStepProgress(element, 1); | ||
else notifyStepProgress(element, 0); | ||
if (direction === 'down') notifyStepProgress(element, 0); | ||
else notifyStepProgress(element, 1); | ||
} | ||
} | ||
function notifyStepExit(element, direction) { | ||
const index = +element.getAttribute('data-scrollama-index'); | ||
function notifyStepExit(element) { | ||
const index = getIndex(element); | ||
const resp = { element, index, direction }; | ||
// store most recent trigger | ||
stepStates[index].direction = direction; | ||
stepStates[index].state = 'exit'; | ||
if (callback.stepExit && typeof callback.stepExit === 'function') | ||
callback.stepExit(resp); | ||
if (progressMode) { | ||
if (direction === 'up') notifyStepProgress(element, 0); | ||
else notifyStepProgress(element, 1); | ||
if (direction === 'down') notifyStepProgress(element, 1); | ||
else notifyStepProgress(element, 0); | ||
} | ||
@@ -52,3 +78,3 @@ } | ||
function notifyStepProgress(element, progress) { | ||
const index = +element.getAttribute('data-scrollama-index'); | ||
const index = getIndex(element); | ||
const resp = { element, index, progress }; | ||
@@ -59,3 +85,3 @@ if (callback.stepProgress && typeof callback.stepProgress === 'function') | ||
function notifyContainerEnter(direction) { | ||
function notifyContainerEnter() { | ||
const resp = { direction }; | ||
@@ -69,3 +95,3 @@ if ( | ||
function notifyContainerExit(direction) { | ||
function notifyContainerExit() { | ||
const resp = { direction }; | ||
@@ -80,3 +106,4 @@ if (callback.containerExit && typeof callback.containerExit === 'function') | ||
// bottom must be > 0 which means it is on "screen" (shifted by offset) | ||
function intersectStepTop(entries) { | ||
function intersectStepAbove(entries) { | ||
updateDirection(); | ||
entries.forEach(entry => { | ||
@@ -89,8 +116,16 @@ const { | ||
} = entry; | ||
// bottom is how far bottom edge of el is from top of viewport | ||
const { bottom } = boundingClientRect; | ||
const bottomAdjusted = bottom - offsetMargin; | ||
const index = getIndex(target); | ||
if (bottomAdjusted >= -ZERO_MOE) { | ||
const direction = isIntersecting ? 'down' : 'up'; | ||
if (isIntersecting) notifyStepEnter(target, direction); | ||
else notifyStepExit(target, direction); | ||
if (isIntersecting && direction === 'down') | ||
notifyStepEnter(target, direction); | ||
else if (direction === 'up') { | ||
// we went from exit to exit, must have skipped an enter | ||
if (stepStates[index].state === 'exit') | ||
notifyStepEnter(target, direction); | ||
notifyStepExit(target, direction); | ||
} | ||
} | ||
@@ -100,3 +135,4 @@ }); | ||
function intersectStepBottom(entries) { | ||
function intersectStepBelow(entries) { | ||
updateDirection(); | ||
entries.forEach(entry => { | ||
@@ -111,11 +147,18 @@ const { | ||
const bottomAdjusted = bottom - offsetMargin; | ||
const index = getIndex(target); | ||
if ( | ||
bottomAdjusted >= -ZERO_MOE && | ||
bottomAdjusted < height && | ||
isIntersecting | ||
isIntersecting && | ||
direction === 'up' | ||
) { | ||
const direction = 'up'; | ||
notifyStepEnter(target, direction); | ||
} else if (bottomAdjusted <= ZERO_MOE && !isIntersecting) { | ||
const direction = 'down'; | ||
} else if ( | ||
bottomAdjusted <= ZERO_MOE && | ||
!isIntersecting && | ||
direction === 'down' | ||
) { | ||
if (stepStates[index].state === 'exit') | ||
notifyStepEnter(target, direction); | ||
notifyStepExit(target, direction); | ||
@@ -126,3 +169,53 @@ } | ||
// if there is a scroll even that skips the entire enter/exit of a step, | ||
// fallback to trigger the enter/exit if element lands in viewport | ||
function intersectViewportAbove(entries) { | ||
updateDirection(); | ||
entries.forEach(entry => { | ||
const { | ||
isIntersecting, | ||
intersectionRatio, | ||
boundingClientRect, | ||
target | ||
} = entry; | ||
const index = getIndex(target); | ||
if (isIntersecting && direction === 'down') { | ||
if ( | ||
stepStates[index].state === 'exit' && | ||
stepStates[index].direction === 'up' | ||
) { | ||
notifyStepEnter(target, 'down'); | ||
notifyStepExit(target, 'down'); | ||
} | ||
} | ||
}); | ||
} | ||
function intersectViewportBelow(entries) { | ||
updateDirection(); | ||
entries.forEach(entry => { | ||
const { | ||
isIntersecting, | ||
intersectionRatio, | ||
boundingClientRect, | ||
target | ||
} = entry; | ||
const index = getIndex(target); | ||
if (isIntersecting && direction === 'up') { | ||
if ( | ||
stepStates[index].state === 'exit' && | ||
stepStates[index].direction === 'down' | ||
) { | ||
notifyStepEnter(target, 'up'); | ||
notifyStepExit(target, 'up'); | ||
} | ||
} | ||
}); | ||
} | ||
function intersectStepProgress(entries) { | ||
updateDirection(); | ||
entries.forEach(entry => { | ||
@@ -145,6 +238,6 @@ const { | ||
function intersectTop(entries) { | ||
updateDirection(); | ||
const { isIntersecting, boundingClientRect } = entries[0]; | ||
const { top, bottom } = boundingClientRect; | ||
if (bottom > -ZERO_MOE) { | ||
const direction = isIntersecting ? 'down' : 'up'; | ||
if (isIntersecting) notifyContainerEnter(direction); | ||
@@ -156,6 +249,6 @@ else notifyContainerExit(direction); | ||
function intersectBottom(entries) { | ||
updateDirection(); | ||
const { isIntersecting, boundingClientRect } = entries[0]; | ||
const { top } = boundingClientRect; | ||
if (top < ZERO_MOE) { | ||
const direction = isIntersecting ? 'up' : 'down'; | ||
if (isIntersecting) notifyContainerEnter(direction); | ||
@@ -193,6 +286,6 @@ else notifyContainerExit(direction); | ||
// top edge | ||
function updateStepTopIO() { | ||
if (io.stepTop) io.stepTop.forEach(d => d.disconnect()); | ||
function updateStepAboveIO() { | ||
if (io.stepAbove) io.stepAbove.forEach(d => d.disconnect()); | ||
io.stepTop = stepEl.map((el, i) => { | ||
io.stepAbove = stepEl.map((el, i) => { | ||
const marginTop = stepHeights[i] - offsetMargin; | ||
@@ -208,3 +301,3 @@ const marginBottom = -vh + offsetMargin; | ||
const obs = new IntersectionObserver(intersectStepTop, options); | ||
const obs = new IntersectionObserver(intersectStepAbove, options); | ||
obs.observe(el); | ||
@@ -216,6 +309,6 @@ return obs; | ||
// bottom edge | ||
function updateStepBottomIO() { | ||
if (io.stepBottom) io.stepBottom.forEach(d => d.disconnect()); | ||
function updateStepBelowIO() { | ||
if (io.stepBelow) io.stepBelow.forEach(d => d.disconnect()); | ||
io.stepBottom = stepEl.map((el, i) => { | ||
io.stepBelow = stepEl.map((el, i) => { | ||
const marginTop = -offsetMargin; | ||
@@ -231,3 +324,3 @@ const marginBottom = -vh + stepHeights[i] + offsetMargin; | ||
const obs = new IntersectionObserver(intersectStepBottom, options); | ||
const obs = new IntersectionObserver(intersectStepBelow, options); | ||
obs.observe(el); | ||
@@ -238,2 +331,41 @@ return obs; | ||
// jump into viewport | ||
function updateViewportAboveIO() { | ||
if (io.viewportAbove) io.viewportAbove.forEach(d => d.disconnect()); | ||
io.viewportAbove = stepEl.map((el, i) => { | ||
const marginTop = 0; | ||
const marginBottom = -(vh - offsetMargin + stepHeights[i]); | ||
const rootMargin = `${marginTop}px 0px ${marginBottom}px 0px`; | ||
const options = { | ||
root: null, | ||
rootMargin, | ||
threshold: 0 | ||
}; | ||
const obs = new IntersectionObserver(intersectViewportAbove, options); | ||
obs.observe(el); | ||
return obs; | ||
}); | ||
} | ||
function updateViewportBelowIO() { | ||
if (io.viewportBelow) io.viewportBelow.forEach(d => d.disconnect()); | ||
io.viewportBelow = stepEl.map((el, i) => { | ||
const marginTop = -(offsetMargin + stepHeights[i]); | ||
const marginBottom = 0; | ||
const rootMargin = `${marginTop}px 0px ${marginBottom}px 0px`; | ||
const options = { | ||
root: null, | ||
rootMargin, | ||
threshold: 0 | ||
}; | ||
const obs = new IntersectionObserver(intersectViewportBelow, options); | ||
obs.observe(el); | ||
return obs; | ||
}); | ||
} | ||
// progress progress tracker | ||
@@ -261,4 +393,6 @@ function updateStepProgressIO() { | ||
function updateIO() { | ||
updateStepTopIO(); | ||
updateStepBottomIO(); | ||
updateStepAboveIO(); | ||
updateStepBelowIO(); | ||
updateViewportAboveIO(); | ||
updateViewportBelowIO(); | ||
@@ -299,5 +433,7 @@ if (progressMode) updateStepProgressIO(); | ||
if (io.bottom) io.bottom.disconnect(); | ||
if (io.stepTop) io.stepTop.forEach(d => d.disconnect()); | ||
if (io.stepBottom) io.stepBottom.forEach(d => d.disconnect()); | ||
if (io.stepAbove) io.stepAbove.forEach(d => d.disconnect()); | ||
if (io.stepBelow) io.stepBelow.forEach(d => d.disconnect()); | ||
if (io.stepProgress) io.stepProgress.forEach(d => d.disconnect()); | ||
if (io.viewportAbove) io.viewportAbove.forEach(d => d.disconnect()); | ||
if (io.viewportBelow) io.viewportBelow.forEach(d => d.disconnect()); | ||
isEnabled = false; | ||
@@ -311,2 +447,10 @@ } | ||
function setupStepStates() { | ||
stepStates = stepEl.map(() => ({ | ||
direction: null, | ||
state: null, | ||
bottom: -1 | ||
})); | ||
} | ||
function addDebug() { | ||
@@ -366,2 +510,3 @@ if (debugMode) { | ||
indexSteps(); | ||
setupStepStates(); | ||
if (progressMode) setThreshold(); | ||
@@ -368,0 +513,0 @@ handleResize(); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Mixed license
License(Experimental) Package contains multiple licenses.
Found 1 instance in 1 package
0
289
608754
8
24
1758
1
1
Updatedintersection-observer@^0.4.3