【★】从拓扑图案例来分析如何写可视化组件
我准备今后每一周都给自己一个技术方面的尝试主题,来提升自己的技术能力。
一般这种主题都是和当前或者未来的工作相关的,做到学以致用、目标明确。
本周的主题就是:拓扑可视化。通过拆解之前同事的代码,加上扩展新的功能,来实现。
写在前面的思考
一开始我感觉这个比较难,不知道每一个模块的实现思路,有畏难情绪。
然后看了大约一个半小时,熟悉代码后,发现其实并不难,还是和业务开发类似,站在别人的肩膀上(ZRender、Dagre)实现功能,有套路可循的。
需求目标
1、产出技术拆解文章
2、扩展布局功能
3、实现聚合功能:缩小到一定程度,自动根据相似规则做聚合?
4、实现图标自定义功能
技术准备
还是老规矩,对应技术的API文档先仔细过一遍,事半功倍。
ZRender
图形元素
| 页面元素 | ZRender元素 | 备注 |
|---|---|---|
| 关系连线 | Polyline | 通过2个点来画图 |
| 箭头 | Polygon | 通过3个点+rotation来画图 |
| 节点的方块 | Rect | 可以自定义,但是目前局限于矩形 |
样式自定义
了解下ZRender的各种图形元素的配置即可,一般来说,每个图形元素都可以通过配置style属性来设置样式。
D3.js
目前我们暂未用到D3.js,后续支持多种布局时(比如树状布局、力导向布局等),可能会用到。
为了今后考虑,我们现在计算布局位置这部分代码,一定要设计好,要足够独立,最好支持插件式扩展。
Dagre.js
需要了解这个的node和edge的数据结构。
注意edge的键名是一个对象,不是字符串。
new dagre.graphlib.Graph()对象常用的几个api方法也要熟悉,比如:setGraph、setDefaultEdgeLabel、setNode、setEdge、node、nodes等。
计算布局是通过dagre.layout(g)这个方法。
设计思路
通过《The Grammar of Graphics》中的树状层级结构图来进行程序设计。
group
组的概念在可视化绘图中非常重要,因为你经常会涉及一批图形元素的定位、移动/形变和美化(即CSS三要素)。这种情况下肯定不能一个个去修改他们的属性,都是通过组,或者也可以理解为容器,批量去操作的。
数据绑定
给页面元素设置属性,将数据绑定上去。然后需要的时候,通过类似e.target.parent.name这样的方式,获取元素的属性数据,执行对应的元素筛选操作和样式修改操作。
配置项
可视化开发,或者说前端开发,其配置项其实都是有固定的套路可循,大致可以分为如下几个类型:
实体数据结构
我把每一个节点、每一个关系,叫做一个实体。每个实体最终会映射为页面上的一个/组可视元素,比如一个圆圈、一条线等等。
实体的数据,一般用来标记其本身的特性,比如唯一id、名称、分类、各种标签等等,用途是对实体做分类筛选,或者直接在页面上展示这些属性信息。
CSS配置:定位、移动、美化
定位:
通常是通过提供几种可选的、固定的布局方式,让用户配置布局名称;
移动:
这块一般不需要配置,直接通过时间监听去实现;
美化:
这块所需的配置最多,我们一般会将其放在一个名为style的配置中,包含如下几项:
1 | |
且针对里面的每一项,如果需要的话,还会允许其传入一个Lambda函数,以实现高度自定义的功能。
事件监听
相对来说,用户需要自己处理事件监听的情况较少,因此我们一般是将事件监听从整体配置里面独立出来,在页面初始化之后,单独给某些元素绑定时间监听。
具体实现
我将每个小模块的技术实现,通过xmind做了拆解,如下:

思考:可视化开发的套路
技术拆解是看着别人的代码去点评,这是相对很容易的。如果今后我需要自己开发可视化的组件,该怎么做呢?
这个感觉和近期我们要做的《组件编写指南》很类似,可以相互参考借鉴。
元素拆分
参考《The Grammar of Graphics》中的树状层级结构图,将页面元素和交互进行拆解,并标注每一个依赖的技术和实现方案。
数据结构
分为实体/关系的数据结构、样式配置项的数据结构、事件配置的数据结构、API配置结构。
程序结构
这个我得好好琢磨下,然后形成一个规范,再将其做成脚手架工具。
这个弄好了,程序设计就完成一小半了。