Skip to content
This repository has been archived by the owner on Nov 13, 2021. It is now read-only.

Question: How to generate a table with cell word wrap? #129

Open
vegh1010 opened this issue Aug 23, 2017 · 20 comments
Open

Question: How to generate a table with cell word wrap? #129

vegh1010 opened this issue Aug 23, 2017 · 20 comments

Comments

@vegh1010
Copy link

Hi, I'm trying to create a table where each cell can be word wrap. How can I do that? I tried using MultiCell but it goes to the next line for each cell and CellFormat does not seem to support MultiCell.

Something like this.

Name Description
John John has a cat.
John has a dog.
Jane Jane has a cat.
@jung-kurt
Copy link
Owner

jung-kurt commented Aug 23, 2017

This can be done with SplitLines(). The limitation is that only one font and attribute per cell are supported.

For each row, you will need to loop through each column twice. The first time, call SplitLines() to calculate each cell's height. The second time, use the maximum cell height from the previous loop as the
row height. Apply padding as needed to vertically center the text of cells that have a height less than the row height.

@vegh1010
Copy link
Author

I've tried your suggestion and manage to get the max height but i couldn't word wrap using CellFormat like MultiCell

@jung-kurt
Copy link
Owner

The example accompanying the documentation for SplitLines() shows how each of the substrings (of type []byte) returned by SplitLines() has to be passed to CellFormat() individually. It's really SplitLines() that determines where the wrap breaks are; after that the substrings are manually rendered.

I'll try to find some time tomorrow to augment the table example to demonstrate this.

@vegh1010
Copy link
Author

Cool thanks

@jung-kurt
Copy link
Owner

Demonstrated in 4491d0f

@vegh1010
Copy link
Author

Awesome. I'll have a go on your example. Thanks

@vegh1010
Copy link
Author

Your example works. Thanks

@andreynering
Copy link

Hi @jung-kurt, thank you for this awesome lib!

I think it would be awesome if the lib had that abstracted in a function or struct. It's a pretty common use case.

Thanks again! 😃

@jung-kurt
Copy link
Owner

Thanks, @andreynering. I agree, an abstraction of word-wrapped table cells make sense. If it is done at the table level, then it could facilitate alternate row shading and page breaks with header rows. I'll reflect on various approaches and put something together in the days ahead.

@jacobfederer
Copy link

I tried the approach it works fine with only one page. If the table is longer than one page and auto break is enabled the layout gets messed up. I'm working on a solution.

@jung-kurt
Copy link
Owner

Thanks, @jacobfederer -- I look forward to seeing what you come up with.

@dineshkumars98
Copy link

hi @jung-kurt
Can merge the cell's in the table? How would you do?

@jung-kurt
Copy link
Owner

Can merge the cell's in the table? How would you do?

Tables in gofpdf are built up of individual cells. You can merge them manually with something like this:

package main

import (
  "fmt"

  "github.com/jung-kurt/gofpdf/v2"
)

func main() {
  const (
    colCount = 4
    rowCount = 3
    margin   = 32.0
    fontHt   = 14.0 // point
  )
  pdf := gofpdf.New("L", "mm", "A4", "")
  cellWd := (297 - margin - margin) / colCount
  cellHt := pdf.PointToUnitConvert(fontHt) + 10.0
  pdf.SetFont("Arial", "", fontHt)
  pdf.AddPage()
  pdf.SetXY(margin, margin)
  for rowJ := 0; rowJ < rowCount; rowJ++ {
    for colJ := 0; colJ < colCount; colJ++ {
      pdf.SetXY(margin+float64(colJ)*cellWd, margin+float64(rowJ)*cellHt)
      if rowJ == 1 && (colJ == 1 || colJ == 2) {
        if colJ == 1 { // Merged cells
          pdf.CellFormat(cellWd*2.0, cellHt, fmt.Sprintf("Merged cells"), "1", 0, "CM", false, 0, "")
        }
      } else {
        pdf.CellFormat(cellWd, cellHt, fmt.Sprintf("Row %d, Col %d", rowJ, colJ), "1", 0, "CM", false, 0, "")
      }
    }
  }
  err := pdf.OutputFileAndClose("colmerge.pdf")
  if err != nil {
    fmt.Printf("%s\n", err)
  }
}

@dineshkumars98
Copy link

dineshkumars98 commented Mar 27, 2019 via email

@dineshkumars98
Copy link

dineshkumars98 commented Mar 27, 2019 via email

@dineshkumars98
Copy link

dineshkumars98 commented Mar 27, 2019 via email

@jung-kurt
Copy link
Owner

Thank you... I got it!

Great!

@dineshkumars98
Copy link

hi @jung-kurt
One more question..!
If the table exists the 1-page alignment is missed... This is a bug or else need to configure anything?
like:
Screenshot from 2019-04-01 15-47-20

@sk0g
Copy link

sk0g commented Jul 2, 2019

Sorry to bump this issue, but I ran into this too! The above was a complete dealbreaker, so I actually solved it a rather different way - by creating a writeRow() function. Do you think, if I flesh it out and fix it a little, this might be merged into the library?

type rowContents struct {
	Contents            string
	ColumnWidthFraction float64
}
...
    usablePageWidth = pageWidth - 2*margin
...

func writeRow(pdf *gofpdf.Fpdf, lineHeight int, contents ...rowContents) {
	var maxHeight float64

	for _, cellContent := range contents {
		columnWidth := (cellContent.ColumnWidthFraction * usablePageWidth) - 2 // -2 for table margins

		splitStrings := pdf.SplitText(cellContent.Contents, columnWidth)
		if newHeight := float64(len(splitStrings)) * float64(lineHeight); newHeight > maxHeight {
			maxHeight = newHeight
		}
	}

	for _, cellContent := range contents {
		pdf.CellFormat(cellContent.ColumnWidthFraction*usablePageWidth, maxHeight,
			cellContent.Contents, "1", 0, "L", false, 0, "")
	}
	pdf.Ln(-1)
}

@jung-kurt
Copy link
Owner

jung-kurt commented Jul 2, 2019

Do you think, if I flesh it out and fix it a little, this might be merged into the library?

Definitely! Thanks, @sk0g.

Of course, an example demonstrating it is always helpful.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

6 participants