代码如下:
var aXY = [[x1, y1], [x2, y2], [x3, y3], [x4, y4]...]; var context = canvas.getContext('2d'); for (var i = 0, len = aXY.length; i < len; i++) { var x = aXY[i][0], y = aXY[i][1]; //绘制径向渐变 var radgrad = this.context.createRadialGradient(x, y, 1, x, y, 8); //锚点 radgrad.addColorStop( 0, 'rgba(255,30,0,1)'); //锚点 radgrad.addColorStop( 1, 'rgba(255,30,0,0)'); context.fillStyle = radgrad; context.fillRect( x - 8, y - 8, 16, 16); }
效果如下:

方案度量:这是比较简单的实现方案,稍微麻烦的地方在于根据alpha值计算红蓝绿值,使得alpha高的地方显示红色,alpha低的显示蓝色,中间部分显示黄/绿色(考虑到效率与简单性,使用了简单的三角函数,如果需要更为精确的色相渐变,可以使用幂次变换)。同时这个方案的缺点也十分明显:在点数据量低的时候效率很高,但是点数据超过10000之后就会有明显的时间延迟>3s,原因在于循环绘制渐变色会消耗资源。其次该方案的性能也会取决于画布的大小。画布大的情况,比如画布尺寸为1200*3000,对其取位数据的时候,将会循环360万次,同时进行3*360万sin运算~~对于客户端性能是个问题。
方法二
思路:对所有点数据进行计算,得出每个点的密度值,然后依据密度值由低到高,绘制点数据。
代码:
var points = [[x1, y1], [x2, y2], [x3, y3], [x4, y4]...]; var cache = {}; //计算每个点的密度 for (var i = 0, len = points.length; i < len; i++) { for (var j = 0, len2 = points[i].length; j < len2; j++) { var key = points[i][j][0] + '*' + points[i][j][1]; if (cache[key]) { cache[key] ++; } else { cache[key] = 1; } } } //点数据还原 var oData = []; for (var m in cache) { if (m == '0*0') continue; var x = parseInt(m.split('*')[0], 10); var y = parseInt(m.split('*')[1], 0); oData.push([x, y, cache[m]]); } //简单排序,使用数组内建的sort oData.sort(function(a, b){ return a[2] - b[2]; }); var max = oData[oData.length - 1][2]; var pi2 = Math.PI * 2; //设置阈值,可以过滤掉密度极小的点 var threshold = this._points_min_threshold * max; //alpha增强参数 var pr = (Math.log(245)-1)/245; for (var i = 0, len = oData.length; i < len; i++) { if (oData[i][2] 0 ? 0 : 1); //q参数用于平衡梯度差,使之符合人的感知曲线log2N,如需要精确梯度,去掉log计算 var q = parseInt(Math.log(oData[i][2]) / Math.log(max) * 255); var r = parseInt(128 * Math.sin((1 / 256 * q - 0.5 ) * Math.PI ) + 200); var g = parseInt(128 * Math.sin((1 / 128 * q - 0.5 ) * Math.PI ) + 127); var b = parseInt(256 * Math.sin((1 / 256 * q + 0.5 ) * Math.PI )); var alp = (0.92 * q + 20) / 255; //如果需要灰度增强,则取消此行注释 //var alp = (Math.exp(pr * q + 1) + 10) / 255 var radgrad = this.context.createRadialGradient(oData[i][0], oData[i][1], 1, oData[i][0], oData[i][1], 8); radgrad.addColorStop( 0, 'rgba(' + r + ',' + g + ','+ b + ',' + alp + ')'); radgrad.addColorStop( 1, 'rgba(' + r + ',' + g + ','+ b + ',0)'); this.context.fillStyle = radgrad; this.context.fillRect( oData[i][0] - 8, oData[i][1] - 8, 16, 16); }
以上代码结果如下:

大约处理了25000个点,用时大约700ms(鄙人的小本性能还行)。属于可接受范围内。
方案度量:此方案性能比方案一有明显优势。目前Marmot采用此方案。
原文:http://www.baiduux.com/blog/2010/08/31/%e5%9f%ba%e4%ba%8ecanvas%e7%9a%84%e7%83%ad%e5%8a%9b%e5%9b%be%e7%bb%98%e5%88%b6%e6%96%b9%e6%b3%95/
本文链接:http://www.blueidea.com/tech/web/2010/7933.asp
出处:百度泛用户体验
责任编辑:bluehearts
上一页 基于Canvas的热力图绘制方法 [2] 下一页
◎进入论坛网页制作、WEB标准化版块参加讨论,我还想发表评论。
|