Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v0.4.0 API Simplifications and Uniformity Changes #27

Merged
merged 16 commits into from
Jan 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 30 additions & 46 deletions axis.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,21 @@ package charts
import (
"math"
"strings"

"github.com/go-analyze/charts/chartdraw"
)

type axisPainter struct {
p *Painter
opt *AxisOption
opt *axisOption
}

func NewAxisPainter(p *Painter, opt AxisOption) *axisPainter {
func newAxisPainter(p *Painter, opt axisOption) *axisPainter {
return &axisPainter{
p: p,
opt: &opt,
}
}

type AxisOption struct {
type axisOption struct {
// Show specifies if the axis should be rendered, set this to *false (through False()) to hide the axis.
Show *bool
// Theme specifies the colors used for the axis.
Expand Down Expand Up @@ -97,22 +95,7 @@ func (a *axisPainter) Render() (Box, error) {
tickLength := getDefaultInt(opt.TickLength, 5)
labelMargin := getDefaultInt(opt.LabelMargin, 5)

style := chartdraw.Style{
StrokeColor: theme.GetAxisStrokeColor(),
StrokeWidth: strokeWidth,
FontStyle: fontStyle,
}
top.SetDrawingStyle(style).OverrideFontStyle(style.FontStyle)

isTextRotation := opt.TextRotation != 0

if isTextRotation {
top.SetTextRotation(opt.TextRotation)
}
textMaxWidth, textMaxHeight := top.MeasureTextMaxWidthHeight(opt.Data)
if isTextRotation {
top.ClearTextRotation()
}
textMaxWidth, textMaxHeight := top.measureTextMaxWidthHeight(opt.Data, opt.TextRotation, fontStyle)

width := 0
height := 0
Expand Down Expand Up @@ -221,51 +204,52 @@ func (a *axisPainter) Render() (Box, error) {
} else {
// there is always one more tick than data sample, and if we are centering labels we use that extra tick to
// center the label against, if not centering then we need one less tick spacing
// passing the tickSpaces reduces the need to copy the logic from painter.go:MultiText
// passing the tickSpaces reduces the need to copy the logic from painter.go:multiText
tickSpaces--
}

if strokeWidth > 0 {
strokeColor := theme.GetAxisStrokeColor()
p.Child(PainterPaddingOption(Box{
Top: ticksPaddingTop,
Left: ticksPaddingLeft,
IsSet: true,
})).Ticks(TicksOption{
LabelCount: labelCount,
TickCount: tickCount,
TickSpaces: tickSpaces,
Length: tickLength,
Vertical: isVertical,
First: opt.DataStartIndex,
})).ticks(ticksOption{
labelCount: labelCount,
tickCount: tickCount,
tickSpaces: tickSpaces,
length: tickLength,
vertical: isVertical,
firstIndex: opt.DataStartIndex,
strokeWidth: strokeWidth,
strokeColor: strokeColor,
})
p.LineStroke([]Point{
{X: x0, Y: y0},
{X: x1, Y: y1},
})
}, strokeColor, strokeWidth)
}

p.Child(PainterPaddingOption(Box{
Left: labelPaddingLeft,
Top: labelPaddingTop,
Right: labelPaddingRight,
IsSet: true,
})).MultiText(MultiTextOption{
First: opt.DataStartIndex,
Align: textAlign,
TextList: opt.Data,
Vertical: isVertical,
LabelCount: labelCount,
TickCount: tickCount,
LabelSkipCount: opt.LabelSkipCount,
CenterLabels: centerLabels,
TextRotation: opt.TextRotation,
Offset: opt.LabelOffset,
})).multiText(multiTextOption{
firstIndex: opt.DataStartIndex,
align: textAlign,
textList: opt.Data,
fontStyle: fontStyle,
vertical: isVertical,
labelCount: labelCount,
tickCount: tickCount,
labelSkipCount: opt.LabelSkipCount,
centerLabels: centerLabels,
textRotation: opt.TextRotation,
offset: opt.LabelOffset,
})

if opt.SplitLineShow { // show auxiliary lines
style.StrokeColor = theme.GetAxisSplitLineColor()
style.StrokeWidth = 1
top.OverrideDrawingStyle(style)
if isVertical {
x0 := p.Width()
x1 := top.Width()
Expand All @@ -279,7 +263,7 @@ func (a *axisPainter) Render() (Box, error) {
top.LineStroke([]Point{
{X: x0, Y: y},
{X: x1, Y: y},
})
}, theme.GetAxisSplitLineColor(), 1)
}
} else {
y0 := p.Height() - defaultXAxisHeight
Expand All @@ -292,7 +276,7 @@ func (a *axisPainter) Render() (Box, error) {
top.LineStroke([]Point{
{X: x, Y: y0},
{X: x, Y: y1},
})
}, theme.GetAxisSplitLineColor(), 1)
}
}
}
Expand Down
147 changes: 77 additions & 70 deletions axis_test.go

Large diffs are not rendered by default.

93 changes: 49 additions & 44 deletions bar_chart.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,34 @@ import (
"math"

"github.com/golang/freetype/truetype"

"github.com/go-analyze/charts/chartdraw"
)

type barChart struct {
p *Painter
opt *BarChartOption
}

