Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Table cells that are too tall to fit on one page get truncated; should continue cell contents on next page #147

Closed
TylerRick opened this issue Aug 24, 2010 · 15 comments

Comments

@TylerRick
Copy link

Here's an example showing this issue:

Prawn::Document.generate(filename = File.basename(__FILE__) + ".pdf") do
  line_count = 80
  table([
    ["Shorter cell", "Column 2"],
    [(0...line_count).map{|i| "This is line #{i} of #{line_count}\n"}.join, "Column 2"],
    ["Shorter cell", "Column 2"],
  ])
end

I believe the expected/desired behavior would to have all content displayed, no matter how many page breaks are required to do so.

Also, I don't think we'd want a bottom border on the first page (or a top border on last page), since we want it to be clear that the cell is continued on the next page.

@bradediger
Copy link
Member

This problem also prevents subtables from spanning more than one page.

@igorbozato
Copy link
Contributor

A code example of this problem with subtables:

Prawn::Document.generate("tables.pdf") do
  content = []
  content << ["test", "test"]
  subtable = (1..50).map { |i| ["test", i.to_s]}

  content << [subtable]
  content << ["test", "test"]

  table content
end

@DefV
Copy link
Contributor

DefV commented Dec 2, 2011

Has anyone started to tackle this problem? I'm having the same issue, and need it fixed so I'm willing to take the time to get my hands dirty. Any plan of approach / pointers?

@bradediger
Copy link
Member

It's a bit of a complicated problem. Though this seems to be a common request, we still want to support the current case (where cells are constrained to lie on a single page), and we probably want it to still be the default. Splitting cells across pages can be an opt-in feature.

The abstract Prawn::Table::Cell API includes the assumption that a cell will be drawn on a single page. Table sets up a bounding box representing the cell's content area and calls draw_content on it (see Cell#draw_bounded_content). So that protocol is going to have to change if you want certain cells to span pages. This might not make sense for all cell types (for example, image cells).

I'd start out by defining a method on each subclass of Cell that determines whether it can participate in this new protocol. Image cells wouldn't; text cells would; subtables might (depending on their content). Then, I'd add a method parallel to draw_content to draw as much content as possible on the current page. The semantics of this would be something like "if spannable? returns true, then we can call draw_partial_content regardless of how much room is available on the page; it then returns the remainder of the content that couldn't be drawn".

Then you'll have to modify Prawn::Table#draw to participate in this new protocol, only if a user has requested this option.

Some corner cases you'd have to think about:

  • Rows can contain both spannable and non-spannable cells.
  • What happens if a cell spans three or more pages?
  • Should Prawn assume that spannable cells don't have a bottom border on the first page and a top border on the next? (Probably.) Should it override the cell's border styling to do so?
  • Say there's 3pt available at the bottom of the page, and you're about to draw a spannable text cell. The text won't fit in 3pt of vertical space, so draw_partial_content will draw nothing and return the entire content of the cell. But you probably don't want to draw a 3pt border on the previous page around an empty cell.
  • We use a method, Prawn::Table::Cell.draw_cells(cells), whenever we're putting a group of cells on the page. This renders all of the given cells in the proper drawing order to ensure that backgrounds show up behind borders and content. When refactoring Table#draw, you must ensure that this drawing order is preserved, otherwise weird rendering bugs can crop up.

Good luck if you'd like to tackle this. I'd love to see it in Prawn; I just haven't had the time to work on it yet. Let us know on the mailing list if you try this out and run into issues.

Brad

@royalghost
Copy link

Any update on this feature?

@bradediger
Copy link
Member

No updates yet. I've posted a summary of the issues involved above for anyone who wants to take a crack at starting.

@jsarma
Copy link

jsarma commented Jun 7, 2013

"Though this seems to be a common request, we still want to support the current case (where cells are constrained to lie on a single page), and we probably want it to still be the default. Splitting cells across pages can be an opt-in feature."

I can see how this would be a tricky problem to solve. But I don't understand why truncating the page should be the default. Is there any use case where users would want the data in their PDF truncated? This seems like more of a bug than a feature request.

For anyone else with this problem, I think there's an easy workaround: Just split long rows when you generate your input content.

@jsarma
Copy link

jsarma commented Jun 8, 2013

Hi Brad. Do you think there is any way one could determine before drawing the table how big the bounding box of each cell is?

If so, then a good workaround would be to just split rows that are too long before inputting the data into the table call. I've implemented this sort of solution, but since font characters are all different width, and there are linebreaks, etc..., the number of characters is the box is not a good estimate of whether it will overflow. So I end up splitting the rows too early.

Thank you for your feedback on this issue.

@fluxsaas
Copy link

@jsarma do you found a workaround yet for calculating height to split cells? i'm going crazy about this :)

@jsarma
Copy link

jsarma commented Aug 19, 2013

@fluxsaas Unfortunately, I couldn't find any way to use prawn to estimate the height of the cell for splitting.

Instead, I did some experimenting. In my particular case, 1700 characters turned out to be a pretty safe place to split. But this assumes line breaks aren't used heavily. If you split after too few chars, you occasionally end up with cases where both cells are on the same page, but are split. This doesn't look very professional, but it's not a disaster. If you split after too many characters, you end up with the overflow bug which is really bad. Below is the code I used to implement this total hack. It was hastily thrown together, so don't expect too much from it. It would probably function a bit better if recognized line breaks and counted them as 50 characters or something.

    def self.find_prev_space(s, index) #find last space before index and return it
        for i in 0..200
            return index - i if (s[index-i].chr==' ')
            break if (index-i<=0)
        end
        return index #could not find space, so just break anywhere
    end

    #if second column has more than max_size characters, split into multiple rows.
    #Repeat first column, and add cont... to it
    def self.split_big_row(array, max_size) 
        return [array] if (array[1].size <= max_size)
        src = array.dup
        dst = []
        count = 0
        while (src[1].size > max_size)
            i = self.find_prev_space(src[1], max_size)
            if (count==0)
                label = src[0]
            else
                label = "#{src[0]} (cont...)" 
            end
            dst << [label, src[1][0..i]] 
            src[1] = src[1][i+1..-1]
            count+=1
        end
        if (count==0)
            label = src[0]
        else
            label = "#{src[0]} (cont...)" 
        end
        dst << [label, src[1]]
        return dst
    end

@practicingruby
Copy link
Member

It's possible to get the height of a cell now before rendering a table, but there should be some defined behavior for when a row exceeds the size of the page. Re-opening for further investigation / research, although it will be a very long time before I can look into this problem myself.

@practicingruby
Copy link
Member

I am closing all issues for Prawn::Table, because it is being extracted into its own gem with its own repository (https://github.com/prawnpdf/prawn-table).

As I close tickets, I'm marking them with a "table" tag, so that @hbrandl can easily find them and optionally move them over to the prawn-table issue tracker. Anything that has the table tag can be assumed to have been unresolved at the time I closed it.

@rusllonrails
Copy link

Still getting this error with Rails '4.2.7.1', prawn (1.3.0) and prawn-table (0.2.1).
Any success on fixing it?

@kashifnaseer
Copy link

any update on this ?

@melcher
Copy link

melcher commented Jan 14, 2020

Successor to this ticket is prawnpdf/prawn-table#41

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

No branches or pull requests