HTML散点图(Scatter Plot)的三种不同实现方式性能比较

来源:互联网 发布:vb picturebox加载图片 编辑:程序博客网 时间:2024/05/14 04:19

介绍

相对于其他图表类型而言,散点图往往会接收大数据做为输入,而需要同时显示上万甚至上百万的数据点在图上。对于基于HTML的散点图来说,其性能无疑是一个非常重要的考虑因素。

下面就对比一下3种不同的散点图实现,来看看其性能如何。实现的源码可在这儿下载。为了有可比性,这儿的散点图都是在一个500*500的区域内,绘制10,0000个半径为1的绿色点。其位置完全随机。

 

散点图实现 

1. 基于SVG的散点图实现

SVG被广泛用于 基于HTML的图表实现。而用SVG实现散点图也很简单。在HTML中建一个<svg>节点,再生成相应数量的<circle>节点就可以。

因为要生成的节点比较多,因此这儿借用了node.js,先在服务器端用d3+jsdom生成了HTML页面[1],再在浏览器上直接加载。

pre-render.js

var el = window.document.querySelector('#dataviz-container'), body = window.document.querySelector('body'), circleId = 'a2324'  // say, this value was dynamically retrieved from some database// set sample datadata = [];for(var i=0; i<100000;  i++){data.push(1);}// generate the datavizvar svg = d3.select(el).append('svg:svg').attr('width', 500).attr('height', 500);svg.selectAll('.circle').data( data ).enter().append('circle').attr('r', 1).attr('fill', '#26963c').attr('cx', function(){ return Math.floor(Math.random() * 1000); })    .attr('cy', function(){ return Math.floor(Math.random() * 1000); });

index1.html

<div id="dataviz-container"><svg width="500" height="500"><circle r="1" fill="#26963c" cx="406" cy="619">more circle nodes...</circle></svg></div>
 

2. 基于SVG+d3.js的散点图实现

这个实现与上一个实现的不同之处在于,这儿不直接在HTML中罗列所有的<circle>节点,而是通过d3.js代码在浏览器加载时实时生成。

index2.html

<div id="dataviz-container"></div><script src="d3.v3.min.js"></script><script>// set sample datadata = [];for(var i=0; i<100000;  i++){data.push(1);}// generate the datavizvar svg = d3.select('#dataviz-container').append('svg:svg').attr('width', 500).attr('height', 500);svg.selectAll('.circle').data( data ).enter().append('circle').attr('r', 1).attr('fill', '#26963c').attr('cx', function(){ return Math.floor(Math.random() * 1000); })    .attr('cy', function(){ return Math.floor(Math.random() * 1000); });</script>

3. 基于HTML5 Canvas的散点图实现

HTML5 Canvas支持在<canvas>节点中绘制各种图形,因此自然也支持散点图的绘制。同样的,这儿通过JavaScript代码在<canvas>节点中生成10,0000个圆形,设置其半径为1,填色绿色。

index3.html

<canvas id="myCanvas" width="500" height="500"></canvas><script>var canvas=document.getElementById("myCanvas");var ctx=canvas.getContext("2d");ctx.beginPath();for(var i=0; i<100000; i++){  var cx = Math.floor(Math.random() * canvas.width);  var cy = Math.floor(Math.random() * canvas.height);  ctx.moveTo(cx,cy);  ctx.arc(cx,cy,1,0,Math.PI*2);}ctx.fillStyle='#26963c';ctx.fill();</script>


结果对比 

首先来看看渲染后的效果。

从图1和图2可以看出,SVG绘制的散点图边缘更加清晰,颜色比较锐利,且放大后保持了原有的清晰度。而Canvas的散点图边缘更加模糊,虽然点的数目与SVG中一样,但看起来更加密集,点与点的区分也不清楚,放大后也不能区分点与点之间的距离。这样看起来,SVG对图形的渲染更胜一筹。


图1


图2

再看看图3中页面从一开始加载到完成散点图显示的用时。这个时候Canvas显示出了巨大的优势,用了大约300ms就完成了渲染。而SVG普遍需要约3000ms。单单从这个例子来看,SVG用时是Canvas的十倍。有意思的是两个SVG实现。与想象中不同,虽然第二个SVG实现还需要通过d3.js生成<circle>节点后再绑到<svg>上去,但其用时却比第一个直接有<circle>节点的实现要少。值得注意的是,如果只是算开始渲染的时间,也就是出现散点的时间,那么第一个实现其实是发生在600ms左右的时候。如果那个时候能先渲染关键形状,那么对于用户体验来说也是一个改进。而第二种实现,目前采用的是在JavaScript中生成散点数据。如果数据来源于后端,那么从后端加载数据也需要花一定的时候,要算在页面加载的总时间里。


图3

总结 

从上面的结果来看,如果需要比较清晰的、高分辨率的渲染,那么推荐用基于SVG的实现。如果比较注重性能,则HTML5Canvas更胜一筹。

当然,这次试验用的是比较原始的实现方式。而目前很多画图的框架在SVG或者Canvas的基础架构上,想必也做了非常多的优化。还是需要根据自身的需要,选择合适自己的。

参考文献

[1] Pre-render d3.js charts at server side. https://mango-is.com/blog/engineering/pre-render-d3-js-charts-at-server-side/

原创粉丝点击