glide-data-grid
glide-data-grid copied to clipboard
Grid fails to bring selected cell into view when exceeding max renderable div size.
The grid fails to scroll to the correct position when its height exceeds 28,000,000 pixels. Browsers seem to have a limit on the max height of an element. Chrome is around 28,000,000.
If you look at the playcode below you can see the issue when the grid has too many rows and total height of rows exceeds 28,000,000 in pixels.
Grid1: has 500,000 rows (here you just select a row that the other two grids to should scroll to) Grid2: has 500,000 rows (height is less than 28m pixels). It scrolls to the same row as Grid1 Grid3: has 3,000,000 rows (height exceeds 28m pixels). It scrolls a different than Grid1. It's not even close, it's way off.
PlayCode: https://playcode.io/1470140
Great catch. This is caused by the scroll region compression. The fix is straightforward but hard. Will get it done.
At Streak, we ran into this and found it can happen with as few as 550,000 rows at 32 row height (17.6m px total height), and the issue happens specifically when the cell being jumped to is more than 2000 pixels away. We tracked this number to https://github.com/glideapps/glide-data-grid/blob/2ad08c86f43e78de6512ed4e1378494a2c5b97d3/packages/core/src/scrolling-data-grid/infinite-scroller.tsx#L205-L209
A jump like this can be triggered when using ctrl-F searching, or if you select a cell, scroll a hundred rows up, and then press an arrow key to move the selection.
Additionally, after a 2000+ px jump happens, then if you scroll to the top, there's a sudden jump in the rows you see when you reach the top. You can be looking at rows 550-570, scroll the final pixel up to the very top, and suddenly you're looking at rows 0-20.
Yeah this behavior is expected to a certain extent. You are exceeding the maximum scrollable height of a div in your browser. Once scroll compression kicks in there are some edge case behaviors. The only "perfect" fix is to replace the native scroller with non-native scrolling. This has been considered many times but it would break kinetic scroll which was considered to be worse.
I just want to leave an expanded comment here to explain what I mean above.
Lets say the maximum div size of your browser is such that you have 100pixels you can scroll. In this example you have 110 pixels worth of content.
One thing you could do is make it so that scrolling is 10% faster than expected. Unfortunately, this is pretty noticeable once that compression gets to around 20%. You would virtually scroll 11px for every 10px actually scrolled. It works, I've seen other libraries take this approach, but it feels bad. Not good.
The only other reasonable thing to do is to instead adopt a course + fine scrolling amount. The way this works is straightforward.
- On course scrolling, you scroll as if compression was on. Course scrolling is imprecise, not triggered by kinetic scrolling. This is doing things like pressing end, or dragging the scrollbar.
- On fine scrolling, you "offset" the current course scroll position. This is what happens when you move the mouse wheel or scroll with the trackpad. 1px of scrolling === 1px of motion.
The problem is you only have 100px of scrolling at 110px of content. So if you course scroll to the bottom and then fine scroll to the top, the last pixel you will see before hard stopping is 10. In our case when we hard stop we also fix the scroll position to be "correct".
Now there is a general solution to this, and that is every time you get "near" a hard stop you adjust the scroll position and update the fine/course positions such that the scrollbar gives you enough pixels above/below to hit the hard stop perfectly, but the user doesn't see the update (excpet the scrollbar flickering maybe). This is a perfect solution minus that flicker. I have not done this part yet.
As for the original bug report. Well the reason this gets off is the cell scrollTo algorithm only knows about the course scroll and doesn't properly set the fine scroll to actually position the window correctly. If compression is enough this can push the cell entirely off screen if you are unlucky. Once compression becomes extreme enough, it will almost always be offscreen. Setting the fine scroll resolves this.
Fix methodology:
- Adjust DataGridRef
getBoundscall to have a boolean to get the position relative to the root of the scroll region - Instead of doing the math to figure out the delta, the data editor can now scroll directly to the correct location
- Infinite scroller can now accept the inbound results and adapt them the scaling