aboutsummaryrefslogblamecommitdiffstats
path: root/vendor/github.com/gizak/termui/barchart.go
blob: 6560c8b14e462954d078d0101416d17ba30318c0 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
                                                                       











                                                                
                               
















                                   
                       









                                                          


                                                    

                       
                         



                              
                                                                 



















                                                                                                                                                       
                                                                 









                                        

                                     




                                                                                      











                                                                             


                                                  
                                          


                                                        
                                 
 


                                                                                       




                                                              







                                                                       



                                                         


                                                     
                                          
                         
 
                                   
                                            
                         


                                                                                               


                 
                  
 
// Copyright 2017 Zack Guo <zack.y.guo@gmail.com>. All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.

package termui

import "fmt"

// BarChart creates multiple bars in a widget:
/*
   bc := termui.NewBarChart()
   data := []int{3, 2, 5, 3, 9, 5}
   bclabels := []string{"S0", "S1", "S2", "S3", "S4", "S5"}
   bc.BorderLabel = "Bar Chart"
   bc.Data = data
   bc.Width = 26
   bc.Height = 10
   bc.DataLabels = bclabels
   bc.TextColor = termui.ColorGreen
   bc.BarColor = termui.ColorRed
   bc.NumColor = termui.ColorYellow
*/
type BarChart struct {
    Block
    BarColor   Attribute
    TextColor  Attribute
    NumColor   Attribute
    Data       []int
    DataLabels []string
    BarWidth   int
    BarGap     int
    CellChar   rune
    labels     [][]rune
    dataNum    [][]rune
    numBar     int
    scale      float64
    max        int
}

// NewBarChart returns a new *BarChart with current theme.
func NewBarChart() *BarChart {
    bc := &BarChart{Block: *NewBlock()}
    bc.BarColor = ThemeAttr("barchart.bar.bg")
    bc.NumColor = ThemeAttr("barchart.num.fg")
    bc.TextColor = ThemeAttr("barchart.text.fg")
    bc.BarGap = 1
    bc.BarWidth = 3
    bc.CellChar = ' '
    return bc
}

func (bc *BarChart) layout() {
    bc.numBar = bc.innerArea.Dx() / (bc.BarGap + bc.BarWidth)
    bc.labels = make([][]rune, bc.numBar)
    bc.dataNum = make([][]rune, len(bc.Data))

    for i := 0; i < bc.numBar && i < len(bc.DataLabels) && i < len(bc.Data); i++ {
        bc.labels[i] = trimStr2Runes(bc.DataLabels[i], bc.BarWidth)
        n := bc.Data[i]
        s := fmt.Sprint(n)
        bc.dataNum[i] = trimStr2Runes(s, bc.BarWidth)
    }

    //bc.max = bc.Data[0] //  what if Data is nil? Sometimes when bar graph is nill it produces panic with panic: runtime error: index out of range
    // Asign a negative value to get maxvalue auto-populates
    if bc.max == 0 {
        bc.max = -1
    }
    for i := 0; i < len(bc.Data); i++ {
        if bc.max < bc.Data[i] {
            bc.max = bc.Data[i]
        }
    }
    bc.scale = float64(bc.max) / float64(bc.innerArea.Dy()-1)
}

func (bc *BarChart) SetMax(max int) {

    if max > 0 {
        bc.max = max
    }
}

// Buffer implements Bufferer interface.
func (bc *BarChart) Buffer() Buffer {
    buf := bc.Block.Buffer()
    bc.layout()

    for i := 0; i < bc.numBar && i < len(bc.Data) && i < len(bc.DataLabels); i++ {
        h := int(float64(bc.Data[i]) / bc.scale)
        oftX := i * (bc.BarWidth + bc.BarGap)

        barBg := bc.Bg
        barFg := bc.BarColor

        if bc.CellChar == ' ' {
            barBg = bc.BarColor
            barFg = ColorDefault
            if bc.BarColor == ColorDefault { // the same as above
                barBg |= AttrReverse
            }
        }

        // plot bar
        for j := 0; j < bc.BarWidth; j++ {
            for k := 0; k < h; k++ {
                c := Cell{
                    Ch: bc.CellChar,
                    Bg: barBg,
                    Fg: barFg,
                }

                x := bc.innerArea.Min.X + i*(bc.BarWidth+bc.BarGap) + j
                y := bc.innerArea.Min.Y + bc.innerArea.Dy() - 2 - k
                buf.Set(x, y, c)
            }
        }
        // plot text
        for j, k := 0, 0; j < len(bc.labels[i]); j++ {
            w := charWidth(bc.labels[i][j])
            c := Cell{
                Ch: bc.labels[i][j],
                Bg: bc.Bg,
                Fg: bc.TextColor,
            }
            y := bc.innerArea.Min.Y + bc.innerArea.Dy() - 1
            x := bc.innerArea.Min.X + oftX + k
            buf.Set(x, y, c)
            k += w
        }
        // plot num
        for j := 0; j < len(bc.dataNum[i]); j++ {
            c := Cell{
                Ch: bc.dataNum[i][j],
                Fg: bc.NumColor,
                Bg: barBg,
            }

            if h == 0 {
                c.Bg = bc.Bg
            }
            x := bc.innerArea.Min.X + oftX + (bc.BarWidth-len(bc.dataNum[i]))/2 + j
            y := bc.innerArea.Min.Y + bc.innerArea.Dy() - 2
            buf.Set(x, y, c)
        }
    }

    return buf
}