From 7f39bf5f90d08f93a83f2107e8185acc5063b46e Mon Sep 17 00:00:00 2001 From: devonChurch Date: Sun, 19 Jan 2020 13:42:10 +1300 Subject: [PATCH] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20integrate=20dynamic=20sc?= =?UTF-8?q?roll=20POC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.js | 2 ++ src/Scroll.js | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 src/Scroll.js diff --git a/src/App.js b/src/App.js index ebe435b..46ff6d1 100644 --- a/src/App.js +++ b/src/App.js @@ -8,6 +8,7 @@ import { createGlobalStyle } from "styled-components"; import { Swatches, UserSwatch, AppendSwatch } from "./Swatch"; import { Compositions, UserComposition, AppendComposition } from "./Composition"; import { Header } from "./Header"; +import { Scroll } from "./Scroll"; import { SWATCH_WIDTH, BLACK, @@ -324,6 +325,7 @@ const App = () => { <>
+ {isUserDragging && } {[...swatches].map(([swatchId, hex], swatchIndex) => ( diff --git a/src/Scroll.js b/src/Scroll.js new file mode 100644 index 0000000..8c1f555 --- /dev/null +++ b/src/Scroll.js @@ -0,0 +1,72 @@ +import React, { useEffect, useRef } from "react"; +import throttle from "lodash.throttle"; + +export const Scroll = () => { + const offset = useRef(); + const throttledScroll = useRef(); + + useEffect(() => { + const setScroll = () => { + const { innerHeight, scrollY } = window; + const nextScroll = scrollY + offset.current; + const isTooHigh = nextScroll < 0; + const isTooLow = nextScroll > document.body.clientHeight - innerHeight; + const shouldScroll = !isTooHigh && !isTooLow; + + if (shouldScroll) { + window.scroll(0, nextScroll); + throttledScroll.current = requestAnimationFrame(setScroll); + } else { + throttledScroll.current = null; + } + }; + + const checkScenario = event => { + const viewPortHeight = window.innerHeight; + const viewPortQuarter = viewPortHeight / 4; + const pointerPosition = event.clientY; + const isOverTopQuarter = pointerPosition < viewPortQuarter; + const isOverBottomQuarter = pointerPosition > viewPortQuarter * 3; + const maxScrollOffset = viewPortQuarter; + const shouldUpdateScroll = + !throttledScroll.current && (isOverTopQuarter || isOverBottomQuarter); + const shouldStopScroll = + throttledScroll.current && !(isOverTopQuarter || isOverBottomQuarter); + + if (isOverTopQuarter) { + const percentageOffset = (viewPortQuarter - pointerPosition) / viewPortQuarter; + const pixelOffset = maxScrollOffset * percentageOffset; + offset.current = -pixelOffset; + } + + if (isOverBottomQuarter) { + const percentageOffset = (pointerPosition - viewPortQuarter * 3) / viewPortQuarter; + const pixelOffset = maxScrollOffset * percentageOffset; + offset.current = pixelOffset; + } + + if (shouldUpdateScroll) { + throttledScroll.current = requestAnimationFrame(setScroll); + } + + if (shouldStopScroll) { + throttledScroll.current = null; + } + }; + + const handlePointerMove = event => { + checkScenario(event); + }; + + const throttledDrag = throttle(handlePointerMove, 250, { trailing: false }); + + window.addEventListener("dragover", throttledDrag); + + return function cleanUp() { + throttledScroll.current = null; + window.removeEventListener("dragover", handlePointerMove); + }; + }, []); + + return null; +};