代碼如下:
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); }
效果如下:
方案度量:這是比較簡單的實現(xiàn)方案,稍微麻煩的地方在于根據(jù)alpha值計算紅藍綠值,使得alpha高的地方顯示紅色,alpha低的顯示藍色,中間部分顯示黃/綠色(考慮到效率與簡單性,使用了簡單的三角函數(shù),如果需要更為精確的色相漸變,可以使用冪次變換)。同時這個方案的缺點也十分明顯:在點數(shù)據(jù)量低的時候效率很高,但是點數(shù)據(jù)超過10000之后就會有明顯的時間延遲>3s,原因在于循環(huán)繪制漸變色會消耗資源。其次該方案的性能也會取決于畫布的大小。畫布大的情況,比如畫布尺寸為1200*3000,對其取位數(shù)據(jù)的時候,將會循環(huán)360萬次,同時進行3*360萬sin運算~~對于客戶端性能是個問題。
方法二
思路:對所有點數(shù)據(jù)進行計算,得出每個點的密度值,然后依據(jù)密度值由低到高,繪制點數(shù)據(jù)。
代碼:
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; } } } //點數(shù)據(jù)還原 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]]); } //簡單排序,使用數(shù)組內(nèi)建的sort oData.sort(function(a, b){ return a[2] - b[2]; }); var max = oData[oData.length - 1][2]; var pi2 = Math.PI * 2; //設(shè)置閾值,可以過濾掉密度極小的點 var threshold = this._points_min_threshold * max; //alpha增強參數(shù) 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參數(shù)用于平衡梯度差,使之符合人的感知曲線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); }
以上代碼結(jié)果如下:
大約處理了25000個點,用時大約700ms(鄙人的小本性能還行)。屬于可接受范圍內(nèi)。
方案度量:此方案性能比方案一有明顯優(yōu)勢。目前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://m.95time.cn/tech/web/2010/7933.asp
出處:百度泛用戶體驗
責任編輯:bluehearts
上一頁 基于Canvas的熱力圖繪制方法 [2] 下一頁
◎進入論壇網(wǎng)頁制作、WEB標準化版塊參加討論,我還想發(fā)表評論。
|