diff --git a/chart.go b/chart.go index ed6b8e2..0d06a21 100644 --- a/chart.go +++ b/chart.go @@ -225,13 +225,13 @@ func (c Chart) hasAxes() bool { func (c Chart) getAxesTicks(r Renderer, xr, yr, yar Range, xf, yf, yfa ValueFormatter) (xticks, yticks, yticksAlt []Tick) { if c.XAxis.Style.Show { - xticks = c.XAxis.GetTicks(r, xr, xf) + xticks = c.XAxis.GetTicks(r, xr, c.styleDefaultsAxis(), xf) } if c.YAxis.Style.Show { - yticks = c.YAxis.GetTicks(r, yr, yf) + yticks = c.YAxis.GetTicks(r, yr, c.styleDefaultsAxis(), yf) } if c.YAxisSecondary.Style.Show { - yticksAlt = c.YAxisSecondary.GetTicks(r, yar, yf) + yticksAlt = c.YAxisSecondary.GetTicks(r, yar, c.styleDefaultsAxis(), yfa) } return } diff --git a/chart_test.go b/chart_test.go index 4705b02..ae1b06f 100644 --- a/chart_test.go +++ b/chart_test.go @@ -122,7 +122,123 @@ func TestChartGetRanges(t *testing.T) { assert.Equal(19.7, yra2.Max) } -// TestChartSingleSeries is more of a sanity check than anything. +func TestChartGetDefaultCanvasBox(t *testing.T) { + assert := assert.New(t) + + c := Chart{} + canvasBoxDefault := c.getDefaultCanvasBox() + assert.False(canvasBoxDefault.IsZero()) + assert.Equal(DefaultBackgroundPadding.Top, canvasBoxDefault.Top) + assert.Equal(DefaultBackgroundPadding.Left, canvasBoxDefault.Left) + assert.Equal(c.GetWidth()-DefaultBackgroundPadding.Right, canvasBoxDefault.Right) + assert.Equal(c.GetHeight()-DefaultBackgroundPadding.Bottom, canvasBoxDefault.Bottom) + + custom := Chart{ + Background: Style{ + Padding: Box{ + Top: DefaultBackgroundPadding.Top + 1, + Left: DefaultBackgroundPadding.Left + 1, + Right: DefaultBackgroundPadding.Right + 1, + Bottom: DefaultBackgroundPadding.Bottom + 1, + }, + }, + } + canvasBoxCustom := custom.getDefaultCanvasBox() + assert.False(canvasBoxCustom.IsZero()) + assert.Equal(DefaultBackgroundPadding.Top+1, canvasBoxCustom.Top) + assert.Equal(DefaultBackgroundPadding.Left+1, canvasBoxCustom.Left) + assert.Equal(c.GetWidth()-(DefaultBackgroundPadding.Right+1), canvasBoxCustom.Right) + assert.Equal(c.GetHeight()-(DefaultBackgroundPadding.Bottom+1), canvasBoxCustom.Bottom) +} + +func TestChartGetValueFormatters(t *testing.T) { + assert := assert.New(t) + + c := Chart{ + Series: []Series{ + ContinuousSeries{ + XValues: []float64{-2.0, -1.0, 0, 1.0, 2.0}, + YValues: []float64{1.0, 2.0, 3.0, 4.0, 4.5}, + }, + ContinuousSeries{ + XValues: []float64{1.0, 2.0, 3.0, 4.0, 5.0}, + YValues: []float64{-2.1, -1.0, 0, 1.0, 2.0}, + }, + ContinuousSeries{ + YAxis: YAxisSecondary, + XValues: []float64{1.0, 2.0, 3.0, 4.0, 5.0}, + YValues: []float64{10.0, 11.0, 12.0, 13.0, 14.0}, + }, + }, + } + + dxf, dyf, dyaf := c.getValueFormatters() + assert.NotNil(dxf) + assert.NotNil(dyf) + assert.NotNil(dyaf) +} + +func TestChartHasAxes(t *testing.T) { + assert := assert.New(t) + + assert.False(Chart{}.hasAxes()) + + x := Chart{ + XAxis: XAxis{ + Style: Style{ + Show: true, + }, + }, + } + assert.True(x.hasAxes()) + + y := Chart{ + YAxis: YAxis{ + Style: Style{ + Show: true, + }, + }, + } + assert.True(y.hasAxes()) + + ya := Chart{ + YAxisSecondary: YAxis{ + Style: Style{ + Show: true, + }, + }, + } + assert.True(ya.hasAxes()) +} + +func TestChartGetAxesTicks(t *testing.T) { + assert := assert.New(t) + + r, err := PNG(1024, 1024) + assert.Nil(err) + + c := Chart{ + XAxis: XAxis{ + Style: Style{Show: true}, + Range: Range{Min: 9.8, Max: 19.8}, + }, + YAxis: YAxis{ + Style: Style{Show: true}, + Range: Range{Min: 9.9, Max: 19.9}, + }, + YAxisSecondary: YAxis{ + Style: Style{Show: true}, + Range: Range{Min: 9.7, Max: 19.7}, + }, + } + xr, yr, yar := c.getRanges() + + xt, yt, yat := c.getAxesTicks(r, xr, yr, yar, FloatValueFormatter, FloatValueFormatter, FloatValueFormatter) + assert.NotEmpty(xt) + assert.NotEmpty(yt) + assert.NotEmpty(yat) +} + func TestChartSingleSeries(t *testing.T) { assert := assert.New(t) now := time.Now() diff --git a/xaxis.go b/xaxis.go index d1ef328..8df875f 100644 --- a/xaxis.go +++ b/xaxis.go @@ -30,27 +30,27 @@ func (xa XAxis) GetStyle() Style { // GetTicks returns the ticks for a series. It coalesces between user provided ticks and // generated ticks. -func (xa XAxis) GetTicks(r Renderer, ra Range, vf ValueFormatter) []Tick { +func (xa XAxis) GetTicks(r Renderer, ra Range, defaults Style, vf ValueFormatter) []Tick { if len(xa.Ticks) > 0 { return xa.Ticks } - return xa.generateTicks(r, ra, vf) + return xa.generateTicks(r, ra, defaults, vf) } -func (xa XAxis) generateTicks(r Renderer, ra Range, vf ValueFormatter) []Tick { - step := xa.getTickStep(r, ra, vf) +func (xa XAxis) generateTicks(r Renderer, ra Range, defaults Style, vf ValueFormatter) []Tick { + step := xa.getTickStep(r, ra, defaults, vf) return GenerateTicksWithStep(ra, step, vf) } -func (xa XAxis) getTickStep(r Renderer, ra Range, vf ValueFormatter) float64 { - tickCount := xa.getTickCount(r, ra, vf) +func (xa XAxis) getTickStep(r Renderer, ra Range, defaults Style, vf ValueFormatter) float64 { + tickCount := xa.getTickCount(r, ra, defaults, vf) step := ra.Delta() / float64(tickCount) return step } -func (xa XAxis) getTickCount(r Renderer, ra Range, vf ValueFormatter) int { - fontSize := xa.Style.GetFontSize(DefaultFontSize) - r.SetFontSize(fontSize) +func (xa XAxis) getTickCount(r Renderer, ra Range, defaults Style, vf ValueFormatter) int { + r.SetFont(xa.Style.GetFont(defaults.GetFont())) + r.SetFontSize(xa.Style.GetFontSize(defaults.GetFontSize(DefaultFontSize))) // take a cut at determining the 'widest' value. l0 := vf(ra.Min) diff --git a/xaxis_test.go b/xaxis_test.go new file mode 100644 index 0000000..a558d48 --- /dev/null +++ b/xaxis_test.go @@ -0,0 +1,89 @@ +package chart + +import ( + "testing" + + "github.com/blendlabs/go-assert" +) + +func TestXAxisGetTickCount(t *testing.T) { + assert := assert.New(t) + + r, err := PNG(1024, 1024) + assert.Nil(err) + + f, err := GetDefaultFont() + assert.Nil(err) + + xa := XAxis{} + xr := Range{Min: 10, Max: 100, Domain: 1024} + styleDefaults := Style{ + Font: f, + FontSize: 10.0, + } + vf := FloatValueFormatter + count := xa.getTickCount(r, xr, styleDefaults, vf) + assert.Equal(16, count) +} + +func TestXAxisGetTickStep(t *testing.T) { + assert := assert.New(t) + + r, err := PNG(1024, 1024) + assert.Nil(err) + + f, err := GetDefaultFont() + assert.Nil(err) + + xa := XAxis{} + xr := Range{Min: 10, Max: 100, Domain: 1024} + styleDefaults := Style{ + Font: f, + FontSize: 10.0, + } + vf := FloatValueFormatter + step := xa.getTickStep(r, xr, styleDefaults, vf) + assert.Equal(xr.Delta()/16.0, step) +} + +func TestXAxisGetTicks(t *testing.T) { + assert := assert.New(t) + + r, err := PNG(1024, 1024) + assert.Nil(err) + + f, err := GetDefaultFont() + assert.Nil(err) + + xa := XAxis{} + xr := Range{Min: 10, Max: 100, Domain: 1024} + styleDefaults := Style{ + Font: f, + FontSize: 10.0, + } + vf := FloatValueFormatter + ticks := xa.GetTicks(r, xr, styleDefaults, vf) + assert.Len(ticks, 17) +} + +func TestXAxisGetTicksWithUserDefaults(t *testing.T) { + assert := assert.New(t) + + r, err := PNG(1024, 1024) + assert.Nil(err) + + f, err := GetDefaultFont() + assert.Nil(err) + + xa := XAxis{ + Ticks: []Tick{Tick{Value: 1.0, Label: "1.0"}}, + } + xr := Range{Min: 10, Max: 100, Domain: 1024} + styleDefaults := Style{ + Font: f, + FontSize: 10.0, + } + vf := FloatValueFormatter + ticks := xa.GetTicks(r, xr, styleDefaults, vf) + assert.Len(ticks, 1) +} diff --git a/yaxis.go b/yaxis.go index 5193b4e..36c6ccd 100644 --- a/yaxis.go +++ b/yaxis.go @@ -36,30 +36,32 @@ func (ya YAxis) GetStyle() Style { // GetTicks returns the ticks for a series. It coalesces between user provided ticks and // generated ticks. -func (ya YAxis) GetTicks(r Renderer, ra Range, vf ValueFormatter) []Tick { +func (ya YAxis) GetTicks(r Renderer, ra Range, defaults Style, vf ValueFormatter) []Tick { var ticks []Tick if len(ya.Ticks) > 0 { ticks = ya.Ticks } else { - ticks = ya.generateTicks(r, ra, vf) + ticks = ya.generateTicks(r, ra, defaults, vf) } return ticks } -func (ya YAxis) generateTicks(r Renderer, ra Range, vf ValueFormatter) []Tick { - step := ya.getTickStep(r, ra, vf) +func (ya YAxis) generateTicks(r Renderer, ra Range, defaults Style, vf ValueFormatter) []Tick { + step := ya.getTickStep(r, ra, defaults, vf) ticks := GenerateTicksWithStep(ra, step, vf) return ticks } -func (ya YAxis) getTickStep(r Renderer, ra Range, vf ValueFormatter) float64 { - tickCount := ya.getTickCount(r, ra, vf) +func (ya YAxis) getTickStep(r Renderer, ra Range, defaults Style, vf ValueFormatter) float64 { + tickCount := ya.getTickCount(r, ra, defaults, vf) step := ra.Delta() / float64(tickCount) return step } -func (ya YAxis) getTickCount(r Renderer, ra Range, vf ValueFormatter) int { +func (ya YAxis) getTickCount(r Renderer, ra Range, defaults Style, vf ValueFormatter) int { + r.SetFont(ya.Style.GetFont(defaults.GetFont())) + r.SetFontSize(ya.Style.GetFontSize(defaults.GetFontSize(DefaultFontSize))) //given the domain, figure out how many ticks we can draw ... label := vf(ra.Min) tb := r.MeasureText(label) @@ -127,7 +129,7 @@ func (ya YAxis) Render(r Renderer, canvasBox Box, ra Range, defaults Style, tick r.SetStrokeWidth(ya.Style.GetStrokeWidth(defaults.StrokeWidth)) r.SetFont(ya.Style.GetFont(defaults.GetFont())) r.SetFontColor(ya.Style.GetFontColor(DefaultAxisColor)) - r.SetFontSize(ya.Style.GetFontSize(defaults.GetFontSize())) + r.SetFontSize(ya.Style.GetFontSize(defaults.GetFontSize(DefaultFontSize))) sort.Sort(Ticks(ticks)) diff --git a/yaxis_test.go b/yaxis_test.go new file mode 100644 index 0000000..de0b032 --- /dev/null +++ b/yaxis_test.go @@ -0,0 +1,89 @@ +package chart + +import ( + "testing" + + "github.com/blendlabs/go-assert" +) + +func TestYAxisGetTickCount(t *testing.T) { + assert := assert.New(t) + + r, err := PNG(1024, 1024) + assert.Nil(err) + + f, err := GetDefaultFont() + assert.Nil(err) + + ya := YAxis{} + yr := Range{Min: 10, Max: 100, Domain: 1024} + styleDefaults := Style{ + Font: f, + FontSize: 10.0, + } + vf := FloatValueFormatter + count := ya.getTickCount(r, yr, styleDefaults, vf) + assert.Equal(34, count) +} + +func TestYAxisGetTickStep(t *testing.T) { + assert := assert.New(t) + + r, err := PNG(1024, 1024) + assert.Nil(err) + + f, err := GetDefaultFont() + assert.Nil(err) + + ya := YAxis{} + yr := Range{Min: 10, Max: 100, Domain: 1024} + styleDefaults := Style{ + Font: f, + FontSize: 10.0, + } + vf := FloatValueFormatter + step := ya.getTickStep(r, yr, styleDefaults, vf) + assert.Equal(yr.Delta()/34.0, step) +} + +func TestYAxisGetTicks(t *testing.T) { + assert := assert.New(t) + + r, err := PNG(1024, 1024) + assert.Nil(err) + + f, err := GetDefaultFont() + assert.Nil(err) + + ya := YAxis{} + yr := Range{Min: 10, Max: 100, Domain: 1024} + styleDefaults := Style{ + Font: f, + FontSize: 10.0, + } + vf := FloatValueFormatter + ticks := ya.GetTicks(r, yr, styleDefaults, vf) + assert.Len(ticks, 35) +} + +func TestYAxisGetTicksWithUserDefaults(t *testing.T) { + assert := assert.New(t) + + r, err := PNG(1024, 1024) + assert.Nil(err) + + f, err := GetDefaultFont() + assert.Nil(err) + + ya := YAxis{ + Ticks: []Tick{Tick{Value: 1.0, Label: "1.0"}}, + } + yr := Range{Min: 10, Max: 100, Domain: 1024} + styleDefaults := Style{ + Font: f, + FontSize: 10.0, + } + vf := FloatValueFormatter + ticks := ya.GetTicks(r, yr, styleDefaults, vf) + assert.Len(ticks, 1) +}