123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132 |
- // Copyright (C) 2018 The Syncthing Authors.
- //
- // This Source Code Form is subject to the terms of the Mozilla Public
- // License, v. 2.0. If a copy of the MPL was not distributed with this file,
- // You can obtain one at https://mozilla.org/MPL/2.0/.
- package serve
- import (
- "bytes"
- "fmt"
- "strings"
- )
- type NumberType int
- const (
- NumberMetric NumberType = iota
- NumberBinary
- NumberDuration
- )
- func number(ntype NumberType, v float64) string {
- switch ntype {
- case NumberMetric:
- return metric(v)
- case NumberDuration:
- return duration(v)
- case NumberBinary:
- return binary(v)
- default:
- return metric(v)
- }
- }
- type suffix struct {
- Suffix string
- Multiplier float64
- }
- var metricSuffixes = []suffix{
- {"G", 1e9},
- {"M", 1e6},
- {"k", 1e3},
- }
- var binarySuffixes = []suffix{
- {"Gi", 1 << 30},
- {"Mi", 1 << 20},
- {"Ki", 1 << 10},
- }
- var durationSuffix = []suffix{
- {"year", 365 * 24 * 60 * 60},
- {"month", 30 * 24 * 60 * 60},
- {"day", 24 * 60 * 60},
- {"hour", 60 * 60},
- {"minute", 60},
- {"second", 1},
- }
- func metric(v float64) string {
- return withSuffix(v, metricSuffixes, false)
- }
- func binary(v float64) string {
- return withSuffix(v, binarySuffixes, false)
- }
- func duration(v float64) string {
- return withSuffix(v, durationSuffix, true)
- }
- func withSuffix(v float64, ps []suffix, pluralize bool) string {
- for _, p := range ps {
- if v >= p.Multiplier {
- suffix := p.Suffix
- if pluralize && v/p.Multiplier != 1.0 {
- suffix += "s"
- }
- // If the number only has decimal zeroes, strip em off.
- num := strings.TrimRight(strings.TrimRight(fmt.Sprintf("%.1f", v/p.Multiplier), "0"), ".")
- return fmt.Sprintf("%s %s", num, suffix)
- }
- }
- return strings.TrimRight(strings.TrimRight(fmt.Sprintf("%.1f", v), "0"), ".")
- }
- // commatize returns a number with sep as thousands separators. Handles
- // integers and plain floats.
- func commatize(sep, s string) string {
- // If no dot, don't do anything.
- if !strings.ContainsRune(s, '.') {
- return s
- }
- var b bytes.Buffer
- fs := strings.SplitN(s, ".", 2)
- l := len(fs[0])
- for i := range fs[0] {
- b.Write([]byte{s[i]})
- if i < l-1 && (l-i)%3 == 1 {
- b.WriteString(sep)
- }
- }
- if len(fs) > 1 && len(fs[1]) > 0 {
- b.WriteString(".")
- b.WriteString(fs[1])
- }
- return b.String()
- }
- func proportion(m map[string]int, count int) float64 {
- total := 0
- isMax := true
- for _, n := range m {
- total += n
- if n > count {
- isMax = false
- }
- }
- pct := (100 * float64(count)) / float64(total)
- // To avoid rounding errors in the template, surpassing 100% and breaking
- // the progress bars.
- if isMax && len(m) > 1 && count != total {
- pct -= 0.01
- }
- return pct
- }
|