Skip to content

Statistic Component #802

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
May 28, 2019
Merged
Show file tree
Hide file tree
Changes from 3 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
4 changes: 4 additions & 0 deletions components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ import { default as Slider } from './slider';

import { default as Spin } from './spin';

import { default as Statistic } from './statistic';

import { default as Steps } from './steps';

import { default as Switch } from './switch';
Expand Down Expand Up @@ -172,6 +174,7 @@ const components = [
Select,
Slider,
Spin,
Statistic,
Steps,
Switch,
Table,
Expand Down Expand Up @@ -254,6 +257,7 @@ export {
Select,
Slider,
Spin,
Statistic,
Steps,
Switch,
Table,
Expand Down
105 changes: 105 additions & 0 deletions components/statistic/Countdown.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import * as moment from 'moment';
import interopDefault from '../_util/interopDefault';
import { cloneElement } from '../_util/vnode';
import { initDefaultProps } from '../_util/props-util';
import Statistic, { StatisticProps } from './Statistic';
import { formatCountdown } from './utils';

const REFRESH_INTERVAL = 1000 / 30;

function getTime(value) {
return interopDefault(moment)(value).valueOf();
}

export default {
name: 'AStatisticCountdown',
props: initDefaultProps(StatisticProps, {
format: 'HH:mm:ss',
}),

data() {
return {
uniKey: 0,
};
},

countdownId: undefined,

mounted() {
this.$nextTick(() => {
this.syncTimer();
});
},

updated() {
this.$nextTick(() => {
this.syncTimer();
});
},

beforeDestroy() {
this.stopTimer();
},

methods: {
syncTimer() {
const { value } = this.$props;
const timestamp = getTime(value);
if (timestamp >= Date.now()) {
this.startTimer();
} else {
this.stopTimer();
}
},

startTimer() {
if (this.countdownId) {
return;
}
this.countdownId = window.setInterval(() => {
this.uniKey++;
}, REFRESH_INTERVAL);
},

stopTimer() {
const { value } = this.$props;
if (this.countdownId) {
clearInterval(this.countdownId);
this.countdownId = undefined;

const timestamp = getTime(value);
if (timestamp < Date.now()) {
this.$emit('finish');
}
}
},

formatCountdown(value, config) {
const { format } = this.$props;
return formatCountdown(value, { ...config, format });
},

// Countdown do not need display the timestamp
valueRenderHtml: node =>
cloneElement(node, {
props: {
title: undefined,
},
}),
},

render() {
return (
<Statistic
key={this.uniKey}
{...{
props: {
...this.$props,
valueRender: this.valueRenderHtml,
formatter: this.formatCountdown,
},
}}
/>
);
},
};
58 changes: 58 additions & 0 deletions components/statistic/Number.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import padEnd from 'lodash/padEnd';

export default {
name: 'AStatisticNumber',
functional: true,
render(h, context) {
const {
value,
formatter,
precision,
decimalSeparator,
groupSeparator = '',
prefixCls,
} = context.props;

let valueNode;

if (typeof formatter === 'function') {
// Customize formatter
valueNode = formatter(value);
} else {
// Internal formatter
const val = String(value);
const cells = val.match(/^(-?)(\d*)(\.(\d+))?$/);
// Process if illegal number
if (!cells) {
valueNode = val;
} else {
const negative = cells[1];
let int = cells[2] || '0';
let decimal = cells[4] || '';

int = int.replace(/\B(?=(\d{3})+(?!\d))/g, groupSeparator);
if (typeof precision === 'number') {
decimal = padEnd(decimal, precision, '0').slice(0, precision);
}

if (decimal) {
decimal = `${decimalSeparator}${decimal}`;
}

valueNode = [
<span key="int" class={`${prefixCls}-content-value-int`}>
{negative}
{int}
</span>,
decimal && (
<span key="decimal" class={`${prefixCls}-content-value-decimal`}>
{decimal}
</span>
),
];
}
}

return <span class={`${prefixCls}-content-value`}>{valueNode}</span>;
},
};
64 changes: 64 additions & 0 deletions components/statistic/Statistic.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import PropTypes from '../_util/vue-types';
import { getComponentFromProp, initDefaultProps } from '../_util/props-util';
import { ConfigConsumerProps } from '../config-provider';
import StatisticNumber from './Number';

export const StatisticProps = {
prefixCls: PropTypes.string,
decimalSeparator: PropTypes.string,
groupSeparator: PropTypes.string,
format: PropTypes.string,
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
valueStyle: PropTypes.any,
valueRender: PropTypes.any,
formatter: PropTypes.any,
precision: PropTypes.number,
prefix: PropTypes.any,
suffix: PropTypes.any,
title: PropTypes.any,
};

export default {
name: 'AStatistic',
props: initDefaultProps(StatisticProps, {
prefixCls: 'ant-statistic',
decimalSeparator: '.',
groupSeparator: ',',
}),
inject: {
configProvider: { default: () => ({}) },
},

render() {
const {
prefixCls: customizePrefixCls,
value = 0,
valueStyle,
valueRender,
} = this.$props;
const getPrefixCls = this.configProvider.getPrefixCls || ConfigConsumerProps.getPrefixCls;
const prefixCls = getPrefixCls('statistic', customizePrefixCls);

const title = getComponentFromProp(this, 'title');
let prefix = getComponentFromProp(this, 'prefix');
let suffix = getComponentFromProp(this, 'suffix');
const formatter = getComponentFromProp(this, 'formatter');
let valueNode = (
<StatisticNumber {...{ props: this.$props }} value={value} formatter={formatter} />
);
if (valueRender) {
valueNode = valueRender(valueNode);
}

return (
<div class={prefixCls}>
{title && <div class={`${prefixCls}-title`}>{title}</div>}
<div style={valueStyle} class={`${prefixCls}-content`}>
{prefix && <span class={`${prefixCls}-content-prefix`}>{prefix}</span>}
{valueNode}
{suffix && <span class={`${prefixCls}-content-suffix`}>{suffix}</span>}
</div>
</div>
);
},
};
57 changes: 57 additions & 0 deletions components/statistic/__tests__/__snapshots__/demo.test.js.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`renders ./components/statistic/demo/basic.md correctly 1`] = `
<div>
<div class="ant-statistic" style="margin-right: 50px;">
<div class="ant-statistic-title">Active Users</div>
<div class="ant-statistic-content"><span class="ant-statistic-content-value"><span class="ant-statistic-content-value-int">112,893</span></span></div>
</div>
<div class="ant-statistic">
<div class="ant-statistic-title">Account Balance (CNY)</div>
<div class="ant-statistic-content"><span class="ant-statistic-content-value"><span class="ant-statistic-content-value-int">112,893</span><span class="ant-statistic-content-value-decimal">.00</span></span></div>
</div>
</div>
`;

exports[`renders ./components/statistic/demo/card.md correctly 1`] = `
<div>
<div class="ant-card ant-card-bordered" style="padding: 30px;">
<div class="ant-card-body">
<div class="ant-statistic" style="margin-right: 50px;">
<div class="ant-statistic-title">Feedback</div>
<div class="ant-statistic-content"><span class="ant-statistic-content-prefix"><i class="anticon anticon-like"><svg viewBox="64 64 896 896" data-icon="like" width="1em" height="1em" fill="currentColor" aria-hidden="true" class=""><path d="M885.9 533.7c16.8-22.2 26.1-49.4 26.1-77.7 0-44.9-25.1-87.4-65.5-111.1a67.67 67.67 0 0 0-34.3-9.3H572.4l6-122.9c1.4-29.7-9.1-57.9-29.5-79.4A106.62 106.62 0 0 0 471 99.9c-52 0-98 35-111.8 85.1l-85.9 311H144c-17.7 0-32 14.3-32 32v364c0 17.7 14.3 32 32 32h601.3c9.2 0 18.2-1.8 26.5-5.4 47.6-20.3 78.3-66.8 78.3-118.4 0-12.6-1.8-25-5.4-37 16.8-22.2 26.1-49.4 26.1-77.7 0-12.6-1.8-25-5.4-37 16.8-22.2 26.1-49.4 26.1-77.7-.2-12.6-2-25.1-5.6-37.1zM184 852V568h81v284h-81zm636.4-353l-21.9 19 13.9 25.4a56.2 56.2 0 0 1 6.9 27.3c0 16.5-7.2 32.2-19.6 43l-21.9 19 13.9 25.4a56.2 56.2 0 0 1 6.9 27.3c0 16.5-7.2 32.2-19.6 43l-21.9 19 13.9 25.4a56.2 56.2 0 0 1 6.9 27.3c0 22.4-13.2 42.6-33.6 51.8H329V564.8l99.5-360.5a44.1 44.1 0 0 1 42.2-32.3c7.6 0 15.1 2.2 21.1 6.7 9.9 7.4 15.2 18.6 14.6 30.5l-9.6 198.4h314.4C829 418.5 840 436.9 840 456c0 16.5-7.2 32.1-19.6 43z"></path></svg></i></span><span class="ant-statistic-content-value"><span class="ant-statistic-content-value-int">1,128</span></span></div>
</div>
<div class="ant-statistic" valueclass="demo-class">
<div class="ant-statistic-title">Unmerged</div>
<div class="ant-statistic-content"><span class="ant-statistic-content-value"><span class="ant-statistic-content-value-int">1,234,567,890</span></span><span class="ant-statistic-content-suffix"><span> / 100</span></span></div>
</div>
</div>
</div>
</div>
`;

exports[`renders ./components/statistic/demo/countdown.md correctly 1`] = `
<div>
<div class="ant-statistic" style="margin-right: 50px;">
<div class="ant-statistic-title">Countdown</div>
<div class="ant-statistic-content"><span class="ant-statistic-content-value">48:00:30</span></div>
</div>
<div class="ant-statistic">
<div class="ant-statistic-title">Million Seconds</div>
<div class="ant-statistic-content"><span class="ant-statistic-content-value">48:00:30:000</span></div>
</div>
</div>
`;

exports[`renders ./components/statistic/demo/unit.md correctly 1`] = `
<div>
<div class="ant-statistic" style="margin-right: 50px;">
<div class="ant-statistic-title">Feedback</div>
<div class="ant-statistic-content" style="color: rgb(63, 134, 0);"><span class="ant-statistic-content-prefix"><i class="anticon anticon-arrow-up"><svg viewBox="64 64 896 896" data-icon="arrow-up" width="1em" height="1em" fill="currentColor" aria-hidden="true" class=""><path d="M868 545.5L536.1 163a31.96 31.96 0 0 0-48.3 0L156 545.5a7.97 7.97 0 0 0 6 13.2h81c4.6 0 9-2 12.1-5.5L474 300.9V864c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V300.9l218.9 252.3c3 3.5 7.4 5.5 12.1 5.5h81c6.8 0 10.5-8 6-13.2z"></path></svg></i></span><span class="ant-statistic-content-value"><span class="ant-statistic-content-value-int">11</span><span class="ant-statistic-content-value-decimal">.28</span></span><span class="ant-statistic-content-suffix">%</span></div>
</div>
<div class="ant-statistic" valueclass="demo-class">
<div class="ant-statistic-title">Unmerged</div>
<div class="ant-statistic-content"><span class="ant-statistic-content-value"><span class="ant-statistic-content-value-int">78</span></span><span class="ant-statistic-content-suffix"><span> / 100</span></span></div>
</div>
</div>
`;
3 changes: 3 additions & 0 deletions components/statistic/__tests__/demo.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import demoTest from '../../../tests/shared/demoTest';

demoTest('statistic');
18 changes: 18 additions & 0 deletions components/statistic/demo/basic.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<cn>
#### 基本
简单展示
</cn>

<us>
#### Basic
Simplest Usage.
</us>

```html
<template>
<div>
<a-statistic title="Active Users" :value="112893" style="margin-right: 50px" />
<a-statistic title="Account Balance (CNY)" :precision="2" :value="112893" />
</div>
</template>
```
32 changes: 32 additions & 0 deletions components/statistic/demo/card.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<cn>
#### 在卡片中使用
在卡片中展示统计数值。
</cn>

<us>
#### In Card
Display statistic data in Card.
</us>

```html
<template>
<div>
<a-card style="padding: 30px">
<a-statistic
title="Feedback"
:value="1128"
style="margin-right: 50px"
>
<a-icon slot="prefix" type="like" />
</a-statistic>
<a-statistic
title="Unmerged"
:value="1234567890"
valueClass="demo-class"
>
<span slot="suffix"> / 100</span>
</a-statistic>
</a-card>
</div>
</template>
```
Loading