Skip to content

Commit

Permalink
mini chart utils
Browse files Browse the repository at this point in the history
  • Loading branch information
kevincobain2000 committed Jan 29, 2024
1 parent eb40795 commit a6f8317
Show file tree
Hide file tree
Showing 4 changed files with 146 additions and 111 deletions.
29 changes: 19 additions & 10 deletions pkg/bar_chart.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,25 @@ func NewBarChart() *BarChart {
}

func (c *BarChart) GetVertical(xData []string, yData [][]float64, names []string, req *ChartRequest) ([]byte, error) {
isMini := IsMiniChart(req)
showLegend := true
paddings := GetPaddings(req)
titleSizes := GetTitleSizes(req)
if isMini {
showLegend = false
}
p, err := charts.BarRender(
yData,
charts.TitleOptionFunc(charts.TitleOption{
Text: req.ChartTitle,
Subtext: req.ChartSubtitle,
SubtextFontSize: DEFAULT_SUBTITLE_FONT_SIZE,
Left: charts.PositionCenter,
SubtextFontColor: DEFAULT_SUBTITLE_COLOR,
}),
charts.TitleOptionFunc(titleSizes),
charts.HeightOptionFunc(req.Height),
charts.WidthOptionFunc(req.Width),
charts.PaddingOptionFunc(paddings),
charts.XAxisDataOptionFunc(xData),
charts.LegendOptionFunc(charts.LegendOption{
Orient: charts.OrientHorizontal,
Data: names,
Left: charts.PositionLeft,
Show: &showLegend,
}),
charts.MarkLineOptionFunc(0, charts.SeriesMarkDataTypeAverage),
charts.MarkPointOptionFunc(0, charts.SeriesMarkDataTypeMax,
Expand All @@ -47,7 +50,11 @@ func (c *BarChart) GetVertical(xData []string, yData [][]float64, names []string
Bottom: DEFAULT_PADDING_BOTTOM,
}
opt.ValueFormatter = func(f float64) string {
if isMini {
return "-"
}
return fmt.Sprintf("%s %s", NumberToK(&f), req.Metric)

}
idx := len(opt.SeriesList) - 1
if len(opt.SeriesList) > 1 {
Expand All @@ -57,9 +64,11 @@ func (c *BarChart) GetVertical(xData []string, yData [][]float64, names []string
charts.SeriesMarkDataTypeMax,
charts.SeriesMarkDataTypeMin,
)
opt.SeriesList[idx].MarkLine = charts.NewMarkLine(
charts.SeriesMarkDataTypeAverage,
)
if !isMini {
opt.SeriesList[idx].MarkLine = charts.NewMarkLine(
charts.SeriesMarkDataTypeAverage,
)
}
},
)
if err != nil {
Expand Down
106 changes: 39 additions & 67 deletions pkg/chart.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,9 @@ package pkg
import (
"errors"
"net/http"
"net/url"
"os"
"strconv"
"strings"

"github.com/imroc/req/v3"
charts "github.com/vicanso/go-charts/v2"
"github.com/wcharczuk/go-chart/v2/drawing"
)

Expand All @@ -19,6 +16,8 @@ const (
DEFAULT_PADDING_LEFT = 20
DEFAULT_TITLE_FONT_SIZE = 12
DEFAULT_SUBTITLE_FONT_SIZE = 10
MINI_CHART_WIDTH = 300
MINI_CHART_HEIGHT = 300

BAR_STYLE_VERTICAL = "vertical"
BAR_STYLE_HORIZONTAL = "horizontal"
Expand Down Expand Up @@ -89,44 +88,6 @@ func SetHeadersResponseTxt(header http.Header) {
header.Set("X-XSS-Protection", "1; mode=block")
}

func IsURL(urlStr string) bool {
parsedURL, err := url.ParseRequestURI(urlStr)
return err == nil && parsedURL.Scheme != "" && parsedURL.Host != ""
}

func IsAllowedDomain(urlStr string, allowedDomains string) bool {
if allowedDomains == "" {
return false // default do not allow any urls
}

// Parse the URL to extract the domain
parsedURL, err := url.Parse(urlStr)
if err != nil {
return false // If the URL is invalid, do not allow
}
domain := parsedURL.Hostname()

// Split the allowedDomains into a slice
domains := strings.Split(allowedDomains, ",")

// Check if the domain is in the list of allowed domains
for _, d := range domains {
if domain == d {
return true
}
}

return false
}

func GetURL(urlStr string) (string, error) {
resp, err := req.Get(urlStr)
if err != nil {
return "", err
}
return resp.ToString()
}

func SetDataIfRemoteURL(req *ChartRequest) error {
allowedRemoteDomains := os.Getenv("ALLOWED_REMOTE_DOMAINS")
if allowedRemoteDomains == "" {
Expand All @@ -145,35 +106,46 @@ func SetDataIfRemoteURL(req *ChartRequest) error {
return nil
}

// NumberToK converts a number to a string with 'k' for thousands and 'm' for millions.
func NumberToK(num *float64) string {
if num == nil {
return "0"
}

formatNumber := func(n float64) string {
if n == float64(int64(n)) {
// If n is an integer, format without decimal places.
return strconv.FormatFloat(n, 'f', 0, 64)
}
// Otherwise, format with one decimal place.
return strconv.FormatFloat(n, 'f', 1, 64)
}
func IsMiniChart(req *ChartRequest) bool {
return req.Width <= MINI_CHART_WIDTH && req.Height <= MINI_CHART_HEIGHT
}

if *num < 1000 {
return formatNumber(*num)
func GetPaddings(req *ChartRequest) charts.Box {
paddings := charts.Box{
Top: 10,
Bottom: 10,
Left: 10,
Right: 10,
}

if *num < 1000000 {
return formatNumber(*num/1000) + "k"
if IsMiniChart(req) {
paddings = charts.Box{
Top: 10,
Bottom: -20,
Left: -10,
Right: 10,
}
}

return formatNumber(*num/1000000) + "m"
return paddings
}

func Truncate(s string, max int) string {
if len(s) > max {
return s[:max] + "..."
func GetTitleSizes(req *ChartRequest) charts.TitleOption {
titleSizes := charts.TitleOption{
Text: req.ChartTitle,
Subtext: req.ChartSubtitle,
FontSize: DEFAULT_TITLE_FONT_SIZE,
SubtextFontSize: DEFAULT_SUBTITLE_FONT_SIZE,
Left: charts.PositionCenter,
SubtextFontColor: DEFAULT_SUBTITLE_COLOR,
}
if IsMiniChart(req) {
titleSizes = charts.TitleOption{
Text: Truncate(req.ChartTitle, 17),
Subtext: Truncate(req.ChartSubtitle, 17),
FontSize: DEFAULT_TITLE_FONT_SIZE,
SubtextFontSize: DEFAULT_SUBTITLE_FONT_SIZE,
Left: charts.PositionCenter,
SubtextFontColor: DEFAULT_SUBTITLE_COLOR,
}
}
return s
return titleSizes
}
42 changes: 8 additions & 34 deletions pkg/line_chart.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,43 +17,17 @@ func NewLineChart() *LineChart {
}

func (c *LineChart) Get(xData []string, yData [][]float64, names []string, req *ChartRequest) ([]byte, error) {
fill := true
fill := false
if req.Line == "fill" {
fill = true
}
isMini := false
isMini := IsMiniChart(req)

showLegend := true
paddings := charts.Box{
Top: 10,
Bottom: 10,
Left: 10,
Right: 10,
}
titleSizes := charts.TitleOption{
Text: req.ChartTitle,
Subtext: req.ChartSubtitle,
FontSize: DEFAULT_TITLE_FONT_SIZE,
SubtextFontSize: DEFAULT_SUBTITLE_FONT_SIZE,
Left: charts.PositionCenter,
SubtextFontColor: DEFAULT_SUBTITLE_COLOR,
}
if req.Width <= 300 && req.Height <= 300 {
paddings := GetPaddings(req)
titleSizes := GetTitleSizes(req)
if isMini {
showLegend = false
isMini = true
paddings = charts.Box{
Top: 10,
Bottom: -20,
Left: -10,
Right: 10,
}
titleSizes = charts.TitleOption{
Text: Truncate(req.ChartTitle, 17),
Subtext: Truncate(req.ChartSubtitle, 17),
FontSize: DEFAULT_TITLE_FONT_SIZE,
SubtextFontSize: DEFAULT_SUBTITLE_FONT_SIZE,
Left: charts.PositionCenter,
SubtextFontColor: DEFAULT_SUBTITLE_COLOR,
}
}
p, err := charts.LineRender(
yData,
Expand All @@ -72,8 +46,8 @@ func (c *LineChart) Get(xData []string, yData [][]float64, names []string, req *
opt.Type = req.Output
opt.Theme = req.Theme
opt.Legend.Padding = charts.Box{
Top: 0,
Bottom: 0,
Top: DEFAULT_PADDING_TOP * 2,
Bottom: DEFAULT_PADDING_BOTTOM,
}
opt.ValueFormatter = func(f float64) string {
if isMini {
Expand Down
80 changes: 80 additions & 0 deletions pkg/util.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package pkg

import (
"net/url"
"strconv"
"strings"

"github.com/imroc/req/v3"
)

func IsURL(urlStr string) bool {
parsedURL, err := url.ParseRequestURI(urlStr)
return err == nil && parsedURL.Scheme != "" && parsedURL.Host != ""
}

func IsAllowedDomain(urlStr string, allowedDomains string) bool {
if allowedDomains == "" {
return false // default do not allow any urls
}

// Parse the URL to extract the domain
parsedURL, err := url.Parse(urlStr)
if err != nil {
return false // If the URL is invalid, do not allow
}
domain := parsedURL.Hostname()

// Split the allowedDomains into a slice
domains := strings.Split(allowedDomains, ",")

// Check if the domain is in the list of allowed domains
for _, d := range domains {
if domain == d {
return true
}
}

return false
}

func GetURL(urlStr string) (string, error) {
resp, err := req.Get(urlStr)
if err != nil {
return "", err
}
return resp.ToString()
}

// NumberToK converts a number to a string with 'k' for thousands and 'm' for millions.
func NumberToK(num *float64) string {
if num == nil {
return "0"
}

formatNumber := func(n float64) string {
if n == float64(int64(n)) {
// If n is an integer, format without decimal places.
return strconv.FormatFloat(n, 'f', 0, 64)
}
// Otherwise, format with one decimal place.
return strconv.FormatFloat(n, 'f', 1, 64)
}

if *num < 1000 {
return formatNumber(*num)
}

if *num < 1000000 {
return formatNumber(*num/1000) + "k"
}

return formatNumber(*num/1000000) + "m"
}

func Truncate(s string, max int) string {
if len(s) > max {
return s[:max] + "..."
}
return s
}

0 comments on commit a6f8317

Please sign in to comment.