1
0
mirror of https://github.com/mum4k/termdash.git synced 2025-04-28 13:48:51 +08:00

Add round and suffix based value formatter for the Y-axis label representation

Signed-off-by: Xabier Larrakoetxea <slok69@gmail.com>
This commit is contained in:
Xabier Larrakoetxea 2019-05-06 07:56:04 +02:00
parent 38f40428a1
commit a5c7363f43
No known key found for this signature in database
GPG Key ID: FDAD7FD8275E1B32
2 changed files with 133 additions and 8 deletions

View File

@ -20,6 +20,7 @@ package linechart
import (
"fmt"
"math"
"strings"
"time"
)
@ -42,33 +43,34 @@ func durationSingleUnitPrettyFormat(d time.Duration, decimals int) string {
return fmt.Sprintf(dFmt, d.Nanoseconds())
// Microseconds.
case d.Seconds()*1000*1000 < 1000:
dFmt := prefix + decimalFormat(decimals, "µs")
dFmt := prefix + suffixDecimalFormat(decimals, "µs")
return fmt.Sprintf(dFmt, d.Seconds()*1000*1000)
// Milliseconds.
case d.Seconds()*1000 < 1000:
dFmt := prefix + decimalFormat(decimals, "ms")
dFmt := prefix + suffixDecimalFormat(decimals, "ms")
return fmt.Sprintf(dFmt, d.Seconds()*1000)
// Seconds.
case d.Seconds() < 60:
dFmt := prefix + decimalFormat(decimals, "s")
dFmt := prefix + suffixDecimalFormat(decimals, "s")
return fmt.Sprintf(dFmt, d.Seconds())
// Minutes.
case d.Minutes() < 60:
dFmt := prefix + decimalFormat(decimals, "m")
dFmt := prefix + suffixDecimalFormat(decimals, "m")
return fmt.Sprintf(dFmt, d.Minutes())
// Hours.
case d.Hours() < 24:
dFmt := prefix + decimalFormat(decimals, "h")
dFmt := prefix + suffixDecimalFormat(decimals, "h")
return fmt.Sprintf(dFmt, d.Hours())
// Days.
default:
dFmt := prefix + decimalFormat(decimals, "d")
dFmt := prefix + suffixDecimalFormat(decimals, "d")
return fmt.Sprintf(dFmt, d.Hours()/24)
}
}
func decimalFormat(decimals int, unit string) string {
return fmt.Sprintf("%%.%df%s", decimals, unit)
func suffixDecimalFormat(decimals int, suffix string) string {
suffix = strings.ReplaceAll(suffix, "%", "%%") // safe `%` character for fmt.
return fmt.Sprintf("%%.%df%s", decimals, suffix)
}
// ValueFormatterSingleUnitDuration is a factory to create a custom duration
@ -103,3 +105,42 @@ func ValueFormatterSingleUnitSeconds(seconds float64) string {
f := ValueFormatterSingleUnitDuration(time.Second, 0)
return f(seconds)
}
// ValueFormatterRound is a formatter that will receive a float64
// value and will round to the nearest value without decimals.
func ValueFormatterRound(value float64) string {
f := ValueFormatterRoundWithSuffix("")
return f(value)
}
// ValueFormatterRoundWithSuffix is a factory that returns a formatter
// that will receive a float64 value and will round to the nearest value
// without decimals adding a suffix to the final value string representation.
func ValueFormatterRoundWithSuffix(suffix string) ValueFormatter {
return valueFormatterSuffixWithTransformer(0, suffix, math.Round)
}
// ValueFormatterSuffix is a factory that returns a formatter
// that will receive a float64 value and return a string representation with
// the desired number of decimal truncated and a suffix.
func ValueFormatterSuffix(decimals int, suffix string) ValueFormatter {
return valueFormatterSuffixWithTransformer(decimals, suffix, nil)
}
// valueFormatterSuffixWithTransformer is a factory that returns a formatter
// that will apply a tranform function to the received value before
// returning the decimal with suffix representation.
func valueFormatterSuffixWithTransformer(decimals int, suffix string, transformFunc func(float64) float64) ValueFormatter {
dFmt := suffixDecimalFormat(decimals, suffix)
return func(value float64) string {
if math.IsNaN(value) {
return ""
}
if transformFunc != nil {
value = transformFunc(value)
}
return fmt.Sprintf(dFmt, value)
}
}

View File

@ -143,6 +143,90 @@ func TestFormatters(t *testing.T) {
formatter: ValueFormatterSingleUnitDuration(time.Nanosecond, 8),
want: "",
},
{
desc: "Round formatter handles NaN values",
value: math.NaN(),
formatter: ValueFormatterRound,
want: "",
},
{
desc: "Round formatter handles 0 values",
value: 0,
formatter: ValueFormatterRound,
want: "0",
},
{
desc: "Round formatter handles > x.5 values",
value: 96.7,
formatter: ValueFormatterRound,
want: "97",
},
{
desc: "Round formatter handles < x.5 values",
value: 1621.2,
formatter: ValueFormatterRound,
want: "1621",
},
{
desc: "Round formatter handles x.5 values",
value: 6.5,
formatter: ValueFormatterRound,
want: "7",
},
{
desc: "Round formatter handles minus > x.5 values",
value: -96.7,
formatter: ValueFormatterRound,
want: "-97",
},
{
desc: "Round formatter handles minus < x.5 values",
value: -1621.2,
formatter: ValueFormatterRound,
want: "-1621",
},
{
desc: "Round formatter handles minus x.5 values",
value: -6.5,
formatter: ValueFormatterRound,
want: "-7",
},
{
desc: "Round formatter handles values with suffix",
value: 96.7,
formatter: ValueFormatterRoundWithSuffix("km"),
want: "97km",
},
{
desc: "Suffix formatter handles values with decimals",
value: 11234567890.71234567890,
formatter: ValueFormatterSuffix(4, " reqps"),
want: "11234567890.7123 reqps",
},
{
desc: "Suffix formatter handles NaN values",
value: math.NaN(),
formatter: ValueFormatterSuffix(2, "test"),
want: "",
},
{
desc: "Suffix formatter handles 0 values",
value: 0,
formatter: ValueFormatterSuffix(2, "test"),
want: "0.00test",
},
{
desc: "Suffix formatters handles correctly percent suffix",
value: 96.78,
formatter: ValueFormatterSuffix(2, "%"),
want: "96.78%",
},
{
desc: "Round formatter handles values with percent suffix",
value: 96.7,
formatter: ValueFormatterRoundWithSuffix("%"),
want: "97%",
},
}
for _, tc := range tests {