forked from signintech/gopdf
-
Notifications
You must be signed in to change notification settings - Fork 0
/
table.go
260 lines (227 loc) · 7.15 KB
/
table.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
package gopdf
// Represents an RGB color with red, green, and blue components
type RGBColor struct {
R uint8 // Red component (0-255)
G uint8 // Green component (0-255)
B uint8 // Blue component (0-255)
}
// Defines the border style for a cell or table
type BorderStyle struct {
Top bool // Whether to draw the top border
Left bool // Whether to draw the left border
Right bool // Whether to draw the right border
Bottom bool // Whether to draw the bottom border
Width float64 // Width of the border line
RGBColor RGBColor // Color of the border
}
// Defines the style for a cell, including border, fill, text, and font properties
type CellStyle struct {
BorderStyle BorderStyle // Border style for the cell
FillColor RGBColor // Background color of the cell
TextColor RGBColor // Color of the text in the cell
Font string // Font name for the cell text
FontSize float64 // Font size for the cell text
}
// Represents the layout of a table
type tableLayout struct {
pdf *GoPdf // Reference to the GoPdf instance
startX float64 // Starting X coordinate of the table
startY float64 // Starting Y coordinate of the table
rowHeight float64 // Height of each row in the table
columns []column // Slice of column definitions
rows [][]string // Slice of rows, each containing cell contents
maxRows int // Maximum number of rows in the table
padding float64 // Padding inside each cell
cellOption CellOption // Options for cell content rendering
tableStyle CellStyle // Style for the entire table
headerStyle CellStyle // Style for the header row
cellStyle CellStyle // Style for regular cells
}
// Represents a column in the table
type column struct {
header string // Header text for the column
width float64 // Width of the column
align string // Alignment of content within the column
}
// Creates a new table layout with the given parameters
func (gp *GoPdf) NewTableLayout(startX, startY, rowHeight float64, maxRows int) *tableLayout {
return &tableLayout{
pdf: gp,
startX: startX,
startY: startY,
rowHeight: rowHeight,
maxRows: maxRows,
padding: 2.0,
cellOption: CellOption{
BreakOption: &BreakOption{
Mode: BreakModeIndicatorSensitive,
BreakIndicator: ' ',
},
},
tableStyle: CellStyle{
BorderStyle: BorderStyle{
Top: true, Left: true, Right: true, Bottom: true,
Width: 0.5,
RGBColor: RGBColor{R: 0, G: 0, B: 0},
},
},
headerStyle: CellStyle{
BorderStyle: BorderStyle{
Top: true, Left: true, Right: true, Bottom: true,
Width: 0.5,
RGBColor: RGBColor{R: 0, G: 0, B: 0},
},
FillColor: RGBColor{R: 240, G: 240, B: 240},
TextColor: RGBColor{R: 0, G: 0, B: 0},
},
cellStyle: CellStyle{
BorderStyle: BorderStyle{
Top: true, Left: true, Right: true, Bottom: true,
Width: 0.5,
RGBColor: RGBColor{R: 0, G: 0, B: 0},
},
TextColor: RGBColor{R: 0, G: 0, B: 0},
},
}
}
// Adds a column to the table with the specified header, width, and alignment
func (t *tableLayout) AddColumn(header string, width float64, align string) {
t.columns = append(t.columns, column{header, width, align})
}
// Adds a row of data to the table
func (t *tableLayout) AddRow(row []string) {
t.rows = append(t.rows, row)
}
// Sets the style for the entire table
func (t *tableLayout) SetTableStyle(style CellStyle) {
t.tableStyle = style
}
// Sets the style for the header row
func (t *tableLayout) SetHeaderStyle(style CellStyle) {
t.headerStyle = style
}
// Sets the style for regular cells
func (t *tableLayout) SetCellStyle(style CellStyle) {
t.cellStyle = style
}
// DrawTable the entire table on the PDF
func (t *tableLayout) DrawTable() error {
x := t.startX
y := t.startY
// Draw the header row
for _, col := range t.columns {
if err := t.drawCell(x, y, col.width, t.rowHeight, col.header, "center", true); err != nil {
return err
}
x += col.width
}
y += t.rowHeight
// Draw the data rows
for _, row := range t.rows {
x = t.startX
for i, cell := range row {
if err := t.drawCell(x, y, t.columns[i].width, t.rowHeight, cell, t.columns[i].align, false); err != nil {
return err
}
x += t.columns[i].width
}
y += t.rowHeight
}
// Fill any remaining rows with empty cells
for i := len(t.rows); i < t.maxRows; i++ {
x = t.startX
for _, col := range t.columns {
if err := t.drawCell(x, y, col.width, t.rowHeight, "", col.align, false); err != nil {
return err
}
x += col.width
}
y += t.rowHeight
}
// Draw the outer border of the table and header
if err := t.drawTableAndHeaderBorder(); err != nil {
return err
}
return nil
}
// Draws the outer border of the table and header
func (t *tableLayout) drawTableAndHeaderBorder() error {
x1 := t.startX
y1 := t.startY
x2 := t.startX
y2 := t.startY + float64(t.maxRows+1)*t.rowHeight
for _, col := range t.columns {
x2 += col.width
}
// Draw borders of the table
err := t.drawBorder(x1, y1, x2, y2, t.tableStyle.BorderStyle)
if err != nil {
return err
}
// Draw borders of the header
return t.drawBorder(x1, y1, x2, y1+t.rowHeight, t.headerStyle.BorderStyle)
}
// Draws a single cell of the table
func (t *tableLayout) drawCell(x, y, width, height float64, content, align string, isHeader bool) error {
style := t.cellStyle
if isHeader {
style = t.headerStyle
}
// Fill the cell background if a fill color is specified
if style.FillColor != (RGBColor{}) {
t.pdf.SetFillColor(style.FillColor.R, style.FillColor.G, style.FillColor.B)
t.pdf.RectFromUpperLeftWithStyle(x, y, width, height, "F")
}
if !isHeader {
// Draw the cell border
if err := t.drawBorder(x, y, x+width, y+height, style.BorderStyle); err != nil {
return err
}
}
// Calculate the text area within the cell
textX := x + t.padding
textY := y + t.padding
textWidth := width - (2 * t.padding)
textHeight := height - (2 * t.padding)
t.pdf.SetXY(textX, textY)
// Set the text alignment
var textOption = t.cellOption
if align == "right" {
textOption.Align = Right | Middle
} else if align == "center" {
textOption.Align = Center | Middle
} else {
textOption.Align = Left | Middle
}
// Set the text color and font
t.pdf.SetTextColor(style.TextColor.R, style.TextColor.G, style.TextColor.B)
if style.Font != "" {
t.pdf.SetFont(style.Font, "", style.FontSize)
}
// Draw the cell content
err := t.pdf.MultiCellWithOption(&Rect{W: textWidth, H: textHeight}, content, textOption)
if err != nil && err.Error() == "empty string" {
err = nil
}
return err
}
// Draws a border around a rectangular area
func (t *tableLayout) drawBorder(x1, y1, x2, y2 float64, borderStyle BorderStyle) error {
t.pdf.SetLineWidth(borderStyle.Width)
t.pdf.SetStrokeColor(borderStyle.RGBColor.R, borderStyle.RGBColor.G, borderStyle.RGBColor.B)
half := borderStyle.Width / 2
// Draw each side of the border if specified
if borderStyle.Top {
t.pdf.Line(x1-half, y1, x2+half, y1)
}
if borderStyle.Bottom {
t.pdf.Line(x1-half, y2, x2+half, y2)
}
if borderStyle.Left {
t.pdf.Line(x1, y1-half, x1, y2+half)
}
if borderStyle.Right {
t.pdf.Line(x2, y1-half, x2, y2+half)
}
return nil
}