193 lines
4.5 KiB
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
|
|
}
|
|
|
|
|
|
|
|
|