// NewBarChart returns a bar chart renderer
func NewBarChart(p *Painter, opt BarChartOption) *barChart {
// newBarChart returns a bar chart renderer
func newBarChart(p *Painter, opt BarChartOption) *barChart {
return &barChart{
p: p,
opt: &opt,
}
}

// NewBarChartOptionWithData returns an initialized BarChartOption with the SeriesList set for the provided data slice.
func NewBarChartOptionWithData(data [][]float64) BarChartOption {
sl := NewSeriesListBar(data)
return BarChartOption{
SeriesList: sl,
Padding: defaultPadding,
Theme: GetDefaultTheme(),
Font: GetDefaultFont(),
YAxis: make([]YAxisOption, sl.getYAxisCount()),
ValueFormatter: defaultValueFormatter,
}
}

type BarChartOption struct {
// Theme specifies the colors used for the bar chart.
Theme ColorPalette
Expand All @@ -43,14 +54,17 @@ type BarChartOption struct {
BarWidth int
// RoundedBarCaps set to `true` to produce a bar graph where the bars have rounded tops.
RoundedBarCaps *bool
// ValueFormatter defines how float values should be rendered to strings, notably for numeric axis labels.
ValueFormatter ValueFormatter
}

func (b *barChart) render(result *defaultRenderResult, seriesList SeriesList) (Box, error) {
p := b.p
opt := b.opt
seriesPainter := result.seriesPainter

xRange := NewRange(b.p, seriesPainter.Width(), len(opt.XAxis.Data), 0.0, 0.0, 0.0, 0.0)
xRange := newRange(b.p, getPreferredValueFormatter(opt.XAxis.ValueFormatter, opt.ValueFormatter),
seriesPainter.Width(), len(opt.XAxis.Data), 0.0, 0.0, 0.0, 0.0)
x0, x1 := xRange.GetRange(0)
width := int(x1 - x0)
// margin between each block
Expand Down Expand Up @@ -78,9 +92,9 @@ func (b *barChart) render(result *defaultRenderResult, seriesList SeriesList) (B
theme := opt.Theme
seriesNames := seriesList.Names()

markPointPainter := NewMarkPointPainter(seriesPainter)
markLinePainter := NewMarkLinePainter(seriesPainter)
rendererList := []Renderer{
markPointPainter := newMarkPointPainter(seriesPainter)
markLinePainter := newMarkLinePainter(seriesPainter)
rendererList := []renderer{
markPointPainter,
markLinePainter,
}
Expand All @@ -91,15 +105,9 @@ func (b *barChart) render(result *defaultRenderResult, seriesList SeriesList) (B

divideValues := xRange.AutoDivide()
points := make([]Point, len(series.Data))
var labelPainter *SeriesLabelPainter
if series.Label.Show {
labelPainter = NewSeriesLabelPainter(SeriesLabelPainterParams{
P: seriesPainter,
SeriesNames: seriesNames,
Label: series.Label,
Theme: opt.Theme,
Font: opt.Font,
})
var labelPainter *seriesLabelPainter
if flagIs(true, series.Label.Show) {
labelPainter = newSeriesLabelPainter(seriesPainter, seriesNames, series.Label, opt.Theme, opt.Font)
rendererList = append(rendererList, labelPainter)
}

Expand All @@ -113,29 +121,26 @@ func (b *barChart) render(result *defaultRenderResult, seriesList SeriesList) (B
x += index * (barWidth + barMargin)
}

h := yRange.getHeight(item.Value)
fillColor := seriesColor
h := yRange.getHeight(item)
top := barMaxHeight - h

seriesPainter.OverrideDrawingStyle(chartdraw.Style{
FillColor: fillColor,
})
if flagIs(true, opt.RoundedBarCaps) {
seriesPainter.RoundedRect(Box{
seriesPainter.roundedRect(Box{
Top: top,
Left: x,
Right: x + barWidth,
Bottom: barMaxHeight - 1,
IsSet: true,
}, barWidth, true, false)
}, barWidth, true, false,
seriesColor, seriesColor, 0.0)
} else {
seriesPainter.Rect(Box{
seriesPainter.filledRect(Box{
Top: top,
Left: x,
Right: x + barWidth,
Bottom: barMaxHeight - 1,
IsSet: true,
})
}, seriesColor, seriesColor, 0.0)
}
// generate marker point by hand
points[j] = Point{
Expand All @@ -153,23 +158,22 @@ func (b *barChart) render(result *defaultRenderResult, seriesList SeriesList) (B
y = barMaxHeight
radians = -math.Pi / 2
if fontStyle.FontColor.IsZero() {
if isLightColor(fillColor) {
if isLightColor(seriesColor) {
fontStyle.FontColor = defaultLightFontColor
} else {
fontStyle.FontColor = defaultDarkFontColor
}
}
}
labelPainter.Add(LabelValue{
Vertical: true, // label is above bar
Index: index,
Value: item.Value,
FontStyle: fontStyle,
X: x + barWidth>>1,
Y: y,
// rotate
Radians: radians,
Offset: series.Label.Offset,
labelPainter.Add(labelValue{
vertical: true, // label is above bar
index: index,
value: item,
fontStyle: fontStyle,
x: x + (barWidth >> 1),
y: y,
radians: radians,
offset: series.Label.Offset,
})
}

Expand Down Expand Up @@ -203,13 +207,14 @@ func (b *barChart) Render() (Box, error) {
opt.Theme = getPreferredTheme(p.theme)
}
renderResult, err := defaultRender(p, defaultRenderOption{
Theme: opt.Theme,
Padding: opt.Padding,
SeriesList: opt.SeriesList,
XAxis: opt.XAxis,
YAxis: opt.YAxis,
Title: opt.Title,
Legend: opt.Legend,
theme: opt.Theme,
padding: opt.Padding,
seriesList: opt.SeriesList,
xAxis: &b.opt.XAxis,
yAxis: opt.YAxis,
title: opt.Title,
legend: &b.opt.Legend,
valueFormatter: opt.ValueFormatter,
})
if err != nil {
return BoxZero, err
Expand Down
Loading
Loading