diff --git a/component/barchart/barchart.go b/component/barchart/barchart.go index 12d9080..5803ae6 100644 --- a/component/barchart/barchart.go +++ b/component/barchart/barchart.go @@ -11,7 +11,6 @@ import ( "github.com/sqshq/sampler/data" "image" "math" - "strconv" ) const ( @@ -149,9 +148,9 @@ func (b *BarChart) Draw(buffer *ui.Buffer) { image.Pt(labelXCoordinate, b.Inner.Max.Y-1)) // draw value & delta - value := formatValue(bar.value, b.scale) + value := util.FormatValue(bar.value, b.scale) if bar.delta != 0 { - value = fmt.Sprintf("%s / %s", value, formatValueWithSign(bar.delta, b.scale)) + value = fmt.Sprintf("%s / %s", value, util.FormatValueWithSign(bar.delta, b.scale)) } valueXCoordinate := barXCoordinate + int(float64(barWidth)/2) - @@ -166,24 +165,3 @@ func (b *BarChart) Draw(buffer *ui.Buffer) { component.RenderAlert(b.alert, b.Rectangle, buffer) } - -// TODO extract to utils -func formatValue(value float64, scale int) string { - if math.Abs(value) == math.MaxFloat64 { - return "Inf" - } else { - format := "%." + strconv.Itoa(scale) + "f" - return fmt.Sprintf(format, value) - } -} - -// TODO extract to utils -func formatValueWithSign(value float64, scale int) string { - if value == 0 { - return " 0" - } else if value > 0 { - return "+" + formatValue(value, scale) - } else { - return formatValue(value, scale) - } -} diff --git a/component/gauge/gauge.go b/component/gauge/gauge.go index 110fc30..afddf28 100644 --- a/component/gauge/gauge.go +++ b/component/gauge/gauge.go @@ -9,8 +9,6 @@ import ( "github.com/sqshq/sampler/console" "github.com/sqshq/sampler/data" "image" - "math" - "strconv" ) const ( @@ -89,7 +87,7 @@ func (g *Gauge) Draw(buffer *ui.Buffer) { percent = (100 * g.curValue) / (g.maxValue - g.minValue) } - label := fmt.Sprintf("%v%% (%v)", formatValue(percent, g.scale), g.curValue) + label := fmt.Sprintf("%v%% (%v)", util.FormatValue(percent, g.scale), g.curValue) // draw bar barWidth := int((percent / 100) * float64(g.Inner.Dx())) @@ -118,13 +116,3 @@ func (g *Gauge) Draw(buffer *ui.Buffer) { component.RenderAlert(g.alert, g.Rectangle, buffer) } - -// TODO extract to utils -func formatValue(value float64, scale int) string { - if math.Abs(value) == math.MaxFloat64 { - return "Inf" - } else { - format := "%." + strconv.Itoa(scale) + "f" - return fmt.Sprintf(format, value) - } -} diff --git a/component/util/format.go b/component/util/format.go index fa692e3..22aca80 100644 --- a/component/util/format.go +++ b/component/util/format.go @@ -1,17 +1,17 @@ package util import ( - "fmt" + "bytes" "math" "strconv" + "strings" ) func FormatValue(value float64, scale int) string { if math.Abs(value) == math.MaxFloat64 { return "Inf" } else { - format := "%." + strconv.Itoa(scale) + "f" - return fmt.Sprintf(format, value) + return formatTrailingDigits(addRadixChars(value), scale) } } @@ -24,3 +24,53 @@ func FormatValueWithSign(value float64, scale int) string { return FormatValue(value, scale) } } + +func addRadixChars(value float64) string { + buf := &bytes.Buffer{} + if value < 0 { + buf.Write([]byte{'-'}) + value = 0 - value + } + + radix := []byte{','} + + parts := strings.Split(strconv.FormatFloat(value, 'f', -1, 64), ".") + pos := 0 + if len(parts[0])%3 != 0 { + pos += len(parts[0]) % 3 + buf.WriteString(parts[0][:pos]) + buf.Write(radix) + } + for ; pos < len(parts[0]); pos += 3 { + buf.WriteString(parts[0][pos : pos+3]) + buf.Write(radix) + } + buf.Truncate(buf.Len() - 1) + + if len(parts) > 1 { + buf.Write([]byte{'.'}) + buf.WriteString(parts[1]) + } + return buf.String() +} + +func formatTrailingDigits(value string, scale int) string { + + if i := strings.Index(value, "."); i >= 0 { + + formatted := value + + if scale <= 0 { + formatted = value[:i] + } + + i++ + if i+scale < len(value) { + formatted = value[:i+scale] + } + + return strings.TrimRight(formatted, "0.") + } + + return value +}