Unverified Commit c2f34d52 authored by 偏右's avatar 偏右 Committed by GitHub

Better pie responsive (#37)

* refactor Pie

* Less js calculation

* Responsive Pie

* Fix pies height

* use react-fittext
parent 57eb471a
...@@ -30,7 +30,8 @@ ...@@ -30,7 +30,8 @@
"qs": "^6.5.0", "qs": "^6.5.0",
"react": "^16.0.0", "react": "^16.0.0",
"react-document-title": "^2.0.3", "react-document-title": "^2.0.3",
"react-dom": "^16.0.0" "react-dom": "^16.0.0",
"react-fittext": "^1.0.0"
}, },
"devDependencies": { "devDependencies": {
"babel-eslint": "^8.0.1", "babel-eslint": "^8.0.1",
......
import React, { Component } from 'react'; import React, { Component } from 'react';
import G2 from 'g2'; import G2 from 'g2';
import { Divider } from 'antd'; import { Divider } from 'antd';
import classNames from 'classnames';
import ReactFitText from 'react-fittext';
import equal from '../equal'; import equal from '../equal';
import styles from './index.less'; import styles from './index.less';
...@@ -8,8 +10,7 @@ import styles from './index.less'; ...@@ -8,8 +10,7 @@ import styles from './index.less';
class Pie extends Component { class Pie extends Component {
state = { state = {
legendData: [], legendData: [],
left: undefined, };
}
componentDidMount() { componentDidMount() {
this.renderChart(this.props.data); this.renderChart(this.props.data);
...@@ -30,9 +31,6 @@ class Pie extends Component { ...@@ -30,9 +31,6 @@ class Pie extends Component {
handleRef = (n) => { handleRef = (n) => {
this.node = n; this.node = n;
} }
handleTotalRef = (n) => {
this.totalNode = n;
}
handleLegendClick = (item, i) => { handleLegendClick = (item, i) => {
const newItem = item; const newItem = item;
...@@ -54,8 +52,9 @@ class Pie extends Component { ...@@ -54,8 +52,9 @@ class Pie extends Component {
renderChart(data) { renderChart(data) {
const { const {
title, height = 0, height = 0,
hasLegend, fit = true, hasLegend,
fit = true,
margin, percent, color, margin, percent, color,
inner = 0.75, inner = 0.75,
animate = true, animate = true,
...@@ -97,19 +96,6 @@ class Pie extends Component { ...@@ -97,19 +96,6 @@ class Pie extends Component {
return; return;
} }
let m = margin;
if (!margin) {
if (hasLegend) {
m = [24, 240, 24, 8];
} else if (percent) {
m = [0, 0, 0, 0];
} else {
m = [24, 0, 24, 0];
}
}
const h = title ? (height + m[0] + m[2] + (-46)) : (height + m[0] + m[2]);
// clean // clean
this.node.innerHTML = ''; this.node.innerHTML = '';
...@@ -118,9 +104,9 @@ class Pie extends Component { ...@@ -118,9 +104,9 @@ class Pie extends Component {
const chart = new G2.Chart({ const chart = new G2.Chart({
container: this.node, container: this.node,
forceFit: fit, forceFit: fit,
height: h, height,
plotCfg: { plotCfg: {
margin: m, margin,
}, },
animate, animate,
}); });
...@@ -176,36 +162,25 @@ class Pie extends Component { ...@@ -176,36 +162,25 @@ class Pie extends Component {
this.setState({ this.setState({
legendData, legendData,
}, () => {
let left = 0;
if (this.totalNode) {
left = -((this.totalNode.offsetWidth / 2) + ((margin || m)[1] / 2)) + lineWidth;
}
this.setState({ left });
}); });
} }
render() { render() {
const { height, title, valueFormat, subTitle, total, hasLegend } = this.props; const { valueFormat, subTitle, total, hasLegend, className, style } = this.props;
const { legendData, left } = this.state; const { legendData } = this.state;
const mt = -(((legendData.length * 38) - 16) / 2); const pieClassName = classNames(styles.pie, className, {
[styles.hasLegend]: !!hasLegend,
});
return ( return (
<div className={styles.pie} style={{ height }}> <div className={pieClassName} style={style}>
<div> <ReactFitText maxFontSize={40}>
{title && <h4 className={styles.title}>{title}</h4>} <div className={styles.chart}>
<div className={styles.content}> <div ref={this.handleRef} style={{ fontSize: 0 }} />
<div ref={this.handleRef} />
{ {
(subTitle || total) && ( (subTitle || total) && (
<div <div className={styles.total}>
className={styles.total} {subTitle && <h4 className="pie-sub-title">{subTitle}</h4>}
ref={this.handleTotalRef}
style={{ marginLeft: left, opacity: left ? 1 : 0 }}
>
{
subTitle && <h4 className="pie-sub-title">{subTitle}</h4>
}
{ {
// eslint-disable-next-line // eslint-disable-next-line
total && <p className="pie-stat" dangerouslySetInnerHTML={{ __html: total }} /> total && <p className="pie-stat" dangerouslySetInnerHTML={{ __html: total }} />
...@@ -213,30 +188,31 @@ class Pie extends Component { ...@@ -213,30 +188,31 @@ class Pie extends Component {
</div> </div>
) )
} }
{
hasLegend && (
<ul className={styles.legend} style={{ marginTop: mt }}>
{
legendData.map((item, i) => (
<li key={item.x} onClick={() => this.handleLegendClick(item, i)}>
<span className={styles.dot} style={{ backgroundColor: !item.checked ? '#aaa' : item.color }} />
<span className={styles.legendTitle}>{item.x}</span>
<Divider type="vertical" />
<span className={styles.percent}>{`${(item['..percent'] * 100).toFixed(2)}%`}</span>
<span
className={styles.value}
dangerouslySetInnerHTML={{
__html: valueFormat ? valueFormat(item.y) : item.y,
}}
/>
</li>
))
}
</ul>
)
}
</div> </div>
</div> </ReactFitText>
{
hasLegend && (
<ul className={styles.legend}>
{
legendData.map((item, i) => (
<li key={item.x} onClick={() => this.handleLegendClick(item, i)}>
<span className={styles.dot} style={{ backgroundColor: !item.checked ? '#aaa' : item.color }} />
<span className={styles.legendTitle}>{item.x}</span>
<Divider type="vertical" />
<span className={styles.percent}>{`${(item['..percent'] * 100).toFixed(2)}%`}</span>
<span
className={styles.value}
dangerouslySetInnerHTML={{
__html: valueFormat ? valueFormat(item.y) : item.y,
}}
/>
</li>
))
}
</ul>
)
}
</div> </div>
); );
} }
......
...@@ -2,19 +2,28 @@ ...@@ -2,19 +2,28 @@
@import "../../../utils/utils.less"; @import "../../../utils/utils.less";
.pie { .pie {
.content { position: relative;
.chart {
position: relative; position: relative;
} }
&.hasLegend .chart {
width: ~"calc(100% - 264px)";
margin-left: 24px;
}
.legend { .legend {
position: absolute; position: absolute;
top: 50%;
right: 0; right: 0;
min-width: 200px; min-width: 200px;
top: 50%;
transform: translateY(-50%);
li { li {
cursor: pointer; cursor: pointer;
margin-bottom: 16px; margin-bottom: 16px;
height: 22px; height: 22px;
line-height: 22px; line-height: 22px;
&:last-child {
margin-bottom: 0;
}
} }
} }
.dot { .dot {
...@@ -47,13 +56,12 @@ ...@@ -47,13 +56,12 @@
margin-bottom: 8px; margin-bottom: 8px;
} }
.total { .total {
opacity: 0;
position: absolute; position: absolute;
left: 50%; left: 50%;
top: 50%; top: 50%;
margin-top: -34px;
text-align: center; text-align: center;
height: 62px; height: 62px;
transform: translate(-50%, -50%);
& > h4 { & > h4 {
color: @text-color-secondary; color: @text-color-secondary;
font-size: 14px; font-size: 14px;
...@@ -65,9 +73,23 @@ ...@@ -65,9 +73,23 @@
& > p { & > p {
color: @heading-color; color: @heading-color;
display: block; display: block;
font-size: 30px; font-size: 1.3em;
height: 32px; height: 32px;
line-height: 32px; line-height: 32px;
white-space: nowrap;
}
}
}
@media screen and (max-width: @screen-sm) {
.pie {
&.hasLegend .chart {
width: 100%;
margin: 0 0 32px 0;
}
.legend {
position: static;
transform: none;
} }
} }
} }
...@@ -71,7 +71,6 @@ Ant Design Pro 提供的业务中常用的图表类型,都是基于 [G2](https ...@@ -71,7 +71,6 @@ Ant Design Pro 提供的业务中常用的图表类型,都是基于 [G2](https
| hasLegend | 是否显示 legend | boolean | `false` | | hasLegend | 是否显示 legend | boolean | `false` |
| margin | 图表内部间距 | array | \[24, 0, 24, 0\] | | margin | 图表内部间距 | array | \[24, 0, 24, 0\] |
| percent | 占比 | number | - | | percent | 占比 | number | - |
| title | 图表标题 | ReactNode\|string | - |
| tooltip | 是否显示 tooltip | boolean | true | | tooltip | 是否显示 tooltip | boolean | true |
| valueFormat | 显示值的格式化函数 | function | - | | valueFormat | 显示值的格式化函数 | function | - |
| subTitle | 图表子标题 | ReactNode\|string | - | | subTitle | 图表子标题 | ReactNode\|string | - |
......
...@@ -436,18 +436,17 @@ export default class Analysis extends Component { ...@@ -436,18 +436,17 @@ export default class Analysis extends Component {
)} )}
style={{ marginTop: 24 }} style={{ marginTop: 24 }}
> >
<div style={{ marginTop: 8, marginBottom: 77 }}> <h4 style={{ marginTop: 8, marginBottom: 32 }}>销售额</h4>
<Pie <Pie
hasLegend hasLegend
title="销售额" subTitle="销售额"
subTitle="销售额" total={yuan(salesPieData.reduce((pre, now) => now.y + pre, 0))}
total={yuan(salesPieData.reduce((pre, now) => now.y + pre, 0))} data={salesPieData}
data={salesPieData} valueFormat={val => yuan(val)}
valueFormat={val => yuan(val)} height={240}
height={268} lineWidth={4}
lineWidth={4} style={{ marginBottom: 52 }}
/> />
</div>
</Card> </Card>
</Col> </Col>
</Row> </Row>
......
...@@ -119,7 +119,7 @@ export default class Monitor extends PureComponent { ...@@ -119,7 +119,7 @@ export default class Monitor extends PureComponent {
percent={28} percent={28}
subTitle="中式快餐" subTitle="中式快餐"
total="28%" total="28%"
height={129} height={128}
lineWidth={2} lineWidth={2}
/> />
</Col> </Col>
...@@ -130,7 +130,7 @@ export default class Monitor extends PureComponent { ...@@ -130,7 +130,7 @@ export default class Monitor extends PureComponent {
percent={22} percent={22}
subTitle="西餐" subTitle="西餐"
total="22%" total="22%"
height={129} height={128}
lineWidth={2} lineWidth={2}
/> />
</Col> </Col>
...@@ -141,7 +141,7 @@ export default class Monitor extends PureComponent { ...@@ -141,7 +141,7 @@ export default class Monitor extends PureComponent {
percent={32} percent={32}
subTitle="火锅" subTitle="火锅"
total="32%" total="32%"
height={129} height={128}
lineWidth={2} lineWidth={2}
/> />
</Col> </Col>
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment