可视化引擎antv系列(一)
概述
5年前的时候,接触过一点可视化开发,因为要做用户画像,那个时候很自然了选择了百度的echarts,感觉很酷炫,很好用,纯配置写法。当时可选择的可视化引擎大概有echarts,d3,hightcharts等,相比,echarts文档最全,最易上手,功能也最强大。不过大概也就是用用api的程度,就没有然后了,感觉做的东西还花里胡哨的很好看。
时隔5年,再次开始接触到可视化,发现多了些新的选择,时代在变化。这次满脑子都是阿里开源的antv系列。
为什么是antv?
因为它真的很好看,我们的设计师也很喜欢。
啊哈。
因为它的简介写的非常棒
G2 是一套基于图形语法理论的可视化底层引擎,以数据驱动,提供图形语法与交互语法,具有高度的易用性和扩展性。文档系统 刚接触这个,文档看起来很完善,排版也很清晰。
这根本看不懂在说啥呀。。。
嗯,很有生活美感 和 哲学的味道,整了一大推的术语和理念。
哦,原来可视化不仅仅是渲染,还有底层理论支撑?
还有什么比新事物更吸引人的呢
但是想搞懂还是比较难得,起码得读3遍吧,非常多的 术语 和 概念。
当你认为你懂了一些去开发的时候,会发现文档很不完善。。。
很多东西文档并没有写出来,需要去源码里寻找,而且社区还不是很完善。
antv家族
文章图片
很完善的一整套解决方案。
react技术栈系列 由下至上,技术架构链条如下:
G ---> G2 ---> G2Plot ---> Ant Design Charts
当然G绘图引擎底层还有其他库.
我们从上到下,先做个大方向的技术分析,对整套技术架构有个基本的认知。
Ant Design Charts
这个非常简单,就是对G2Plot封装了一个 React版本,通用一个useChart的hook完成,通过props透传属性。
优点如下:
- 进一步封装了G2Plot的api,弱化底层逻辑
- 扩展了一些额外的能力
const PieChart = forwardRef((props: PieConfig, ref) => {
const {
chartRef,
style = {
height: 'inherit',
},
className,
loading,
loadingTemplate,
errorTemplate,
...rest
} = props;
const { chart, container } = useChart(G2plotPie, rest);
useEffect(() => {
getChart(chartRef, chart.current);
}, [chart.current]);
useImperativeHandle(ref, () => ({
getChart: () => chart.current,
}));
return (
{loading && }
);
});
export default PieChart;
然后在组件初始化后实例化 G2Plot实例即可,其他做一个事件传递工作。
useEffect(() => {
if (!container.current) {
return () => null;
}
processConfig();
const chartInstance: T = new (ChartClass as any)(container.current, {
...config,
});
}, [])
当然,如果有不满足需求的地方,需要操作G2Plot实例,依然可以通过 ref 等方式来获取g2plot的实例,直接调用其属性和方法。
G2Plot
G2本身是声明式语法,使用起来还是有点琐碎,G2Plot封装了G2的指令语法,通过 配置式的方式使用,大大简化了上手成本。本质就是把json配置转化成G2命令语法。
G2Plot的技术实现架构特别好,逻辑清晰,层次非常分明,通用性极高。
所有图形类都继承自 base 基类。
代码如下:非常简单,拿到参数配置,实例化G2,绑定事件。
文章图片
然后再看一个图形类的封装,比如柱状图:
文章图片
很简单吧,其他图形基本都是这个模式的,核心只需要实现两个点:
- 参数配置
- 适配器
参数配置没啥好讲的,核心看下 适配器:
文章图片
这里的flow实质就是一个类似高阶函数reduce的聚合操作,核心逻辑就是 函数式编程的 组合方式。本质就是流式传输参数options和实例chart,去调用转换各个环节的api。
G2也比较意思,它依赖底层绘图引擎G,所以它本身也是隐藏了绘图api命令,做了一个参数的转换操作。
/**
* Chart 类,是使用 G2 进行绘图的入口。
*/
export default class Chart extends View {}/**
* G2 视图 View 类
*/
export class View extends Base {}/**
* G2 Chart、View、Geometry 以及 Element 等的基类,提供事件以及一些通用的方法。
*/
export default class Base extends EE {}EE 就是一个发布订阅的事件类
看上面的继承逻辑,已经很清晰了表达了各个类处理的事情。这里面需要理解view容器层的概念,后续再做详细解释。
【可视化引擎antv系列(一)】接着往下看,比较有意思的public 方法api。
文章图片
认真看这些方法的调用,仅仅是进行了 options的set操作,然后就没有然后了。
看到这里,会疑惑,那G2到底在哪里进行界面绘制呢?我们看render函数:
文章图片
这个方法进行真正的递归绘制,内部调用G引擎,各组件维护自身绘制,细节后续再讲。
到了这里产生了一个疑惑,既然需要调用render函数才能绘制,那么交互动作并没有调用render是如何实现界面重绘的呢?
交互的绘制时机 在找答案之前,先思考了一番,以为它是通过循环机制来控制的,因为我之前搞游戏开发就是这个模式。
结果只猜对了一半,G引擎的实现真的很机智,找了很久才找到,如下:
文章图片
文章图片
竟然使用 监听模式来启动 帧频绘制,而不是传统意义上的主循环,这对性能是个很大的提升。
里面还涉及了局部绘制,这个逻辑就相当复杂了。
这个运用之妙,自省体会。
下期再见!
推荐阅读
- 为什么孩子一定要学会可视化思维!
- 17个搜索引擎
- 搜索引擎有哪些
- 正则匹配
- PHP简易规则引擎
- [数据可视化]Seaborn简单介绍
- r语言|手把手(R语言文本挖掘和词云可视化实践)
- R|【R数据可视化手册】笔记1-条形图
- Python--matplotlib绘图可视化
- Pyecharts|Pyecharts 猎聘招聘数据可视化