From c60456abb177c216b362453282c1c1428de03ded Mon Sep 17 00:00:00 2001 From: Vladislav Kozulya Date: Fri, 2 Jun 2017 23:27:54 +0300 Subject: [PATCH 1/2] Add handleScroll for handling external scroll events --- docs/Grid.md | 5 ++ source/Grid/Grid.js | 125 +++++++++++++++++++++++--------------------- 2 files changed, 71 insertions(+), 59 deletions(-) diff --git a/docs/Grid.md b/docs/Grid.md index bcf71be1c..57956540c 100644 --- a/docs/Grid.md +++ b/docs/Grid.md @@ -71,6 +71,11 @@ This method can be used to safely scroll back to a cell that a user has scrolled Scroll to the specified offset(s). Useful for animating position changes. +##### handleScroll ({ scrollLeft, scrollTop }) + +Handle scroll event. +Can be used to pass an external scroll event. + ### Class names The Grid component supports the following static class names diff --git a/source/Grid/Grid.js b/source/Grid/Grid.js index c6422a41b..1c37824cd 100644 --- a/source/Grid/Grid.js +++ b/source/Grid/Grid.js @@ -418,6 +418,71 @@ export default class Grid extends PureComponent { this._setScrollPosition({ scrollLeft, scrollTop }) } + /** + * Handle scroll event. + * Can be used to pass an external scroll event. + */ + handleScroll ({ + scrollLeft: eventScrollLeft, + scrollTop: eventScrollTop, + }) { + // Prevent pointer events from interrupting a smooth scroll + this._debounceScrollEnded() + + const { autoHeight, autoWidth, height, width } = this.props + + // When this component is shrunk drastically, React dispatches a series of back-to-back scroll events, + // Gradually converging on a scrollTop that is within the bounds of the new, smaller height. + // This causes a series of rapid renders that is slow for long lists. + // We can avoid that by doing some simple bounds checking to ensure that scroll offsets never exceed their bounds. + const scrollbarSize = this._scrollbarSize + const totalRowsHeight = this._rowSizeAndPositionManager.getTotalSize() + const totalColumnsWidth = this._columnSizeAndPositionManager.getTotalSize() + const scrollLeft = Math.min(Math.max(0, totalColumnsWidth - width + scrollbarSize), eventScrollLeft) + const scrollTop = Math.min(Math.max(0, totalRowsHeight - height + scrollbarSize), eventScrollTop) + + // Certain devices (like Apple touchpad) rapid-fire duplicate events. + // Don't force a re-render if this is the case. + // The mouse may move faster then the animation frame does. + // Use requestAnimationFrame to avoid over-updating. + if ( + this.state.scrollLeft !== scrollLeft || + this.state.scrollTop !== scrollTop + ) { + // Track scrolling direction so we can more efficiently overscan rows to reduce empty space around the edges while scrolling. + // Don't change direction for an axis unless scroll offset has changed. + const scrollDirectionHorizontal = scrollLeft !== this.state.scrollLeft + ? scrollLeft > this.state.scrollLeft + ? SCROLL_DIRECTION_FORWARD + : SCROLL_DIRECTION_BACKWARD + : this.state.scrollDirectionHorizontal + const scrollDirectionVertical = scrollTop !== this.state.scrollTop + ? scrollTop > this.state.scrollTop + ? SCROLL_DIRECTION_FORWARD + : SCROLL_DIRECTION_BACKWARD + : this.state.scrollDirectionVertical + + const newState = { + isScrolling: true, + scrollDirectionHorizontal, + scrollDirectionVertical, + scrollPositionChangeReason: SCROLL_POSITION_CHANGE_REASONS.OBSERVED + } + + if (!autoHeight) { + newState.scrollTop = scrollTop + } + + if (!autoWidth) { + newState.scrollLeft = scrollLeft + } + + this.setState(newState) + } + + this._invokeOnScrollMemoizer({ scrollLeft, scrollTop, totalColumnsWidth, totalRowsHeight }) + } + componentDidMount () { const { getScrollbarSize, scrollLeft, scrollToColumn, scrollTop, scrollToRow } = this.props @@ -1121,64 +1186,6 @@ export default class Grid extends PureComponent { return } - // Prevent pointer events from interrupting a smooth scroll - this._debounceScrollEnded() - - const { autoHeight, autoWidth, height, width } = this.props - - const { - scrollLeft: eventScrollLeft, - scrollTop: eventScrollTop - } = event.target - - // When this component is shrunk drastically, React dispatches a series of back-to-back scroll events, - // Gradually converging on a scrollTop that is within the bounds of the new, smaller height. - // This causes a series of rapid renders that is slow for long lists. - // We can avoid that by doing some simple bounds checking to ensure that scroll offsets never exceed their bounds. - const scrollbarSize = this._scrollbarSize - const totalRowsHeight = this._rowSizeAndPositionManager.getTotalSize() - const totalColumnsWidth = this._columnSizeAndPositionManager.getTotalSize() - const scrollLeft = Math.min(Math.max(0, totalColumnsWidth - width + scrollbarSize), eventScrollLeft) - const scrollTop = Math.min(Math.max(0, totalRowsHeight - height + scrollbarSize), eventScrollTop) - - // Certain devices (like Apple touchpad) rapid-fire duplicate events. - // Don't force a re-render if this is the case. - // The mouse may move faster then the animation frame does. - // Use requestAnimationFrame to avoid over-updating. - if ( - this.state.scrollLeft !== scrollLeft || - this.state.scrollTop !== scrollTop - ) { - // Track scrolling direction so we can more efficiently overscan rows to reduce empty space around the edges while scrolling. - // Don't change direction for an axis unless scroll offset has changed. - const scrollDirectionHorizontal = scrollLeft !== this.state.scrollLeft - ? scrollLeft > this.state.scrollLeft - ? SCROLL_DIRECTION_FORWARD - : SCROLL_DIRECTION_BACKWARD - : this.state.scrollDirectionHorizontal - const scrollDirectionVertical = scrollTop !== this.state.scrollTop - ? scrollTop > this.state.scrollTop - ? SCROLL_DIRECTION_FORWARD - : SCROLL_DIRECTION_BACKWARD - : this.state.scrollDirectionVertical - - const newState = { - isScrolling: true, - scrollDirectionHorizontal, - scrollDirectionVertical, - scrollPositionChangeReason: SCROLL_POSITION_CHANGE_REASONS.OBSERVED - } - - if (!autoHeight) { - newState.scrollTop = scrollTop - } - if (!autoWidth) { - newState.scrollLeft = scrollLeft - } - - this.setState(newState) - } - - this._invokeOnScrollMemoizer({ scrollLeft, scrollTop, totalColumnsWidth, totalRowsHeight }) + this.handleScroll(event.target); } } From 6bd27e27d7b16bb8092a6b73b629e65d056a39ca Mon Sep 17 00:00:00 2001 From: Vladislav Kozulya Date: Fri, 2 Jun 2017 23:38:58 +0300 Subject: [PATCH 2/2] fix lint --- source/Grid/Grid.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/Grid/Grid.js b/source/Grid/Grid.js index 1c37824cd..5f83d21ff 100644 --- a/source/Grid/Grid.js +++ b/source/Grid/Grid.js @@ -424,7 +424,7 @@ export default class Grid extends PureComponent { */ handleScroll ({ scrollLeft: eventScrollLeft, - scrollTop: eventScrollTop, + scrollTop: eventScrollTop }) { // Prevent pointer events from interrupting a smooth scroll this._debounceScrollEnded() @@ -1186,6 +1186,6 @@ export default class Grid extends PureComponent { return } - this.handleScroll(event.target); + this.handleScroll(event.target) } }