bizcharts圖表封裝之百分比堆疊柱狀圖(可設置Slider)

一、百分比堆積柱狀圖(可設置Slider)

需求:

        統計出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 IStackedPercentageColumnProps {
  data: any[]; // 數據源
  xAxis: string; // x軸座標
  yAxis: string; // y軸座標
  legendName: string; // 圖例對應的變量(數據中表示種類的字段)
  color?: string[];
  height?: number;
  maxLen?: number;
}

/**
 * 百分比堆積柱狀圖(可設置滾動條)
 * @param props
 * @constructor
 */
const StackedPercentageColumn: React.FC<IStackedPercentageColumnProps> = (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)  }%`;
      }
    }
  };
  return (
    <>
      <Chart height={height} data={dv} forceFit scale={cols}>
        <Axis name={xAxis} />
        <Axis name="percent" />
        <Legend />
        <Tooltip
        />
        <Geom type="intervalStack"
              position={`${xAxis}*percent`}
              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 StackedPercentageColumn;

二、使用

import React,{memo}  from 'react';
import BasicLine from "@/pages/charts/compnent/BasicLine";
import Cured from "@/pages/charts/compnent/Curved";
import BasicColumn from "@/pages/charts/compnent/BasicColumn";
import GroupedColumn from "@/pages/charts/compnent/GroupedColumn";
import StackedColumn from "@/pages/charts/compnent/StackedColumn";
import BasicArea from "@/pages/charts/compnent/BasicArea";
import Bubbles from "@/pages/charts/compnent/Bubbles";
import StackedPercentageColumn from "@/pages/charts/compnent/StackedPercentageColumn";

import {maxLen} from "@/pages/charts/utils/chartsCommon";

const BasicLineMemo=memo(BasicLine);
const CuredMemo=memo(Cured);
const BasicColumnMemo=memo(BasicColumn);
const GroupedColumnMemo=memo(GroupedColumn);
const StackedColumnMemo=memo(StackedColumn);
const BasicAreaMemo=memo(BasicArea);
const BubblesMemo=memo(Bubbles);
const StackedPercentageColumnMemo=memo(StackedPercentageColumn);

const basicLineData= [
  {
    year: "1991",
    value: 3
  },
  {
    year: "1992",
    value: 4
  },
  {
    year: "1993",
    value: 3.5
  },
  {
    year: "1994",
    value: 5
  },
  {
    year: "1995",
    value: 4.9
  },
  {
    year: "1996",
    value: 6
  },
  {
    year: "1997",
    value: 7
  },
  {
    year: "1998",
    value: 9
  },
  {
    year: "1999",
    value: 13
  }
];
const doubleData= [
  {
    month: "Jan",
    city: "Tokyo",
    temperature: 7
  },
  {
    month: "Jan",
    city: "London",
    temperature: 3.9
  },
  {
    month: "Feb",
    city: "Tokyo",
    temperature: 6.9
  },
  {
    month: "Feb",
    city: "London",
    temperature: 4.2
  },
  {
    month: "Mar",
    city: "Tokyo",
    temperature: 9.5
  },
  {
    month: "Mar",
    city: "London",
    temperature: 5.7
  },
  {
    month: "Apr",
    city: "Tokyo",
    temperature: 14.5
  },
  {
    month: "Apr",
    city: "London",
    temperature: 8.5
  },
  {
    month: "May",
    city: "Tokyo",
    temperature: 18.4
  },
  {
    month: "May",
    city: "London",
    temperature: 11.9
  },
  {
    month: "Jun",
    city: "Tokyo",
    temperature: 21.5
  },
  {
    month: "Jun",
    city: "London",
    temperature: 15.2
  },
  {
    month: "Jul",
    city: "Tokyo",
    temperature: 25.2
  },
  {
    month: "Jul",
    city: "London",
    temperature: 17
  },
  {
    month: "Aug",
    city: "Tokyo",
    temperature: 26.5
  },
  {
    month: "Aug",
    city: "London",
    temperature: 16.6
  },
  {
    month: "Sep",
    city: "Tokyo",
    temperature: 23.3
  },
  {
    month: "Sep",
    city: "London",
    temperature: 14.2
  },
  {
    month: "Oct",
    city: "Tokyo",
    temperature: 18.3
  },
  {
    month: "Oct",
    city: "London",
    temperature: 10.3
  },
  {
    month: "Nov",
    city: "Tokyo",
    temperature: 13.9
  },
  {
    month: "Nov",
    city: "London",
    temperature: 6.6
  },
  {
    month: "Dec",
    city: "Tokyo",
    temperature: 9.6
  },
  {
    month: "Dec",
    city: "London",
    temperature: 4.8
  }
];
const  basicColumnData = [
  {
    year: "1951 年",
    sales: 38
  },
  {
    year: "1952 年",
    sales: 52
  },
  {
    year: "1956 年",
    sales: 61
  },
  {
    year: "1957 年",
    sales: 145
  },
  {
    year: "1958 年",
    sales: 48
  },
  {
    year: "1959 年",
    sales: 38
  },
  {
    year: "1960 年",
    sales: 38
  },
  {
    year: "1962 年",
    sales: 38
  },
  {
    year: "1969 年",
    sales: 68
  }
];
const basicColumnData2=[
  {
    x: "分類一",
    y: [76, 100]
  },
  {
    x: "分類二",
    y: [56, 108]
  },
  {
    x: "分類三",
    y: [38, 129]
  },
  {
    x: "分類四",
    y: [58, 155]
  },
  {
    x: "分類五",
    y: [45, 120]
  },
  {
    x: "分類六",
    y: [23, 99]
  },
  {
    x: "分類七",
    y: [18, 56]
  },
  {
    x: "分類八",
    y: [18, 34]
  }
];
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>
      <BasicLineMemo data={basicLineData} xAxis='year' yAxis='value' maxLen={maxLen}/>
      <h2>折線圖-多條</h2>
      <CuredMemo data={doubleData} xAxis="month" yAxis="temperature" legendName="city" maxLen={maxLen}/>
      <h2>柱狀圖-單條</h2>
      <BasicColumnMemo data={basicColumnData} xAxis="year" yAxis="sales"  maxLen={maxLen}/>
      <h2>柱狀圖-單條-區間柱狀圖:區別只是數據(格式)不同</h2>
      <BasicColumnMemo data={basicColumnData2} xAxis="x" yAxis="y"  maxLen={maxLen}/>
      <h2>柱狀圖-多條</h2>
      <GroupedColumnMemo data={doubleData} xAxis="month" yAxis="temperature" legendName="city" maxLen={maxLen}/>
      <h2>柱狀圖-多條-堆疊柱狀圖</h2>
      <StackedColumnMemo data={doubleData} xAxis="month" yAxis="temperature" legendName="city" maxLen={maxLen}/>
      <h2>面積圖-單-基礎面積圖</h2>
      <BasicAreaMemo  data={basicLineData} xAxis='year' yAxis='value' maxLen={maxLen}/>
      <h2>面積圖-多-多面積圖</h2>
      <BubblesMemo  data={doubleData} xAxis="month" yAxis="temperature" legendName="city" maxLen={maxLen}/>
      <h2>柱狀圖-多-百分比堆積柱狀圖</h2>
      <StackedPercentageColumnMemo data={stackedData} xAxis="year" yAxis="value" legendName="country" maxLen={maxLen}/>
      </div>
  );
}
export default ChartsIndex;

三、涉及到的公共方法

    https://mp.csdn.net/console/editor/html/106548389

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章