diff --git a/widgets/heatmap/heatmap.go b/widgets/heatmap/heatmap.go index 6f6fac3..104121c 100644 --- a/widgets/heatmap/heatmap.go +++ b/widgets/heatmap/heatmap.go @@ -47,6 +47,10 @@ type HeatMap struct { // YLabels are the labels on the Y axis in an increasing order. YLabels []string + // MinValue and MaxValue are the Min and Max values in the values, + // which will be used to calculate the color of each cell. + MinValue, MaxValue float64 + // opts are the provided options. opts *options @@ -72,19 +76,20 @@ func (hp *HeatMap) axesDetails(cvs *canvas.Canvas) (*axes.XDetails, *axes.YDetai return nil, nil, errors.New("not implemented") } -// Draw draws the values as HeatMap. +// Draw draws cells, X labels and Y labels as HeatMap. // Implements widgetapi.Widget.Draw. func (hp *HeatMap) Draw(cvs *canvas.Canvas, meta *widgetapi.Meta) error { return errors.New("not implemented") } -// drawCells draws the graph representing the stored values. +// drawCells draws m*n cells (rectangles) representing the stored values. +// The height of each cell is 1 and the default width is 3. func (hp *HeatMap) drawCells(cvs *canvas.Canvas, xd *axes.XDetails, yd *axes.YDetails) error { return errors.New("not implemented") } -// drawAxes draws the X,Y axes and their labels. -func (hp *HeatMap) drawAxes(cvs *canvas.Canvas, xd *axes.XDetails, yd *axes.YDetails) error { +// drawAxes draws X labels (under the cells) and Y Labels (on the left side of the cell). +func (hp *HeatMap) drawLabels(cvs *canvas.Canvas, xd *axes.XDetails, yd *axes.YDetails) error { return errors.New("not implemented") } @@ -112,8 +117,8 @@ func (hp *HeatMap) Options() widgetapi.Options { // getCellColor returns the color of the cell according to its value. // The larger the value, the darker the color. +// The color range is in Xterm color, from 232 to 255. // Refer to https://jonasjacek.github.io/colors/. -// The color range is in Xterm color [232, 255]. func (hp *HeatMap) getCellColor(value float64) cell.Color { return cell.ColorDefault } diff --git a/widgets/heatmap/heatmapdemo/heatmapdemo.go b/widgets/heatmap/heatmapdemo/heatmapdemo.go index b749a96..c8114d7 100644 --- a/widgets/heatmap/heatmapdemo/heatmapdemo.go +++ b/widgets/heatmap/heatmapdemo/heatmapdemo.go @@ -27,47 +27,18 @@ import ( ) func main() { - xLabels := []string{ - "12:00", - "12:05", - "12:10", - "12:15", - "12:20", - } - yLabels := []string{ - "10", - "20", - "30", - "40", - "50", - "60", - "70", - "80", - "90", - "100", - } - values := map[string][]int64{ - "12:00": {10, 20, 30, 40, 50, 50, 40, 30, 20, 10}, - "12:05": {50, 40, 30, 20, 10, 10, 20, 30, 40, 50}, - "12:10": {10, 20, 30, 40, 50, 50, 40, 30, 20, 10}, - "12:15": {50, 40, 30, 20, 10, 10, 20, 30, 40, 50}, - "12:20": {10, 20, 30, 40, 50, 50, 40, 30, 0, 0}, - } - t, err := termbox.New() if err != nil { panic(err) } defer t.Close() - hp, err := heatmap.NewHeatMap() + hp, err := heatmap.New() if err != nil { panic(err) } - if err := hp.SetColumns(xLabels, values); err != nil { - panic(err) - } - hp.SetYLabels(yLabels) + + // TODO: set heatmap's data c, err := container.New( t, diff --git a/widgets/heatmap/internal/axes/axes.go b/widgets/heatmap/internal/axes/axes.go index b0c8448..eac6110 100644 --- a/widgets/heatmap/internal/axes/axes.go +++ b/widgets/heatmap/internal/axes/axes.go @@ -16,6 +16,7 @@ package axes import ( + "errors" "image" "github.com/mum4k/termdash/private/runewidth" @@ -24,7 +25,7 @@ import ( const AxisWidth = 1 // YDetails contain information about the Y axis -// that will be drawn onto the canvas. +// that will NOT be drawn onto the canvas, but will take up space. type YDetails struct { // Width in character cells of the Y axis and its character labels. Width int @@ -42,30 +43,15 @@ type YDetails struct { // RequiredWidth calculates the minimum width required // in order to draw the Y axis and its labels. -func RequiredWidth(max string) int { - return runewidth.StringWidth(max) + AxisWidth +// The parameter ls is the longest string in YLabels. +func RequiredWidth(ls string) int { + return runewidth.StringWidth(ls) + AxisWidth } // NewYDetails retrieves details about the Y axis required // to draw it on a canvas of the provided area. func NewYDetails(stringLabels []string) (*YDetails, error) { - graphHeight := len(stringLabels) - - // See how the labels would look like on the entire maxWidth. - maxLabelWidth := LongestString(stringLabels) - labels, err := yLabels(graphHeight, maxLabelWidth, stringLabels) - if err != nil { - return nil, err - } - - width := maxLabelWidth + 1 - - return &YDetails{ - Width: width, - Start: image.Point{X: width - 1, Y: 0}, - End: image.Point{X: width - 1, Y: graphHeight}, - Labels: labels, - }, nil + return nil, errors.New("not implemented") } // LongestString returns the length of the longest string in the string array. @@ -80,7 +66,7 @@ func LongestString(strings []string) int { } // XDetails contain information about the X axis -// that will be drawn onto the canvas. +// that will NOT be drawn onto the canvas. type XDetails struct { // Start is the point where the X axis starts. // Both coordinates of Start are less than End. @@ -94,23 +80,6 @@ type XDetails struct { // NewXDetails retrieves details about the X axis required to draw it on a canvas // of the provided area. The yStart is the point where the Y axis starts. -// The numPoints is the number of points in the largest series that will be -// plotted. -// customLabels are the desired labels for the X axis, these are preferred if -// provided. func NewXDetails(cvsAr image.Rectangle, yEnd image.Point, stringLabels []string, cellWidth int) (*XDetails, error) { - // The space between the start of the axis and the end of the canvas. - // graphWidth := cvsAr.Dx() - yEnd.X - 1 - graphWidth := len(stringLabels) * cellWidth - - labels, err := xLabels(yEnd, graphWidth, stringLabels, cellWidth) - if err != nil { - return nil, err - } - - return &XDetails{ - Start: image.Point{yEnd.X, yEnd.Y - 1}, - End: image.Point{yEnd.X + graphWidth, yEnd.Y - 1}, - Labels: labels, - }, nil + return nil, errors.New("not implemented") } diff --git a/widgets/heatmap/internal/axes/label.go b/widgets/heatmap/internal/axes/label.go index b5f7a71..9f11ded 100644 --- a/widgets/heatmap/internal/axes/label.go +++ b/widgets/heatmap/internal/axes/label.go @@ -17,11 +17,8 @@ package axes // label.go contains code that calculates the positions of labels on the axes. import ( - "fmt" + "errors" "image" - - "github.com/mum4k/termdash/align" - "github.com/mum4k/termdash/private/alignfor" ) // Label is one text label on an axis. @@ -33,74 +30,27 @@ type Label struct { Pos image.Point } -// yLabels returns labels that should be placed next to the Y axis. +// yLabels returns labels that should be placed next to the cells. // The labelWidth is the width of the area from the left-most side of the // canvas until the Y axis (not including the Y axis). This is the area where // the labels will be placed and aligned. // Labels are returned with Y coordinates in ascending order. // Y coordinates grow down. func yLabels(graphHeight, labelWidth int, stringLabels []string) ([]*Label, error) { - if min := 2; graphHeight < min { - return nil, fmt.Errorf("cannot place labels on a canvas with height %d, minimum is %d", graphHeight, min) - } - if min := 0; labelWidth < min { - return nil, fmt.Errorf("cannot place labels in label area width %d, minimum is %d", labelWidth, min) - } - - var labels []*Label - for row, l := range stringLabels { - label, err := rowLabel(row, l, labelWidth) - if err != nil { - return nil, err - } - - labels = append(labels, label) - } - - return labels, nil + return nil, errors.New("not implemented") } // rowLabel returns one label for the specified row. // The row is the Y coordinate of the row, Y coordinates grow down. func rowLabel(row int, label string, labelWidth int) (*Label, error) { - // The area available for the label - ar := image.Rect(0, row, labelWidth, row+1) - - pos, err := alignfor.Text(ar, label, align.HorizontalRight, align.VerticalMiddle) - if err != nil { - return nil, fmt.Errorf("unable to align the label value: %v", err) - } - - return &Label{ - Text: label, - Pos: pos, - }, nil + return nil, errors.New("not implemented") } -// xLabels returns labels that should be placed under the X axis. +// xLabels returns labels that should be placed under the cells. // Labels are returned with X coordinates in ascending order. // X coordinates grow right. func xLabels(yEnd image.Point, graphWidth int, stringLabels []string, cellWidth int) ([]*Label, error) { - var ret []*Label - - length, index := paddedLabelLength(graphWidth, LongestString(stringLabels), cellWidth) - - for x := yEnd.X + 1; x <= graphWidth && index < len(stringLabels); x += length { - ar := image.Rect(x, yEnd.Y, x+length, yEnd.Y+1) - pos, err := alignfor.Text(ar, stringLabels[index], align.HorizontalCenter, align.VerticalMiddle) - if err != nil { - return nil, fmt.Errorf("unable to align the label value: %v", err) - } - - l := &Label{ - Text: stringLabels[index], - Pos: pos, - } - index += length / cellWidth - ret = append(ret, l) - } - - return ret, nil + return nil, errors.New("not implemented") } // paddedLabelLength calculates the length of the padded label and @@ -110,13 +60,5 @@ func xLabels(yEnd image.Point, graphWidth int, stringLabels []string, cellWidth // the label belongs to the middle column of the three columns, // and the padded length is 3*3, which is 9. func paddedLabelLength(graphWidth, longest, cellWidth int) (l, index int) { - l, index = 0, 0 - for i := longest/cellWidth + 1; i < graphWidth/cellWidth; i++ { - if (i*cellWidth-longest)%2 == 0 { - l = i * cellWidth - index = i / 2 - break - } - } return } diff --git a/widgets/heatmap/options.go b/widgets/heatmap/options.go index 7970a7d..f8a28dc 100644 --- a/widgets/heatmap/options.go +++ b/widgets/heatmap/options.go @@ -28,6 +28,7 @@ type Option interface { // options stores the provided options. type options struct { + // The default value is 3 cellWidth int xLabelCellOpts []cell.Option yLabelCellOpts []cell.Option