feat: support table render

This commit is contained in:
vicanso 2022-06-23 23:29:13 +08:00
parent 8c5647f65f
commit 2fb0ebcbf7
6 changed files with 476 additions and 23 deletions

201
table.go
View file

@ -22,6 +22,14 @@
package charts
import (
"errors"
"github.com/golang/freetype/truetype"
"github.com/wcharczuk/go-chart/v2"
"github.com/wcharczuk/go-chart/v2/drawing"
)
type tableChart struct {
p *Painter
opt *TableChartOption
@ -38,16 +46,205 @@ func NewTableChart(p *Painter, opt TableChartOption) *tableChart {
}
type TableChartOption struct {
// The output type
Type string
// The width of table
Width int
// The height of table
Height int
// The theme
Theme ColorPalette
// The padding of table cell
Padding Box
// The header data of table
HeaderData []string
Header []string
// The data of table
Data [][]string
// The span of table column
Spans []int
// The font size of table
FontSize float64
Font *truetype.Font
// The font color of table
FontColor Color
// The background color of header
HeaderBackgroundColor Color
// The header font color
HeaderFontColor Color
// The background color of row
RowBackgroundColors []Color
// The background color
BackgroundColor Color
}
var defaultTableHeaderColor = Color{
R: 34,
G: 34,
B: 34,
A: 255,
}
var defaultTableRowColors = []Color{
drawing.ColorWhite,
{
R: 242,
G: 242,
B: 242,
A: 255,
},
}
var defaultTablePadding = Box{
Left: 10,
Top: 10,
Right: 10,
Bottom: 10,
}
type renderInfo struct {
Width int
Height int
HeaderHeight int
RowHeights []int
}
func (c *tableChart) render() (*renderInfo, error) {
info := renderInfo{
RowHeights: make([]int, 0),
}
p := c.p
opt := c.opt
if len(opt.Header) == 0 {
return nil, errors.New("header can not be nil")
}
theme := opt.Theme
if theme == nil {
theme = p.theme
}
fontSize := opt.FontSize
if fontSize == 0 {
fontSize = 12
}
fontColor := opt.FontColor
if fontColor.IsZero() {
fontColor = theme.GetTextColor()
}
font := opt.Font
if font == nil {
font = theme.GetFont()
}
headerFontColor := opt.HeaderFontColor
if opt.HeaderFontColor.IsZero() {
headerFontColor = drawing.ColorWhite
}
spans := opt.Spans
if len(spans) != 0 && len(spans) != len(opt.Header) {
newSpans := make([]int, len(opt.Header))
for index := range opt.Header {
if len(spans) < index {
newSpans[index] = 1
} else {
newSpans[index] = spans[index]
}
}
spans = newSpans
}
values := autoDivideSpans(p.Width(), len(opt.Header)+1, spans)
height := 0
textStyle := Style{
FontSize: fontSize,
FontColor: headerFontColor,
FillColor: headerFontColor,
Font: font,
}
p.SetStyle(textStyle)
headerHeight := 0
padding := opt.Padding
if padding.IsZero() {
padding = defaultTablePadding
}
renderTableCells := func(textList []string, currentHeight int, cellPadding Box) int {
cellMaxHeight := 0
paddingHeight := cellPadding.Top + cellPadding.Bottom
paddingWidth := cellPadding.Left + cellPadding.Right
for index, text := range textList {
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
}
}
return cellMaxHeight
}
headerHeight = renderTableCells(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)
info.RowHeights = append(info.RowHeights, cellHeight)
height += cellHeight
}
info.Width = p.Width()
info.Height = height
return &info, nil
}
func (c *tableChart) Render() (Box, error) {
return BoxZero, nil
p := c.p
opt := c.opt
if !opt.BackgroundColor.IsZero() {
p.SetBackground(p.Width(), p.Height(), opt.BackgroundColor)
}
headerBGColor := opt.HeaderBackgroundColor
if headerBGColor.IsZero() {
headerBGColor = defaultTableHeaderColor
}
r := p.render
newRender, err := chart.SVG(p.Width(), 100)
if err != nil {
return BoxZero, err
}
p.render = newRender
info, err := c.render()
if err != nil {
return BoxZero, err
}
p.render = r
// 如果设置表头背景色
p.SetBackground(info.Width, info.HeaderHeight, headerBGColor, true)
currentHeight := info.HeaderHeight
rowColors := opt.RowBackgroundColors
if len(rowColors) == 0 {
rowColors = defaultTableRowColors
}
for index, h := range info.RowHeights {
color := rowColors[index%len(rowColors)]
child := p.Child(PainterPaddingOption(Box{
Top: currentHeight,
}))
child.SetBackground(p.Width(), h, color, true)
currentHeight += h
}
_, err = c.render()
if err != nil {
return BoxZero, err
}
return Box{
Right: info.Width,
Bottom: info.Height,
}, nil
}