Skip to content

Commit

Permalink
Minor ChartOption changes
Browse files Browse the repository at this point in the history
This changes the `parent` field to be internal only, specified only when `Children` are defined by the user.
There are other code simplifications are the OptionFunc usage was reviewed, but no functional changes.
  • Loading branch information
jentfoo committed Jun 18, 2024
1 parent d3dde0a commit c2147b6
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 60 deletions.
78 changes: 44 additions & 34 deletions chart_option.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package charts

import (
"fmt"
"sort"

"github.com/golang/freetype/truetype"
Expand Down Expand Up @@ -29,8 +30,7 @@ type ChartOption struct {
// Font is the font to use for rendering the chart.
Font *truetype.Font
// Box specifies the canvas box for the chart.
Box Box
Parent *Painter
Box Box
// SeriesList provides the data series.
SeriesList SeriesList
// RadarIndicators are radar indicator list for radar charts
Expand All @@ -47,8 +47,9 @@ type ChartOption struct {
BarWidth int
// BarHeight is the height of the bars for horizontal bar charts.
BarHeight int
// Children are child charts to pull options from.
// Children are child charts to render together.
Children []ChartOption
parent *Painter
// ValueFormatter to format numeric values into labels.
ValueFormatter ValueFormatter
}
Expand Down Expand Up @@ -227,35 +228,36 @@ func MarkPointOptionFunc(seriesIndex int, markPointTypes ...string) OptionFunc {
}
}

func (o *ChartOption) fillDefault() {
func (o *ChartOption) fillDefault() error {
o.Width = getDefaultInt(o.Width, defaultChartWidth)
o.Height = getDefaultInt(o.Height, defaultChartHeight)

yaxisCount := 1
for _, series := range o.SeriesList {
if series.YAxisIndex >= yaxisCount {
if series.YAxisIndex == 1 {
yaxisCount++
break
} else if series.YAxisIndex > 1 {
return fmt.Errorf("series '%s' specified invalid y-axis index: %v", series.Name, series.YAxisIndex)
}
}
o.Width = getDefaultInt(o.Width, defaultChartWidth)
o.Height = getDefaultInt(o.Height, defaultChartHeight)

yAxisOptions := make([]YAxisOption, yaxisCount)
copy(yAxisOptions, o.YAxis)
o.YAxis = yAxisOptions
if len(o.YAxis) < yaxisCount {
yAxisOptions := make([]YAxisOption, yaxisCount)
copy(yAxisOptions, o.YAxis)
o.YAxis = yAxisOptions
}
// TODO - this is a hack, we need to update the yaxis based on the markpoint state
// TODO - but can't do this earlier due to needing the axis initialized
// TODO - we should reconsider the API for configuration
hasMarkpoint := false
for _, sl := range o.SeriesList {
if len(sl.MarkPoint.Data) > 0 {
hasMarkpoint = true
break
}
}
if hasMarkpoint {
for i := range o.YAxis {
if o.YAxis[i].RangeValuePaddingScale == nil {
defaultPadding := 2.5 // default a larger padding to give space for the mark point
o.YAxis[i].RangeValuePaddingScale = &defaultPadding
if len(sl.MarkPoint.Data) > 0 { // if graph has markpoint
// adjust padding scale to give space for mark point (if not specified by user)
for i := range o.YAxis {
if o.YAxis[i].RangeValuePaddingScale == nil {
o.YAxis[i].RangeValuePaddingScale = FloatPointer(2.5)
}
}
break
}
}

Expand All @@ -265,6 +267,7 @@ func (o *ChartOption) fillDefault() {
if o.Theme == nil {
o.Theme = GetDefaultTheme()
}
fillThemeDefaults(o.Theme, &o.Title, &o.Legend, &o.XAxis)

if o.Padding.IsZero() {
o.Padding = Box{
Expand All @@ -280,8 +283,7 @@ func (o *ChartOption) fillDefault() {
} else {
seriesCount := len(o.SeriesList)
for index, name := range o.Legend.Data {
if index < seriesCount &&
len(o.SeriesList[index].Name) == 0 {
if index < seriesCount && len(o.SeriesList[index].Name) == 0 {
o.SeriesList[index].Name = name
}
}
Expand All @@ -294,29 +296,39 @@ func (o *ChartOption) fillDefault() {
return nameIndexDict[o.SeriesList[i].Name] < nameIndexDict[o.SeriesList[j].Name]
})
}
return nil
}

func fillThemeDefaults(defaultTheme ColorPalette, title *TitleOption, legend *LegendOption, xaxis *XAxisOption) {
if title.Theme == nil {
title.Theme = defaultTheme
}
if legend.Theme == nil {
legend.Theme = defaultTheme
}
if xaxis.Theme == nil {
xaxis.Theme = defaultTheme
}
}

// LineRender line chart render
func LineRender(values [][]float64, opts ...OptionFunc) (*Painter, error) {
seriesList := NewSeriesListDataFromValues(values, ChartTypeLine)
return Render(ChartOption{
SeriesList: seriesList,
SeriesList: NewSeriesListDataFromValues(values, ChartTypeLine),
}, opts...)
}

// BarRender bar chart render
func BarRender(values [][]float64, opts ...OptionFunc) (*Painter, error) {
seriesList := NewSeriesListDataFromValues(values, ChartTypeBar)
return Render(ChartOption{
SeriesList: seriesList,
SeriesList: NewSeriesListDataFromValues(values, ChartTypeBar),
}, opts...)
}

// HorizontalBarRender horizontal bar chart render
func HorizontalBarRender(values [][]float64, opts ...OptionFunc) (*Painter, error) {
seriesList := NewSeriesListDataFromValues(values, ChartTypeHorizontalBar)
return Render(ChartOption{
SeriesList: seriesList,
SeriesList: NewSeriesListDataFromValues(values, ChartTypeHorizontalBar),
}, opts...)
}

Expand All @@ -329,17 +341,15 @@ func PieRender(values []float64, opts ...OptionFunc) (*Painter, error) {

// RadarRender radar chart render
func RadarRender(values [][]float64, opts ...OptionFunc) (*Painter, error) {
seriesList := NewSeriesListDataFromValues(values, ChartTypeRadar)
return Render(ChartOption{
SeriesList: seriesList,
SeriesList: NewSeriesListDataFromValues(values, ChartTypeRadar),
}, opts...)
}

// FunnelRender funnel chart render
func FunnelRender(values []float64, opts ...OptionFunc) (*Painter, error) {
seriesList := NewFunnelSeriesList(values)
return Render(ChartOption{
SeriesList: seriesList,
SeriesList: NewFunnelSeriesList(values),
}, opts...)
}

Expand Down
29 changes: 10 additions & 19 deletions charts.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ type defaultRenderResult struct {
}

func defaultRender(p *Painter, opt defaultRenderOption) (*defaultRenderResult, error) {
fillThemeDefaults(getPreferredTheme(opt.Theme), &opt.Title, &opt.Legend, &opt.XAxis)

seriesList := opt.SeriesList
seriesList.init()
if !opt.backgroundIsFilled {
Expand All @@ -118,9 +120,6 @@ func defaultRender(p *Painter, opt defaultRenderOption) (*defaultRenderResult, e

legendHeight := 0
if len(opt.Legend.Data) != 0 {
if opt.Legend.Theme == nil {
opt.Legend.Theme = opt.Theme
}
legendResult, err := NewLegendPainter(p, opt.Legend).Render()
if err != nil {
return nil, err
Expand All @@ -129,10 +128,6 @@ func defaultRender(p *Painter, opt defaultRenderOption) (*defaultRenderResult, e
}

if opt.Title.Text != "" {
if opt.Title.Theme == nil {
opt.Title.Theme = opt.Theme
}

titleBox, err := NewTitlePainter(p, opt.Title).Render()
if err != nil {
return nil, err
Expand Down Expand Up @@ -248,7 +243,6 @@ func defaultRender(p *Painter, opt defaultRenderOption) (*defaultRenderResult, e
opt.XAxis.isValueAxis = true
}
reverseStringSlice(yAxisOption.Data)
// TODO - generate other positions and y-axis
child := p.Child(PainterPaddingOption(Box{
Left: rangeWidthLeft,
Right: rangeWidthRight,
Expand All @@ -268,9 +262,6 @@ func defaultRender(p *Painter, opt defaultRenderOption) (*defaultRenderResult, e
}
}

if opt.XAxis.Theme == nil {
opt.XAxis.Theme = opt.Theme
}
xAxis := NewBottomXAxis(p.Child(PainterPaddingOption(Box{
Left: rangeWidthLeft,
Right: rangeWidthRight,
Expand Down Expand Up @@ -300,11 +291,12 @@ func Render(opt ChartOption, opts ...OptionFunc) (*Painter, error) {
for _, fn := range opts {
fn(&opt)
}
opt.fillDefault()
if err := opt.fillDefault(); err != nil {
return nil, err
}

isChild := true
if opt.Parent == nil {
isChild = false
isChild := opt.parent != nil
if !isChild {
p, err := NewPainter(PainterOptions{
OutputFormat: opt.OutputFormat,
Width: opt.Width,
Expand All @@ -314,9 +306,9 @@ func Render(opt ChartOption, opts ...OptionFunc) (*Painter, error) {
if err != nil {
return nil, err
}
opt.Parent = p
opt.parent = p
}
p := opt.Parent
p := opt.parent
if opt.ValueFormatter != nil {
p.valueFormatter = opt.ValueFormatter
}
Expand All @@ -329,7 +321,6 @@ func Render(opt ChartOption, opts ...OptionFunc) (*Painter, error) {
seriesList := opt.SeriesList
seriesList.init()

// line chart
lineSeriesList := seriesList.Filter(ChartTypeLine)
barSeriesList := seriesList.Filter(ChartTypeBar)
horizontalBarSeriesList := seriesList.Filter(ChartTypeHorizontalBar)
Expand Down Expand Up @@ -463,7 +454,7 @@ func Render(opt ChartOption, opts ...OptionFunc) (*Painter, error) {
}

for _, item := range opt.Children {
item.Parent = p
item.parent = p
if item.Theme == nil {
item.Theme = opt.Theme
}
Expand Down
2 changes: 1 addition & 1 deletion pie_chart.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ func (p *pieChart) render(result *defaultRenderResult, seriesList SeriesList) (B
total += value
}
if total <= 0 {
return BoxZero, errors.New("The sum value of pie chart should gt 0")
return BoxZero, errors.New("the sum value of pie chart should greater than 0")
}
seriesPainter := result.seriesPainter
cx := seriesPainter.Width() >> 1
Expand Down
9 changes: 3 additions & 6 deletions series.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ type Series struct {
Type string
// Data provides the series data list.
Data []SeriesData
// YAxisIndex is the index for the axis, it should be 0 or 1.
// YAxisIndex is the index for the axis, it must be 0 or 1.
YAxisIndex int
// Style represents the style for the series.
Style chart.Style
Expand All @@ -114,11 +114,8 @@ type Series struct {
type SeriesList []Series

func (sl SeriesList) init() {
if len(sl) == 0 {
return
}
if sl[len(sl)-1].index != 0 {
return
if len(sl) == 0 || sl[len(sl)-1].index != 0 {
return // already initialized
}
for i := 0; i < len(sl); i++ {
if sl[i].Type == "" {
Expand Down

0 comments on commit c2147b6

Please sign in to comment.