feat: support customize table cell style
This commit is contained in:
parent
0eecb6c5b7
commit
d53fa1a329
2 changed files with 142 additions and 9 deletions
|
|
@ -4,18 +4,20 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"github.com/vicanso/go-charts/v2"
|
"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"
|
tmpPath := "./tmp"
|
||||||
err := os.MkdirAll(tmpPath, 0700)
|
err := os.MkdirAll(tmpPath, 0700)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
file := filepath.Join(tmpPath, "table.png")
|
file := filepath.Join(tmpPath, filename)
|
||||||
err = ioutil.WriteFile(file, buf, 0600)
|
err = ioutil.WriteFile(file, buf, 0600)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -77,7 +79,54 @@ func main() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
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 {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
96
table.go
96
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 {
|
type TableChartOption struct {
|
||||||
// The output type
|
// The output type
|
||||||
Type string
|
Type string
|
||||||
|
|
@ -76,6 +87,10 @@ type TableChartOption struct {
|
||||||
RowBackgroundColors []Color
|
RowBackgroundColors []Color
|
||||||
// The background color
|
// The background color
|
||||||
BackgroundColor 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 {
|
type TableSetting struct {
|
||||||
|
|
@ -180,6 +195,7 @@ type renderInfo struct {
|
||||||
Height int
|
Height int
|
||||||
HeaderHeight int
|
HeaderHeight int
|
||||||
RowHeights []int
|
RowHeights []int
|
||||||
|
ColumnWidths []int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *tableChart) render() (*renderInfo, error) {
|
func (t *tableChart) render() (*renderInfo, error) {
|
||||||
|
|
@ -227,6 +243,15 @@ func (t *tableChart) render() (*renderInfo, error) {
|
||||||
|
|
||||||
sum := sumInt(spans)
|
sum := sumInt(spans)
|
||||||
values := autoDivideSpans(p.Width(), sum, 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
|
height := 0
|
||||||
textStyle := Style{
|
textStyle := Style{
|
||||||
FontSize: fontSize,
|
FontSize: fontSize,
|
||||||
|
|
@ -234,25 +259,48 @@ func (t *tableChart) render() (*renderInfo, error) {
|
||||||
FillColor: headerFontColor,
|
FillColor: headerFontColor,
|
||||||
Font: font,
|
Font: font,
|
||||||
}
|
}
|
||||||
p.SetStyle(textStyle)
|
|
||||||
|
|
||||||
headerHeight := 0
|
headerHeight := 0
|
||||||
padding := opt.Padding
|
padding := opt.Padding
|
||||||
if padding.IsZero() {
|
if padding.IsZero() {
|
||||||
padding = tableDefaultSetting.Padding
|
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
|
cellMaxHeight := 0
|
||||||
paddingHeight := cellPadding.Top + cellPadding.Bottom
|
paddingHeight := cellPadding.Top + cellPadding.Bottom
|
||||||
paddingWidth := cellPadding.Left + cellPadding.Right
|
paddingWidth := cellPadding.Left + cellPadding.Right
|
||||||
for index, text := range textList {
|
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]
|
x := values[index]
|
||||||
y := currentHeight + cellPadding.Top
|
y := currentHeight + cellPadding.Top
|
||||||
width := values[index+1] - x
|
width := values[index+1] - x
|
||||||
x += cellPadding.Left
|
x += cellPadding.Left
|
||||||
width -= paddingWidth
|
width -= paddingWidth
|
||||||
box := p.TextFit(text, x, y+int(fontSize), width)
|
box := p.TextFit(text, x, y+int(fontSize), width)
|
||||||
|
// 计算最高的高度
|
||||||
if box.Height()+paddingHeight > cellMaxHeight {
|
if box.Height()+paddingHeight > cellMaxHeight {
|
||||||
cellMaxHeight = box.Height() + paddingHeight
|
cellMaxHeight = box.Height() + paddingHeight
|
||||||
}
|
}
|
||||||
|
|
@ -260,15 +308,16 @@ func (t *tableChart) render() (*renderInfo, error) {
|
||||||
return cellMaxHeight
|
return cellMaxHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
headerHeight = renderTableCells(opt.Header, height, padding)
|
// 表头的处理
|
||||||
|
headerHeight = renderTableCells(textStyle, 0, opt.Header, height, padding)
|
||||||
height += headerHeight
|
height += headerHeight
|
||||||
info.HeaderHeight = headerHeight
|
info.HeaderHeight = headerHeight
|
||||||
|
|
||||||
|
// 表格内容的处理
|
||||||
textStyle.FontColor = fontColor
|
textStyle.FontColor = fontColor
|
||||||
textStyle.FillColor = fontColor
|
textStyle.FillColor = fontColor
|
||||||
p.SetStyle(textStyle)
|
for index, textList := range opt.Data {
|
||||||
for _, textList := range opt.Data {
|
cellHeight := renderTableCells(textStyle, index+1, textList, height, padding)
|
||||||
cellHeight := renderTableCells(textList, height, padding)
|
|
||||||
info.RowHeights = append(info.RowHeights, cellHeight)
|
info.RowHeights = append(info.RowHeights, cellHeight)
|
||||||
height += cellHeight
|
height += cellHeight
|
||||||
}
|
}
|
||||||
|
|
@ -304,6 +353,41 @@ func (t *tableChart) renderWithInfo(info *renderInfo) (Box, error) {
|
||||||
child.SetBackground(p.Width(), h, color, true)
|
child.SetBackground(p.Width(), h, color, true)
|
||||||
currentHeight += h
|
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()
|
_, err := t.render()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return BoxZero, err
|
return BoxZero, err
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue