欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Bizcharts: 基于react封装的G2图表插件

程序员文章站 2022-04-22 10:36:55
...

简介

AntV: AntV 是蚂蚁金服全新一代数据可视化解决方案。其中,G2是以数据驱动,具有高度的易用性和扩展性的可视化图形语法。在 React 环境下使用 G2,官方推荐可以尝试使用 BizCharts 和 Viser-react。 总结: Bizcharts是一款基于antv的G2进行react封装的组件,是以数据为驱动的可视化图表。

Antv官网:antv.alipay.com/zh-cn/index…

Bizcharts: bizcharts.net/index

官网实例

tips:

  1. 这是官网给出的简单实例,是一款基础的柱状图实例。
  2. 官网实例有一个错误之处: 要想通过alias进行坐标轴标题的展示,必须要Axis中加上title,此问题可在issue中找到具体回答 github.com/alibaba/Biz…
import React from 'react';
import ReactDOM from 'react-dom';
import { Chart, Geom, Axis, Tooltip, Legend, Coord } from 'bizcharts';

// 数据源
const data = [
  { genre: 'Sports', sold: 275, income: 2300 },
  { genre: 'Strategy', sold: 115, income: 667 },
  { genre: 'Action', sold: 120, income: 982 },
  { genre: 'Shooter', sold: 350, income: 5271 },
  { genre: 'Other', sold: 150, income: 3710 }
];

// 定义度量, alias: 坐标轴标题
const cols = {
  sold: { alias: '销售量' },
  genre: { alias: '游戏种类' }
};

// 渲染图表
ReactDOM.render((
  <Chart width={600} height={400} data={data} scale={cols}>
      <Axis name="genre" title />
      <Axis name="sold" title />
      <Legend position="top" dy={-20} />
      <Tooltip />
      <Geom type="interval" position="genre*sold" color="genre" />
    </Chart>
), document.getElementById('mountNode'));
复制代码

使用难点

1. Label: 自定义柱状图顶端的HTML

htmlTemplate: (Function)可用于自定义柱状图顶部的html文本 tip: 要使用htmlTemplate,Label组件中必须有content属性

htmlTemplate = (text, item) => {
    switch(Number(item._origin.ranking)) {
    case 1:
      return `<img src=${Rank} style="display: inline-block;width: 24px;height: 24px;" />`;
    case 2:
      return `<img src=${Rank} style="display: inline-block;width: 24px;height: 24px;" />`;
    case 3:
      return `<img src=${Rank} style="display: inline-block;width: 24px;height: 24px;" />`;
    default:
      return '<span class="title" style="display: inline-block;width: 50px;text-align: center;">' + item._origin.sold + '</span>';
    }
  }
复制代码

2. Chart: 父容器宽度改变时, 自适应改变

需求: 产品要求,当数据list.length<10,自适应当前宽度;list数量>10,采用滚动来展示. 实现:

  1. 第一次尝试:

    思路:

       list.length>10: chart关闭forcefit(自适应),width=length*80
    
       list.length<10:  chart开启forcefit(自适应)
    复制代码

    结果: 不成功

    原因: forcefit在首次生成实例的时候,读取了数值;后续forcefit的值发生变化,无效.forcefit的设置只在首次有效

    // 图表宽度
    const chartWidth = list.length > 10 ? list.length * 80 : '100%';
    <ChartWrap overflow={list.length>10?'auto':'hidden'} display={list.length?'block':'none'} >
        <Chart forceFit={list.length>10?false:true} width={chartWith} height={400} data={list} scale={cols}>
            <Axis name="departmentName" />
            <Axis name="countOrAmount" title />
            <Legend name="rankType" />
            <Geom type="interval" position="departmentName*countOrAmount" color="rankType" size={30}>
              <Label content="countOrAmount" />
            </Geom>
        </Chart>
    </ChartWrap>
