From 8ab4a4865f3439aeee457f49d54dcb82992b61cb Mon Sep 17 00:00:00 2001 From: ameerabuf Date: Mon, 12 Aug 2024 10:55:21 +0300 Subject: [PATCH 01/12] supporting entry-crossing range name --- dist/index.cjs | 17 ++++++++++++++++- src/view.js | 4 ++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/dist/index.cjs b/dist/index.cjs index 2919918..e4ce8a0 100644 --- a/dist/index.cjs +++ b/dist/index.cjs @@ -124,6 +124,10 @@ function transformRangeToPosition (range, viewportSize, rect) { startPosition = start - viewportSize; duration = Math.min(viewportSize, height); } + else if (name === 'entry-crossing') { + startPosition = start - viewportSize; + duration = height; + } else if (name === 'contain') { startPosition = Math.min(end - viewportSize, start); // it's either VH - height OR height - VH; so it boils down to just the absolute value of that @@ -214,6 +218,7 @@ function computeStickinessIntoFullRange(offsetTree, absoluteStartOffset, absolut } } }); + return newAbsoluteRange; } @@ -225,6 +230,7 @@ function computeStickinessIntoFullRange(offsetTree, absoluteStartOffset, absolut * @param {number} viewportSize * @param {boolean} isHorizontal * @param {AbsoluteOffsetContext} absoluteOffsetContext + * @param {Array<{element: HTMLElement, offset: number, sticky: {start?: number, end?: number}}>} offsetTree * @return {ScrollScene} */ function transformSceneRangesToOffsets (scene, rect, viewportSize, isHorizontal, absoluteOffsetContext, offsetTree) { @@ -239,28 +245,38 @@ function transformSceneRangesToOffsets (scene, rect, viewportSize, isHorizontal, if (typeof duration === 'string') { startRange = { name: duration, offset: 0 }; endRange = { name: duration, offset: 100 }; + startOffset = transformRangeToPosition(startRange, viewportSize, rect); endOffset = transformRangeToPosition(endRange, viewportSize, rect); overrideDuration = endOffset - startOffset; + const newAbsoluteRange = computeStickinessIntoFullRange(offsetTree, startOffset, endOffset, viewportSize, isHorizontal); + startOffset = newAbsoluteRange.start; endOffset = newAbsoluteRange.end; } else { if (startRange || start?.name) { startRange = startRange || start; + const startAdd = transformAbsoluteOffsetToNumber(startRange.add, absoluteOffsetContext); const absoluteStartOffset = transformRangeToPosition({...startRange, offset: 0}, viewportSize, rect); const absoluteEndOffset = transformRangeToPosition({...startRange, offset: 100}, viewportSize, rect); + // we take 0% to 100% of the named range for start, and we compute the position by adding the sticky addition for the given start offset const newAbsoluteRange = computeStickinessIntoFullRange(offsetTree, absoluteStartOffset, absoluteEndOffset, viewportSize, isHorizontal); + startOffset = newAbsoluteRange.start + (startRange.offset / 100) * (newAbsoluteRange.end - newAbsoluteRange.start) + startAdd; } + if (endRange || end?.name) { endRange = endRange || end; + const endAdd = transformAbsoluteOffsetToNumber(endRange.add, absoluteOffsetContext); const absoluteStartOffset = transformRangeToPosition({...endRange, offset: 0}, viewportSize, rect); const absoluteEndOffset = transformRangeToPosition({...endRange, offset: 100}, viewportSize, rect); + // we take 0% to 100% of the named range for end, and we compute the position by adding the sticky addition for the given end offset const newAbsoluteRange = computeStickinessIntoFullRange(offsetTree, absoluteStartOffset, absoluteEndOffset, viewportSize, isHorizontal); + endOffset = newAbsoluteRange.start + (endRange.offset / 100) * (newAbsoluteRange.end - newAbsoluteRange.start) + endAdd; } else if (typeof duration === 'number') { @@ -423,7 +439,6 @@ function getTransformedScene (scene, root, viewportSize, isHorizontal, absoluteO transformedScene.isFixed = isFixed; - return transformedScene; } diff --git a/src/view.js b/src/view.js index 5786b0a..8301c0f 100644 --- a/src/view.js +++ b/src/view.js @@ -37,6 +37,10 @@ function transformRangeToPosition (range, viewportSize, rect) { startPosition = start - viewportSize; duration = Math.min(viewportSize, height); } + else if (name === 'entry-crossing') { + startPosition = start - viewportSize; + duration = height; + } else if (name === 'contain') { startPosition = Math.min(end - viewportSize, start); // it's either VH - height OR height - VH; so it boils down to just the absolute value of that From 7479b4d8a95c50cc4467428c4df15538b51e7830 Mon Sep 17 00:00:00 2001 From: ameerabuf Date: Mon, 12 Aug 2024 11:02:49 +0300 Subject: [PATCH 02/12] cleanup --- dist/index.cjs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/dist/index.cjs b/dist/index.cjs index e4ce8a0..c5f7144 100644 --- a/dist/index.cjs +++ b/dist/index.cjs @@ -218,7 +218,6 @@ function computeStickinessIntoFullRange(offsetTree, absoluteStartOffset, absolut } } }); - return newAbsoluteRange; } @@ -245,11 +244,9 @@ function transformSceneRangesToOffsets (scene, rect, viewportSize, isHorizontal, if (typeof duration === 'string') { startRange = { name: duration, offset: 0 }; endRange = { name: duration, offset: 100 }; - startOffset = transformRangeToPosition(startRange, viewportSize, rect); endOffset = transformRangeToPosition(endRange, viewportSize, rect); overrideDuration = endOffset - startOffset; - const newAbsoluteRange = computeStickinessIntoFullRange(offsetTree, startOffset, endOffset, viewportSize, isHorizontal); startOffset = newAbsoluteRange.start; @@ -258,23 +255,18 @@ function transformSceneRangesToOffsets (scene, rect, viewportSize, isHorizontal, else { if (startRange || start?.name) { startRange = startRange || start; - const startAdd = transformAbsoluteOffsetToNumber(startRange.add, absoluteOffsetContext); const absoluteStartOffset = transformRangeToPosition({...startRange, offset: 0}, viewportSize, rect); const absoluteEndOffset = transformRangeToPosition({...startRange, offset: 100}, viewportSize, rect); - // we take 0% to 100% of the named range for start, and we compute the position by adding the sticky addition for the given start offset const newAbsoluteRange = computeStickinessIntoFullRange(offsetTree, absoluteStartOffset, absoluteEndOffset, viewportSize, isHorizontal); startOffset = newAbsoluteRange.start + (startRange.offset / 100) * (newAbsoluteRange.end - newAbsoluteRange.start) + startAdd; } - if (endRange || end?.name) { endRange = endRange || end; - const endAdd = transformAbsoluteOffsetToNumber(endRange.add, absoluteOffsetContext); const absoluteStartOffset = transformRangeToPosition({...endRange, offset: 0}, viewportSize, rect); const absoluteEndOffset = transformRangeToPosition({...endRange, offset: 100}, viewportSize, rect); - // we take 0% to 100% of the named range for end, and we compute the position by adding the sticky addition for the given end offset const newAbsoluteRange = computeStickinessIntoFullRange(offsetTree, absoluteStartOffset, absoluteEndOffset, viewportSize, isHorizontal); endOffset = newAbsoluteRange.start + (endRange.offset / 100) * (newAbsoluteRange.end - newAbsoluteRange.start) + endAdd; @@ -283,7 +275,6 @@ function transformSceneRangesToOffsets (scene, rect, viewportSize, isHorizontal, endOffset = startOffset + duration; } } - return {...scene, start: startOffset, end: endOffset, startRange, endRange, duration: overrideDuration || duration }; } From 51042ceb4f72a2ba2a3cc0b88d6fc0b48b92df7c Mon Sep 17 00:00:00 2001 From: ameerabuf Date: Mon, 12 Aug 2024 11:04:19 +0300 Subject: [PATCH 03/12] cleanup --- dist/index.cjs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/dist/index.cjs b/dist/index.cjs index c5f7144..d409f97 100644 --- a/dist/index.cjs +++ b/dist/index.cjs @@ -248,7 +248,6 @@ function transformSceneRangesToOffsets (scene, rect, viewportSize, isHorizontal, endOffset = transformRangeToPosition(endRange, viewportSize, rect); overrideDuration = endOffset - startOffset; const newAbsoluteRange = computeStickinessIntoFullRange(offsetTree, startOffset, endOffset, viewportSize, isHorizontal); - startOffset = newAbsoluteRange.start; endOffset = newAbsoluteRange.end; } @@ -259,7 +258,6 @@ function transformSceneRangesToOffsets (scene, rect, viewportSize, isHorizontal, const absoluteStartOffset = transformRangeToPosition({...startRange, offset: 0}, viewportSize, rect); const absoluteEndOffset = transformRangeToPosition({...startRange, offset: 100}, viewportSize, rect); const newAbsoluteRange = computeStickinessIntoFullRange(offsetTree, absoluteStartOffset, absoluteEndOffset, viewportSize, isHorizontal); - startOffset = newAbsoluteRange.start + (startRange.offset / 100) * (newAbsoluteRange.end - newAbsoluteRange.start) + startAdd; } if (endRange || end?.name) { @@ -268,13 +266,13 @@ function transformSceneRangesToOffsets (scene, rect, viewportSize, isHorizontal, const absoluteStartOffset = transformRangeToPosition({...endRange, offset: 0}, viewportSize, rect); const absoluteEndOffset = transformRangeToPosition({...endRange, offset: 100}, viewportSize, rect); const newAbsoluteRange = computeStickinessIntoFullRange(offsetTree, absoluteStartOffset, absoluteEndOffset, viewportSize, isHorizontal); - endOffset = newAbsoluteRange.start + (endRange.offset / 100) * (newAbsoluteRange.end - newAbsoluteRange.start) + endAdd; } else if (typeof duration === 'number') { endOffset = startOffset + duration; } } + return {...scene, start: startOffset, end: endOffset, startRange, endRange, duration: overrideDuration || duration }; } @@ -430,6 +428,7 @@ function getTransformedScene (scene, root, viewportSize, isHorizontal, absoluteO transformedScene.isFixed = isFixed; + return transformedScene; } From 90e53ae37be00ef63091f4718e2b450fe0e6c9dc Mon Sep 17 00:00:00 2001 From: ameerabuf Date: Wed, 14 Aug 2024 14:38:38 +0300 Subject: [PATCH 04/12] sceneGroup support + exit-crossing --- dist/index.cjs | 99 ++++++++++++++++++++++++--------------- docs/reference/index.html | 6 +-- src/controller.js | 66 +++++++++++++++----------- src/view.js | 23 +++++---- test/Scroll.spec.js | 69 +++++++++++++++++++++++++++ test/view.spec.js | 32 ++++++------- types.d.ts | 3 +- 7 files changed, 204 insertions(+), 94 deletions(-) diff --git a/dist/index.cjs b/dist/index.cjs index d409f97..232bdaa 100644 --- a/dist/index.cjs +++ b/dist/index.cjs @@ -137,6 +137,10 @@ function transformRangeToPosition (range, viewportSize, rect) { startPosition = Math.max(start, end - viewportSize); duration = Math.min(viewportSize, height); } + else if (name === 'exit-crossing') { + startPosition = start; + duration = height; + } else if (name === 'cover') { startPosition = start - viewportSize; duration = height + viewportSize; @@ -218,6 +222,7 @@ function computeStickinessIntoFullRange(offsetTree, absoluteStartOffset, absolut } } }); + return newAbsoluteRange; } @@ -244,28 +249,38 @@ function transformSceneRangesToOffsets (scene, rect, viewportSize, isHorizontal, if (typeof duration === 'string') { startRange = { name: duration, offset: 0 }; endRange = { name: duration, offset: 100 }; + startOffset = transformRangeToPosition(startRange, viewportSize, rect); endOffset = transformRangeToPosition(endRange, viewportSize, rect); overrideDuration = endOffset - startOffset; + const newAbsoluteRange = computeStickinessIntoFullRange(offsetTree, startOffset, endOffset, viewportSize, isHorizontal); + startOffset = newAbsoluteRange.start; endOffset = newAbsoluteRange.end; } else { if (startRange || start?.name) { startRange = startRange || start; + const startAdd = transformAbsoluteOffsetToNumber(startRange.add, absoluteOffsetContext); const absoluteStartOffset = transformRangeToPosition({...startRange, offset: 0}, viewportSize, rect); const absoluteEndOffset = transformRangeToPosition({...startRange, offset: 100}, viewportSize, rect); + // we take 0% to 100% of the named range for start, and we compute the position by adding the sticky addition for the given start offset const newAbsoluteRange = computeStickinessIntoFullRange(offsetTree, absoluteStartOffset, absoluteEndOffset, viewportSize, isHorizontal); + startOffset = newAbsoluteRange.start + (startRange.offset / 100) * (newAbsoluteRange.end - newAbsoluteRange.start) + startAdd; } + if (endRange || end?.name) { endRange = endRange || end; + const endAdd = transformAbsoluteOffsetToNumber(endRange.add, absoluteOffsetContext); const absoluteStartOffset = transformRangeToPosition({...endRange, offset: 0}, viewportSize, rect); const absoluteEndOffset = transformRangeToPosition({...endRange, offset: 100}, viewportSize, rect); + // we take 0% to 100% of the named range for end, and we compute the position by adding the sticky addition for the given end offset const newAbsoluteRange = computeStickinessIntoFullRange(offsetTree, absoluteStartOffset, absoluteEndOffset, viewportSize, isHorizontal); + endOffset = newAbsoluteRange.start + (endRange.offset / 100) * (newAbsoluteRange.end - newAbsoluteRange.start) + endAdd; } else if (typeof duration === 'number') { @@ -273,7 +288,7 @@ function transformSceneRangesToOffsets (scene, rect, viewportSize, isHorizontal, } } - return {...scene, start: startOffset, end: endOffset, startRange, endRange, duration: overrideDuration || duration }; + return {...scene, start: startOffset, end: endOffset, startRange, endRange, duration: overrideDuration || duration || (endOffset - startOffset) }; } /** @@ -355,15 +370,15 @@ function getStickyData (style, isHorizontal) { /** * Returns a converted scene data from ranges into offsets in pixels. * - * @param {ScrollScene} scene + * @param {ScrollScene[]} scene * @param {Window|HTMLElement} root * @param {number} viewportSize * @param {boolean} isHorizontal * @param {AbsoluteOffsetContext} absoluteOffsetContext - * @return {ScrollScene} + * @return {ScrollScene[]} */ -function getTransformedScene (scene, root, viewportSize, isHorizontal, absoluteOffsetContext) { - const element = scene.viewSource; +function getTransformedSceneGroup (scenes, root, viewportSize, isHorizontal, absoluteOffsetContext) { + const element = scenes[0].viewSource; const elementStyle = window.getComputedStyle(element); const isElementSticky = getIsSticky(elementStyle); const elementStickiness = isElementSticky ? getStickyData(elementStyle, isHorizontal) : undefined; @@ -417,19 +432,17 @@ function getTransformedScene (scene, root, viewportSize, isHorizontal, absoluteO offsetTree.reverse(); - const transformedScene = transformSceneRangesToOffsets( + const transformedScenes = scenes.map(scene => transformSceneRangesToOffsets( scene, {start: elementLayoutStart, end: elementLayoutStart + size}, viewportSize, isHorizontal, absoluteOffsetContext, offsetTree - ); - - transformedScene.isFixed = isFixed; - + )); + transformedScenes.forEach(scene => {scene.isFixed = isFixed;}); - return transformedScene; + return transformedScenes; } const VIEWPORT_RESIZE_INTERVAL = 100; @@ -523,45 +536,58 @@ function getController (config) { /* * Prepare scenes data. */ - _config.scenes = config.scenes.map((scene, index) => { - scene.index = index; - - if (scene.viewSource && (typeof scene.duration === 'string' || scene.start?.name)) { - scene = getTransformedScene(scene, root, viewportSize, horizontal, absoluteOffsetContext); + _config.scenes = Object.values( + config.scenes.reduce((acc, scene, index) => { + const key = scene.groupId || String(index); + if (acc[key]) { + acc[key].push(scene); + } else { + acc[key] = [scene]; + } + return acc; + }, + {}) + ).flatMap(sceneGroup => { + if (sceneGroup.every(scene => (scene.viewSource && (typeof scene.duration === 'string' || scene.start?.name)))) { + sceneGroup = getTransformedSceneGroup(sceneGroup, root, viewportSize, horizontal, absoluteOffsetContext); if (_config.observeSourcesResize) { - rangesToObserve.push(scene); + rangesToObserve.push(sceneGroup); } - } - else if (scene.end == null) { - scene.end = scene.start + scene.duration; - } - - if (scene.duration == null) { - scene.duration = scene.end - scene.start; + } else { + sceneGroup.forEach(scene => { + if (scene.end == null) { + scene.end = scene.start + scene.duration; + } + if (scene.duration == null) { + scene.duration = scene.end - scene.start; + } + }); } - return scene; + return sceneGroup; }); + _config.scenes.forEach((scene, index) => {scene.index = index;}); if (rangesToObserve.length) { if (window.ResizeObserver) { - const targetToScene = new Map(); + const targetToSceneGroup = new Map(); rangesResizeObserver = new window.ResizeObserver(function (entries) { entries.forEach(entry => { - const scene = targetToScene.get(entry.target); + const sceneGroup = targetToSceneGroup.get(entry.target); // TODO: try to optimize by using `const {blockSize, inlineSize} = entry.borderBoxSize[0]` - _config.scenes[scene.index] = getTransformedScene(scene, root, viewportSize, horizontal, absoluteOffsetContext); + const transformedSceneGroup = getTransformedSceneGroup(sceneGroup, root, viewportSize, horizontal, absoluteOffsetContext); + transformedSceneGroup.forEach((scene, localIndex) => {_config.scenes[scene.index] = transformedSceneGroup[localIndex];}); // replace the old object from the cache with the new one - rangesToObserve.splice(rangesToObserve.indexOf(scene), 1, _config.scenes[scene.index]); + rangesToObserve.splice(rangesToObserve.indexOf(sceneGroup), 1, transformedSceneGroup); }); }); - rangesToObserve.forEach(scene => { - rangesResizeObserver.observe(scene.viewSource, {box: 'border-box'}); - targetToScene.set(scene.viewSource, scene); + rangesToObserve.forEach(sceneGroup => { + rangesResizeObserver.observe(sceneGroup[0].viewSource, {box: 'border-box'}); + targetToSceneGroup.set(sceneGroup[0].viewSource, sceneGroup); }); } @@ -569,12 +595,11 @@ function getController (config) { viewportResizeHandler = debounce(function () { viewportSize = getViewportSize(root, horizontal); - const newRanges = rangesToObserve.map(scene => { - const newScene = getTransformedScene(scene, root, viewportSize, horizontal, absoluteOffsetContext); - - _config.scenes[scene.index] = newScene; + const newRanges = rangesToObserve.map(sceneGroup => { + const newSceneGroup = getTransformedSceneGroup(sceneGroup, root, viewportSize, horizontal, absoluteOffsetContext); + newSceneGroup.forEach((scene, localIndex) => {_config.scenes[scene.index] = newSceneGroup[localIndex];}); - return newScene; + return newSceneGroup; }); // reset cache diff --git a/docs/reference/index.html b/docs/reference/index.html index 7b82862..0b036fa 100644 --- a/docs/reference/index.html +++ b/docs/reference/index.html @@ -323,7 +323,7 @@

fizban

  • - getTransformedScene + getTransformedSceneGroup @@ -2659,7 +2659,7 @@

    - getTransformedScene + getTransformedSceneGroup

    @@ -2668,7 +2668,7 @@

    Returns a converted scene data from ranges into offsets in pixels.

    -
    getTransformedScene(scene: ScrollScene, root: (Window | HTMLElement), viewportSize: number, isHorizontal: boolean, absoluteOffsetContext: AbsoluteOffsetContext): ScrollScene
    +
    getTransformedSceneGroup(scene: ScrollScene, root: (Window | HTMLElement), viewportSize: number, isHorizontal: boolean, absoluteOffsetContext: AbsoluteOffsetContext): ScrollScene
    diff --git a/src/controller.js b/src/controller.js index 0807b7e..7bed6e6 100644 --- a/src/controller.js +++ b/src/controller.js @@ -1,5 +1,5 @@ import { debounce, defaultTo } from './utilities.js'; -import { getTransformedScene } from './view.js'; +import { getTransformedSceneGroup } from './view.js'; const VIEWPORT_RESIZE_INTERVAL = 100; @@ -92,45 +92,58 @@ export function getController (config) { /* * Prepare scenes data. */ - _config.scenes = config.scenes.map((scene, index) => { - scene.index = index; - - if (scene.viewSource && (typeof scene.duration === 'string' || scene.start?.name)) { - scene = getTransformedScene(scene, root, viewportSize, horizontal, absoluteOffsetContext); + _config.scenes = Object.values( + config.scenes.reduce((acc, scene, index) => { + const key = scene.groupId || String(index); + if (acc[key]) { + acc[key].push(scene) + } else { + acc[key] = [scene]; + } + return acc; + }, + {}) + ).flatMap(sceneGroup => { + if (sceneGroup.every(scene => (scene.viewSource && (typeof scene.duration === 'string' || scene.start?.name)))) { + sceneGroup = getTransformedSceneGroup(sceneGroup, root, viewportSize, horizontal, absoluteOffsetContext); if (_config.observeSourcesResize) { - rangesToObserve.push(scene); + rangesToObserve.push(sceneGroup); } - } - else if (scene.end == null) { - scene.end = scene.start + scene.duration; - } - - if (scene.duration == null) { - scene.duration = scene.end - scene.start; + } else { + sceneGroup.forEach(scene => { + if (scene.end == null) { + scene.end = scene.start + scene.duration; + } + if (scene.duration == null) { + scene.duration = scene.end - scene.start; + } + }); } - return scene; + return sceneGroup; }); + _config.scenes.forEach((scene, index) => {scene.index = index;}) if (rangesToObserve.length) { if (window.ResizeObserver) { - const targetToScene = new Map(); + const targetToSceneGroup = new Map(); rangesResizeObserver = new window.ResizeObserver(function (entries) { entries.forEach(entry => { - const scene = targetToScene.get(entry.target); + const sceneGroup = targetToSceneGroup.get(entry.target); // TODO: try to optimize by using `const {blockSize, inlineSize} = entry.borderBoxSize[0]` - _config.scenes[scene.index] = getTransformedScene(scene, root, viewportSize, horizontal, absoluteOffsetContext); + const transformedSceneGroup = getTransformedSceneGroup(sceneGroup, root, viewportSize, horizontal, absoluteOffsetContext); + transformedSceneGroup.forEach((scene, localIndex) => {_config.scenes[scene.index] = transformedSceneGroup[localIndex];}); // replace the old object from the cache with the new one - rangesToObserve.splice(rangesToObserve.indexOf(scene), 1, _config.scenes[scene.index]); + rangesToObserve.splice(rangesToObserve.indexOf(sceneGroup), 1, transformedSceneGroup); }) }); - rangesToObserve.forEach(scene => { - rangesResizeObserver.observe(scene.viewSource, {box: 'border-box'}); - targetToScene.set(scene.viewSource, scene); + rangesToObserve.forEach(sceneGroup => { + rangesResizeObserver.observe(sceneGroup[0].viewSource, {box: 'border-box'}); + targetToSceneGroup.set(sceneGroup[0].viewSource, sceneGroup); }); } @@ -138,12 +151,11 @@ export function getController (config) { viewportResizeHandler = debounce(function () { viewportSize = getViewportSize(root, horizontal); - const newRanges = rangesToObserve.map(scene => { - const newScene = getTransformedScene(scene, root, viewportSize, horizontal, absoluteOffsetContext); - - _config.scenes[scene.index] = newScene; + const newRanges = rangesToObserve.map(sceneGroup => { + const newSceneGroup = getTransformedSceneGroup(sceneGroup, root, viewportSize, horizontal, absoluteOffsetContext); + newSceneGroup.forEach((scene, localIndex) => {_config.scenes[scene.index] = newSceneGroup[localIndex];}); - return newScene; + return newSceneGroup; }); // reset cache diff --git a/src/view.js b/src/view.js index 8301c0f..837cff5 100644 --- a/src/view.js +++ b/src/view.js @@ -50,6 +50,10 @@ function transformRangeToPosition (range, viewportSize, rect) { startPosition = Math.max(start, end - viewportSize); duration = Math.min(viewportSize, height); } + else if (name === 'exit-crossing') { + startPosition = start; + duration = height; + } else if (name === 'cover') { startPosition = start - viewportSize; duration = height + viewportSize; @@ -197,7 +201,7 @@ function transformSceneRangesToOffsets (scene, rect, viewportSize, isHorizontal, } } - return {...scene, start: startOffset, end: endOffset, startRange, endRange, duration: overrideDuration || duration }; + return {...scene, start: startOffset, end: endOffset, startRange, endRange, duration: overrideDuration || duration || (endOffset - startOffset) }; } /** @@ -279,15 +283,15 @@ function getStickyData (style, isHorizontal) { /** * Returns a converted scene data from ranges into offsets in pixels. * - * @param {ScrollScene} scene + * @param {ScrollScene[]} scene * @param {Window|HTMLElement} root * @param {number} viewportSize * @param {boolean} isHorizontal * @param {AbsoluteOffsetContext} absoluteOffsetContext - * @return {ScrollScene} + * @return {ScrollScene[]} */ -export function getTransformedScene (scene, root, viewportSize, isHorizontal, absoluteOffsetContext) { - const element = scene.viewSource; +export function getTransformedSceneGroup (scenes, root, viewportSize, isHorizontal, absoluteOffsetContext) { + const element = scenes[0].viewSource; const elementStyle = window.getComputedStyle(element); const isElementSticky = getIsSticky(elementStyle); const elementStickiness = isElementSticky ? getStickyData(elementStyle, isHorizontal) : undefined; @@ -341,17 +345,16 @@ export function getTransformedScene (scene, root, viewportSize, isHorizontal, ab offsetTree.reverse(); - const transformedScene = transformSceneRangesToOffsets( + const transformedScenes = scenes.map(scene => transformSceneRangesToOffsets( scene, {start: elementLayoutStart, end: elementLayoutStart + size}, viewportSize, isHorizontal, absoluteOffsetContext, offsetTree - ); - - transformedScene.isFixed = isFixed; + )); + transformedScenes.forEach(scene => {scene.isFixed = isFixed;}) - return transformedScene; + return transformedScenes; } diff --git a/test/Scroll.spec.js b/test/Scroll.spec.js index 3b2d059..14bafb0 100644 --- a/test/Scroll.spec.js +++ b/test/Scroll.spec.js @@ -142,6 +142,75 @@ test('start :: effect progress :: view ranges', t => { t.is(progress, 1); }); +test('start :: effect progress :: view ranges :: sceneGroup', t => { + const element = { + offsetHeight: 100, + offsetTop: 100, + offsetParent: { + offsetTop: 200, + offsetParent: { + offsetTop: 0 + } + } + }; + + let progress = [0, 0]; + + const scroll = new Scroll({ + root: window, + scenes: [ + { + effect(s, p) { + progress[0] = p; + }, + start: {name: 'entry', offset: 50}, // 275 + end: {name: 'contain', offset: 50}, // 325 + viewSource: element + }, + { + effect(s, p) { + progress[1] = p; + }, + start: {name: 'cover', offset: 0}, // 250 + end: {name: 'exit', offset: 75}, // 387.5 + viewSource: element + } + ] + }); + + scroll.start(); + + window.scrollTo(0, 250); + window.executeAnimationFrame(0); + + t.is(progress[0], 0); + t.is(progress[1], 0); + + window.scrollTo(0, 285); + window.executeAnimationFrame(1); + + t.is(progress[0], 0.2); + t.is(+progress[1].toFixed(3), 0.255); + + window.scrollTo(0, 300); + window.executeAnimationFrame(2); + + t.is(progress[0], 0.5); + t.is(+progress[1].toFixed(3), 0.364); + + window.scrollTo(0, 325); + window.executeAnimationFrame(3); + + t.is(progress[0], 1); + t.is(+progress[1].toFixed(3), 0.545); + + window.scrollTo(0, 390); + window.executeAnimationFrame(3); + + t.is(progress[0], 1); + t.is(progress[1], 1); +}); + test('start :: effect progress :: view ranges :: add absolute offsets', t => { const element = { offsetHeight: 100, diff --git a/test/view.spec.js b/test/view.spec.js index eb031dc..84ac813 100644 --- a/test/view.spec.js +++ b/test/view.spec.js @@ -1,6 +1,6 @@ import test from 'ava'; import './mocks.js'; -import { getTransformedScene } from '../src/view.js'; +import { getTransformedSceneGroup } from '../src/view.js'; const VIEWPORT_SIZE = 200; const SMALLER_VIEWPORT_SIZE = 50; @@ -28,7 +28,7 @@ test('duration :: entry', t => { duration: 'entry' }); - const result = getTransformedScene(input, null, VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext); + const result = getTransformedSceneGroup([input], null, VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext)[0]; t.is(result.start, -200); t.is(result.end, -50); @@ -43,7 +43,7 @@ test('duration :: contain', t => { duration: 'contain' }); - const result = getTransformedScene(input, null, VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext); + const result = getTransformedSceneGroup([input], null, VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext)[0]; t.is(result.start, -50); t.is(result.end, 0); @@ -58,7 +58,7 @@ test('duration :: exit', t => { duration: 'exit' }); - const result = getTransformedScene(input, null, VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext); + const result = getTransformedSceneGroup([input], null, VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext)[0]; t.is(result.start, 0); t.is(result.end, 150); @@ -73,7 +73,7 @@ test('duration :: entry :: larger than viewport', t => { duration: 'entry'} ); - const result = getTransformedScene(input, null, SMALLER_VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext); + const result = getTransformedSceneGroup([input], null, SMALLER_VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext)[0]; t.is(result.start, -50); t.is(result.end, 0); @@ -88,7 +88,7 @@ test('duration :: contain :: larger than viewport', t => { duration: 'contain' }); - const result = getTransformedScene(input, null, SMALLER_VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext); + const result = getTransformedSceneGroup([input], null, SMALLER_VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext)[0]; t.is(result.start, 0); t.is(result.end, 100); @@ -103,7 +103,7 @@ test('duration :: exit :: larger than viewport', t => { duration: 'exit' }); - const result = getTransformedScene(input, null, SMALLER_VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext); + const result = getTransformedSceneGroup([input], null, SMALLER_VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext)[0]; t.is(result.start, 100); t.is(result.end, 150); @@ -118,7 +118,7 @@ test('duration :: cover', t => { duration: 'cover' }); - const result = getTransformedScene(input, null, VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext); + const result = getTransformedSceneGroup([input], null, VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext)[0]; t.is(result.start, -200); t.is(result.end, 150); @@ -134,7 +134,7 @@ test('start :: entry 40% & contain 60%', t => { end: {name: 'contain', offset: 60} }); - const result = getTransformedScene(input, null, VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext); + const result = getTransformedSceneGroup([input], null, VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext)[0]; t.is(result.start, -140); t.is(result.end, -20); @@ -150,7 +150,7 @@ test('start :: entry 40% :: end exit 60%', t => { end: {name: 'exit', offset: 60} }); - const result = getTransformedScene(input, null, VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext); + const result = getTransformedSceneGroup([input], null, VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext)[0]; t.is(result.start, -140); t.is(result.end, 90); @@ -166,7 +166,7 @@ test('start :: entry 40% - 50px :: end exit 60% + 50px', t => { end: {name: 'exit', offset: 60, add: '50px'} }); - const result = getTransformedScene(input, null, VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext); + const result = getTransformedSceneGroup([input], null, VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext)[0]; t.is(result.start, -190); t.is(result.end, 140); @@ -182,7 +182,7 @@ test('start :: entry 40% - 20vh :: end exit 60% + 20vw', t => { end: {name: 'exit', offset: 60, add: '20vw'} }); - const result = getTransformedScene(input, null, VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext); + const result = getTransformedSceneGroup([input], null, VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext)[0]; t.is(result.start, -140 + parseInt(-20 / 100 * absoluteOffsetContext.viewportHeight)); t.is(result.end, 90 + parseInt(20 / 100 * absoluteOffsetContext.viewportWidth)); @@ -198,7 +198,7 @@ test('start :: entry 40% :: duration 160px', t => { duration: 160 }); - const result = getTransformedScene(input, null, VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext); + const result = getTransformedSceneGroup([input], null, VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext)[0]; t.is(result.start, -140); t.is(result.end, 20); @@ -214,7 +214,7 @@ test('start :: entry 40% & contain 60% :: larger than viewport', t => { end: {name: 'contain', offset: 60} }); - const result = getTransformedScene(input, null, SMALLER_VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext); + const result = getTransformedSceneGroup([input], null, SMALLER_VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext)[0]; t.is(result.start, -30); t.is(result.end, 60); @@ -230,7 +230,7 @@ test('start :: entry 40% :: end exit 60% :: larger than viewport', t => { end: {name: 'exit', offset: 60} }); - const result = getTransformedScene(input, null, SMALLER_VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext); + const result = getTransformedSceneGroup([input], null, SMALLER_VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext)[0]; t.is(result.start, -30); t.is(result.end, 130); @@ -246,7 +246,7 @@ test('start :: entry 40% :: duration 160px :: larger than viewport', t => { duration: 160 }); - const result = getTransformedScene(input, null, SMALLER_VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext); + const result = getTransformedSceneGroup([input], null, SMALLER_VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext)[0]; t.is(result.start, -30); t.is(result.end, 130); diff --git a/types.d.ts b/types.d.ts index f8b0df8..e8ee28e 100644 --- a/types.d.ts +++ b/types.d.ts @@ -1,4 +1,4 @@ -declare type RangeName = 'entry' | 'exit' | 'contain' | 'cover'; +declare type RangeName = 'entry' | 'exit' | 'contain' | 'cover' | 'entry-crossing' | 'exit-crossing'; declare type RangeOffset = { name?: RangeName; @@ -18,6 +18,7 @@ declare type ScrollScene = { end?: RangeOffset; disabled?: boolean; viewSource?: HTMLElement; + groupId?: string; } declare module "fizban"; From d9ac8dac0057410df3798900ef6532cc2b3e449e Mon Sep 17 00:00:00 2001 From: ameerabuf Date: Wed, 14 Aug 2024 15:28:51 +0300 Subject: [PATCH 05/12] adding groupid to test --- test/Scroll.spec.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/Scroll.spec.js b/test/Scroll.spec.js index 14bafb0..784a809 100644 --- a/test/Scroll.spec.js +++ b/test/Scroll.spec.js @@ -165,7 +165,8 @@ test('start :: effect progress :: view ranges :: sceneGroup', t => { }, start: {name: 'entry', offset: 50}, // 275 end: {name: 'contain', offset: 50}, // 325 - viewSource: element + viewSource: element, + groupId: 'awesomeGroup' }, { effect(s, p) { @@ -173,7 +174,8 @@ test('start :: effect progress :: view ranges :: sceneGroup', t => { }, start: {name: 'cover', offset: 0}, // 250 end: {name: 'exit', offset: 75}, // 387.5 - viewSource: element + viewSource: element, + groupId: 'awesomeGroup' } ] }); From e94c7bf1dfe7e6d24615850eca590602a46a665f Mon Sep 17 00:00:00 2001 From: ameerabuf Date: Thu, 15 Aug 2024 12:38:10 +0300 Subject: [PATCH 06/12] support of sum in offset string parsing --- src/view.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/view.js b/src/view.js index 837cff5..e27f1c5 100644 --- a/src/view.js +++ b/src/view.js @@ -1,3 +1,12 @@ +/** + * parses offsetString of the format calc( + ) + * @param {string|undefined} offsetString + */ +function parseOffsetCalc(offsetString) { + const match = /^calc\s*\(\s*(-?\d+((px)|(vh)|(vw)))\s*\+\s*(-?\d+((px)|(vh)|(vw)))\s*\)\s*$/.match(offsetString); + return transformAbsoluteOffsetToNumber(match[1]) + transformAbsoluteOffsetToNumber(match[6]); +} + /** * Convert an absolute offset as string to number of pixels * @@ -13,7 +22,9 @@ function transformAbsoluteOffsetToNumber (offsetString, absoluteOffsetContext) { ? parseInt(offsetString) * absoluteOffsetContext.viewportHeight / 100 : /^-?\d+vw$/.test(offsetString) ? parseInt(offsetString) * absoluteOffsetContext.viewportWidth / 100 - : parseInt(offsetString) || 0 + : /^calc\s*\(\s*-?\d+((px)|(vh)|(vw))\s*\+\s*-?\d+((px)|(vh)|(vw))\s*\)\s*$/.test(offsetString) + ? parseOffsetCalc(offsetString) + : parseInt(offsetString) || 0 : 0; } From 18e918c4047ebd63750313fc1c2048cdbf5c18cc Mon Sep 17 00:00:00 2001 From: ameerabuf Date: Sat, 17 Aug 2024 04:39:13 +0300 Subject: [PATCH 07/12] wip --- dist/index.cjs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/dist/index.cjs b/dist/index.cjs index 232bdaa..92ee521 100644 --- a/dist/index.cjs +++ b/dist/index.cjs @@ -85,6 +85,15 @@ function debounce (fn, interval) { }; } +/** + * parses offsetString of the format calc( + ) + * @param {string|undefined} offsetString + */ +function parseOffsetCalc(offsetString) { + const match = /^calc\s*\(\s*(-?\d+((px)|(vh)|(vw)))\s*\+\s*(-?\d+((px)|(vh)|(vw)))\s*\)\s*$/.match(offsetString); + return transformAbsoluteOffsetToNumber(match[1]) + transformAbsoluteOffsetToNumber(match[6]); +} + /** * Convert an absolute offset as string to number of pixels * @@ -100,7 +109,9 @@ function transformAbsoluteOffsetToNumber (offsetString, absoluteOffsetContext) { ? parseInt(offsetString) * absoluteOffsetContext.viewportHeight / 100 : /^-?\d+vw$/.test(offsetString) ? parseInt(offsetString) * absoluteOffsetContext.viewportWidth / 100 - : parseInt(offsetString) || 0 + : /^calc\s*\(\s*-?\d+((px)|(vh)|(vw))\s*\+\s*-?\d+((px)|(vh)|(vw))\s*\)\s*$/.test(offsetString) + ? parseOffsetCalc(offsetString) + : parseInt(offsetString) || 0 : 0; } From 8761745fe5eb24f4ebb329648943be75f1aba881 Mon Sep 17 00:00:00 2001 From: ameerabuf Date: Sat, 17 Aug 2024 17:15:50 +0300 Subject: [PATCH 08/12] fixing calc regex computation --- dist/index.cjs | 2 +- src/view.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dist/index.cjs b/dist/index.cjs index 92ee521..15402d7 100644 --- a/dist/index.cjs +++ b/dist/index.cjs @@ -90,7 +90,7 @@ function debounce (fn, interval) { * @param {string|undefined} offsetString */ function parseOffsetCalc(offsetString) { - const match = /^calc\s*\(\s*(-?\d+((px)|(vh)|(vw)))\s*\+\s*(-?\d+((px)|(vh)|(vw)))\s*\)\s*$/.match(offsetString); + const match = offsetString.match(/^calc\s*\(\s*(-?\d+((px)|(vh)|(vw)))\s*\+\s*(-?\d+((px)|(vh)|(vw)))\s*\)\s*$/); return transformAbsoluteOffsetToNumber(match[1]) + transformAbsoluteOffsetToNumber(match[6]); } diff --git a/src/view.js b/src/view.js index e27f1c5..66b8870 100644 --- a/src/view.js +++ b/src/view.js @@ -3,7 +3,7 @@ * @param {string|undefined} offsetString */ function parseOffsetCalc(offsetString) { - const match = /^calc\s*\(\s*(-?\d+((px)|(vh)|(vw)))\s*\+\s*(-?\d+((px)|(vh)|(vw)))\s*\)\s*$/.match(offsetString); + const match = offsetString.match(/^calc\s*\(\s*(-?\d+((px)|(vh)|(vw)))\s*\+\s*(-?\d+((px)|(vh)|(vw)))\s*\)\s*$/); return transformAbsoluteOffsetToNumber(match[1]) + transformAbsoluteOffsetToNumber(match[6]); } From 9f6a935ae12db04cde6a02c15d19dd239c5abc96 Mon Sep 17 00:00:00 2001 From: ameerabuf Date: Sat, 17 Aug 2024 21:45:52 +0300 Subject: [PATCH 09/12] types --- dist/index.cjs | 2 ++ src/Scroll.js | 2 ++ types.d.ts | 3 ++- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/dist/index.cjs b/dist/index.cjs index 15402d7..cc25434 100644 --- a/dist/index.cjs +++ b/dist/index.cjs @@ -948,6 +948,8 @@ class Scroll { * @property {boolean} [disabled] whether to perform updates on the scene. Defaults to false. * @property {Element} [viewSource] an element to be used for observing intersection with viewport for disabling/enabling the scene, or the source of a ViewTimeline if scene start/end are provided as ranges. * @property {function} [destroy] a function clean up the scene when it's controller is destroyed. + * @property {string} [groupId] a string id to group together scenes + * @property {Promise} [ready] a promise that is resolved once the effects are ready. */ /** diff --git a/src/Scroll.js b/src/Scroll.js index bde320a..1465ebd 100644 --- a/src/Scroll.js +++ b/src/Scroll.js @@ -213,6 +213,8 @@ export class Scroll { * @property {boolean} [disabled] whether to perform updates on the scene. Defaults to false. * @property {Element} [viewSource] an element to be used for observing intersection with viewport for disabling/enabling the scene, or the source of a ViewTimeline if scene start/end are provided as ranges. * @property {function} [destroy] a function clean up the scene when it's controller is destroyed. + * @property {string} [groupId] a string id to group together scenes + * @property {Promise} [ready] a promise that is resolved once the effects are ready. */ /** diff --git a/types.d.ts b/types.d.ts index e8ee28e..d5deebb 100644 --- a/types.d.ts +++ b/types.d.ts @@ -6,7 +6,7 @@ declare type RangeOffset = { }; declare type scrollConfig = { - scenes: ScrollScene; + scenes: ScrollScene[]; transitionActive?: boolean; transitionFriction?: number; } @@ -19,6 +19,7 @@ declare type ScrollScene = { disabled?: boolean; viewSource?: HTMLElement; groupId?: string; + ready?: Promise; } declare module "fizban"; From 86a7f02c7981bf64dfab1e45e85d11d378374e76 Mon Sep 17 00:00:00 2001 From: ameerabuf Date: Sun, 18 Aug 2024 01:12:40 +0300 Subject: [PATCH 10/12] fixing calc comp --- dist/index.cjs | 4 ++-- src/view.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dist/index.cjs b/dist/index.cjs index cc25434..b10c0e5 100644 --- a/dist/index.cjs +++ b/dist/index.cjs @@ -89,9 +89,9 @@ function debounce (fn, interval) { * parses offsetString of the format calc( + ) * @param {string|undefined} offsetString */ -function parseOffsetCalc(offsetString) { +function parseOffsetCalc(offsetString, absoluteOffsetContext) { const match = offsetString.match(/^calc\s*\(\s*(-?\d+((px)|(vh)|(vw)))\s*\+\s*(-?\d+((px)|(vh)|(vw)))\s*\)\s*$/); - return transformAbsoluteOffsetToNumber(match[1]) + transformAbsoluteOffsetToNumber(match[6]); + return transformAbsoluteOffsetToNumber(match[1], absoluteOffsetContext) + transformAbsoluteOffsetToNumber(match[6], absoluteOffsetContext); } /** diff --git a/src/view.js b/src/view.js index 66b8870..6644482 100644 --- a/src/view.js +++ b/src/view.js @@ -2,9 +2,9 @@ * parses offsetString of the format calc( + ) * @param {string|undefined} offsetString */ -function parseOffsetCalc(offsetString) { +function parseOffsetCalc(offsetString, absoluteOffsetContext) { const match = offsetString.match(/^calc\s*\(\s*(-?\d+((px)|(vh)|(vw)))\s*\+\s*(-?\d+((px)|(vh)|(vw)))\s*\)\s*$/); - return transformAbsoluteOffsetToNumber(match[1]) + transformAbsoluteOffsetToNumber(match[6]); + return transformAbsoluteOffsetToNumber(match[1], absoluteOffsetContext) + transformAbsoluteOffsetToNumber(match[6], absoluteOffsetContext); } /** From 8ed679c914f9d93d9d10d1b1a34a9460b8293c35 Mon Sep 17 00:00:00 2001 From: ameerabuf Date: Sun, 18 Aug 2024 01:31:47 +0300 Subject: [PATCH 11/12] fixing calc comp --- dist/index.cjs | 1 + src/view.js | 1 + 2 files changed, 2 insertions(+) diff --git a/dist/index.cjs b/dist/index.cjs index b10c0e5..17290c8 100644 --- a/dist/index.cjs +++ b/dist/index.cjs @@ -88,6 +88,7 @@ function debounce (fn, interval) { /** * parses offsetString of the format calc( + ) * @param {string|undefined} offsetString + * @param {AbsoluteOffsetContext} absoluteOffsetContext */ function parseOffsetCalc(offsetString, absoluteOffsetContext) { const match = offsetString.match(/^calc\s*\(\s*(-?\d+((px)|(vh)|(vw)))\s*\+\s*(-?\d+((px)|(vh)|(vw)))\s*\)\s*$/); diff --git a/src/view.js b/src/view.js index 6644482..bc031bd 100644 --- a/src/view.js +++ b/src/view.js @@ -1,6 +1,7 @@ /** * parses offsetString of the format calc( + ) * @param {string|undefined} offsetString + * @param {AbsoluteOffsetContext} absoluteOffsetContext */ function parseOffsetCalc(offsetString, absoluteOffsetContext) { const match = offsetString.match(/^calc\s*\(\s*(-?\d+((px)|(vh)|(vw)))\s*\+\s*(-?\d+((px)|(vh)|(vw)))\s*\)\s*$/); From 232533a930506d45b29433d5b90e4ad8f0a869f4 Mon Sep 17 00:00:00 2001 From: ameerabuf Date: Sun, 18 Aug 2024 19:00:47 +0300 Subject: [PATCH 12/12] fixing calc comp --- src/view.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/view.js b/src/view.js index bc031bd..c969535 100644 --- a/src/view.js +++ b/src/view.js @@ -24,7 +24,7 @@ function transformAbsoluteOffsetToNumber (offsetString, absoluteOffsetContext) { : /^-?\d+vw$/.test(offsetString) ? parseInt(offsetString) * absoluteOffsetContext.viewportWidth / 100 : /^calc\s*\(\s*-?\d+((px)|(vh)|(vw))\s*\+\s*-?\d+((px)|(vh)|(vw))\s*\)\s*$/.test(offsetString) - ? parseOffsetCalc(offsetString) + ? parseOffsetCalc(offsetString, absoluteOffsetContext) : parseInt(offsetString) || 0 : 0; }