React Antv G2Plot 「指标拆解图」 前端可视化实战 实现渲染、重置、筛选功能

背景

实现对指定数据的「指标拆解图」 渲染,并且可以根据筛选项进行变化。
在这里插入图片描述
在这里插入图片描述

任务分解

  • antv 的图表,以及请求后端的载荷对传入的数据结构有严格要求
    • 一个工具函数将后端接口返回的数据格式化成 antv 图表要求的格式
    • 一个工具函数将前端提交的请求数据格式化后端提供的接口规范形式。
  • 刚进入页面图表需要有个初始状态的渲染
    • 可以用 useModel 实现初始化的值
  • 完成筛选、重置功能
    • 结合 form 以及 umi 的 request 实现

代码实现

import { fetchXXXGroup } from '@/services/XXX';
import { DecompositionTreeGraph } from '@ant-design/graphs';
import { Button, Card, Form } from 'antd';
import { useState } from 'react';
import { useModel } from 'umi';

interface XXXGraphType {
  id: string;
  value?: {
    title?: string;
    items?: {
      text?: string;
      value?: string;
    }[];
  };
  children?: XXXGraphType[];
}
// 格式化处理后端接口返回值 使其符合 Antv 基本要求
const toGraphData = (data: any[]) => {
  const basicData: any = data.map(
    ({
      name,
      XXX_id,
      XXX_level,
      children,
      name,
      count,
    }) => ({
      id: XXX_level + '#' + XXX_id,
      value: {
        title: XXX_name,
        items: [{ text: name, value: count + '人' }],
      },
      children: toGraphData(children),
    }),
  );
  return basicData;
};

const DepartmentOverviewTree = () => {
  const [form] = Form.useForm();
  const [loading, setLoading] = useState(false);
  const rawData: any = useModel('useXXX');
  const dataXXX: object[] = rawData.XXX;
  const formattedData:XXXGraphType = toGraphData(dataXXX);
  const initialData = {
    id: 'root',
    value: {
      title: ' XXX概览图',
    },
    children: formattedData,
  };
  const [data, setData] = useState<any>(initialData);
  const onReset = () => {
    form.resetFields();
    onFinish()
  };
// 格式化前端提交数据
  const formatForm = (params: any) => {
    const { address, xxx, ...props } = params || {};
    return {
      address: address ? address.join(',') : undefined,
      xxx: xxx ? xxx.map((arr: any) => arr.join('#')).join(',') : undefined,
      ...props,
    };
  };

  const onFinish = async () => {
    setLoading(true);
    try {
      const { data } = await fetchXXXGroup({
        ...formatForm(form.getFieldsValue()),
      });
      const { depts } = data || {};

      if (Array.isArray(depts)) {
        const basicData = toGraphData(depts)
        const formattedData = {
          id: 'root',
          value: {
            title: 'XXX概览图',
          },
          children: basicData,
        }
        setData(formattedData);
      }
    } finally {
      setLoading(false);
    }
  };

  const config: any = {
    data: data,
    layout: {
      direction: 'TB',
      ranksepFunc: () => 20,
    },
    nodeCfg: {
      size: [120, 20],
      type: 'indicator-card',
      anchorPoints: [
        [0.5, 0],
        [0.5, 1],
      ],
      autoWidth: true,
      items: {
        style: (cfg: any, group: any, type: string | number) => {
          const styles = {
            value: {
              padding: 2,
            },
          };
          // @ts-ignore
          return styles[type];
        },
      },
    },
    markerCfg: (cfg: any) => {
      const { children, id } = cfg;
      return {
        show: id !== 'root' && children?.length,
        position: 'bottom',
        animate: false,
      };
    },
    edgeCfg: {
      type: 'polyline',
    },
    animate: false,
    autoFit: true,
    fitCenter: true,
  };

  return (
    <>
      <Card style={{ marginBottom: '20px' }}>
        <Form layout="inline" onFinish={onFinish} form={form}>
          <Form.Item label="address:" name="address">
            <AddressSelect mode="multiple" style={{ width: '200px' }} />
          </Form.Item>
          <Form.Item label="XXX:" name="XXX">
            <DepartmentSelect style={{ width: '200px' }} />
          </Form.Item>
          <Form.Item labelAlign="right">
            <Button onClick={onReset} style={{ marginLeft: '300px' }}>
              重置
            </Button>
          </Form.Item>
          <Form.Item labelAlign="right">
            <Button type="primary" htmlType="submit">
              查询
            </Button>
          </Form.Item>
        </Form>
      </Card>
      <Card>
        <DecompositionTreeGraph {...config} />
      </Card>
    </>
  );
};

export default DepartmentOverviewTree;

其他

获取图表实例

一、onReady 回调

import React from 'react';
import { Line } from '@ant-design/charts';

const Page: React.FC = () => {
  const data = [];
  const config = {};
  return <Line {...config} onReady={(chart) => console.log(chart)} />;
};

export default Page;

二、挂载到 ref 上

import React from 'react';
import { Bar } from '@ant-design/charts';

const Page: React.FC = () => {
  const data = [];
  const config = {};
  const ref = React.useRef();
  React.useEffect(() => {
    console.log(ref.current.getChart());
  }, []);

  return <Bar {...config} ref={ref} />;
};

export default Page;

注意

Antv DecompositionTreeGraph 指标拆解图的 data 数据源是「对象」不是「对象数组」,后端接口返回的值一般是带有多个字段的对象数组,处理时注意最后要变成严格遵循下面格式的
「对象」类型

interface XXXGraphType {
  id: string;
  value: {
    title: string;
    items: {
      text: string;
      value?: string;
    }[];
  };
  children: XXXGraphType[];
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
您好,以下是使用 ReactG2Plot 2.4.7 版本画折柱的一个简单示例: ```javascript import React, { useEffect } from 'react'; import { Line, Column } from '@antv/g2plot'; const data = [ { 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 }, ]; function Chart() { useEffect(() => { const linePlot = new Line('container', { data, xField: 'year', yField: 'sales', }); linePlot.render(); const columnPlot = new Column('container', { data, xField: 'year', yField: 'sales', seriesField: 'year', columnWidthRatio: 0.4, }); columnPlot.render(); return () => { linePlot.destroy(); columnPlot.destroy(); }; }, []); return <div id="container" />; } export default Chart; ``` 在上述代码中,我们使用了 React 的函数式组件,并在组件的 `useEffect` 钩子中创建了折线和折柱。其中,折线的数据源是 `data`,`xField` 设置为 `year`,`yField` 设置为 `sales`。柱状的数据源和 `xField`、`yField` 设置同折线一致,`seriesField` 设置为 `year`,表示将折柱按照年份进行区分。`columnWidthRatio` 设置为 `0.4`,表示柱状的宽度占比为 0.4。最后,我们将容器的 `id` 设置为 `container`,并在组件中返回该容器作为表的展示。在组件的 `return` 语句中,我们返回了一个 `div` 元素,并设置了其 `id` 为 `container`。最后,我们在 `useEffect` 钩子的返回函数中调用了 `destroy` 方法销毁表,以避免内存泄漏。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zoe_ya

如果你成功申请,可以打赏杯奶茶

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值