This closes #1369, support set, and get font color with theme and tint (#1370)

This commit is contained in:
GaoFei 2022-10-15 00:03:49 +08:00 committed by GitHub
parent 3d02726ad4
commit 3ece904b00
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 67 additions and 35 deletions

View File

@ -823,6 +823,10 @@ func getCellRichText(si *xlsxSI) (runs []RichTextRun) {
font.Strike = v.RPr.Strike != nil
if v.RPr.Color != nil {
font.Color = strings.TrimPrefix(v.RPr.Color.RGB, "FF")
if v.RPr.Color.Theme != nil {
font.ColorTheme = v.RPr.Color.Theme
}
font.ColorTint = v.RPr.Color.Tint
}
run.Font = &font
}
@ -879,9 +883,7 @@ func newRpr(fnt *Font) *xlsxRPr {
if fnt.Size > 0 {
rpr.Sz = &attrValFloat{Val: &fnt.Size}
}
if fnt.Color != "" {
rpr.Color = &xlsxColor{RGB: getPaletteColor(fnt.Color)}
}
rpr.Color = newFontColor(fnt)
return &rpr
}

View File

@ -518,7 +518,7 @@ func TestSetCellFormula(t *testing.T) {
}
func TestGetCellRichText(t *testing.T) {
f := NewFile()
f, theme := NewFile(), 1
runsSource := []RichTextRun{
{
@ -527,13 +527,15 @@ func TestGetCellRichText(t *testing.T) {
{
Text: "b",
Font: &Font{
Underline: "single",
Color: "ff0000",
Bold: true,
Italic: true,
Family: "Times New Roman",
Size: 100,
Strike: true,
Underline: "single",
Color: "ff0000",
ColorTheme: &theme,
ColorTint: 0.5,
Bold: true,
Italic: true,
Family: "Times New Roman",
Size: 100,
Strike: true,
},
},
}
@ -580,6 +582,10 @@ func TestGetCellRichText(t *testing.T) {
// Test set cell rich text with illegal cell reference
_, err = f.GetCellRichText("Sheet1", "A")
assert.EqualError(t, err, newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
// Test set rich text color theme without tint
assert.NoError(t, f.SetCellRichText("Sheet1", "A1", []RichTextRun{{Font: &Font{ColorTheme: &theme}}}))
// Test set rich text color tint without theme
assert.NoError(t, f.SetCellRichText("Sheet1", "A1", []RichTextRun{{Font: &Font{ColorTint: 0.5}}}))
}
func TestSetCellRichText(t *testing.T) {

View File

@ -702,7 +702,7 @@ func parseChartOptions(opts string) (*chartOptions, error) {
//
// title
//
// name: Set the name (title) for the chart. The name is displayed above the chart. The name can also be a formula such as Sheet1!$A$1 or a list with a sheetname. The name property is optional. The default is to have no chart title.
// name: Set the name (title) for the chart. The name is displayed above the chart. The name can also be a formula such as Sheet1!$A$1 or a list with a sheet name. The name property is optional. The default is to have no chart title.
//
// Specifies how blank cells are plotted on the chart by show_blanks_as. The default value is gap. The options that can be set are:
//
@ -750,18 +750,19 @@ func parseChartOptions(opts string) (*chartOptions, error) {
// reverse_order
// maximum
// minimum
// number_font
// font
//
// The properties of y_axis that can be set are:
//
// none
// major_grid_lines
// minor_grid_lines
// major_unit
// tick_label_skip
// reverse_order
// maximum
// minimum
// number_font
// font
//
// none: Disable axes.
//
@ -779,7 +780,7 @@ func parseChartOptions(opts string) (*chartOptions, error) {
//
// minimum: Specifies that the fixed minimum, 0 is auto. The minimum property is optional. The default value is auto.
//
// number_font: Specifies that the font of the horizontal and vertical axis. The properties of number_font that can be set are:
// font: Specifies that the font of the horizontal and vertical axis. The properties of font that can be set are:
//
// bold
// italic

View File

@ -116,7 +116,7 @@ func TestAddChart(t *testing.T) {
// Test add chart on not exists worksheet.
assert.EqualError(t, f.AddChart("SheetN", "P1", "{}"), "sheet SheetN does not exist")
assert.NoError(t, f.AddChart("Sheet1", "P1", `{"type":"col","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$30:$D$30"},{"name":"Sheet1!$A$31","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$31:$D$31"},{"name":"Sheet1!$A$32","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$32:$D$32"},{"name":"Sheet1!$A$33","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$33:$D$33"},{"name":"Sheet1!$A$34","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$34:$D$34"},{"name":"Sheet1!$A$35","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$35:$D$35"},{"name":"Sheet1!$A$36","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$36:$D$36"},{"name":"Sheet1!$A$37","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$37:$D$37"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"none":true,"show_legend_key":true},"title":{"name":"2D Column Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"zero","x_axis":{"number_font":{"bold":true,"italic":true,"underline":"dbl","color":"#000000"}},"y_axis":{"number_font":{"bold":false,"italic":false,"underline":"sng","color":"#777777"}}}`))
assert.NoError(t, f.AddChart("Sheet1", "P1", `{"type":"col","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$30:$D$30"},{"name":"Sheet1!$A$31","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$31:$D$31"},{"name":"Sheet1!$A$32","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$32:$D$32"},{"name":"Sheet1!$A$33","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$33:$D$33"},{"name":"Sheet1!$A$34","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$34:$D$34"},{"name":"Sheet1!$A$35","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$35:$D$35"},{"name":"Sheet1!$A$36","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$36:$D$36"},{"name":"Sheet1!$A$37","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$37:$D$37"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"none":true,"show_legend_key":true},"title":{"name":"2D Column Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"zero","x_axis":{"font":{"bold":true,"italic":true,"underline":"dbl","color":"#000000"}},"y_axis":{"font":{"bold":false,"italic":false,"underline":"sng","color":"#777777"}}}`))
assert.NoError(t, f.AddChart("Sheet1", "X1", `{"type":"colStacked","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$30:$D$30"},{"name":"Sheet1!$A$31","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$31:$D$31"},{"name":"Sheet1!$A$32","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$32:$D$32"},{"name":"Sheet1!$A$33","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$33:$D$33"},{"name":"Sheet1!$A$34","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$34:$D$34"},{"name":"Sheet1!$A$35","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$35:$D$35"},{"name":"Sheet1!$A$36","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$36:$D$36"},{"name":"Sheet1!$A$37","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$37:$D$37"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"left","show_legend_key":false},"title":{"name":"2D Stacked Column Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"zero"}`))
assert.NoError(t, f.AddChart("Sheet1", "P16", `{"type":"colPercentStacked","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$30:$D$30"},{"name":"Sheet1!$A$31","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$31:$D$31"},{"name":"Sheet1!$A$32","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$32:$D$32"},{"name":"Sheet1!$A$33","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$33:$D$33"},{"name":"Sheet1!$A$34","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$34:$D$34"},{"name":"Sheet1!$A$35","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$35:$D$35"},{"name":"Sheet1!$A$36","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$36:$D$36"},{"name":"Sheet1!$A$37","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$37:$D$37"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"left","show_legend_key":false},"title":{"name":"100% Stacked Column Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"zero"}`))
assert.NoError(t, f.AddChart("Sheet1", "X16", `{"type":"col3DClustered","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$30:$D$30"},{"name":"Sheet1!$A$31","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$31:$D$31"},{"name":"Sheet1!$A$32","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$32:$D$32"},{"name":"Sheet1!$A$33","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$33:$D$33"},{"name":"Sheet1!$A$34","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$34:$D$34"},{"name":"Sheet1!$A$35","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$35:$D$35"},{"name":"Sheet1!$A$36","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$36:$D$36"},{"name":"Sheet1!$A$37","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$37:$D$37"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"bottom","show_legend_key":false},"title":{"name":"3D Clustered Column Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"zero"}`))

View File

@ -1177,14 +1177,14 @@ func (f *File) drawPlotAreaTxPr(opts *chartAxisOptions) *cTxPr {
},
}
if opts != nil {
cTxPr.P.PPr.DefRPr.B = opts.NumFont.Bold
cTxPr.P.PPr.DefRPr.I = opts.NumFont.Italic
if idx := inStrSlice(supportedDrawingUnderlineTypes, opts.NumFont.Underline, true); idx != -1 {
cTxPr.P.PPr.DefRPr.B = opts.Font.Bold
cTxPr.P.PPr.DefRPr.I = opts.Font.Italic
if idx := inStrSlice(supportedDrawingUnderlineTypes, opts.Font.Underline, true); idx != -1 {
cTxPr.P.PPr.DefRPr.U = supportedDrawingUnderlineTypes[idx]
}
if opts.NumFont.Color != "" {
if opts.Font.Color != "" {
cTxPr.P.PPr.DefRPr.SolidFill.SchemeClr = nil
cTxPr.P.PPr.DefRPr.SolidFill.SrgbClr = &attrValString{Val: stringPtr(strings.ReplaceAll(strings.ToUpper(opts.NumFont.Color), "#", ""))}
cTxPr.P.PPr.DefRPr.SolidFill.SrgbClr = &attrValString{Val: stringPtr(strings.ReplaceAll(strings.ToUpper(opts.Font.Color), "#", ""))}
}
}
return cTxPr

View File

@ -2084,21 +2084,42 @@ func (f *File) getFontID(styleSheet *xlsxStyleSheet, style *Style) (fontID int)
return
}
// newFontColor set font color by given styles.
func newFontColor(font *Font) *xlsxColor {
var fontColor *xlsxColor
prepareFontColor := func() {
if fontColor != nil {
return
}
fontColor = &xlsxColor{}
}
if font.Color != "" {
prepareFontColor()
fontColor.RGB = getPaletteColor(font.Color)
}
if font.ColorTheme != nil {
prepareFontColor()
fontColor.Theme = font.ColorTheme
}
if font.ColorTint != 0 {
prepareFontColor()
fontColor.Tint = font.ColorTint
}
return fontColor
}
// newFont provides a function to add font style by given cell format
// settings.
func (f *File) newFont(style *Style) *xlsxFont {
if style.Font.Size < MinFontSize {
style.Font.Size = 11
}
if style.Font.Color == "" {
style.Font.Color = "#000000"
}
fnt := xlsxFont{
Sz: &attrValFloat{Val: float64Ptr(style.Font.Size)},
Color: &xlsxColor{RGB: getPaletteColor(style.Font.Color)},
Name: &attrValString{Val: stringPtr(style.Font.Family)},
Family: &attrValInt{Val: intPtr(2)},
}
fnt.Color = newFontColor(style.Font)
if style.Font.Bold {
fnt.B = &attrValBool{Val: &style.Font.Bold}
}

View File

@ -476,7 +476,7 @@ type cNumCache struct {
PtCount *attrValInt `xml:"ptCount"`
}
// cDLbls (Data Lables) directly maps the dLbls element. This element serves
// cDLbls (Data Labels) directly maps the dLbls element. This element serves
// as a root element that specifies the settings for the data labels for an
// entire series or the entire chart. It contains child elements that specify
// the specific formatting and positioning settings.
@ -538,7 +538,7 @@ type chartAxisOptions struct {
Maximum *float64 `json:"maximum"`
Minimum *float64 `json:"minimum"`
NumFormat string `json:"number_format"`
NumFont Font `json:"number_font"`
Font Font `json:"font"`
LogBase float64 `json:"logbase"`
NameLayout layoutOptions `json:"name_layout"`
}

View File

@ -334,14 +334,16 @@ type Border struct {
// Font directly maps the font settings of the fonts.
type Font struct {
Bold bool `json:"bold"`
Italic bool `json:"italic"`
Underline string `json:"underline"`
Family string `json:"family"`
Size float64 `json:"size"`
Strike bool `json:"strike"`
Color string `json:"color"`
VertAlign string `json:"vertAlign"`
Bold bool `json:"bold"`
Italic bool `json:"italic"`
Underline string `json:"underline"`
Family string `json:"family"`
Size float64 `json:"size"`
Strike bool `json:"strike"`
Color string `json:"color"`
ColorTheme *int `json:"color_theme"`
ColorTint float64 `json:"color_tint"`
VertAlign string `json:"vertAlign"`
}
// Fill directly maps the fill settings of the cells.