From 0c5eb3d4c354879c0393dd85b7e577ee5662ca2e Mon Sep 17 00:00:00 2001 From: Luis Flores Date: Mon, 18 Sep 2023 21:31:18 +0000 Subject: [PATCH] pw_web: Improve scrolling behavior Changelist - Enable/disable autoscroll based on scroll direction - Add transition to jump-to-bottom button and bottom overflow indicator Bug: b/298097109 Change-Id: I95b11dda409eeee4482937c20bed1b003e5a9239 Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/171290 Reviewed-by: Amy Hu Presubmit-Verified: CQ Bot Account Commit-Queue: Luis Flores Reviewed-by: Asad Memon --- .../components/log-list/log-list.styles.ts | 28 ++++++- .../src/components/log-list/log-list.ts | 74 +++++++++---------- 2 files changed, 61 insertions(+), 41 deletions(-) diff --git a/pw_web/log-viewer/src/components/log-list/log-list.styles.ts b/pw_web/log-viewer/src/components/log-list/log-list.styles.ts index 5057b4dd92..92b336ef72 100644 --- a/pw_web/log-viewer/src/components/log-list/log-list.styles.ts +++ b/pw_web/log-viewer/src/components/log-list/log-list.styles.ts @@ -140,8 +140,7 @@ export const styles = css` } th[hidden], - td[hidden], - .jump-to-bottom-btn[hidden] { + td[hidden] { display: none; } @@ -172,9 +171,9 @@ export const styles = css` --md-filled-button-hover-container-elevation: 4; bottom: 2.25rem; font-family: 'Roboto Flex', sans-serif; - left: 50%; position: absolute; - transform: translate(-50%); + place-self: center; + transform: translateY(15%) scale(0.9); } .resize-handle { @@ -272,6 +271,27 @@ export const styles = css` outline: 1px solid var(--sys-log-viewer-color-table-mark); } + .jump-to-bottom-btn, + .bottom-indicator { + opacity: 0; + transition: + opacity 100ms ease, + transform 100ms ease, + visibility 100ms ease; + visibility: hidden; + } + + .jump-to-bottom-btn[data-visible='true'], + .bottom-indicator[data-visible='true'] { + opacity: 1; + transform: translateY(0) scale(1); + transition: + opacity 250ms ease, + transform 250ms ease, + 250ms ease; + visibility: visible; + } + ::-webkit-scrollbar { box-shadow: inset 0 0 2rem 2rem var(--md-sys-color-surface-container-low); -webkit-appearance: auto; diff --git a/pw_web/log-viewer/src/components/log-list/log-list.ts b/pw_web/log-viewer/src/components/log-list/log-list.ts index 6137cf16c0..0bba791bcd 100644 --- a/pw_web/log-viewer/src/components/log-list/log-list.ts +++ b/pw_web/log-viewer/src/components/log-list/log-list.ts @@ -63,10 +63,6 @@ export class LogList extends LitElement { @state() private _scrollPercentageLeft = 0; - /** A number representing visibility of vertical scroll indicator. */ - @state() - private _scrollDownOpacity = 0; - /** Indicates whether to enable autosizing of incoming log entries. */ @state() private _autosizeLocked = false; @@ -82,7 +78,6 @@ export class LogList extends LitElement { @query('table') private _table!: HTMLTableElement; @query('tbody') private _tableBody!: HTMLTableSectionElement; @queryAll('tr') private _tableRows!: HTMLTableRowElement[]; - @query('.jump-to-bottom-btn') private _jumpBottomBtn!: HTMLButtonElement; /** * Data used for column resizing including the column index, the starting @@ -102,11 +97,13 @@ export class LogList extends LitElement { private readonly AUTOSIZE_LIMIT: number = 8; /** The minimum width (in px) for table columns. */ private readonly MIN_COL_WIDTH: number = 52; + /** The last known vertical scroll position of the table container. */ + private lastScrollTop: number = 0; firstUpdated() { setInterval(() => this.updateHorizontalOverflowState(), 1000); - window.addEventListener('scroll', this.handleTableScroll); + this._tableContainer.addEventListener('scroll', this.handleTableScroll); this._tableBody.addEventListener('rangeChanged', this.onRangeChanged); const newRowObserver = new MutationObserver(this.onTableRowAdded); @@ -189,9 +186,6 @@ export class LogList extends LitElement { setTimeout(() => { container.scrollTop = container.scrollHeight; }, 0); // Complete any rendering tasks before scrolling - - this._scrollDownOpacity = 0; - this._jumpBottomBtn.hidden = true; } /** @@ -309,15 +303,31 @@ export class LogList extends LitElement { */ private handleTableScroll = () => { const container = this._tableContainer; + const currentScrollTop = container.scrollTop; const containerWidth = container.offsetWidth; const scrollLeft = container.scrollLeft; const scrollY = - container.scrollHeight - container.scrollTop - container.clientHeight; + container.scrollHeight - currentScrollTop - container.clientHeight; const maxScrollLeft = container.scrollWidth - containerWidth; const rowHeight = this._tableRows[0].offsetHeight; - this._scrollPercentageLeft = scrollLeft / maxScrollLeft || 0; + // Determine scroll direction and update the last known scroll position + const isScrollingVertically = currentScrollTop !== this.lastScrollTop; + const isScrollingUp = currentScrollTop < this.lastScrollTop; + this.lastScrollTop = currentScrollTop; + + // Only run autoscroll logic if the user is scrolling vertically + if (!isScrollingVertically) { + return; + } + + // User is scrolling up, disable autoscroll + if (isScrollingUp) { + this._autoscrollIsEnabled = false; + return; + } + // User is scrolling down, enable autoscroll if they're near the bottom if (Math.abs(scrollY) <= 1) { this._autoscrollIsEnabled = true; return; @@ -327,20 +337,7 @@ export class LogList extends LitElement { this._autoscrollIsEnabled = false; } - let debounceTimer: NodeJS.Timer | null = null; - if (debounceTimer) { - clearTimeout(debounceTimer); - } - - debounceTimer = setTimeout(() => { - if (Math.round(scrollY - rowHeight) >= 1) { - this._jumpBottomBtn.hidden = false; - this._scrollDownOpacity = 1; - } else { - this._jumpBottomBtn.hidden = true; - this._scrollDownOpacity = 0; - } - }, 100); + this._scrollPercentageLeft = scrollLeft / maxScrollLeft || 0; }; /** @@ -454,18 +451,8 @@ export class LogList extends LitElement { })} - ${this.overflowIndicators()} + ${this.overflowIndicators()} ${this.jumpToBottomButton()} - `; } @@ -591,7 +578,7 @@ export class LogList extends LitElement { private overflowIndicators = () => html`
`; + + private jumpToBottomButton = () => html` + + + Jump to Bottom + + `; }