github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/ui/src/util/format.ts (about)

     1  // Copyright 2018 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  export const kibi = 1024;
    12  export const byteUnits: string[] = ["B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"];
    13  export const durationUnits: string[] = ["ns", "µs", "ms", "s"];
    14  
    15  interface UnitValue {
    16    value: number;
    17    units: string;
    18  }
    19  
    20  // computePrefixExponent is used to compute an appopriate display unit for a value
    21  // for which the units have metric-style prefixes available. For example, the
    22  // value may be expressed in bytes, but we may want to display it on the graph
    23  // as a larger prefix unit (such as "kilobytes" or "gigabytes") in order to make
    24  // the numbers more readable.
    25  export function ComputePrefixExponent(value: number, prefixMultiple: number, prefixList: string[]) {
    26    // Compute the metric prefix that will be used to label the axis.
    27    let maxUnits = Math.abs(value);
    28    let prefixScale: number;
    29    for (prefixScale = 0;
    30         maxUnits >= prefixMultiple && prefixScale < (prefixList.length - 1);
    31         prefixScale++) {
    32      maxUnits /= prefixMultiple;
    33    }
    34    return prefixScale;
    35  }
    36  
    37  /**
    38   * ComputeByteScale calculates the appropriate scale factor and unit to use to
    39   * display a given byte value, without actually converting the value.
    40   *
    41   * This is used to prescale byte values before passing them to a d3-axis.
    42   */
    43  export function ComputeByteScale(bytes: number): UnitValue {
    44    const scale = ComputePrefixExponent(bytes, kibi, byteUnits);
    45    return {
    46      value: Math.pow(kibi, scale),
    47      units: byteUnits[scale],
    48    };
    49  }
    50  
    51  export function BytesToUnitValue(bytes: number): UnitValue {
    52    const scale = ComputeByteScale(bytes);
    53    return {
    54      value: bytes / scale.value,
    55      units: scale.units,
    56    };
    57  }
    58  
    59  /**
    60   * Bytes creates a string representation for a number of bytes. For
    61   * large numbers of bytes, the value will be converted into a large unit
    62   * (e.g. Kibibytes, Mebibytes).
    63   *
    64   * This function was adapted from
    65   * https://stackoverflow.com/questions/10420352/converting-file-size-in-bytes-to-human-readable
    66   */
    67  export function Bytes(bytes: number): string {
    68    return BytesWithPrecision(bytes, 1);
    69  }
    70  
    71  /**
    72   * BytesWithPrecision is like Bytes, but accepts a precision parameter
    73   * indicating how many digits after the decimal point are desired.
    74   */
    75  export function BytesWithPrecision(bytes: number, precision: number): string {
    76    const unitVal = BytesToUnitValue(bytes);
    77    if (!unitVal.value) {
    78      return "0 B";
    79    }
    80    return unitVal.value.toFixed(precision) + " " + unitVal.units;
    81  }
    82  
    83  /**
    84   * Cast bytes to provided scale units
    85   */
    86  // tslint:disable-next-line: variable-name
    87  export const BytesFitScale = (scale: string) => ( bytes: number) => {
    88    if (!bytes) {
    89      return `0.00 ${scale}`;
    90    }
    91    const n = byteUnits.indexOf(scale);
    92    return `${(bytes / Math.pow(kibi, n)).toFixed(2)} ${scale}`;
    93  };
    94  
    95  /**
    96   * Percentage creates a string representation of a fraction as a percentage.
    97   */
    98  export function Percentage(numerator: number, denominator: number): string {
    99    if (denominator === 0) {
   100      return "--%";
   101    }
   102    return Math.floor(numerator / denominator * 100).toString() + "%";
   103  }
   104  
   105  /**
   106   * ComputeDurationScale calculates an appropriate scale factor and unit to use
   107   * to display a given duration value, without actually converting the value.
   108   */
   109  export function ComputeDurationScale(nanoseconds: number): UnitValue {
   110    const scale = ComputePrefixExponent(nanoseconds, 1000, durationUnits);
   111    return {
   112      value: Math.pow(1000, scale),
   113      units: durationUnits[scale],
   114   };
   115  }
   116  
   117  /**
   118   * Duration creates a string representation for a duration. The expectation is
   119   * that units are passed in nanoseconds; for larger durations, the value will
   120   * be converted into larger units.
   121   */
   122  export function Duration(nanoseconds: number): string {
   123    const scale = ComputeDurationScale(nanoseconds);
   124    const unitVal = nanoseconds / scale.value;
   125    return unitVal.toFixed(1) + " " + scale.units;
   126  }
   127  
   128  /**
   129   * Cast nanonseconds to provided scale units
   130   */
   131  // tslint:disable-next-line: variable-name
   132  export const DurationFitScale = (scale: string) => (nanoseconds: number) => {
   133    if (!nanoseconds) {
   134      return `0.00 ${scale}`;
   135    }
   136    const n = durationUnits.indexOf(scale) ;
   137    return `${(nanoseconds / Math.pow(1000, n)).toFixed(2)} ${scale}`;
   138  };
   139  
   140  export const DATE_FORMAT = "MMM DD, YYYY [at] h:mm A";