简介
AntV: AntV 是蚂蚁金服全新一代数据可视化解决方案。其中,G2是以数据驱动,具有高度的易用性和扩展性的可视化图形语法。在 React 环境下使用 G2,官方推荐可以尝试使用 BizCharts 和 Viser-react。 总结: Bizcharts是一款基于antv的G2进行react封装的组件,是以数据为驱动的可视化图表。
Antv官网:antv.alipay.com/zh-cn/index…
Bizcharts: bizcharts.net/index
官网实例
tips:
- 这是官网给出的简单实例,是一款基础的柱状图实例。
- 官网实例有一个错误之处: 要想通过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,采用滚动来展示. 实现:
-
第一次尝试:
思路:
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>
复制代码
-
第二次尝试:
思路:
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>
复制代码
-
第三次尝试:
思路:
关闭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)
复制代码
显示效果: