tl;dr: How do you calculate the limits for a pagination widget like “« 4 5 6 7 »”? Number the pages starting from 0. Then the first page to display and one page after the last page to display (4 and 8 in the example above) are given by
where
- is the currently displayed page.
- is the number of page numbers to display in the widget.
- is the total number of pages.
- is the ceiling function.
- is the floor function.
- is the maximum of and .
- is the minimum of and .
That’s the short version. Now how do we derive that?
First, a warning. Don’t use page numbers as primitive objects unless you’ll only have one item per page. If you’re going to list multiple items per page, tracking page numbers instead of the first item to display on a page will make your code unbelievably complicated when you have to change the number of items displayed per page, or when you want to show a list of items beginning with a specific index, rather than a particular page.
So label your items from 0 to , and let be the index of the first item to be displayed on the current page. If each page is to show at most entries (“at most” because there may not be enough items to fill the last page to exactly ), then , and the th page will start at . There will be pages in all.
Now let’s move on to deriving the expressions for the actual pagination range. What, precisely, is the problem? For a particular integer between and , we want to find a range of numbers of a fixed size which also fall in and are as centered as possible around . As usual, we’ll describe the range as a half open interval by the first page in the range and one after the last page in the range . For example, in “« 4 5 6 7 »”, and . Let the size of the desired range be .
, but we need a second constraint to center as much as possible in this range. If is odd, then we want the same number of entries on both sides of the current page number. For example, if we are on page 3 and , We should display “« 1 2 3 4 5 »”. If is even, we must make a choice: do we want to display more page numbers after the current one, or more before? I chose to show more numbers after on the theory that a user is more interested in stuff he has not yet reached. This constraint translates to
So, centering the current page in the control, should be one less than since is the first element and is one after the last element. So if isn odd, . If is odd, since I chose to show more following pages, it is . We can combine all these expressions to get
which we’ll solve for and . We’ll be using three properties of the floor and ceiling functions in the calculations below, which I’ll summarize here:
We calculate thus:
{ solve first equation for and second equation for }
{ substitute for in first equation }
{ group and simplify first equation }
{ }
{ substitute for in second equation }
{ }
This works in the middle of the range. At the edges, we have to calculate a different window. The first page is 0 and can never be less. The last page and can never be more. At the left end, and . At the right end, and . We augment the expressions for and to handle these cases (note that the order of operations is important):