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";