复制代码
  1. 第二次尝试:

    思路:

       list.length>10: chart的父元素变宽. chart开启forcefit(自适应)
    
       list.length<10: chart的父元素宽度为100%. chart开启forcefit(自适应)
    复制代码

    结果: 不成功

    原因: forcefit(自适应)始终开启,生成canvas画布的时候,canvas的宽度读取了父元素(Content)的宽度, list.length>10,宽度变大,但是canvas没有重新读取父元素(content)的宽度从而发生变化,因为forfeit监听的是window的resize事件,父元素宽度虽然发生了变化,但是没有触发forcefit,所以canvas没有重新读取宽度后绘制.

    github的issues中有相关的问题: https://github.com/alibaba/BizCharts/issues/610

    这个问题的原因,就是因为虽然父元素宽度变化了,但是没有触发resize事件,所以没有重新父元素宽度进行自适应.

    // 父容器宽度
    const contentWidth = list.length > 10 ? list.length * 10 + '%' : '100%';
    
      <ChartWrap overflow={list.length>10?'auto':'hidden'} display={list.length?'block':'none'} >
        <Content width={contentWidth}>
          <Chart forceFit height={400} data={list} scale={cols}>
            <Axis name="departmentName" />
            <Axis name="countOrAmount" title />
            <Legend name="rankType" />
            <Geom type="interval" position="departmentName*countOrAmount" color="rankType" size={30}>
              <Label content="countOrAmount" />
            </Geom>
          </Chart>
        </Content>
      </ChartWrap>
复制代码
  1. 第三次尝试:

    思路:

       关闭forcefit(自适应),直接根据list长度来算出父元素(content)的宽度,再通过react的ref属性换算成具体的数值,赋值给chart的width
    复制代码

    结果: 成功

    重点: react的ref属性,可以获得父元素的具体宽度, 因为chart的width只接受具体数字,不接受百分比

    // 父容器宽度
    const contentWidth = list.length > 10 ? list.length * 10 + '%' : '100%';
    // chart 具体宽度的计算: 通过react的ref属性,获得content的具体宽度,赋值给chart
    const chartWidth = this.content ? this.content.offsetWidth : 0;
    
    <ChartWrap overflow={list.length>10?'auto':'hidden'} display={list.length?'block':'none'} >
        <div style={{ width: contentWidth }} ref={this.onRef}>
          <Chart width={chartWidth} height={400} data={list} scale={cols}>
            <Axis name="departmentName" />
            <Axis name="countOrAmount" title />
            <Legend name="rankType" />
            <Geom type="interval" position="departmentName*countOrAmount" color="rankType" size={30}>
              <Label content="countOrAmount" />
            </Geom>
          </Chart>
        </div>
    </ChartWrap>
复制代码

3. Axis: 自定义坐标轴显示文本

需求: 在bizcharts中,X轴的刻度重名的话,会出现柱状图重叠的情况。需要解决这种情况。

解决: 用id等唯一的标识作为X轴的name,自定义X轴刻度的显示文本。

    // year 作为X轴的name,重名 
   const data = [
      { year: "1951 年", sales: 38 },
      { year: "1951 年", 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 }
    ];
复制代码

就会出现柱状图重叠

自定义文本的代码:

import React from "react";
import {
  G2,
  Chart,
  Geom,
  Axis,
  Tooltip,
  Coord,
  Label,
  Legend,
  View,
  Guide,
  Shape,
  Facet,
  Util
} from "bizcharts";

class Basiccolumn extends React.Component {
  render() {
    const data = [
      {
        year: "1951 年",
        sales: 38,
        id: '1' //  唯一标识最好为字符串,因为如果是Number类型,显示需要再次进行调整
      },
      {
        year: "1951 年",
        sales: 52,
        id: '2'
      },
      {
        year: "1956 年",
        sales: 61,
        id: '3'
      },
      {
        year: "1957 年",
        sales: 145
      },
      {
        year: "1958 年",
        sales: 48,
        id: '4'
      },
      {
        year: "1959 年",
        sales: 38,
        id: '5'
      },
      {
        year: "1960 年",
        sales: 38,
       	id: '6'
      },
      {
        year: "1962 年",
        sales: 38,
        id: '7'
      }
    ];
    const cols = {
      sales: {
        tickInterval: 20
      }
    };

    const label = {
      formatter(text, item, index) {
        let name = data[index].year;
        return name;
      },
    };
    
    return (
      <div>
        <Chart height={400} data={data} scale={cols} forceFit>
        // 用id这种唯一标识的作为X轴的name, 通过label自定义坐标轴的显示文本
          <Axis name="id" label={label} />
          <Axis name="sales" />
          <Tooltip
            crosshairs={{
              type: "y"
            }}
          />
          <Geom type="interval" position="id*sales" />
        </Chart>
      </div>
    );
  }
}

ReactDOM.render(<Basiccolumn />, mountNode)
复制代码

显示效果:

转载于:https://juejin.im/post/5c6132a7518825628013095e