seekia/internal/createCharts/createCharts.go

193 lines
4.5 KiB
Go

// charts provides functions to create charts
// These are used to show statistics about users
// See userStatistics.go to see how input statistics are created
package createCharts
import "seekia/internal/profiles/userStatistics"
import goChart "github.com/wcharczuk/go-chart/v2"
import "github.com/wcharczuk/go-chart/v2/drawing"
import "image"
import "errors"
// Inputs:
// -string: Chart title
// -[]userStatistics.StatisticsItem: Statistics items list
// -func(float64)(string, error): formatYAxisValuesFunction
// -This will take values such as 1000000 and turn them to "1 million"
// -bool: Y-axis units exist
// -string: Y-axis units (example: " Users")
// Outputs:
// -image.Image
// -error
func CreateBarChart(chartTitle string, chartStatisticsItemsList []userStatistics.StatisticsItem, formatYAxisValuesFunction func(float64)(string, error), yAxisUnitsProvided bool, yAxisUnits string)(image.Image, error){
if (len(chartStatisticsItemsList) == 0) {
return nil, errors.New("CreateBarChart called with empty chartStatisticsItemsList")
}
chartItemsList := make([]goChart.Value, 0, len(chartStatisticsItemsList))
for _, statisticsItem := range chartStatisticsItemsList{
itemLabel := statisticsItem.LabelFormatted
itemValue := statisticsItem.Value
// We make sure this function does not error
_, err := formatYAxisValuesFunction(itemValue)
if (err != nil){
return nil, errors.New("Invalid chartStatisticsItemsList: Item value is invalid. Reason: " + err.Error())
}
newChartValue := goChart.Value{
Label: itemLabel,
Value: itemValue,
}
chartItemsList = append(chartItemsList, newChartValue)
}
if (len(chartItemsList) == 1){
// This package cannot create bar charts with only 1 item
// Thus, we must add an empty item
newChartValue := goChart.Value{
Style: goChart.Style{
StrokeColor: drawing.ColorWhite,
FillColor: drawing.ColorWhite,
},
Label: "",
Value: .001,
}
chartItemsList = append(chartItemsList, newChartValue)
}
chartStyleObject := goChart.Style{
Padding: goChart.Box{
Top: 40,
Bottom: 0,
Left: 0,
Right: 0,
},
}
titleStyleObject := goChart.Style{
Padding: goChart.Box{
Top: 10,
Bottom: 30,
},
FontSize: 15,
FontColor: drawing.ColorBlack,
}
yAxisObject := goChart.YAxis{
ValueFormatter: func(v interface{}) string {
valueFloat64 := v.(float64)
valueFormatted, err := formatYAxisValuesFunction(valueFloat64)
if (err != nil){
return "ERROR"
}
if (yAxisUnitsProvided == false){
return valueFormatted
}
result := valueFormatted + yAxisUnits
return result
},
}
barChartObject := goChart.BarChart{
Title: chartTitle,
TitleStyle: titleStyleObject,
Background: chartStyleObject,
Height: 500,
BarWidth: 60,
Bars: chartItemsList,
YAxis: yAxisObject,
}
collector := &goChart.ImageWriter{}
barChartObject.Render(goChart.PNG, collector)
goImage, err := collector.Image()
if (err != nil) { return nil, err }
return goImage, nil
}
func CreateDonutChart(chartTitle string, chartStatisticsItemsList []userStatistics.StatisticsItem)(image.Image, error){
if (len(chartStatisticsItemsList) == 0) {
return nil, errors.New("CreateDonutChart called with empty chartStatisticsItemsList")
}
chartItemsList := make([]goChart.Value, 0, len(chartStatisticsItemsList))
for _, statisticsItem := range chartStatisticsItemsList{
itemLabel := statisticsItem.LabelFormatted
// Value is always a number representing the percentage of the donut
itemValue := statisticsItem.Value
newChartValue := goChart.Value{
Label: itemLabel,
Value: itemValue,
}
chartItemsList = append(chartItemsList, newChartValue)
}
chartStyleObject := goChart.Style{
Padding: goChart.Box{
Top: 20,
Bottom: 0,
Left: 0,
Right: 0,
},
}
titleStyleObject := goChart.Style{
FontSize: 15,
FontColor: drawing.ColorBlack,
}
donutChartObject := goChart.DonutChart{
Title: chartTitle,
TitleStyle: titleStyleObject,
Background: chartStyleObject,
Height: 500,
Values: chartItemsList,
}
if (len(chartItemsList) == 1){
// Default is transparent, we need to add color
sliceStyleObject := goChart.Style{
FillColor: drawing.ColorRed,
}
donutChartObject.SliceStyle = sliceStyleObject
}
collector := &goChart.ImageWriter{}
donutChartObject.Render(goChart.PNG, collector)
goImage, err := collector.Image()
if (err != nil) { return nil, err }
return goImage, nil
}