|
|
|
import { observer } from 'mobx-react';
|
|
|
|
import { Pie, measureTextWidth } from '@ant-design/plots';
|
|
|
|
import { fixTo2Decimals, merge } from '../utils/commons';
|
|
|
|
import { dataFieldAlias } from './../libs/ht';
|
|
|
|
|
|
|
|
export default observer((props) => {
|
|
|
|
const { dataSource, title, ...extProps } = props;
|
|
|
|
|
|
|
|
const renderStatistic = (containerWidth, text, style) => {
|
|
|
|
const { width: textWidth, height: textHeight } = measureTextWidth(text, style);
|
|
|
|
const R = containerWidth / 2; // r^2 = (w / 2)^2 + (h - offsetY)^2
|
|
|
|
let scale = 1;
|
|
|
|
if (containerWidth < textWidth) {
|
|
|
|
scale = Math.min(Math.sqrt(Math.abs(Math.pow(R, 2) / (Math.pow(textWidth / 2, 2) + Math.pow(textHeight, 2)))), 1);
|
|
|
|
}
|
|
|
|
// const textStyleStr = `width:${containerWidth}px;`;
|
|
|
|
const textStyleStr = `width:auto;`;
|
|
|
|
return `<div style="${textStyleStr};font-size:${scale}em;line-height:${scale < 1 ? 1 : 'inherit'};">${text}</div>`;
|
|
|
|
};
|
|
|
|
|
|
|
|
const config = merge(
|
|
|
|
{
|
|
|
|
appendPadding: 10,
|
|
|
|
// angleField: 'value',
|
|
|
|
// colorField: 'type',
|
|
|
|
radius: 0.8,
|
|
|
|
innerRadius: 0.65,
|
|
|
|
label: {
|
|
|
|
type: 'inner',
|
|
|
|
offset: '-50%',
|
|
|
|
autoRotate: false,
|
|
|
|
// content: '{value}',
|
|
|
|
content: ({ percent }) => percent > 0.02 ? `${fixTo2Decimals(percent * 100)}%`: '',
|
|
|
|
style: {
|
|
|
|
textAlign: 'center',
|
|
|
|
fontSize: 14,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
legend: {
|
|
|
|
position: 'top',
|
|
|
|
},
|
|
|
|
interactions: [{ type: 'element-selected' }, { type: 'element-active' }, { type: 'pie-statistic-active' }],
|
|
|
|
statistic: {
|
|
|
|
title: {
|
|
|
|
offsetY: -4,
|
|
|
|
customHtml: (container, view, datum) => {
|
|
|
|
const { width, height } = container.getBoundingClientRect();
|
|
|
|
const d = Math.sqrt(Math.pow(width / 2, 2) + Math.pow(height / 2, 2));
|
|
|
|
const text = datum ? datum[extProps.colorField] : (title || '');
|
|
|
|
return renderStatistic(d, text, {
|
|
|
|
fontSize: '28px',
|
|
|
|
});
|
|
|
|
},
|
|
|
|
},
|
|
|
|
content: {
|
|
|
|
// style: {
|
|
|
|
// whiteSpace: 'pre-wrap',
|
|
|
|
// overflow: 'hidden',
|
|
|
|
// textOverflow: 'ellipsis',
|
|
|
|
// },
|
|
|
|
// content: title || '',
|
|
|
|
offsetY: 4,
|
|
|
|
style: {
|
|
|
|
fontSize: '28px',
|
|
|
|
},
|
|
|
|
customHtml: (container, view, datum, data) => {
|
|
|
|
const { width } = container.getBoundingClientRect();
|
|
|
|
const _sum = data.reduce((r, d) => r + d[extProps.angleField], 0);
|
|
|
|
const showVal = datum ? datum[extProps.angleField] : _sum;
|
|
|
|
const text = dataFieldAlias[extProps.angleField].formatter(showVal);
|
|
|
|
return renderStatistic(width, text, {
|
|
|
|
fontSize: '28px',
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
},
|
|
|
|
},
|
|
|
|
meta: {
|
|
|
|
[extProps.angleField]: {
|
|
|
|
alias: dataFieldAlias[extProps.angleField]?.alias || extProps.angleField,
|
|
|
|
formatter: (v) => dataFieldAlias[extProps.angleField]?.formatter(v) || v,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
extProps
|
|
|
|
);
|
|
|
|
return <Pie {...config} data={dataSource} />;
|
|
|
|
});
|