Skip to content
This repository has been archived by the owner on Nov 14, 2023. It is now read-only.

feat: Add format usage bar. #107

Merged
merged 4 commits into from
Apr 1, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/content/components/usage-bar.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ date: 2019-06-06
```
<div>
<UsageBar now={900000} max={7000000} isByte />
<UsageBar percent={900000/7000000} max={7000000} formatType="decimal" />
<UsageBar percent={900000/7000000} max={7000000} formatType="binary" />
<UsageBar percent={900000/7000000} max={7000000} isByte />
<UsageBar now={900000} max={7000000} isByte withPercent />
<UsageBar now={900000} max={7000000} isByte withPercent hideNow/>
Expand Down
20 changes: 15 additions & 5 deletions src/components/UsageBar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ const UsageBar: React.FC<UsageBarProps> = props => {
hideRight,
showZeroMax,
withUnavailable,
formatType,
} = props;
const hasNow = props.hasOwnProperty('now');
const hasPercent = props.hasOwnProperty('percent');
Expand All @@ -44,8 +45,8 @@ const UsageBar: React.FC<UsageBarProps> = props => {
const errorPercent = props.unavailableData && max && props.unavailableData / max;
let nowValue: number | string | undefined = now;
let maxValue: number | string | undefined = max;
let nowSuffix = '';
let maxSuffix = '';
let nowSuffix: any = '';
let maxSuffix: any = '';
let left;
let right;
let bsStyle;
Expand All @@ -57,14 +58,19 @@ const UsageBar: React.FC<UsageBarProps> = props => {
nowSuffix = maxSuffix = '%';
}

if (isByte) {
if (isByte || formatType) {
// hasPercent 表明左边数据设置完成(百分比形式),不需要再调整
let byteOptions: object = { splitUnit: true };
if (formatType) {
byteOptions = { splitUnit: true, formatType };
}

if (!hasPercent && now) {
const nowArr: any = xbytes(now, { splitUnit: true });
const nowArr: any = xbytes(now, byteOptions);
nowValue = nowArr[0];
nowSuffix = nowArr[1];
}
const maxArr: any = max && xbytes(max, { splitUnit: true });
const maxArr: any = max && xbytes(max, byteOptions);
maxValue = maxArr[0];
maxSuffix = maxArr[1];
} else if (isBulk) {
Expand Down Expand Up @@ -155,6 +161,10 @@ UsageBar.propTypes = {
* 数字以字节(B, KB, MB, GB...)为单位展示
**/
isByte: PropTypes.bool,
/**
* 格式化输出,可选[decimal|binary]
**/
formatType: PropTypes.string,
/**
* 数字以数量(万, 亿, 兆, 京...)为单位展示
**/
Expand Down
1 change: 1 addition & 0 deletions src/interface.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ export interface UsageBarProps {
hideRight?: boolean;
showZeroMax?: boolean;
withUnavailable?: boolean;
formatType?: string;
}

export interface LoaderProps {
Expand Down
2 changes: 1 addition & 1 deletion src/utils/bulk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export default function bulk(value: number, options: OPTIONS, locale?: LocaleTyp
i++;
}
unit = BULK[i - 1][1];
let resultValue: any = value / (BULK[i - 1][0] as number);
let resultValue: number = value / +BULK[i - 1][0];
if (parseInt(String(resultValue), 10) !== resultValue) {
resultValue = Number(resultValue.toFixed(2));
}
Expand Down
80 changes: 68 additions & 12 deletions src/utils/xbytes.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
interface OPTIONS {
unitSeparator?: boolean
decimalPlaces?: number
fixedDecimals?: boolean
toUnit?: string
withoutFloat?: boolean
splitUnit?: boolean
thousandsSeparator?: string
formatType?: string;
unitSeparator?: boolean;
decimalPlaces?: number;
fixedDecimals?: boolean;
toUnit?: string;
withoutFloat?: boolean;
splitUnit?: boolean;
thousandsSeparator?: string;
}

type Map = {
[key: string] : number;
}

const formatThousandsRegExp = /\B(?=(\d{3})+(?!\d))/g;
const formatDecimalsRegExp = /(?:\.0*|(\.[^0]+)0+)$/;

const map = {
const basicMap = {
b: 1,
kb: 1 << 10,
mb: 1 << 20,
Expand All @@ -22,19 +27,55 @@ const map = {
zb: (1 << 30) * Math.pow(1024, 4),
};

const binaryMap= {
b: 1,
kib: 1 << 10,
mib: 1 << 20,
gib: 1 << 30,
tib: (1 << 30) * 1024,
pib: (1 << 30) * Math.pow(1024, 2),
eib: (1 << 30) * Math.pow(1024, 3),
zib: (1 << 30) * Math.pow(1024, 4),
};

const decimal = 1000;
const decimalMap = {
b: 1,
kb: Math.pow(decimal, 1),
mb: Math.pow(decimal, 2),
gb: Math.pow(decimal, 3),
tb: Math.pow(decimal, 4),
pb: Math.pow(decimal, 5),
eb: Math.pow(decimal, 6),
zb: Math.pow(decimal, 7),
};

const numberIsFinite = Number.isFinite || (v => typeof v === 'number' && isFinite(v));

// 原正则 https://www.npmjs.com/package/bytes (存在bug:当传入 '1.2345678901234568e+29GB'字符串进行转换时,结果为 1)
// const parseRegExp = /^((-|\+)?(\d+(?:\.\d+)?)) *(kb|mb|gb|tb|pb|eb|zb)$/i;

// 2018-12-19 兼容科学计数法: 1.2345678901234568e+29
const parseRegExp = /^((-|\+)?(\d+(?:\.\d*[Ee+-]*\d+)?)) *(kb|mb|gb|tb|pb|eb|zb)$/i;
const basicParseRegExp = /^((-|\+)?(\d+(?:\.\d*[Ee+-]*\d+)?)) *(kb|mb|gb|tb|pb|eb|zb)$/i;
const decimalParseRegExp = basicParseRegExp;
const binaryParseRegExp = /^((-|\+)?(\d+(?:\.\d*[Ee+-]*\d+)?)) *(kib|mib|gib|tib|pib|eib|zib)$/i;

function format(value: number, options: OPTIONS) {
if (!numberIsFinite(value)) {
return null;
}

let map: Map = basicMap;
if (options && options.formatType) {
if (options.formatType === 'decimal') {
map = decimalMap;
}

if (options.formatType === 'binary') {
map = binaryMap;
}
}

const mag = Math.abs(value);
const thousandsSeparator =
options && options.thousandsSeparator ? options.thousandsSeparator : '';
Expand Down Expand Up @@ -82,10 +123,10 @@ function format(value: number, options: OPTIONS) {
if (!isNaN(Number(str))) str = Number(str);
return [str, unit.toUpperCase()];
}
return str + unitSeparator + unit.toUpperCase();
return str + unitSeparator + unit.toUpperCase().replace('I','i');
}

function parse(val: string) {
function parse(val: string, options: OPTIONS) {
if (typeof val === 'number' && !isNaN(val)) {
return val;
}
Expand All @@ -94,6 +135,21 @@ function parse(val: string) {
return null;
}

let parseRegExp = basicParseRegExp;
let map: Map = basicMap;

if (options && options.formatType) {
if (options.formatType === 'decimal') {
map = decimalMap;
parseRegExp = decimalParseRegExp;
}

if (options.formatType === 'binary') {
map = binaryMap;
parseRegExp = binaryParseRegExp;
}
}

const results = parseRegExp.exec(val);
let floatValue;
let unit = 'b';
Expand All @@ -111,7 +167,7 @@ function parse(val: string) {

export default function xbytes(value: number | string, options: OPTIONS) {
if (typeof value === 'string') {
return parse(value);
return parse(value, options);
}

if (typeof value === 'number') {
Expand Down