diff --git a/examples/table/main.go b/examples/table/main.go index 4207b01..f332851 100644 --- a/examples/table/main.go +++ b/examples/table/main.go @@ -4,18 +4,20 @@ import ( "io/ioutil" "os" "path/filepath" + "strconv" "github.com/vicanso/go-charts/v2" + "github.com/wcharczuk/go-chart/v2/drawing" ) -func writeFile(buf []byte) error { +func writeFile(buf []byte, filename string) error { tmpPath := "./tmp" err := os.MkdirAll(tmpPath, 0700) if err != nil { return err } - file := filepath.Join(tmpPath, "table.png") + file := filepath.Join(tmpPath, filename) err = ioutil.WriteFile(file, buf, 0600) if err != nil { return err @@ -77,7 +79,54 @@ func main() { if err != nil { panic(err) } - err = writeFile(buf) + err = writeFile(buf, "table.png") + if err != nil { + panic(err) + } + + p, err = charts.TableOptionRender(charts.TableChartOption{ + Header: header, + Data: data, + CellTextStyle: func(tc charts.TableCell) *charts.Style { + row := tc.Row + column := tc.Column + style := tc.Style + if column == 1 && row != 0 { + age, _ := strconv.Atoi(tc.Text) + if age < 40 { + style.FontColor = drawing.ColorGreen + } else { + style.FontColor = drawing.ColorRed + } + return &style + } + return nil + }, + CellStyle: func(tc charts.TableCell) *charts.Style { + row := tc.Row + column := tc.Column + if row == 2 && column == 1 { + return &charts.Style{ + FillColor: drawing.ColorBlue, + } + } + if row == 3 && column == 4 { + return &charts.Style{ + FillColor: drawing.ColorRed.WithAlpha(100), + } + } + return nil + }, + }) + if err != nil { + panic(err) + } + + buf, err = p.Bytes() + if err != nil { + panic(err) + } + err = writeFile(buf, "table-color.png") if err != nil { panic(err) } diff --git a/table.go b/table.go index 0e72be5..d1af5f9 100644 --- a/table.go +++ b/table.go @@ -46,6 +46,17 @@ func NewTableChart(p *Painter, opt TableChartOption) *tableChart { } } +type TableCell struct { + // Text the text of table cell + Text string + // Style the current style of table cell + Style Style + // Row the row index of table cell + Row int + // Column the column index of table cell + Column int +} + type TableChartOption struct { // The output type Type string @@ -76,6 +87,10 @@ type TableChartOption struct { RowBackgroundColors []Color // The background color BackgroundColor Color + // CellTextStyle customize text style of table cell + CellTextStyle func(TableCell) *Style + // CellStyle customize drawing style of table cell + CellStyle func(TableCell) *Style } type TableSetting struct { @@ -180,6 +195,7 @@ type renderInfo struct { Height int HeaderHeight int RowHeights []int + ColumnWidths []int } func (t *tableChart) render() (*renderInfo, error) { @@ -227,6 +243,15 @@ func (t *tableChart) render() (*renderInfo, error) { sum := sumInt(spans) values := autoDivideSpans(p.Width(), sum, spans) + columnWidths := make([]int, 0) + for index, v := range values { + if index == len(values)-1 { + break + } + columnWidths = append(columnWidths, values[index+1]-v) + } + info.ColumnWidths = columnWidths + height := 0 textStyle := Style{ FontSize: fontSize, @@ -234,25 +259,48 @@ func (t *tableChart) render() (*renderInfo, error) { FillColor: headerFontColor, Font: font, } - p.SetStyle(textStyle) headerHeight := 0 padding := opt.Padding if padding.IsZero() { padding = tableDefaultSetting.Padding } + getCellTextStyle := opt.CellTextStyle + if getCellTextStyle == nil { + getCellTextStyle = func(_ TableCell) *Style { + return nil + } + } - renderTableCells := func(textList []string, currentHeight int, cellPadding Box) int { + // 表格单元的处理 + renderTableCells := func( + currentStyle Style, + rowIndex int, + textList []string, + currentHeight int, + cellPadding Box, + ) int { cellMaxHeight := 0 paddingHeight := cellPadding.Top + cellPadding.Bottom paddingWidth := cellPadding.Left + cellPadding.Right for index, text := range textList { + cellStyle := getCellTextStyle(TableCell{ + Text: text, + Row: rowIndex, + Column: index, + Style: currentStyle, + }) + if cellStyle == nil { + cellStyle = ¤tStyle + } + p.SetStyle(*cellStyle) x := values[index] y := currentHeight + cellPadding.Top width := values[index+1] - x x += cellPadding.Left width -= paddingWidth box := p.TextFit(text, x, y+int(fontSize), width) + // 计算最高的高度 if box.Height()+paddingHeight > cellMaxHeight { cellMaxHeight = box.Height() + paddingHeight } @@ -260,15 +308,16 @@ func (t *tableChart) render() (*renderInfo, error) { return cellMaxHeight } - headerHeight = renderTableCells(opt.Header, height, padding) + // 表头的处理 + headerHeight = renderTableCells(textStyle, 0, opt.Header, height, padding) height += headerHeight info.HeaderHeight = headerHeight + // 表格内容的处理 textStyle.FontColor = fontColor textStyle.FillColor = fontColor - p.SetStyle(textStyle) - for _, textList := range opt.Data { - cellHeight := renderTableCells(textList, height, padding) + for index, textList := range opt.Data { + cellHeight := renderTableCells(textStyle, index+1, textList, height, padding) info.RowHeights = append(info.RowHeights, cellHeight) height += cellHeight } @@ -304,6 +353,41 @@ func (t *tableChart) renderWithInfo(info *renderInfo) (Box, error) { child.SetBackground(p.Width(), h, color, true) currentHeight += h } + // 根据是否有设置表格样式调整背景色 + getCellStyle := opt.CellStyle + if getCellStyle != nil { + arr := [][]string{ + opt.Header, + } + arr = append(arr, opt.Data...) + top := 0 + heights := []int{ + info.HeaderHeight, + } + heights = append(heights, info.RowHeights...) + // 循环所有表格单元,生成背景色 + for i, textList := range arr { + left := 0 + for j, v := range textList { + style := getCellStyle(TableCell{ + Text: v, + Row: i, + Column: j, + }) + if style != nil && !style.FillColor.IsZero() { + child := p.Child(PainterPaddingOption(Box{ + Top: top, + Left: left, + })) + w := info.ColumnWidths[j] + h := heights[i] + child.SetBackground(w, h, style.FillColor, true) + } + left += info.ColumnWidths[j] + } + top += heights[i] + } + } _, err := t.render() if err != nil { return BoxZero, err