github.com/benoitkugler/goacve@v0.0.0-20201217100549-151ce6e55dc8/server/core/utils/pdf/pdftable.go (about)

     1  package pdf
     2  
     3  import (
     4  	"math"
     5  
     6  	rd "github.com/benoitkugler/goACVE/server/core/rawdata"
     7  )
     8  
     9  const paddingCells = 2
    10  
    11  type ColumnMetas struct {
    12  	Field rd.Field
    13  	Label string
    14  	Width float64
    15  	Align string
    16  }
    17  
    18  func (pdf CustomPdf) splitLine(w float64, fullTxt string) []string {
    19  	bytes := pdf.SplitLines([]byte(pdf.Tr(fullTxt)), w)
    20  	out := make([]string, len(bytes))
    21  	for index, b := range bytes {
    22  		out[index] = string(b)
    23  	}
    24  	return out
    25  }
    26  
    27  func (pdf CustomPdf) drawCell(w, lh, maxHeight, padding float64, lines []string, alignStr string, fill bool) {
    28  	x, y := pdf.GetXY()
    29  	styleStr := "D"
    30  	if fill {
    31  		styleStr = "FD"
    32  	}
    33  	cellsHeight := lh * float64(len(lines))
    34  	ySpacing := (maxHeight - cellsHeight - 2*padding) / 2
    35  	pdf.Rect(x, y, w, maxHeight, styleStr)
    36  	pdf.SetXY(x+padding, y+ySpacing+padding)
    37  	for _, line := range lines {
    38  		pdf.Fpdf.CellFormat(w-2*padding, lh, line, "", 2, alignStr, false, 0, "")
    39  	}
    40  	pdf.SetXY(x+w, y)
    41  }
    42  
    43  func (pdf CustomPdf) setBold(field rd.Field, data rd.Item, force bool) {
    44  	style := ""
    45  	if force || data.Bolds[field] {
    46  		style = "B"
    47  	}
    48  	pdf.SetFontStyle(style)
    49  }
    50  
    51  func (pdf CustomPdf) setupLine(fields []ColumnMetas, data rd.Item, lH,
    52  	padding float64, forceBold bool) ([][]string, float64) {
    53  	maxLines := 0
    54  	splittedLines := make([][]string, len(fields))
    55  	for index, col := range fields { // calcul du nombre de ligne nécéssaires
    56  		pdf.setBold(col.Field, data, forceBold)
    57  		neededLines := pdf.splitLine(col.Width-2*padding, data.Fields.Data(col.Field).String())
    58  		if len(neededLines) > maxLines {
    59  			maxLines = len(neededLines)
    60  		}
    61  		splittedLines[index] = neededLines
    62  	}
    63  	rowHeight := float64(maxLines)*lH + 2*padding
    64  	if pdf.GetY()+rowHeight > pdf.areaBottomLimit() {
    65  		pdf.AddPage()
    66  	}
    67  	return splittedLines, rowHeight
    68  }
    69  
    70  func (pdf CustomPdf) drawRow(fields []ColumnMetas, data rd.Item, lH,
    71  	padding float64, fill, forceBold, forceCenter bool) {
    72  	splittedLines, rowHeight := pdf.setupLine(fields, data, lH, padding, forceBold)
    73  	x, y := pdf.GetXY()
    74  	for index, col := range fields {
    75  		pdf.setBold(col.Field, data, forceBold)
    76  		alignStr := col.Align
    77  		if forceCenter { // defaut au centre
    78  			alignStr = "C"
    79  		}
    80  		pdf.drawCell(col.Width, lH, rowHeight, padding, splittedLines[index], alignStr, fill)
    81  	}
    82  	pdf.SetXY(x, y+rowHeight)
    83  }
    84  
    85  // setup fields wdith
    86  func (pdf CustomPdf) drawHeaderTable(fields []ColumnMetas) []ColumnMetas {
    87  	pdf.SetFontSize(11) // influe lineHeight
    88  	aW := pdf.AreaWidth()
    89  	fieldsAbsolute := make([]ColumnMetas, len(fields))
    90  	for index, col := range fields {
    91  		fieldsAbsolute[index] = col                  // copy
    92  		fieldsAbsolute[index].Width = aW * col.Width // relative to absolute
    93  	}
    94  	headers := rd.Item{Fields: make(rd.F)}
    95  	for _, col := range fields {
    96  		headers.Fields[col.Field] = rd.String(col.Label)
    97  	}
    98  	lH, padding := pdf.LineHeight(), 0.5
    99  	pdf.drawRow(fieldsAbsolute, headers, lH, padding, true, true, true) // background + bold
   100  	return fieldsAbsolute
   101  }
   102  
   103  // fields Width est relative (0,1)
   104  func (pdf CustomPdf) drawTable(fields []ColumnMetas, data []rd.Item) {
   105  	pdf.SetFillColor(primaryColor)
   106  	fields = pdf.drawHeaderTable(fields) // absolute width
   107  	pdf.SetFont("Arial", "", 9)
   108  	lH, padding := pdf.LineHeight(), 1.
   109  	for _, item := range data {
   110  		pdf.drawRow(fields, item, lH, padding, false, false, false)
   111  	}
   112  }
   113  
   114  // support html syntax, but must be left aligned
   115  func (pdf CustomPdf) drawMergedColumns(marginLeft, rightWidth, lH float64, left, right string, fill bool) {
   116  	h := pdf.HTMLBasicNew()
   117  	mL, _, mR, _ := pdf.GetMargins()
   118  	aW := pdf.AreaWidth()
   119  	leftWidth := aW - rightWidth - marginLeft
   120  	y := pdf.GetY()
   121  	oldR, oldG, oldB := pdf.GetTextColor()
   122  	pdf.Fpdf.SetTextColor(255, 255, 255)
   123  	pdf.SetLeftMargin(mL + marginLeft + paddingCells) // besoin de connaitre la hauteur avant
   124  	pdf.SetRightMargin(mR + (aW - marginLeft - leftWidth) + paddingCells)
   125  	pdf.SetY(0)
   126  	h.Write(lH, pdf.Tr(left))
   127  	neededHeight := pdf.GetY() + lH
   128  	pdf.SetRightMargin(mR + paddingCells)
   129  	pdf.SetLeftMargin(mL + leftWidth + marginLeft + paddingCells)
   130  	h.Write(lH, pdf.Tr(right))
   131  	neededHeight = math.Max(neededHeight, pdf.GetY()+lH) + 2*paddingCells
   132  	if y+neededHeight > pdf.areaBottomLimit() {
   133  		pdf.AddPage()
   134  		y = pdf.GetY()
   135  		pdf.Line(mL, y, mL+aW, y)
   136  	}
   137  	if fill {
   138  		pdf.Rect(mL, y, aW, neededHeight, "F")
   139  	}
   140  	pdf.Line(mL, y+neededHeight, mL+aW, y+neededHeight)
   141  	pdf.Line(mL, y, mL, y+neededHeight)
   142  	pdf.Line(mL+aW, y, mL+aW, y+neededHeight)
   143  	pdf.Fpdf.SetTextColor(oldR, oldG, oldB)
   144  	pdf.SetXY(mL+paddingCells+marginLeft, y+paddingCells)
   145  	pdf.SetLeftMargin(mL + marginLeft + paddingCells)
   146  	pdf.SetRightMargin(mR + (aW - marginLeft - leftWidth) + paddingCells)
   147  	h.Write(lH, pdf.Tr(left))
   148  	pdf.SetXY(mL+leftWidth+paddingCells+marginLeft, y+paddingCells)
   149  	pdf.SetRightMargin(mR + paddingCells)
   150  	pdf.SetLeftMargin(mL + leftWidth + marginLeft + paddingCells)
   151  	h.Write(lH, pdf.Tr(right))
   152  	pdf.SetXY(mL, y+neededHeight)
   153  	pdf.SetRightMargin(mR)
   154  	pdf.SetLeftMargin(mL)
   155  }