Comparing version 2.2.2 to 3.0.0
(function (global, factory) { | ||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : | ||
typeof define === 'function' && define.amd ? define(factory) : | ||
(global.scrollama = factory()); | ||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : | ||
typeof define === 'function' && define.amd ? define(factory) : | ||
(global = global || self, global.scrollama = factory()); | ||
}(this, (function () { 'use strict'; | ||
// DOM helper functions | ||
// DOM helper functions | ||
// public | ||
function selectAll(selector, parent) { | ||
if ( parent === void 0 ) parent = document; | ||
// public | ||
function selectAll(selector, parent = document) { | ||
if (typeof selector === 'string') { | ||
return Array.from(parent.querySelectorAll(selector)); | ||
} else if (selector instanceof Element) { | ||
return [selector]; | ||
} else if (selector instanceof NodeList) { | ||
return Array.from(selector); | ||
} else if (selector instanceof Array) { | ||
return selector; | ||
} | ||
return []; | ||
} | ||
if (typeof selector === 'string') { | ||
return Array.from(parent.querySelectorAll(selector)); | ||
} else if (selector instanceof Element) { | ||
return [selector]; | ||
} else if (selector instanceof NodeList) { | ||
return Array.from(selector); | ||
} else if (selector instanceof Array) { | ||
return selector; | ||
function err$1(msg) { | ||
console.error(`scrollama error: ${msg}`); | ||
} | ||
return []; | ||
} | ||
function getOffsetId(id) { | ||
return ("scrollama__debug-offset--" + id); | ||
} | ||
function getIndex(node) { | ||
return +node.getAttribute("data-scrollama-index"); | ||
} | ||
// SETUP | ||
function setupOffset(ref) { | ||
var id = ref.id; | ||
var offsetVal = ref.offsetVal; | ||
var stepClass = ref.stepClass; | ||
function createProgressThreshold(height, threshold) { | ||
const count = Math.ceil(height / threshold); | ||
const t = []; | ||
const ratio = 1 / count; | ||
for (let i = 0; i < count + 1; i += 1) { | ||
t.push(i * ratio); | ||
} | ||
return t; | ||
} | ||
var el = document.createElement("div"); | ||
el.id = getOffsetId(id); | ||
el.className = "scrollama__debug-offset"; | ||
el.style.position = "fixed"; | ||
el.style.left = "0"; | ||
el.style.width = "100%"; | ||
el.style.height = "0"; | ||
el.style.borderTop = "2px dashed black"; | ||
el.style.zIndex = "9999"; | ||
var p = document.createElement("p"); | ||
p.innerHTML = "\"." + stepClass + "\" trigger: <span>" + offsetVal + "</span>"; | ||
p.style.fontSize = "12px"; | ||
p.style.fontFamily = "monospace"; | ||
p.style.color = "black"; | ||
p.style.margin = "0"; | ||
p.style.padding = "6px"; | ||
el.appendChild(p); | ||
document.body.appendChild(el); | ||
} | ||
function setup(ref) { | ||
var id = ref.id; | ||
var offsetVal = ref.offsetVal; | ||
var stepEl = ref.stepEl; | ||
var stepClass = stepEl[0].className; | ||
setupOffset({ id: id, offsetVal: offsetVal, stepClass: stepClass }); | ||
} | ||
// UPDATE | ||
function update(ref) { | ||
var id = ref.id; | ||
var offsetMargin = ref.offsetMargin; | ||
var offsetVal = ref.offsetVal; | ||
var format = ref.format; | ||
var post = format === "pixels" ? "px" : ""; | ||
var idVal = getOffsetId(id); | ||
var el = document.getElementById(idVal); | ||
el.style.top = offsetMargin + "px"; | ||
el.querySelector("span").innerText = "" + offsetVal + post; | ||
} | ||
function notifyStep(ref) { | ||
var id = ref.id; | ||
var index = ref.index; | ||
var state = ref.state; | ||
var prefix = "scrollama__debug-step--" + id + "-" + index; | ||
var elA = document.getElementById((prefix + "_above")); | ||
var elB = document.getElementById((prefix + "_below")); | ||
var display = state === "enter" ? "block" : "none"; | ||
if (elA) { elA.style.display = display; } | ||
if (elB) { elB.style.display = display; } | ||
} | ||
function scrollama() { | ||
var OBSERVER_NAMES = [ | ||
"stepAbove", | ||
"stepBelow", | ||
"stepProgress", | ||
"viewportAbove", | ||
"viewportBelow" | ||
]; | ||
var cb = {}; | ||
var io = {}; | ||
var id = null; | ||
var stepEl = []; | ||
var stepOffsetHeight = []; | ||
var stepOffsetTop = []; | ||
var stepStates = []; | ||
var offsetVal = 0; | ||
var offsetMargin = 0; | ||
var viewH = 0; | ||
var pageH = 0; | ||
var previousYOffset = 0; | ||
var progressThreshold = 0; | ||
var isReady = false; | ||
var isEnabled = false; | ||
var isDebug = false; | ||
var progressMode = false; | ||
var preserveOrder = false; | ||
var triggerOnce = false; | ||
var direction = "down"; | ||
var format = "percent"; | ||
var exclude = []; | ||
/* HELPERS */ | ||
function err(msg) { | ||
console.error(("scrollama error: " + msg)); | ||
function parseOffset(x) { | ||
if (typeof x === "string" && x.indexOf("px") > 0) { | ||
const v = +x.replace("px", ""); | ||
if (!isNaN(v)) return { format: "pixels", value: v }; | ||
else { | ||
err("offset value must be in 'px' format. Fallback to 0.5."); | ||
return { format: "percent", value: 0.5 }; | ||
} | ||
} else if (typeof x === "number" || !isNaN(+x)) { | ||
if (x > 1) err("offset value is greater than 1. Fallback to 1."); | ||
if (x < 0) err("offset value is lower than 0. Fallback to 0."); | ||
return { format: "percent", value: Math.min(Math.max(0, x), 1) }; | ||
} | ||
return null; | ||
} | ||
function reset() { | ||
cb = { | ||
stepEnter: function () {}, | ||
stepExit: function () {}, | ||
stepProgress: function () {} | ||
}; | ||
io = {}; | ||
function indexSteps(steps) { | ||
steps.forEach((step) => | ||
step.node.setAttribute("data-scrollama-index", step.index) | ||
); | ||
} | ||
function generateInstanceID() { | ||
var a = "abcdefghijklmnopqrstuv"; | ||
var l = a.length; | ||
var t = Date.now(); | ||
var r = [0, 0, 0].map(function (d) { return a[Math.floor(Math.random() * l)]; }).join(""); | ||
return ("" + r + t); | ||
} | ||
function getOffsetTop(el) { | ||
var ref = el.getBoundingClientRect(); | ||
var top = ref.top; | ||
var scrollTop = window.pageYOffset; | ||
var clientTop = document.body.clientTop || 0; | ||
function getOffsetTop(node) { | ||
const { top } = node.getBoundingClientRect(); | ||
const scrollTop = window.pageYOffset; | ||
const clientTop = document.body.clientTop || 0; | ||
return top + scrollTop - clientTop; | ||
} | ||
function getPageHeight() { | ||
var body = document.body; | ||
var html = document.documentElement; | ||
let currentScrollY = 0; | ||
let comparisonScrollY = 0; | ||
let direction; | ||
return Math.max( | ||
body.scrollHeight, | ||
body.offsetHeight, | ||
html.clientHeight, | ||
html.scrollHeight, | ||
html.offsetHeight | ||
); | ||
function onScroll() { | ||
if (currentScrollY === window.pageYOffset) return; | ||
currentScrollY = window.pageYOffset; | ||
if (currentScrollY > comparisonScrollY) direction = "down"; | ||
else if (currentScrollY < comparisonScrollY) direction = "up"; | ||
comparisonScrollY = currentScrollY; | ||
} | ||
function getIndex(element) { | ||
return +element.getAttribute("data-scrollama-index"); | ||
function setupScroll() { | ||
document.addEventListener("scroll", onScroll); | ||
} | ||
function updateDirection() { | ||
if (window.pageYOffset > previousYOffset) { direction = "down"; } | ||
else if (window.pageYOffset < previousYOffset) { direction = "up"; } | ||
previousYOffset = window.pageYOffset; | ||
} | ||
function scrollama() { | ||
let cb = {}; | ||
let steps = []; | ||
let globalOffset; | ||
function disconnectObserver(name) { | ||
if (io[name]) { io[name].forEach(function (d) { return d.disconnect(); }); } | ||
} | ||
let progressThreshold = 0; | ||
function handleResize() { | ||
viewH = window.innerHeight; | ||
pageH = getPageHeight(); | ||
let isEnabled = false; | ||
let isProgressMode = false; | ||
let isTriggerOnce = false; | ||
var mult = format === "pixels" ? 1 : viewH; | ||
offsetMargin = offsetVal * mult; | ||
let exclude = []; | ||
if (isReady) { | ||
stepOffsetHeight = stepEl.map(function (el) { return el.getBoundingClientRect().height; }); | ||
stepOffsetTop = stepEl.map(getOffsetTop); | ||
if (isEnabled) { updateIO(); } | ||
/* HELPERS */ | ||
function reset() { | ||
cb = { | ||
stepEnter: () => {}, | ||
stepExit: () => {}, | ||
stepProgress: () => {}, | ||
}; | ||
exclude = []; | ||
} | ||
if (isDebug) { update({ id: id, offsetMargin: offsetMargin, offsetVal: offsetVal, format: format }); } | ||
} | ||
function handleEnable(enable) { | ||
if (enable && !isEnabled) { | ||
// enable a disabled scroller | ||
if (isReady) { | ||
// enable a ready scroller | ||
updateIO(); | ||
} else { | ||
// can't enable an unready scroller | ||
err("scrollama error: enable() called before scroller was ready"); | ||
isEnabled = false; | ||
return; // all is not well, don't set the requested state | ||
} | ||
function handleEnable(shouldEnable) { | ||
if (shouldEnable && !isEnabled) updateObservers(); | ||
if (!shouldEnable && isEnabled) disconnectObservers(); | ||
isEnabled = shouldEnable; | ||
} | ||
if (!enable && isEnabled) { | ||
// disable an enabled scroller | ||
OBSERVER_NAMES.forEach(disconnectObserver); | ||
} | ||
isEnabled = enable; // all is well, set requested state | ||
} | ||
function createThreshold(height) { | ||
var count = Math.ceil(height / progressThreshold); | ||
var t = []; | ||
var ratio = 1 / count; | ||
for (var i = 0; i < count; i += 1) { | ||
t.push(i * ratio); | ||
/* NOTIFY CALLBACKS */ | ||
function notifyProgress(element, progress) { | ||
const index = getIndex(element); | ||
const step = steps[index]; | ||
if (progress !== undefined) step.progress = progress; | ||
const response = { element, index, progress, direction }; | ||
if (step.state === "enter") cb.stepProgress(response); | ||
} | ||
return t; | ||
} | ||
/* NOTIFY CALLBACKS */ | ||
function notifyStepProgress(element, progress) { | ||
var index = getIndex(element); | ||
if (progress !== undefined) { stepStates[index].progress = progress; } | ||
var resp = { element: element, index: index, progress: stepStates[index].progress }; | ||
function notifyStepEnter(element, check = true) { | ||
const index = getIndex(element); | ||
const step = steps[index]; | ||
const response = { element, index, direction }; | ||
if (stepStates[index].state === "enter") { cb.stepProgress(resp); } | ||
} | ||
step.direction = direction; | ||
step.state = "enter"; | ||
function notifyOthers(index, location) { | ||
if (location === "above") { | ||
// check if steps above/below were skipped and should be notified first | ||
for (var i = 0; i < index; i += 1) { | ||
var ss = stepStates[i]; | ||
if (ss.state !== "enter" && ss.direction !== "down") { | ||
notifyStepEnter(stepEl[i], "down", false); | ||
notifyStepExit(stepEl[i], "down"); | ||
} else if (ss.state === "enter") { notifyStepExit(stepEl[i], "down"); } | ||
// else if (ss.direction === 'up') { | ||
// notifyStepEnter(stepEl[i], 'down', false); | ||
// notifyStepExit(stepEl[i], 'down'); | ||
// } | ||
} | ||
} else if (location === "below") { | ||
for (var i$1 = stepStates.length - 1; i$1 > index; i$1 -= 1) { | ||
var ss$1 = stepStates[i$1]; | ||
if (ss$1.state === "enter") { | ||
notifyStepExit(stepEl[i$1], "up"); | ||
} | ||
if (ss$1.direction === "down") { | ||
notifyStepEnter(stepEl[i$1], "up", false); | ||
notifyStepExit(stepEl[i$1], "up"); | ||
} | ||
} | ||
// if (isPreserveOrder && check && direction !== "up") | ||
// notifyOthers(index, "above"); | ||
// if (isPreserveOrder && check && direction === "up") | ||
// notifyOthers(index, "below"); | ||
if (!exclude[index]) cb.stepEnter(response); | ||
if (isTriggerOnce) exclude[index] = true; | ||
} | ||
} | ||
function notifyStepEnter(element, dir, check) { | ||
if ( check === void 0 ) check = true; | ||
function notifyStepExit(element, check = true) { | ||
const index = getIndex(element); | ||
const step = steps[index]; | ||
var index = getIndex(element); | ||
var resp = { element: element, index: index, direction: dir }; | ||
if (!step.state) return false; | ||
// store most recent trigger | ||
stepStates[index].direction = dir; | ||
stepStates[index].state = "enter"; | ||
if (preserveOrder && check && dir === "down") { notifyOthers(index, "above"); } | ||
const response = { element, index, direction }; | ||
if (preserveOrder && check && dir === "up") { notifyOthers(index, "below"); } | ||
if (isProgressMode) { | ||
if (direction === "down" && step.progress < 1) notifyProgress(element, 1); | ||
else if (direction === "up" && step.progress > 0) | ||
notifyProgress(element, 0); | ||
} | ||
if (cb.stepEnter && !exclude[index]) { | ||
cb.stepEnter(resp, stepStates); | ||
if (isDebug) { notifyStep({ id: id, index: index, state: "enter" }); } | ||
if (triggerOnce) { exclude[index] = true; } | ||
} | ||
step.direction = direction; | ||
step.state = "exit"; | ||
if (progressMode) { notifyStepProgress(element); } | ||
} | ||
// if (isPreserveOrder && check && direction !== "up") | ||
// notifyOthers(index, "below"); | ||
// if (isPreserveOrder && check && direction === "up") | ||
// notifyOthers(index, "above"); | ||
function notifyStepExit(element, dir) { | ||
var index = getIndex(element); | ||
var resp = { element: element, index: index, direction: dir }; | ||
cb.stepExit(response); | ||
} | ||
if (progressMode) { | ||
if (dir === "down" && stepStates[index].progress < 1) | ||
{ notifyStepProgress(element, 1); } | ||
else if (dir === "up" && stepStates[index].progress > 0) | ||
{ notifyStepProgress(element, 0); } | ||
/* OBSERVERS - HANDLING */ | ||
function resizeStep([entry]) { | ||
const index = getIndex(entry.target); | ||
const step = steps[index]; | ||
const h = entry.target.offsetHeight; | ||
if (h !== step.height) { | ||
step.height = h; | ||
disconnectObserver(step); | ||
updateStepObserver(step); | ||
updateResizeObserver(step); | ||
} | ||
} | ||
// store most recent trigger | ||
stepStates[index].direction = dir; | ||
stepStates[index].state = "exit"; | ||
function intersectStep([entry]) { | ||
onScroll(); | ||
cb.stepExit(resp, stepStates); | ||
if (isDebug) { notifyStep({ id: id, index: index, state: "exit" }); } | ||
} | ||
const { isIntersecting, target } = entry; | ||
if (isIntersecting) notifyStepEnter(target); | ||
else notifyStepExit(target); | ||
} | ||
/* OBSERVER - INTERSECT HANDLING */ | ||
// this is good for entering while scrolling down + leaving while scrolling up | ||
function intersectStepAbove(ref) { | ||
var entry = ref[0]; | ||
function intersectProgress([entry]) { | ||
const index = getIndex(entry.target); | ||
const step = steps[index]; | ||
const { isIntersecting, intersectionRatio, target } = entry; | ||
if (isIntersecting && step.state === "enter") | ||
notifyProgress(target, intersectionRatio); | ||
} | ||
updateDirection(); | ||
var isIntersecting = entry.isIntersecting; | ||
var boundingClientRect = entry.boundingClientRect; | ||
var target = entry.target; | ||
/* OBSERVERS - CREATION */ | ||
function disconnectObserver({ observers }) { | ||
Object.keys(observers).map((name) => { | ||
observers[name].disconnect(); | ||
}); | ||
} | ||
// bottom = bottom edge of element from top of viewport | ||
// bottomAdjusted = bottom edge of element from trigger | ||
var top = boundingClientRect.top; | ||
var bottom = boundingClientRect.bottom; | ||
var topAdjusted = top - offsetMargin; | ||
var bottomAdjusted = bottom - offsetMargin; | ||
var index = getIndex(target); | ||
var ss = stepStates[index]; | ||
// entering above is only when topAdjusted is negative | ||
// and bottomAdjusted is positive | ||
if ( | ||
isIntersecting && | ||
topAdjusted <= 0 && | ||
bottomAdjusted >= 0 && | ||
direction === "down" && | ||
ss.state !== "enter" | ||
) | ||
{ notifyStepEnter(target, direction); } | ||
// exiting from above is when topAdjusted is positive and not intersecting | ||
if ( | ||
!isIntersecting && | ||
topAdjusted > 0 && | ||
direction === "up" && | ||
ss.state === "enter" | ||
) | ||
{ notifyStepExit(target, direction); } | ||
} | ||
// this is good for entering while scrolling up + leaving while scrolling down | ||
function intersectStepBelow(ref) { | ||
var entry = ref[0]; | ||
updateDirection(); | ||
var isIntersecting = entry.isIntersecting; | ||
var boundingClientRect = entry.boundingClientRect; | ||
var target = entry.target; | ||
// bottom = bottom edge of element from top of viewport | ||
// bottomAdjusted = bottom edge of element from trigger | ||
var top = boundingClientRect.top; | ||
var bottom = boundingClientRect.bottom; | ||
var topAdjusted = top - offsetMargin; | ||
var bottomAdjusted = bottom - offsetMargin; | ||
var index = getIndex(target); | ||
var ss = stepStates[index]; | ||
// entering below is only when bottomAdjusted is positive | ||
// and topAdjusted is negative | ||
if ( | ||
isIntersecting && | ||
topAdjusted <= 0 && | ||
bottomAdjusted >= 0 && | ||
direction === "up" && | ||
ss.state !== "enter" | ||
) | ||
{ notifyStepEnter(target, direction); } | ||
// exiting from above is when bottomAdjusted is negative and not intersecting | ||
if ( | ||
!isIntersecting && | ||
bottomAdjusted < 0 && | ||
direction === "down" && | ||
ss.state === "enter" | ||
) | ||
{ notifyStepExit(target, direction); } | ||
} | ||
/* | ||
if there is a scroll event where a step never intersects (therefore | ||
skipping an enter/exit trigger), use this fallback to detect if it is | ||
in view | ||
*/ | ||
function intersectViewportAbove(ref) { | ||
var entry = ref[0]; | ||
updateDirection(); | ||
var isIntersecting = entry.isIntersecting; | ||
var target = entry.target; | ||
var index = getIndex(target); | ||
var ss = stepStates[index]; | ||
if ( | ||
isIntersecting && | ||
direction === "down" && | ||
ss.direction !== "down" && | ||
ss.state !== "enter" | ||
) { | ||
notifyStepEnter(target, "down"); | ||
notifyStepExit(target, "down"); | ||
function disconnectObservers() { | ||
steps.forEach(disconnectObserver); | ||
} | ||
} | ||
function intersectViewportBelow(ref) { | ||
var entry = ref[0]; | ||
updateDirection(); | ||
var isIntersecting = entry.isIntersecting; | ||
var target = entry.target; | ||
var index = getIndex(target); | ||
var ss = stepStates[index]; | ||
if ( | ||
isIntersecting && | ||
direction === "up" && | ||
ss.direction === "down" && | ||
ss.state !== "enter" | ||
) { | ||
notifyStepEnter(target, "up"); | ||
notifyStepExit(target, "up"); | ||
function updateResizeObserver(step) { | ||
const observer = new ResizeObserver(resizeStep); | ||
observer.observe(step.node); | ||
step.observers.resize = observer; | ||
} | ||
} | ||
function intersectStepProgress(ref) { | ||
var entry = ref[0]; | ||
updateDirection(); | ||
var isIntersecting = entry.isIntersecting; | ||
var intersectionRatio = entry.intersectionRatio; | ||
var boundingClientRect = entry.boundingClientRect; | ||
var target = entry.target; | ||
var bottom = boundingClientRect.bottom; | ||
var bottomAdjusted = bottom - offsetMargin; | ||
if (isIntersecting && bottomAdjusted >= 0) { | ||
notifyStepProgress(target, +intersectionRatio); | ||
function updateResizeObservers() { | ||
steps.forEach(updateResizeObserver); | ||
} | ||
} | ||
/* OBSERVER - CREATION */ | ||
// jump into viewport | ||
function updateViewportAboveIO() { | ||
io.viewportAbove = stepEl.map(function (el, i) { | ||
var marginTop = pageH - stepOffsetTop[i]; | ||
var marginBottom = offsetMargin - viewH - stepOffsetHeight[i]; | ||
var rootMargin = marginTop + "px 0px " + marginBottom + "px 0px"; | ||
var options = { rootMargin: rootMargin }; | ||
// console.log(options); | ||
var obs = new IntersectionObserver(intersectViewportAbove, options); | ||
obs.observe(el); | ||
return obs; | ||
}); | ||
} | ||
function updateStepObserver(step) { | ||
const h = window.innerHeight; | ||
const off = step.offset || globalOffset; | ||
const factor = off.format === "pixels" ? 1 : h; | ||
const offset = off.value * factor; | ||
const marginTop = step.height / 2 - offset; | ||
const marginBottom = step.height / 2 - (h - offset); | ||
const rootMargin = `${marginTop}px 0px ${marginBottom}px 0px`; | ||
function updateViewportBelowIO() { | ||
io.viewportBelow = stepEl.map(function (el, i) { | ||
var marginTop = -offsetMargin - stepOffsetHeight[i]; | ||
var marginBottom = offsetMargin - viewH + stepOffsetHeight[i] + pageH; | ||
var rootMargin = marginTop + "px 0px " + marginBottom + "px 0px"; | ||
var options = { rootMargin: rootMargin }; | ||
// console.log(options); | ||
var obs = new IntersectionObserver(intersectViewportBelow, options); | ||
obs.observe(el); | ||
return obs; | ||
}); | ||
} | ||
const threshold = 0.5; | ||
const options = { rootMargin, threshold }; | ||
const observer = new IntersectionObserver(intersectStep, options); | ||
// look above for intersection | ||
function updateStepAboveIO() { | ||
io.stepAbove = stepEl.map(function (el, i) { | ||
var marginTop = -offsetMargin + stepOffsetHeight[i]; | ||
var marginBottom = offsetMargin - viewH; | ||
var rootMargin = marginTop + "px 0px " + marginBottom + "px 0px"; | ||
var options = { rootMargin: rootMargin }; | ||
// console.log(options); | ||
var obs = new IntersectionObserver(intersectStepAbove, options); | ||
obs.observe(el); | ||
return obs; | ||
}); | ||
} | ||
observer.observe(step.node); | ||
step.observers.step = observer; | ||
} | ||
// look below for intersection | ||
function updateStepBelowIO() { | ||
io.stepBelow = stepEl.map(function (el, i) { | ||
var marginTop = -offsetMargin; | ||
var marginBottom = offsetMargin - viewH + stepOffsetHeight[i]; | ||
var rootMargin = marginTop + "px 0px " + marginBottom + "px 0px"; | ||
var options = { rootMargin: rootMargin }; | ||
// console.log(options); | ||
var obs = new IntersectionObserver(intersectStepBelow, options); | ||
obs.observe(el); | ||
return obs; | ||
}); | ||
} | ||
function updateStepObservers() { | ||
steps.forEach(updateStepObserver); | ||
} | ||
// progress progress tracker | ||
function updateStepProgressIO() { | ||
io.stepProgress = stepEl.map(function (el, i) { | ||
var marginTop = stepOffsetHeight[i] - offsetMargin; | ||
var marginBottom = -viewH + offsetMargin; | ||
var rootMargin = marginTop + "px 0px " + marginBottom + "px 0px"; | ||
var threshold = createThreshold(stepOffsetHeight[i]); | ||
var options = { rootMargin: rootMargin, threshold: threshold }; | ||
// console.log(options); | ||
var obs = new IntersectionObserver(intersectStepProgress, options); | ||
obs.observe(el); | ||
return obs; | ||
}); | ||
} | ||
function updateProgressObserver(step) { | ||
const h = window.innerHeight; | ||
const off = step.offset || globalOffset; | ||
const factor = off.format === "pixels" ? 1 : h; | ||
const offset = off.value * factor; | ||
const marginTop = -offset + step.height; | ||
const marginBottom = offset - h; | ||
const rootMargin = `${marginTop}px 0px ${marginBottom}px 0px`; | ||
function updateIO() { | ||
OBSERVER_NAMES.forEach(disconnectObserver); | ||
const threshold = createProgressThreshold(step.height, progressThreshold); | ||
const options = { rootMargin, threshold }; | ||
const observer = new IntersectionObserver(intersectProgress, options); | ||
updateViewportAboveIO(); | ||
updateViewportBelowIO(); | ||
updateStepAboveIO(); | ||
updateStepBelowIO(); | ||
if (progressMode) { updateStepProgressIO(); } | ||
} | ||
/* SETUP FUNCTIONS */ | ||
function indexSteps() { | ||
stepEl.forEach(function (el, i) { return el.setAttribute("data-scrollama-index", i); }); | ||
} | ||
function setupStates() { | ||
stepStates = stepEl.map(function () { return ({ | ||
direction: null, | ||
state: null, | ||
progress: 0 | ||
}); }); | ||
} | ||
function addDebug() { | ||
if (isDebug) { setup({ id: id, stepEl: stepEl, offsetVal: offsetVal }); } | ||
} | ||
function isYScrollable(element) { | ||
var style = window.getComputedStyle(element); | ||
return ( | ||
(style.overflowY === "scroll" || style.overflowY === "auto") && | ||
element.scrollHeight > element.clientHeight | ||
); | ||
} | ||
// recursively search the DOM for a parent container with overflowY: scroll and fixed height | ||
// ends at document | ||
function anyScrollableParent(element) { | ||
if (element && element.nodeType === 1) { | ||
// check dom elements only, stop at document | ||
// if a scrollable element is found return the element | ||
// if not continue to next parent | ||
return isYScrollable(element) | ||
? element | ||
: anyScrollableParent(element.parentNode); | ||
observer.observe(step.node); | ||
step.observers.progress = observer; | ||
} | ||
return false; // didn't find a scrollable parent | ||
} | ||
var S = {}; | ||
S.setup = function (ref) { | ||
var step = ref.step; | ||
var parent = ref.parent; | ||
var offset = ref.offset; if ( offset === void 0 ) offset = 0.5; | ||
var progress = ref.progress; if ( progress === void 0 ) progress = false; | ||
var threshold = ref.threshold; if ( threshold === void 0 ) threshold = 4; | ||
var debug = ref.debug; if ( debug === void 0 ) debug = false; | ||
var order = ref.order; if ( order === void 0 ) order = true; | ||
var once = ref.once; if ( once === void 0 ) once = false; | ||
reset(); | ||
// create id unique to this scrollama instance | ||
id = generateInstanceID(); | ||
stepEl = selectAll(step, parent); | ||
if (!stepEl.length) { | ||
err("no step elements"); | ||
return S; | ||
function updateProgressObservers() { | ||
steps.forEach(updateProgressObserver); | ||
} | ||
// ensure that no step has a scrollable parent element in the dom tree | ||
// check current step for scrollable parent | ||
// assume no scrollable parents to start | ||
var scrollableParent = stepEl.reduce( | ||
function (foundScrollable, s) { return foundScrollable || anyScrollableParent(s.parentNode); }, | ||
false | ||
); | ||
if (scrollableParent) { | ||
console.error( | ||
"scrollama error: step elements cannot be children of a scrollable element. Remove any css on the parent element with overflow: scroll; or overflow: auto; on elements with fixed height.", | ||
scrollableParent | ||
); | ||
function updateObservers() { | ||
disconnectObservers(); | ||
updateResizeObservers(); | ||
updateStepObservers(); | ||
if (isProgressMode) updateProgressObservers(); | ||
} | ||
// options | ||
isDebug = debug; | ||
progressMode = progress; | ||
preserveOrder = order; | ||
triggerOnce = once; | ||
/* SETUP */ | ||
const S = {}; | ||
S.offsetTrigger(offset); | ||
progressThreshold = Math.max(1, +threshold); | ||
S.setup = ({ | ||
step, | ||
parent, | ||
offset = 0.5, | ||
threshold = 4, | ||
progress = false, | ||
order = false, | ||
once = false, | ||
debug = false, | ||
}) => { | ||
steps = selectAll(step, parent).map((node, index) => ({ | ||
index, | ||
direction: undefined, | ||
height: node.offsetHeight, | ||
node, | ||
observers: {}, | ||
offset: parseOffset(node.dataset.offset), | ||
top: getOffsetTop(node), | ||
progress: 0, | ||
state: undefined, | ||
})); | ||
isReady = true; | ||
if (!steps.length) { | ||
err$1("no step elements"); | ||
return S; | ||
} | ||
// customize | ||
addDebug(); | ||
indexSteps(); | ||
setupStates(); | ||
handleResize(); | ||
S.enable(); | ||
return S; | ||
}; | ||
isProgressMode = progress; | ||
isTriggerOnce = once; | ||
progressThreshold = Math.max(1, +threshold); | ||
globalOffset = parseOffset(offset); | ||
reset(); | ||
indexSteps(steps); | ||
handleEnable(true); | ||
return S; | ||
}; | ||
S.resize = function () { | ||
handleResize(); | ||
return S; | ||
}; | ||
S.enable = () => { | ||
handleEnable(true); | ||
return S; | ||
}; | ||
S.enable = function () { | ||
handleEnable(true); | ||
return S; | ||
}; | ||
S.disable = () => { | ||
handleEnable(false); | ||
return S; | ||
}; | ||
S.disable = function () { | ||
handleEnable(false); | ||
return S; | ||
}; | ||
S.destroy = () => { | ||
handleEnable(false); | ||
reset(); | ||
return S; | ||
}; | ||
S.destroy = function () { | ||
handleEnable(false); | ||
reset(); | ||
}; | ||
S.offset = (x) => { | ||
if (x === null || x === undefined) return globalOffset.value; | ||
globalOffset = parseOffset(x); | ||
updateObservers(); | ||
return S; | ||
}; | ||
S.offsetTrigger = function (x) { | ||
if (x === null) { return offsetVal; } | ||
S.onStepEnter = (f) => { | ||
if (typeof f === "function") cb.stepEnter = f; | ||
else err$1("onStepEnter requires a function"); | ||
return S; | ||
}; | ||
if (typeof x === "number") { | ||
format = "percent"; | ||
if (x > 1) { err("offset value is greater than 1. Fallback to 1."); } | ||
if (x < 0) { err("offset value is lower than 0. Fallback to 0."); } | ||
offsetVal = Math.min(Math.max(0, x), 1); | ||
} else if (typeof x === "string" && x.indexOf("px") > 0) { | ||
var v = +x.replace("px", ""); | ||
if (!isNaN(v)) { | ||
format = "pixels"; | ||
offsetVal = v; | ||
} else { | ||
err("offset value must be in 'px' format. Fallback to 0.5."); | ||
offsetVal = 0.5; | ||
} | ||
} else { | ||
err("offset value does not include 'px'. Fallback to 0.5."); | ||
offsetVal = 0.5; | ||
} | ||
return S; | ||
}; | ||
S.onStepExit = (f) => { | ||
if (typeof f === "function") cb.stepExit = f; | ||
else err$1("onStepExit requires a function"); | ||
return S; | ||
}; | ||
S.onStepEnter = function (f) { | ||
if (typeof f === "function") { cb.stepEnter = f; } | ||
else { err("onStepEnter requires a function"); } | ||
S.onStepProgress = (f) => { | ||
if (typeof f === "function") cb.stepProgress = f; | ||
else err$1("onStepProgress requires a function"); | ||
return S; | ||
}; | ||
return S; | ||
}; | ||
} | ||
S.onStepExit = function (f) { | ||
if (typeof f === "function") { cb.stepExit = f; } | ||
else { err("onStepExit requires a function"); } | ||
return S; | ||
}; | ||
setupScroll(); | ||
S.onStepProgress = function (f) { | ||
if (typeof f === "function") { cb.stepProgress = f; } | ||
else { err("onStepProgress requires a function"); } | ||
return S; | ||
}; | ||
return scrollama; | ||
return S; | ||
} | ||
return scrollama; | ||
}))); |
@@ -1,1 +0,1 @@ | ||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.scrollama=t()}(this,function(){"use strict";function e(e){return"scrollama__debug-offset--"+e}function t(t){!function(t){var n=t.id,o=t.offsetVal,r=t.stepClass,i=document.createElement("div");i.id=e(n),i.className="scrollama__debug-offset",i.style.position="fixed",i.style.left="0",i.style.width="100%",i.style.height="0",i.style.borderTop="2px dashed black",i.style.zIndex="9999";var s=document.createElement("p");s.innerHTML='".'+r+'" trigger: <span>'+o+"</span>",s.style.fontSize="12px",s.style.fontFamily="monospace",s.style.color="black",s.style.margin="0",s.style.padding="6px",i.appendChild(s),document.body.appendChild(i)}({id:t.id,offsetVal:t.offsetVal,stepClass:t.stepEl[0].className})}function n(e){var t=e.id,n=e.index,o=e.state,r="scrollama__debug-step--"+t+"-"+n,i=document.getElementById(r+"_above"),s=document.getElementById(r+"_below"),a="enter"===o?"block":"none";i&&(i.style.display=a),s&&(s.style.display=a)}return function(){var o=["stepAbove","stepBelow","stepProgress","viewportAbove","viewportBelow"],r={},i={},s=null,a=[],f=[],c=[],l=[],u=0,p=0,d=0,v=0,g=0,m=0,x=!1,b=!1,w=!1,h=!1,y=!1,E=!1,M="down",I="percent",A=[];function C(e){console.error("scrollama error: "+e)}function O(){r={stepEnter:function(){},stepExit:function(){},stepProgress:function(){}},i={}}function S(e){return e.getBoundingClientRect().top+window.pageYOffset-(document.body.clientTop||0)}function B(e){return+e.getAttribute("data-scrollama-index")}function H(){window.pageYOffset>g?M="down":window.pageYOffset<g&&(M="up"),g=window.pageYOffset}function k(e){i[e]&&i[e].forEach(function(e){return e.disconnect()})}function _(){var t,n;d=window.innerHeight,t=document.body,n=document.documentElement,v=Math.max(t.scrollHeight,t.offsetHeight,n.clientHeight,n.scrollHeight,n.offsetHeight),p=u*("pixels"===I?1:d),x&&(f=a.map(function(e){return e.getBoundingClientRect().height}),c=a.map(S),b&&D()),w&&function(t){var n=t.id,o=t.offsetMargin,r=t.offsetVal,i="pixels"===t.format?"px":"",s=e(n),a=document.getElementById(s);a.style.top=o+"px",a.querySelector("span").innerText=""+r+i}({id:s,offsetMargin:p,offsetVal:u,format:I})}function N(e){if(e&&!b){if(!x)return C("scrollama error: enable() called before scroller was ready"),void(b=!1);D()}!e&&b&&o.forEach(k),b=e}function P(e,t){var n=B(e);void 0!==t&&(l[n].progress=t);var o={element:e,index:n,progress:l[n].progress};"enter"===l[n].state&&r.stepProgress(o)}function R(e,t){if("above"===t)for(var n=0;n<e;n+=1){var o=l[n];"enter"!==o.state&&"down"!==o.direction?(T(a[n],"down",!1),q(a[n],"down")):"enter"===o.state&&q(a[n],"down")}else if("below"===t)for(var r=l.length-1;r>e;r-=1){var i=l[r];"enter"===i.state&&q(a[r],"up"),"down"===i.direction&&(T(a[r],"up",!1),q(a[r],"up"))}}function T(e,t,o){void 0===o&&(o=!0);var i=B(e),a={element:e,index:i,direction:t};l[i].direction=t,l[i].state="enter",y&&o&&"down"===t&&R(i,"above"),y&&o&&"up"===t&&R(i,"below"),r.stepEnter&&!A[i]&&(r.stepEnter(a,l),w&&n({id:s,index:i,state:"enter"}),E&&(A[i]=!0)),h&&P(e)}function q(e,t){var o=B(e),i={element:e,index:o,direction:t};h&&("down"===t&&l[o].progress<1?P(e,1):"up"===t&&l[o].progress>0&&P(e,0)),l[o].direction=t,l[o].state="exit",r.stepExit(i,l),w&&n({id:s,index:o,state:"exit"})}function V(e){var t=e[0];H();var n=t.isIntersecting,o=t.boundingClientRect,r=t.target,i=o.top,s=o.bottom,a=i-p,f=s-p,c=B(r),u=l[c];n&&a<=0&&f>=0&&"down"===M&&"enter"!==u.state&&T(r,M),!n&&a>0&&"up"===M&&"enter"===u.state&&q(r,M)}function Y(e){var t=e[0];H();var n=t.isIntersecting,o=t.boundingClientRect,r=t.target,i=o.top,s=o.bottom,a=i-p,f=s-p,c=B(r),u=l[c];n&&a<=0&&f>=0&&"up"===M&&"enter"!==u.state&&T(r,M),!n&&f<0&&"down"===M&&"enter"===u.state&&q(r,M)}function F(e){var t=e[0];H();var n=t.isIntersecting,o=t.target,r=B(o),i=l[r];n&&"down"===M&&"down"!==i.direction&&"enter"!==i.state&&(T(o,"down"),q(o,"down"))}function j(e){var t=e[0];H();var n=t.isIntersecting,o=t.target,r=B(o),i=l[r];n&&"up"===M&&"down"===i.direction&&"enter"!==i.state&&(T(o,"up"),q(o,"up"))}function z(e){var t=e[0];H();var n=t.isIntersecting,o=t.intersectionRatio,r=t.boundingClientRect,i=t.target,s=r.bottom;n&&s-p>=0&&P(i,+o)}function L(){i.stepProgress=a.map(function(e,t){var n=f[t]-p+"px 0px "+(-d+p)+"px 0px",o=function(e){for(var t=Math.ceil(e/m),n=[],o=1/t,r=0;r<t;r+=1)n.push(r*o);return n}(f[t]),r=new IntersectionObserver(z,{rootMargin:n,threshold:o});return r.observe(e),r})}function D(){o.forEach(k),i.viewportAbove=a.map(function(e,t){var n=v-c[t],o=p-d-f[t],r=new IntersectionObserver(F,{rootMargin:n+"px 0px "+o+"px 0px"});return r.observe(e),r}),i.viewportBelow=a.map(function(e,t){var n=-p-f[t],o=p-d+f[t]+v,r=new IntersectionObserver(j,{rootMargin:n+"px 0px "+o+"px 0px"});return r.observe(e),r}),i.stepAbove=a.map(function(e,t){var n=-p+f[t],o=new IntersectionObserver(V,{rootMargin:n+"px 0px "+(p-d)+"px 0px"});return o.observe(e),o}),i.stepBelow=a.map(function(e,t){var n=-p,o=p-d+f[t],r=new IntersectionObserver(Y,{rootMargin:n+"px 0px "+o+"px 0px"});return r.observe(e),r}),h&&L()}function G(e){return!(!e||1!==e.nodeType)&&(function(e){var t=window.getComputedStyle(e);return("scroll"===t.overflowY||"auto"===t.overflowY)&&e.scrollHeight>e.clientHeight}(e)?e:G(e.parentNode))}var J={};return J.setup=function(e){var n=e.step,o=e.parent,r=e.offset;void 0===r&&(r=.5);var i=e.progress;void 0===i&&(i=!1);var f=e.threshold;void 0===f&&(f=4);var c=e.debug;void 0===c&&(c=!1);var p=e.order;void 0===p&&(p=!0);var d,v,g,b=e.once;if(void 0===b&&(b=!1),O(),v=(d="abcdefghijklmnopqrstuv").length,g=Date.now(),s=""+[0,0,0].map(function(e){return d[Math.floor(Math.random()*v)]}).join("")+g,!(a=function(e,t){return void 0===t&&(t=document),"string"==typeof e?Array.from(t.querySelectorAll(e)):e instanceof Element?[e]:e instanceof NodeList?Array.from(e):e instanceof Array?e:[]}(n,o)).length)return C("no step elements"),J;var M=a.reduce(function(e,t){return e||G(t.parentNode)},!1);return M&&console.error("scrollama error: step elements cannot be children of a scrollable element. Remove any css on the parent element with overflow: scroll; or overflow: auto; on elements with fixed height.",M),w=c,h=i,y=p,E=b,J.offsetTrigger(r),m=Math.max(1,+f),x=!0,w&&t({id:s,stepEl:a,offsetVal:u}),a.forEach(function(e,t){return e.setAttribute("data-scrollama-index",t)}),l=a.map(function(){return{direction:null,state:null,progress:0}}),_(),J.enable(),J},J.resize=function(){return _(),J},J.enable=function(){return N(!0),J},J.disable=function(){return N(!1),J},J.destroy=function(){N(!1),O()},J.offsetTrigger=function(e){if(null===e)return u;if("number"==typeof e)I="percent",e>1&&C("offset value is greater than 1. Fallback to 1."),e<0&&C("offset value is lower than 0. Fallback to 0."),u=Math.min(Math.max(0,e),1);else if("string"==typeof e&&e.indexOf("px")>0){var t=+e.replace("px","");isNaN(t)?(C("offset value must be in 'px' format. Fallback to 0.5."),u=.5):(I="pixels",u=t)}else C("offset value does not include 'px'. Fallback to 0.5."),u=.5;return J},J.onStepEnter=function(e){return"function"==typeof e?r.stepEnter=e:C("onStepEnter requires a function"),J},J.onStepExit=function(e){return"function"==typeof e?r.stepExit=e:C("onStepExit requires a function"),J},J.onStepProgress=function(e){return"function"==typeof e?r.stepProgress=e:C("onStepProgress requires a function"),J},J}}); | ||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e=e||self).scrollama=t()}(this,function(){"use strict";function w(e){console.error(`scrollama error: ${e}`)}function y(e){return+e.getAttribute("data-scrollama-index")}function O(e){if("string"==typeof e&&0<e.indexOf("px")){var t=+e.replace("px","");return isNaN(t)?(err("offset value must be in 'px' format. Fallback to 0.5."),{format:"percent",value:.5}):{format:"pixels",value:t}}return"number"!=typeof e&&isNaN(+e)?null:(1<e&&err("offset value is greater than 1. Fallback to 1."),e<0&&err("offset value is lower than 0. Fallback to 0."),{format:"percent",value:Math.min(Math.max(0,e),1)})}let e=0,t=0,S;function A(){e!==window.pageYOffset&&(e=window.pageYOffset,e>t?S="down":e<t&&(S="up"),t=e)}return document.addEventListener("scroll",A),function(){let o={},i=[],a,f=0,t=!1,c=!1,u=!1,r=[];function p(){o={stepEnter:()=>{},stepExit:()=>{},stepProgress:()=>{}},r=[]}function l(e){e&&!t&&b(),!e&&t&&v(),t=e}function s(e,t){var n=y(e);const r=i[n];void 0!==t&&(r.progress=t);t={element:e,index:n,progress:t,direction:S};"enter"===r.state&&o.stepProgress(t)}function n([e]){var t=y(e.target);const n=i[t];e=e.target.offsetHeight;e!==n.height&&(n.height=e,h(n),m(n),x(n))}function d([e]){A();var{isIntersecting:t,target:e}=e;(t?function(e){var t=y(e);const n=i[t];e={element:e,index:t,direction:S},n.direction=S,n.state="enter",r[t]||o.stepEnter(e),u&&(r[t]=!0)}:function(e){var t=y(e);const n=i[t];n.state&&(t={element:e,index:t,direction:S},c&&("down"===S&&n.progress<1?s(e,1):"up"===S&&0<n.progress&&s(e,0)),n.direction=S,n.state="exit",o.stepExit(t))})(e)}function g([e]){var t=y(e.target),n=i[t],{isIntersecting:r,intersectionRatio:t,target:e}=e;r&&"enter"===n.state&&s(e,t)}function h({observers:t}){Object.keys(t).map(e=>{t[e].disconnect()})}function v(){i.forEach(h)}function x(e){const t=new ResizeObserver(n);t.observe(e.node),e.observers.resize=t}function m(e){var t=window.innerHeight,n=e.offset||a,r="pixels"===n.format?1:t,n=n.value*r,r=e.height/2-n,n=e.height/2-(t-n);const o=new IntersectionObserver(d,{rootMargin:`${r}px 0px ${n}px 0px`,threshold:.5});o.observe(e.node),e.observers.step=o}function e(e){var t=window.innerHeight,n=e.offset||a,r="pixels"===n.format?1:t,r=n.value*r,r=`${-r+e.height}px 0px ${r-t}px 0px`,t=function(e,t){var n=Math.ceil(e/t);const r=[];var o=1/n;for(let e=0;e<n+1;e+=1)r.push(e*o);return r}(e.height,f);const o=new IntersectionObserver(g,{rootMargin:r,threshold:t});o.observe(e.node),e.observers.progress=o}function b(){v(),i.forEach(x),i.forEach(m),c&&i.forEach(e)}const E={};return E.setup=({step:e,parent:t,offset:n=.5,threshold:r=4,progress:o=!1,once:s=!1})=>{return i=([e,t=document]=[e,t],("string"==typeof e?Array.from(t.querySelectorAll(e)):e instanceof Element?[e]:e instanceof NodeList?Array.from(e):e instanceof Array?e:[]).map((e,t)=>({index:t,direction:void 0,height:e.offsetHeight,node:e,observers:{},offset:O(e.dataset.offset),top:function(e){var{top:e}=e.getBoundingClientRect();return e+window.pageYOffset-(document.body.clientTop||0)}(e),progress:0,state:void 0}))),i.length?(c=o,u=s,f=Math.max(1,+r),a=O(n),p(),i.forEach(e=>e.node.setAttribute("data-scrollama-index",e.index)),l(!0)):w("no step elements"),E},E.enable=()=>(l(!0),E),E.disable=()=>(l(!1),E),E.destroy=()=>(l(!1),p(),E),E.offset=e=>null==e?a.value:(a=O(e),b(),E),E.onStepEnter=e=>("function"==typeof e?o.stepEnter=e:w("onStepEnter requires a function"),E),E.onStepExit=e=>("function"==typeof e?o.stepExit=e:w("onStepExit requires a function"),E),E.onStepProgress=e=>("function"==typeof e?o.stepProgress=e:w("onStepProgress requires a function"),E),E}}); |
@@ -1,1 +0,1 @@ | ||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.scrollama=t()}(this,function(){"use strict";function e(e){return"scrollama__debug-offset--"+e}function t(t){!function(t){var n=t.id,o=t.offsetVal,r=t.stepClass,i=document.createElement("div");i.id=e(n),i.className="scrollama__debug-offset",i.style.position="fixed",i.style.left="0",i.style.width="100%",i.style.height="0",i.style.borderTop="2px dashed black",i.style.zIndex="9999";var s=document.createElement("p");s.innerHTML='".'+r+'" trigger: <span>'+o+"</span>",s.style.fontSize="12px",s.style.fontFamily="monospace",s.style.color="black",s.style.margin="0",s.style.padding="6px",i.appendChild(s),document.body.appendChild(i)}({id:t.id,offsetVal:t.offsetVal,stepClass:t.stepEl[0].className})}function n(e){var t=e.id,n=e.index,o=e.state,r="scrollama__debug-step--"+t+"-"+n,i=document.getElementById(r+"_above"),s=document.getElementById(r+"_below"),a="enter"===o?"block":"none";i&&(i.style.display=a),s&&(s.style.display=a)}return function(){var o=["stepAbove","stepBelow","stepProgress","viewportAbove","viewportBelow"],r={},i={},s=null,a=[],f=[],c=[],l=[],u=0,p=0,d=0,v=0,g=0,m=0,x=!1,b=!1,w=!1,h=!1,y=!1,E=!1,M="down",I="percent",A=[];function C(e){console.error("scrollama error: "+e)}function O(){r={stepEnter:function(){},stepExit:function(){},stepProgress:function(){}},i={}}function S(e){return e.getBoundingClientRect().top+window.pageYOffset-(document.body.clientTop||0)}function B(e){return+e.getAttribute("data-scrollama-index")}function H(){window.pageYOffset>g?M="down":window.pageYOffset<g&&(M="up"),g=window.pageYOffset}function k(e){i[e]&&i[e].forEach(function(e){return e.disconnect()})}function _(){var t,n;d=window.innerHeight,t=document.body,n=document.documentElement,v=Math.max(t.scrollHeight,t.offsetHeight,n.clientHeight,n.scrollHeight,n.offsetHeight),p=u*("pixels"===I?1:d),x&&(f=a.map(function(e){return e.getBoundingClientRect().height}),c=a.map(S),b&&D()),w&&function(t){var n=t.id,o=t.offsetMargin,r=t.offsetVal,i="pixels"===t.format?"px":"",s=e(n),a=document.getElementById(s);a.style.top=o+"px",a.querySelector("span").innerText=""+r+i}({id:s,offsetMargin:p,offsetVal:u,format:I})}function N(e){if(e&&!b){if(!x)return C("scrollama error: enable() called before scroller was ready"),void(b=!1);D()}!e&&b&&o.forEach(k),b=e}function P(e,t){var n=B(e);void 0!==t&&(l[n].progress=t);var o={element:e,index:n,progress:l[n].progress};"enter"===l[n].state&&r.stepProgress(o)}function R(e,t){if("above"===t)for(var n=0;n<e;n+=1){var o=l[n];"enter"!==o.state&&"down"!==o.direction?(T(a[n],"down",!1),q(a[n],"down")):"enter"===o.state&&q(a[n],"down")}else if("below"===t)for(var r=l.length-1;r>e;r-=1){var i=l[r];"enter"===i.state&&q(a[r],"up"),"down"===i.direction&&(T(a[r],"up",!1),q(a[r],"up"))}}function T(e,t,o){void 0===o&&(o=!0);var i=B(e),a={element:e,index:i,direction:t};l[i].direction=t,l[i].state="enter",y&&o&&"down"===t&&R(i,"above"),y&&o&&"up"===t&&R(i,"below"),r.stepEnter&&!A[i]&&(r.stepEnter(a,l),w&&n({id:s,index:i,state:"enter"}),E&&(A[i]=!0)),h&&P(e)}function q(e,t){var o=B(e),i={element:e,index:o,direction:t};h&&("down"===t&&l[o].progress<1?P(e,1):"up"===t&&l[o].progress>0&&P(e,0)),l[o].direction=t,l[o].state="exit",r.stepExit(i,l),w&&n({id:s,index:o,state:"exit"})}function V(e){var t=e[0];H();var n=t.isIntersecting,o=t.boundingClientRect,r=t.target,i=o.top,s=o.bottom,a=i-p,f=s-p,c=B(r),u=l[c];n&&a<=0&&f>=0&&"down"===M&&"enter"!==u.state&&T(r,M),!n&&a>0&&"up"===M&&"enter"===u.state&&q(r,M)}function Y(e){var t=e[0];H();var n=t.isIntersecting,o=t.boundingClientRect,r=t.target,i=o.top,s=o.bottom,a=i-p,f=s-p,c=B(r),u=l[c];n&&a<=0&&f>=0&&"up"===M&&"enter"!==u.state&&T(r,M),!n&&f<0&&"down"===M&&"enter"===u.state&&q(r,M)}function F(e){var t=e[0];H();var n=t.isIntersecting,o=t.target,r=B(o),i=l[r];n&&"down"===M&&"down"!==i.direction&&"enter"!==i.state&&(T(o,"down"),q(o,"down"))}function j(e){var t=e[0];H();var n=t.isIntersecting,o=t.target,r=B(o),i=l[r];n&&"up"===M&&"down"===i.direction&&"enter"!==i.state&&(T(o,"up"),q(o,"up"))}function z(e){var t=e[0];H();var n=t.isIntersecting,o=t.intersectionRatio,r=t.boundingClientRect,i=t.target,s=r.bottom;n&&s-p>=0&&P(i,+o)}function L(){i.stepProgress=a.map(function(e,t){var n=f[t]-p+"px 0px "+(-d+p)+"px 0px",o=function(e){for(var t=Math.ceil(e/m),n=[],o=1/t,r=0;r<t;r+=1)n.push(r*o);return n}(f[t]),r=new IntersectionObserver(z,{rootMargin:n,threshold:o});return r.observe(e),r})}function D(){o.forEach(k),i.viewportAbove=a.map(function(e,t){var n=v-c[t],o=p-d-f[t],r=new IntersectionObserver(F,{rootMargin:n+"px 0px "+o+"px 0px"});return r.observe(e),r}),i.viewportBelow=a.map(function(e,t){var n=-p-f[t],o=p-d+f[t]+v,r=new IntersectionObserver(j,{rootMargin:n+"px 0px "+o+"px 0px"});return r.observe(e),r}),i.stepAbove=a.map(function(e,t){var n=-p+f[t],o=new IntersectionObserver(V,{rootMargin:n+"px 0px "+(p-d)+"px 0px"});return o.observe(e),o}),i.stepBelow=a.map(function(e,t){var n=-p,o=p-d+f[t],r=new IntersectionObserver(Y,{rootMargin:n+"px 0px "+o+"px 0px"});return r.observe(e),r}),h&&L()}function G(e){return!(!e||1!==e.nodeType)&&(function(e){var t=window.getComputedStyle(e);return("scroll"===t.overflowY||"auto"===t.overflowY)&&e.scrollHeight>e.clientHeight}(e)?e:G(e.parentNode))}var J={};return J.setup=function(e){var n=e.step,o=e.parent,r=e.offset;void 0===r&&(r=.5);var i=e.progress;void 0===i&&(i=!1);var f=e.threshold;void 0===f&&(f=4);var c=e.debug;void 0===c&&(c=!1);var p=e.order;void 0===p&&(p=!0);var d,v,g,b=e.once;if(void 0===b&&(b=!1),O(),v=(d="abcdefghijklmnopqrstuv").length,g=Date.now(),s=""+[0,0,0].map(function(e){return d[Math.floor(Math.random()*v)]}).join("")+g,!(a=function(e,t){return void 0===t&&(t=document),"string"==typeof e?Array.from(t.querySelectorAll(e)):e instanceof Element?[e]:e instanceof NodeList?Array.from(e):e instanceof Array?e:[]}(n,o)).length)return C("no step elements"),J;var M=a.reduce(function(e,t){return e||G(t.parentNode)},!1);return M&&console.error("scrollama error: step elements cannot be children of a scrollable element. Remove any css on the parent element with overflow: scroll; or overflow: auto; on elements with fixed height.",M),w=c,h=i,y=p,E=b,J.offsetTrigger(r),m=Math.max(1,+f),x=!0,w&&t({id:s,stepEl:a,offsetVal:u}),a.forEach(function(e,t){return e.setAttribute("data-scrollama-index",t)}),l=a.map(function(){return{direction:null,state:null,progress:0}}),_(),J.enable(),J},J.resize=function(){return _(),J},J.enable=function(){return N(!0),J},J.disable=function(){return N(!1),J},J.destroy=function(){N(!1),O()},J.offsetTrigger=function(e){if(null===e)return u;if("number"==typeof e)I="percent",e>1&&C("offset value is greater than 1. Fallback to 1."),e<0&&C("offset value is lower than 0. Fallback to 0."),u=Math.min(Math.max(0,e),1);else if("string"==typeof e&&e.indexOf("px")>0){var t=+e.replace("px","");isNaN(t)?(C("offset value must be in 'px' format. Fallback to 0.5."),u=.5):(I="pixels",u=t)}else C("offset value does not include 'px'. Fallback to 0.5."),u=.5;return J},J.onStepEnter=function(e){return"function"==typeof e?r.stepEnter=e:C("onStepEnter requires a function"),J},J.onStepExit=function(e){return"function"==typeof e?r.stepExit=e:C("onStepExit requires a function"),J},J.onStepProgress=function(e){return"function"==typeof e?r.stepProgress=e:C("onStepProgress requires a function"),J},J}}); | ||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e=e||self).scrollama=t()}(this,function(){"use strict";function w(e){console.error(`scrollama error: ${e}`)}function y(e){return+e.getAttribute("data-scrollama-index")}function O(e){if("string"==typeof e&&0<e.indexOf("px")){var t=+e.replace("px","");return isNaN(t)?(err("offset value must be in 'px' format. Fallback to 0.5."),{format:"percent",value:.5}):{format:"pixels",value:t}}return"number"!=typeof e&&isNaN(+e)?null:(1<e&&err("offset value is greater than 1. Fallback to 1."),e<0&&err("offset value is lower than 0. Fallback to 0."),{format:"percent",value:Math.min(Math.max(0,e),1)})}let e=0,t=0,S;function A(){e!==window.pageYOffset&&(e=window.pageYOffset,e>t?S="down":e<t&&(S="up"),t=e)}return document.addEventListener("scroll",A),function(){let o={},i=[],a,f=0,t=!1,c=!1,u=!1,r=[];function p(){o={stepEnter:()=>{},stepExit:()=>{},stepProgress:()=>{}},r=[]}function l(e){e&&!t&&b(),!e&&t&&v(),t=e}function s(e,t){var n=y(e);const r=i[n];void 0!==t&&(r.progress=t);t={element:e,index:n,progress:t,direction:S};"enter"===r.state&&o.stepProgress(t)}function n([e]){var t=y(e.target);const n=i[t];e=e.target.offsetHeight;e!==n.height&&(n.height=e,h(n),m(n),x(n))}function d([e]){A();var{isIntersecting:t,target:e}=e;(t?function(e){var t=y(e);const n=i[t];e={element:e,index:t,direction:S},n.direction=S,n.state="enter",r[t]||o.stepEnter(e),u&&(r[t]=!0)}:function(e){var t=y(e);const n=i[t];n.state&&(t={element:e,index:t,direction:S},c&&("down"===S&&n.progress<1?s(e,1):"up"===S&&0<n.progress&&s(e,0)),n.direction=S,n.state="exit",o.stepExit(t))})(e)}function g([e]){var t=y(e.target),n=i[t],{isIntersecting:r,intersectionRatio:t,target:e}=e;r&&"enter"===n.state&&s(e,t)}function h({observers:t}){Object.keys(t).map(e=>{t[e].disconnect()})}function v(){i.forEach(h)}function x(e){const t=new ResizeObserver(n);t.observe(e.node),e.observers.resize=t}function m(e){var t=window.innerHeight,n=e.offset||a,r="pixels"===n.format?1:t,n=n.value*r,r=e.height/2-n,n=e.height/2-(t-n);const o=new IntersectionObserver(d,{rootMargin:`${r}px 0px ${n}px 0px`,threshold:.5});o.observe(e.node),e.observers.step=o}function e(e){var t=window.innerHeight,n=e.offset||a,r="pixels"===n.format?1:t,r=n.value*r,r=`${-r+e.height}px 0px ${r-t}px 0px`,t=function(e,t){var n=Math.ceil(e/t);const r=[];var o=1/n;for(let e=0;e<n+1;e+=1)r.push(e*o);return r}(e.height,f);const o=new IntersectionObserver(g,{rootMargin:r,threshold:t});o.observe(e.node),e.observers.progress=o}function b(){v(),i.forEach(x),i.forEach(m),c&&i.forEach(e)}const E={};return E.setup=({step:e,parent:t,offset:n=.5,threshold:r=4,progress:o=!1,once:s=!1})=>{return i=([e,t=document]=[e,t],("string"==typeof e?Array.from(t.querySelectorAll(e)):e instanceof Element?[e]:e instanceof NodeList?Array.from(e):e instanceof Array?e:[]).map((e,t)=>({index:t,direction:void 0,height:e.offsetHeight,node:e,observers:{},offset:O(e.dataset.offset),top:function(e){var{top:e}=e.getBoundingClientRect();return e+window.pageYOffset-(document.body.clientTop||0)}(e),progress:0,state:void 0}))),i.length?(c=o,u=s,f=Math.max(1,+r),a=O(n),p(),i.forEach(e=>e.node.setAttribute("data-scrollama-index",e.index)),l(!0)):w("no step elements"),E},E.enable=()=>(l(!0),E),E.disable=()=>(l(!1),E),E.destroy=()=>(l(!1),p(),E),E.offset=e=>null==e?a.value:(a=O(e),b(),E),E.onStepEnter=e=>("function"==typeof e?o.stepEnter=e:w("onStepEnter requires a function"),E),E.onStepExit=e=>("function"==typeof e?o.stepExit=e:w("onStepExit requires a function"),E),E.onStepProgress=e=>("function"==typeof e?o.stepProgress=e:w("onStepProgress requires a function"),E),E}}); |
@@ -1,3 +0,3 @@ | ||
import init from './src/init.js'; | ||
import entry from "./src/entry"; | ||
export default init; | ||
export default entry; |
{ | ||
"name": "scrollama", | ||
"version": "2.2.2", | ||
"version": "3.0.0", | ||
"description": "Lightweight scrollytelling library using IntersectionObserver", | ||
@@ -38,17 +38,10 @@ "main": "build/scrollama.js", | ||
"devDependencies": { | ||
"babel-eslint": "10.0.3", | ||
"cross-env": "^5.1.3", | ||
"eslint": "6.6.0", | ||
"eslint-config-airbnb-base": "14.0.0", | ||
"eslint-config-prettier": "6.6.0", | ||
"eslint-plugin-import": "2.18.2", | ||
"eslint-plugin-prettier": "3.1.1", | ||
"prettier": "1.19.1", | ||
"rollup": "^0.55.3", | ||
"rollup-plugin-buble": "^0.18.0", | ||
"rollup-plugin-commonjs": "^8.3.0", | ||
"rollup-plugin-filesize": "^1.5.0", | ||
"rollup-plugin-node-resolve": "^3.0.2", | ||
"rollup-plugin-uglify": "^3.0.0" | ||
"cross-env": "^7.0.3", | ||
"rollup": "^1.32.1", | ||
"rollup-plugin-buble": "^0.19.8", | ||
"rollup-plugin-commonjs": "^10.1.0", | ||
"rollup-plugin-filesize": "^9.1.1", | ||
"rollup-plugin-node-resolve": "^5.2.0", | ||
"rollup-plugin-uglify": "^6.0.4" | ||
} | ||
} |
@@ -1,3 +0,21 @@ | ||
###### scrollama.js | ||
# v3 roadmap | ||
- revamp intersection observer | ||
- use resize observer for auto resize (polyfill note) | ||
- offset | ||
- progress | ||
- custom offset trigger | ||
- progress enter/exit | ||
- sinngle rAF scroll updates | ||
- deprecate resize | ||
- auto-update on offset trigger date (rename to offset) | ||
- better debugger | ||
- dont disconnect resize | ||
- update docs | ||
- update examples (no stickyfill, mobile pattern obsolete?) | ||
- scrollable check needed? (maybe a soft warning) | ||
- preserve order: try adding queue, store how it was detected last time or position, position jump checks? (only works with ordered steps + global offset?) | ||
<img src="https://russellgoldenberg.github.io/scrollama/logo.png" width="160" alt="scrollama.js"/> | ||
@@ -121,7 +139,7 @@ | ||
- `threshold` (number, 1+): The granularity of the progress interval in pixels (smaller = more granular). **(default: 4)** | ||
- `order` (boolean): Fire previous step triggers if they were jumped. **(default: true)** | ||
- `order` (boolean): Fire previous step triggers if they were jumped. **(default: false)** | ||
- `once` (boolean): Only trigger the step to enter once then remove listener. **(default: false)** | ||
- `debug` (boolean): Whether to show visual debugging tools or not. **(default: | ||
false)** | ||
- `parent` (HTMLElement[]): Parent element for step selector (use if you steps are in shadow DOM) **(default: undefined)** | ||
- parent (HTMLElement[]): Parent element for step selector (use if you steps are in shadow DOM). **(default: undefined)** | ||
@@ -166,2 +184,4 @@ #### scrollama.onStepEnter(callback) | ||
`direction`: 'up' or 'down' | ||
#### scrollama.offsetTrigger([number or string]) | ||
@@ -231,2 +251,3 @@ | ||
- [tuckergordon](https://github.com/tuckergordon) | ||
- [emma-k-alexandra](https://github.com/emma-k-alexandra) | ||
@@ -237,3 +258,3 @@ ### License | ||
Copyright (c) 2020 Russell Goldenberg | ||
Copyright (c) 2021 Russell Goldenberg | ||
@@ -240,0 +261,0 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of |
@@ -1,10 +0,9 @@ | ||
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'; | ||
import commonjs from "rollup-plugin-commonjs"; | ||
import resolve from "rollup-plugin-node-resolve"; | ||
import { uglify } from "rollup-plugin-uglify"; | ||
import filesize from "rollup-plugin-filesize"; | ||
const isProd = process.env.NODE_ENV === 'production'; | ||
const isProd = process.env.NODE_ENV === "production"; | ||
const file = `build/scrollama${isProd ? '.min' : ''}.js`; | ||
const file = `build/scrollama${isProd ? ".min" : ""}.js`; | ||
@@ -14,21 +13,19 @@ const plugins = [ | ||
jsnext: true, | ||
main: true | ||
main: true, | ||
}), | ||
commonjs({ | ||
sourceMap: false | ||
sourceMap: false, | ||
}), | ||
buble(), | ||
filesize() | ||
filesize(), | ||
isProd && uglify(), | ||
]; | ||
isProd && plugins.push(uglify()); | ||
export default { | ||
input: 'index.js', | ||
input: "index.js", | ||
output: { | ||
file, | ||
format: 'umd', | ||
name: 'scrollama' | ||
format: "umd", | ||
name: "scrollama", | ||
}, | ||
plugins | ||
plugins, | ||
}; |
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
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
7
37
273
366495
896
1