I think it is no secret to anyone that tasks that include displaying something in the form of a grid (
data grid ) or a table are very common. At the same time, if there is a lot of data, then displaying the results (in HTML) becomes a very nontrivial task, which is usually solved by pagination.
Let's see what else there are ways to show the user a large pile of data, and preferably with filtering of results and search, and even that it is not too slow :).
Brakes usually "view", rather than "model"
As a rule, if you display the result in the form of an HTML table, then we run into display performance — the entire result is rendered at once. As practice shows, in Mozilla Firefox and Internet Explorer, the time spent on the initial rendering of a large table is very large, and I would like to somehow solve this problem.
')
Usually, this problem is avoided by paginating and rendering only a small part of the table at a time, but the user must switch pages manually, which is not very convenient. If you use pagination, then, probably, the speed of data sampling is much higher than the speed of its rendering, and this fact is used when creating grids.
The most common case is a fixed row height.
If we have the height of the rows that we want to show, it is fixed, then there are many ready-made solutions, for example
SlickGrid , and they all use a very simple idea that you can calculate the height of the resulting table in advance and draw the rows as needed when the user scrolls to the appropriate area.
Such grids exist in almost all GUI libraries and frameworks, such as Cocoa, WPF, Swing, etc. In some implementations, scrolling is allowed only line by line (most solutions under Windows), in others it can be scrolled to the middle of a line (Cocoa)
Anyway, the existing solutions are doing quite well with this task.
Less typical and more complicated case - variable row height
Let us now consider a more interesting option - suppose that the height of rows can be variable, and we can know the height of each row only after we render it. In some cases, the height can be known to us without rendering, but in any case, the fact that the height of the cells can change is important. To prevent raspberry life from appearing, we also put a condition that it is forbidden to cache height, since we can also change the width of the columns in the table, which, together with word wrap, means variable height :).
There are 2 approaches, one of which is used in Numbers.app from iWork, and the other in OpenOffice.org Calc and Microsoft Excel. Let's look at both and analyze the advantages and disadvantages.
Easy way. Full table rendering
With full table rendering, we do 3 things:
1. Render the entire table, define its height and draw a real scroll to the user
2. All the time we recalculate the height of the edited line and update the state of the scroll
3. If the width of the column (s) changes, recalculate the height of all rows and update the state of the scroll
Numbers.app chose this path for itself, and the same path is used when drawing ordinary HTML tables in browsers (with some additions, since browsers also try to write a table in the width of the container).
Than this approach is bad, I think, it can be easily understood by trying to open a fairly large table (say, 10,000 entries with 10 columns) in a browser or in Numbers.app. Everything loads and works terribly slowly and tightly hangs the application when working with content, as well as when loading a table.
The approach is good because the content scrolling can be done very quickly (because all the content has already been rendered) and smoothly, and the height of the scrolling that is shown to the user corresponds to the actual height of the displayed content.
As you might have guessed, there is another way:
Sly way. Rendering the visible part with a fake scroll
The idea is that, if there is a lot of data in the table, the user is unlikely to notice the fact that the height of the scroll does not correspond to the sum of the heights of all the cells. What does this mean, and how can we use it? A very simple:
We will not render anything at all to find out the height of the scroll - we will calculate it, as well as in the case of a fixed row height, using the following simple formula:
SCROLL_HEIGHT = N * ROW_HEIGHT
Where SCROLL_HEIGHT is the height of the scroll (i.e. the height of the “content” that we scroll with the scroll), N is the number of lines, ROW_HEIGHT is the height of one line (for example, 30px)
A natural question arises - how can we understand what we draw at a given value of the scroll position (SCROLL_TOP), because it does not correspond to the actual height of the content? The answer follows from the formula we used to calculate the height:
CURRENT_POSITION = [SCROLL_TOP / ROW_HEIGHT]

Where [...] means the integer part of the number, CURRENT_POSITION - the index of the first currently visible row, if the numbering is from zero
What do we do with this number :)? It is necessary to draw all visible lines, starting with CURRENT_POSITION. That is, we draw line by line all the lines, starting with CURRENT_POSITION and until we go beyond the bounds of cell visibility.
This method of scrolling corresponds to
line-by-line scrolling , that is, we will not be able to scroll to the middle of the line, because we always draw from a specific line, and not from the middle. This will mean that if the height of the line exceeds the height of the area in which we draw,
we will see only part of the line without the ability to see the rest of the contents ! If you try to scroll in this case, we will immediately get to the next line, and the previous cell will be completely hidden from view. You can check this behavior, for example, in Microsoft Excel, if you do not believe :).
After the user has released the scroll, you can align it, according to the first formula:
SCROLL_TOP = CURRENT_POSITION * ROW_HEIGHT
In fact, determining the current line number can be done in different ways, this is just one of the ways that does not lead to excessive “jerking” of the scroll.
In Microsoft Excel and in OpenOffice.org Calc, exactly the same rendering mechanism is used not only for rows, but also for columns — in this case, rendering is not line by line, but according to a more complex algorithm, I did not go into details
Allowance for beginners
I used these rendering mechanisms myself in several projects, including my file manager, the site of which is now disabled for non-payment :). In any case, if someone wants to implement the above algorithm on their own, here are some tips from practice:
1. The easiest way to draw a grid with virtual scrolling is to make an absolutely positioned <div> that will be displayed on top of any container, the position of which can be easily determined using the offset () method in jQuery
2. The <div> 's can be made 2 - one with the content, the other exclusively with a scroll, so that the browser does not try to scroll the <div> with the content on its own, otherwise it leads to unpleasant effects when redrawing. You can also try using position: fixed, but it works strangely in IE 7
3. The position of the scroll is best not to align, because browsers do not give much control over the scroll
4. The maximum element height in IE 7 is about 1 million pixels, so if you take 30px for the virtual line height, you get a limit of about 30,000 lines. To deal with this, you can reduce the virtual line height with an increase in the number of entries if the browser is IE
5. To scroll the strings while scrolling with the mouse wheel, you can handle the DOMMouseScroll event in Gecko-based browsers and mousewheel in all other browsers.
6. If you make a smarter redrawing than redrawing a fully visible area (i.e., for example, dynamically deleting and adding new lines to scroll a few lines), please tell me about the results :)
Well, if you still implement your grid, look at the documentation for the grid's API, say, in Cocoa - this will help you better understand how to make a well-scalable solution.
I do not want to spread my decisions, everything was written in a hurry and for specific tasks, so it is unlikely for any of you to fit. Thank you for reading to the end :))