1
0
mirror of https://github.com/mum4k/termdash.git synced 2025-05-04 22:18:07 +08:00

Refactoring y.Details off the object.

This commit is contained in:
Jakub Sobon 2019-02-15 21:19:04 -05:00
parent 9b3edb42b9
commit feb406ec11
No known key found for this signature in database
GPG Key ID: F2451A77FB05D3B7
3 changed files with 111 additions and 85 deletions

View File

@ -88,19 +88,30 @@ func RequiredWidth(minVal, maxVal float64) int {
}) + axisWidth }) + axisWidth
} }
// Details retrieves details about the Y axis required to draw it on a canvas // YProperties are the properties of the Y axis.
// of the provided area. type YProperties struct {
// The argument reqXHeight is the height required for the X axis and its labels. // Min is the minimum value on the axis.
func (y *Y) Details(cvsAr image.Rectangle, reqXHeight int, mode YScaleMode) (*YDetails, error) { Min float64
// Max is the maximum value on the axis.
Max float64
// ReqXHeight is the height required for the X axis and its labels.
ReqXHeight int
// ScaleMode determines how the Y axis scales.
ScaleMode YScaleMode
}
// NewYDetails retrieves details about the Y axis required to draw it on a
// canvas of the provided area.
func NewYDetails(cvsAr image.Rectangle, yp *YProperties) (*YDetails, error) {
cvsWidth := cvsAr.Dx() cvsWidth := cvsAr.Dx()
cvsHeight := cvsAr.Dy() cvsHeight := cvsAr.Dy()
maxWidth := cvsWidth - 1 // Reserve one column for the line chart itself. maxWidth := cvsWidth - 1 // Reserve one column for the line chart itself.
if req := RequiredWidth(y.min.Value, y.max.Value); maxWidth < req { if req := RequiredWidth(yp.Min, yp.Max); maxWidth < req {
return nil, fmt.Errorf("the available maxWidth %d is smaller than the reported required width %d", maxWidth, req) return nil, fmt.Errorf("the available maxWidth %d is smaller than the reported required width %d", maxWidth, req)
} }
graphHeight := cvsHeight - reqXHeight graphHeight := cvsHeight - yp.ReqXHeight
scale, err := NewYScale(y.min.Value, y.max.Value, graphHeight, nonZeroDecimals, mode) scale, err := NewYScale(yp.Min, yp.Max, graphHeight, nonZeroDecimals, yp.ScaleMode)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -28,51 +28,55 @@ type updateY struct {
func TestY(t *testing.T) { func TestY(t *testing.T) {
tests := []struct { tests := []struct {
desc string desc string
minVal float64 yp *YProperties
maxVal float64 cvsAr image.Rectangle
update *updateY wantWidth int
reqXHeight int want *YDetails
mode YScaleMode wantErr bool
cvsAr image.Rectangle
wantWidth int
want *YDetails
wantErr bool
}{ }{
{ {
desc: "fails on canvas too small", desc: "fails on canvas too small",
minVal: 0, yp: &YProperties{
maxVal: 3, Min: 0,
cvsAr: image.Rect(0, 0, 3, 2), Max: 3,
reqXHeight: 2, ReqXHeight: 2,
wantWidth: 2, },
wantErr: true, cvsAr: image.Rect(0, 0, 3, 2),
wantWidth: 2,
wantErr: true,
}, },
{ {
desc: "fails on cvsWidth less than required width", desc: "fails on cvsWidth less than required width",
minVal: 0, yp: &YProperties{
maxVal: 3, Min: 0,
cvsAr: image.Rect(0, 0, 2, 4), Max: 3,
reqXHeight: 2, ReqXHeight: 2,
wantWidth: 2, },
wantErr: true, cvsAr: image.Rect(0, 0, 2, 4),
wantWidth: 2,
wantErr: true,
}, },
{ {
desc: "fails when max is less than min", desc: "fails when max is less than min",
minVal: 0, yp: &YProperties{
maxVal: -1, Min: 0,
cvsAr: image.Rect(0, 0, 4, 4), Max: -1,
reqXHeight: 2, ReqXHeight: 2,
wantWidth: 3, },
wantErr: true, cvsAr: image.Rect(0, 0, 4, 4),
wantWidth: 3,
wantErr: true,
}, },
{ {
desc: "cvsWidth equals required width", desc: "cvsWidth equals required width",
minVal: 0, yp: &YProperties{
maxVal: 3, Min: 0,
cvsAr: image.Rect(0, 0, 3, 4), Max: 3,
wantWidth: 2, ReqXHeight: 2,
reqXHeight: 2, },
cvsAr: image.Rect(0, 0, 3, 4),
wantWidth: 2,
want: &YDetails{ want: &YDetails{
Width: 2, Width: 2,
Start: image.Point{1, 0}, Start: image.Point{1, 0},
@ -85,13 +89,15 @@ func TestY(t *testing.T) {
}, },
}, },
{ {
desc: "success for anchored scale", desc: "success for anchored scale",
minVal: 1, yp: &YProperties{
maxVal: 3, Min: 1,
mode: YScaleModeAnchored, Max: 3,
cvsAr: image.Rect(0, 0, 3, 4), ReqXHeight: 2,
reqXHeight: 2, ScaleMode: YScaleModeAnchored,
wantWidth: 2, },
cvsAr: image.Rect(0, 0, 3, 4),
wantWidth: 2,
want: &YDetails{ want: &YDetails{
Width: 2, Width: 2,
Start: image.Point{1, 0}, Start: image.Point{1, 0},
@ -104,13 +110,15 @@ func TestY(t *testing.T) {
}, },
}, },
{ {
desc: "accommodates X scale that needs more height", desc: "accommodates X scale that needs more height",
minVal: 1, yp: &YProperties{
maxVal: 3, Min: 1,
mode: YScaleModeAnchored, Max: 3,
cvsAr: image.Rect(0, 0, 3, 6), ReqXHeight: 4,
reqXHeight: 4, ScaleMode: YScaleModeAnchored,
wantWidth: 2, },
cvsAr: image.Rect(0, 0, 3, 6),
wantWidth: 2,
want: &YDetails{ want: &YDetails{
Width: 2, Width: 2,
Start: image.Point{1, 0}, Start: image.Point{1, 0},
@ -123,13 +131,15 @@ func TestY(t *testing.T) {
}, },
}, },
{ {
desc: "success for adaptive scale", desc: "success for adaptive scale",
minVal: 1, yp: &YProperties{
maxVal: 6, Min: 1,
mode: YScaleModeAdaptive, Max: 6,
cvsAr: image.Rect(0, 0, 3, 4), ReqXHeight: 2,
reqXHeight: 2, ScaleMode: YScaleModeAdaptive,
wantWidth: 2, },
cvsAr: image.Rect(0, 0, 3, 4),
wantWidth: 2,
want: &YDetails{ want: &YDetails{
Width: 2, Width: 2,
Start: image.Point{1, 0}, Start: image.Point{1, 0},
@ -142,12 +152,14 @@ func TestY(t *testing.T) {
}, },
}, },
{ {
desc: "cvsWidth just accommodates the longest label", desc: "cvsWidth just accommodates the longest label",
minVal: 0, yp: &YProperties{
maxVal: 3, Min: 0,
cvsAr: image.Rect(0, 0, 6, 4), Max: 3,
reqXHeight: 2, ReqXHeight: 2,
wantWidth: 2, },
cvsAr: image.Rect(0, 0, 6, 4),
wantWidth: 2,
want: &YDetails{ want: &YDetails{
Width: 5, Width: 5,
Start: image.Point{4, 0}, Start: image.Point{4, 0},
@ -160,12 +172,14 @@ func TestY(t *testing.T) {
}, },
}, },
{ {
desc: "cvsWidth is more than we need", desc: "cvsWidth is more than we need",
minVal: 0, yp: &YProperties{
maxVal: 3, Min: 0,
cvsAr: image.Rect(0, 0, 7, 4), Max: 3,
reqXHeight: 2, ReqXHeight: 2,
wantWidth: 2, },
cvsAr: image.Rect(0, 0, 7, 4),
wantWidth: 2,
want: &YDetails{ want: &YDetails{
Width: 5, Width: 5,
Start: image.Point{4, 0}, Start: image.Point{4, 0},
@ -181,17 +195,12 @@ func TestY(t *testing.T) {
for _, tc := range tests { for _, tc := range tests {
t.Run(tc.desc, func(t *testing.T) { t.Run(tc.desc, func(t *testing.T) {
y := NewY(tc.minVal, tc.maxVal) gotWidth := RequiredWidth(tc.yp.Min, tc.yp.Max)
if tc.update != nil {
y.Update(tc.update.minVal, tc.update.maxVal)
}
gotWidth := RequiredWidth(tc.minVal, tc.maxVal)
if gotWidth != tc.wantWidth { if gotWidth != tc.wantWidth {
t.Errorf("RequiredWidth => got %v, want %v", gotWidth, tc.wantWidth) t.Errorf("RequiredWidth => got %v, want %v", gotWidth, tc.wantWidth)
} }
got, err := y.Details(tc.cvsAr, tc.reqXHeight, tc.mode) got, err := NewYDetails(tc.cvsAr, tc.yp)
if (err != nil) != tc.wantErr { if (err != nil) != tc.wantErr {
t.Errorf("Details => unexpected error: %v, wantErr: %v", err, tc.wantErr) t.Errorf("Details => unexpected error: %v, wantErr: %v", err, tc.wantErr)
} }

View File

@ -212,7 +212,13 @@ func (lc *LineChart) Draw(cvs *canvas.Canvas) error {
} }
reqXHeight := axes.RequiredHeight(lc.maxPoints(), lc.xLabels, lc.opts.xLabelOrientation) reqXHeight := axes.RequiredHeight(lc.maxPoints(), lc.xLabels, lc.opts.xLabelOrientation)
yd, err := lc.yAxis.Details(cvs.Area(), reqXHeight, lc.opts.yAxisMode) yp := &axes.YProperties{
Min: lc.yMin,
Max: lc.yMax,
ReqXHeight: reqXHeight,
ScaleMode: lc.opts.yAxisMode,
}
yd, err := axes.NewYDetails(cvs.Area(), yp)
if err != nil { if err != nil {
return fmt.Errorf("lc.yAxis.Details => %v", err) return fmt.Errorf("lc.yAxis.Details => %v", err)
} }