又炫又酷又炸的数据可视化前端开发揭秘(下篇)

作者 | 个推前端高级工程师  东风


《又炫又酷又炸的数据可视化之前端开发揭秘(上篇)》已经为大家介绍了数据可视化的构成、应用及地图的基本原理;本文则主要和大家分享下半部分的内容:个推数据可视化的实践、遇到的问题及解决思路。



个推数据可视化实践


个推的数据可视化建设有下发图、热力图等。


1)   个推消息下发图 实时展现了个推当天累计消息下发量、应用下发群体画像(包括性别比例、年龄段分布、当日应用下发城市Top5等)。


个推消息下发图


2)   个推区域人口热力图 则对区域人口分布、人口性别比例、人口年龄段等进行了数据可视化呈现。


个推打造的湖滨商圈区域人口热力图


接下来,就以下发图和热力图为例,来为大家剖析下个推的数据可视化实践过程。


前期技术选型


从效率和经济角度考虑,我们首先调研了一下现成的方案是否能满足需求。


方案一:地图应用
前面讲过,地图是以地图瓦片的形式渲染出来的,地图应用不能实现设计稿中的效果,所以该方案不可行。


方案二:图表应用
ECharts这类综合的图表库,能基本实现一些地图的效果,并且能切换视角,配置简单;但ECharts中线的效果非常有限,达不到设计稿中想要的渐变以及落地效果,也只能被忍痛放弃。


方案三:D3.js
D3.js非常优秀,我们称它是图表界的jQuery,基本能实现我们想要的效果。但是,它也存在一个问题,即它是使用SVG的。SVG是一种矢量图格式,可以保护图片呈现时不失真,但是如果用来实现动画效果,则存在性能问题。


这里,我们将SVG和Canvas进行了性能对比:当飞行数量达到100时,SVG的动画帧数FPS只有12-43,CPU占用很高;Canvas则好很多,基本上是42-60FPS,CPU占用率是20%-30%,在内存占用等各方面都完胜。


飞行数量达100时

SVG和Canvas性能对比


综合来看,以上三种方案都不完美。所以,最终,我们决定用自己的方式来实现。


第一步:分层


首先,如下图,在对地理数据进行渲染之前,我们先根据数据类型进行了分层:

1)   地图底层;

2)   热力图层;

3)   飞线层;

4)   其他任何地理空间数据层,比如柱状图、交通图等。


根据数据类型进行分层


第二步:地图底层的实现


1)   数据&配置:从阿里云DataV拿到中国地图的数据,再通过墨卡托投影算法得到转换后的数据。

2)   Canvas渲染:把数据渲染到Canvas上,这里用的是D3.js的墨卡托转换函数,再用.context方法渲染到Canvas上。

3)   调整效果:渲染完地图后,调整效果,比如阴影、边框、变形等。


第三步:热力图的实现


热力图以特殊高亮的形式显示访客热衷的页面区域和访客所在的地理区域。


热力图有两个重要的参数:Max(阈值)和Radius(半径)。

· Max:即阈值,就是刚才讲到的标尺,告诉我们某个颜色段的含义。这张图里面0表示透明度值最低,颜色最浅;然后100则表示透明度值为1,颜色最深。

· Radius:即半径,代表数据的有效范围和影响力。



而热力图的具体实现过程,大家可参考个推之前推送的一篇文章:数据可视化:浅谈热力图如何在前端实现


第四步:飞线层的实现


分线层的实现可以拆开为曲线、动画、光效三部分。



关于飞线层的具体实现,大家可以点击查看:数据可视化之下发图实践,篇幅有限,这里就不再重复叙述啦。


遇到的问题

个推在开展数据可视化实践的过程中,也遇到了一些问题。这里主要和大家分享两个问题:跨级别热力图的渲染卡顿问题样式变形后数据图层的对应问题


问题1:跨级别热力图的渲染卡顿问题


由于热力图的数据本身很大,当发生视图级别跨越的时候,数据量级成倍增长,这对性能是一个很大的考验,最终数据可视化呈现的效果会有卡顿的问题存在。


为了解决该问题,我们做了几步优化:


请求优化:首先我们将请求分成了6块,根据可视窗口进行切割,类似图片的懒加载。


缓存、防抖:然后是缓存和防抖,我们将转换过的热力图数据缓存了下来,对频繁操作进行了防抖,以避免请求堵塞。


数据聚合:最后,我们还对拿到的数据做了聚合处理。热力图本身就是一个数据融合的过程,那么,我们是否有必要再去做一个聚合?事实证明,我们做了这个聚合之后,对于数据量大或者级别过深的热力图,确实是有效果的。


其中,对于数据聚合,我们研究了四种方案:Kmeans、网格法、距离法、网格距离法。


Kmeans:首先随机选取n个聚类质心点,然后遍历每个点到每个聚类的距离并归类,再不断地迭代再归类。但这个方案对于热力图是不适用的,更适合关系图。


网格法:网格法比较简单,网格法是把屏幕里面的每个区域画成一个个格子,看哪个数据在这个格子里面,把点聚合到格子的中心,有个别点的偏差会比较大。


距离法:距离法是通过迭代每一个点、设置点的外包正方形去碰撞,若相交,则把该点聚合到该聚合点中,所以每次聚合的结果都不一样。


网格距离法:还有一个是网格距离法,顾名思义,就是前面两个方法的结合。首先迭代格子,算出网格质心,再次迭代聚合后的点,通过距离法再算一次质心。相对来讲,网格距离法会比网格法和距离法,在算法时间上多一点,但是它的结果会更准确一点。我们也正是使用该方法,使数据卡顿的问题不那么明显。


问题2:样式变形后数据图层的对应问题


第二个问题是样式变形后数据图层的对应问题。

因为对地图进行渲染的时候,我们用了一个CSS变形,模拟了一个透视效果,根据这个效果,我们渲染出来的效果如下图。



热力图和地图因为是平面效果,可以用样式变形来模拟透视效果;可是飞线和点,却是3D的效果。想象下,看烟花的时候,烟花正对我们视角的时候是不是一条直线,而呈90度角的时候,是不是正好可以看到飞线角度。


这其实正好印证了余弦定律,所以从模拟的角度来讲,这个效果已经达到了,只要我们把曲线的曲率根据视角的角度配合余弦定律转换一下。



但是这样的办法不够准确,比如曲线的控制点会不会随视角的转换而转换?

 

再来看一张图,我们之所以能模拟3D的效果渲染在屏幕上,是因为眼睛会骗人。所以,只要画出一张图跟实际看到的物体一样,我们就认为是3D的。


在地图中,我们则用样式变形,通过设置rotate X、rotate Y、rotate Z等三个参数进行转换,可以看出,旋转其实就是一系列的三角函数变换



Perspective,即假定我们坐在屏幕前面的距离一定,有了这个设定的值,就能模拟出CSS的样式变形。


当然,透视的算法非常复杂,有单点透视、两点透视以及散点透视等。这里我们只是简单地把模型映射到屏幕。


结语


数据可视化以直观、高度视觉冲击力的方式向受众揭示数据背后隐藏的规律,传达数据价值。视觉效果的背后,个推数据可视化实践的核心依托于自身海量数据的积累和数据智能技术的沉淀。


目前,个推热力图正应用于智慧城市人口空间规划公共服务等领域,为其提供强大的数据支撑。未来,个推还将持续探索将数据智能的技术应用到各垂直行业中,探索用数据智能带来产业智变。