需求:
统计出x年下,人民年收入(收入:1万以下、1万-10万、10万-20万、20万以上)所占比例
要求:
使用堆叠面积图;保留小数点后两位小数
遇到问题:
后端接口返回x年各收入所占比例,四舍五入导致这些数据加起来后有时候会大于100% ,有时候会小于100%,而这又是合理的。小于100% 时,图表正常(异常的不太明显),但是若大于100%时,纵坐标会多出一个刻度,对应的grid也会多出一条。
演示时,领导说,虽然数据上是合理的,但是看着太突兀了,想个办法让纵坐标看起来最大为100%。技术上可实现,设置maxLimit就行,此处不详说。
解决问题:
使用百分比堆积柱状图,此时,后端不需要返回具体比例(百分比),只需要返回数量,至于占比、保留小数,统统交给组件,这样可以保证一组数据的百分比和是100%(最起码看起来是===》图表纵坐标最大值100%)
import React from "react";
import {Axis, Chart, Geom, Legend, Tooltip} from "bizcharts";
// @ts-ignore
import Slider from 'bizcharts-plugin-slider';
// @ts-ignore
import DataSet from '@antv/data-set';
import {dealSliderChange, filterSliderData} from "@/pages/charts/utils/chartsCommon";
interface IStackedPercentageAreaProps {
data: any[]; // 数据源
xAxis: string; // x轴坐标
yAxis: string; // y轴坐标
legendName: string; // 图例对应的变量(数据中表示种类的字段)
color?: string[];
height?: number;
maxLen?: number;
}
/**
* 百分比堆叠面积图(可设置滚动条)
* @param props
* @constructor
*/
const StackedPercentageArea: React.FC<IStackedPercentageAreaProps> = (props) => {
const {height = 400, xAxis, yAxis, data, maxLen, color, legendName} = props;
let flag: boolean = false;
let ds = new DataSet();
let rows=[];
let dv = ds
.createView()
.source(data)
.transform({
type: "percent",
field: yAxis,
dimension:legendName ,
groupBy: [xAxis],
as: "percent"
});
// 获取数据中横坐标的个数,作为是否出现滚动条的依据;
if (maxLen) {
const xAxisData = [...new Set(data.map((item) => item[xAxis]))];
// 设置一个flag,用来判断是否出现滚动条(以及是否需要处理数据)
flag = xAxisData.length > maxLen;
if (flag) {
const startLength = 0;
const endLength = maxLen - 1;
/*
此处处理区别于单条折线图
初始化时,应取xAxisData中的第1个(index为0)作为start,取所能展示的最后一个(index为max-1)作为end
*/
ds = new DataSet({
state: {
start: xAxisData[startLength],
end: xAxisData[endLength],
},
});
rows=dv.rows||[];
dv = ds.createView()
.source(data).transform({
type: "percent",
field: yAxis,
// 统计销量
dimension:legendName ,
// 每年的占比
groupBy: [xAxis],
// 以不同产品类别为分组
as: "percent"
}).transform({
type: 'filter',
// eslint-disable-next-line consistent-return
callback: (obj: any) => filterSliderData(flag, ds, data, obj, xAxis),
});
}
}
const cols = {
percent: {
min: 0,
formatter(val:number) {
// 保留两位小数
return `${(val * 100).toFixed(2) }%`;
}
}
};
cols[xAxis]={
range: [0, 1]
}
return (
<>
<Chart height={height} data={dv} forceFit scale={cols}>
<Axis name={xAxis} />
<Axis name="percent" />
<Legend />
<Tooltip
/>
<Geom type="areaStack"
position={`${xAxis}*percent`}
color={color ? [`${legendName}`, color] : legendName}
/>
<Geom
type="lineStack"
position={`${xAxis}*percent`}
size={2}
color={color ? [`${legendName}`, color] : legendName}
/>
</Chart>
{
flag && <Slider
onChange={(obj: any) => dealSliderChange(obj, ds)}
height={20}
width="auto"
xAxis={xAxis}
yAxis="percent"
data={rows}
start={ds.state.start}
end={ds.state.end}
padding={[50]}
textStyle={{
fontSize: '0',
}}
backgroundChart={{
type: 'heatmap',
}}
/>
}
</>
);
};
export default StackedPercentageArea;
import React,{memo} from 'react';
import StackedPercentageArea from "@/pages/charts/compnent/StackedPercentageArea";
import {maxLen} from "@/pages/charts/utils/chartsCommon";
const StackedPercentageAreaMemo=memo(StackedPercentageArea);
const stackedData= [
{
country: "Europe",
year: "1750",
value: 163
},
{
country: "Europe",
year: "1800",
value: 203
},
{
country: "Europe",
year: "1850",
value: 276
},
{
country: "Europe",
year: "1900",
value: 408
},
{
country: "Europe",
year: "1950",
value: 547
},
{
country: "Europe",
year: "1999",
value: 729
},
{
country: "Europe",
year: "2050",
value: 628
},
{
country: "Europe",
year: "2100",
value: 828
},
{
country: "Asia",
year: "1750",
value: 502
},
{
country: "Asia",
year: "1800",
value: 635
},
{
country: "Asia",
year: "1850",
value: 809
},
{
country: "Asia",
year: "1900",
value: 947
},
{
country: "Asia",
year: "1950",
value: 1402
},
{
country: "Asia",
year: "1999",
value: 3634
},
{
country: "Asia",
year: "2050",
value: 5268
},
{
country: "Asia",
year: "2100",
value: 7268
},
{
country: "Asia",
year: "2200",
value: 7568
},
{
country: "Europe",
year: "2200",
value: 7568
}
];
const ChartsIndex:React.FC<{}>=()=>{
return(
<div style={{background:'white'}}>
<h1>bizCharts图表封装</h1>
<h2>面积图-多-百分比堆叠面积图</h2>
<StackedPercentageAreaMemo data={stackedData} xAxis="year" yAxis="value" legendName="country" maxLen={maxLen}/>
</div>
);
}
export default ChartsIndex;