數據可視化的目的其實就是直觀地展示數據,例如讓花費數小時甚至更久才能概括的數據量,轉化成一眼就能讀懂的指標;經過加減乘除、各種公式權衡計算獲得的兩組數據差別,在圖中顏色敏感、長短大小即能造成對比;數據可視化是一個溝通複雜信息的強大武器。經過可視化信息,咱們的大腦可以更好地抓取和保存有效信息,增長信息的印象。但若是數據可視化作的較弱,反而會帶來負面效果;錯誤的表達每每會損害數據的傳播,徹底曲解和誤導用戶,因此更須要咱們多維的展示數據,就不只僅是單一層面,
目前有多種第三方庫來實現數據的可視化:Highcharts, Echarts, Chart.js, D3.js等。
總的來講,如今的第三方庫都是基於這兩種瀏覽器圖形渲染技術實現的:Canvas和SVG。canvas和webGL都是基於openGL來進行封裝。可是webGL因爲更貼近openGL因此學習曲線較陡,這裏就講解Canvas和SVG兩種。
下面是兩種圖形渲染技術的對比javascript
SVG | Canvas |
---|---|
不依賴分辨率 | 依賴分辨率 |
支持事件處理器 | 不支持事件處理器 |
最適合帶有大型渲染區域的應用程序 | 弱的文本渲染能力 |
複雜度高會減慢渲染速度(任何過分使用 DOM 的應用都不快) | 可以以 .png 或 .jpg 格式保存結果圖像 |
不適合遊戲應用 | 最適合圖圖像密集型的遊戲 |
能夠爲某個元素附加 JavaScript 事件處理器。在 SVG 中,每一個被繪製的圖形均被視爲對象。 | 一旦圖形被繪製完成,它就不會繼續獲得瀏覽器的關注。若是其位置發生變化,那麼整個場景都須要從新繪製。 |
是百度的一個開源的數據可視化工具,一個純 Javascript 的圖表庫,可以在 PC 端和移動設備上流暢運行,兼容當前絕大部分瀏覽器(IE6/7/8/9/10/11,chrome,firefox,Safari等),底層依賴輕量級的 Canvas 庫 ZRender,ECharts 提供直觀,生動,可交互,可高度個性化定製的數據可視化圖表。下面是簡單的使用方法:css
option = { xAxis: { type: 'category', data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] }, yAxis: { type: 'value' }, series: [{ data: [820, 932, 901, 934, 1290, 1330, 1320], type: 'line' }] };
echarts支持svg、canvas、vml等底層技術
echarts會根據具體的渲染平臺去作不一樣的渲染實現,底層是一個叫路徑代理PathProxy的類,它會負責這個底層的繪製指令。根據不一樣的渲染器,底層進行不一樣的實現。html
const rect = new zrender.Rect({ shape: { x: 10, y: 10, width: 80, height: 80 } });
在canvas不可以爲某個元素綁定事件,因此採用給整個圖表容器綁定事件。當進行事件處理的時候,先判斷鼠標是否在圖形之內。由於圖形通過旋轉和縮放,因此須要將鼠標座標切換到圖形座標系。獲取到圖形座標系之後,就能夠知道鼠標和圖形之間的關係,就能夠進行相應的事件處理。java
在渲染的時候canvas一旦改變就徹底重繪,可是效率很高。對於SVG而言,假如說散點圖有一千個,那麼DOM就有一千個節點。若是每一幀都須要把DOM元素進行刪除而後添加,效率是很是低的。因此這裏但是使用virtual-Dom的方法,經過維護一個渲染對象列表,每幀將新的渲染對象列表與上一幀的進行diff,得到新增、修改、刪除的渲染對象列表,在根據列表對DOM相關節點進行調整。web
這裏基於兩種實現方式,一種canvas一種svg。chrome
在這裏實現了一個簡單的庫,能夠繪製柱狀圖、餅狀圖、折線圖、雷達圖。
下面是使用方法:canvas
const canvas = document.getElementById('canvas'); const data = [{ name: '籃球', value: 2260, }, { name: '羽毛球', value: 1170, }, { name: '乒乓球', value: 1230, }, { name: '足球', value: 1450, }, ]; const settings = { type: 'bar' }; new Chart(canvas, data, { title: 'Sport' }, settings);
下面是效果圖
構造函數能夠傳入的參數有四個,canvas畫布對象,data是咱們傳入的數據對象,settings是傳入的配置,就能夠定義圖形的類型,能夠是柱狀圖,或者折線圖。在這裏根據傳入的type進行相應的繪圖更改。內部的實現原理以下:瀏覽器
if (settings) { Object.keys(settings).map((key) => { this[key] = settings[key]; }); }
上面這個部分就可以讓傳入的參數覆蓋已有的默認設置,顏色,座標。有些設置須要經過計算才能得到,例如每一個單位長度的標記,獲取每一個值的比例。例如:app
this.totalValue = this.getTotalValue(); this.maxValue = this.getMaxValue(); function getTotalValue() { let total = 0; this.data.map((item) => { total += item.value; }); return total; }
這裏先計算出總數,而後繪製餅狀圖的時候就計算出每一條數據所佔的比例,進行繪圖。
下面這部分會根據傳入的type來繪製不一樣的圖形,下面是具體實現:echarts
if (this.type === 'bar' || this.type === 'line') { this.drawBarUpdate(); } else if (this.type === 'pie' || this.type === 'ring') { this.drawPieUpdate(); } else if (this.type === 'radar') { this.drawRadarUpdate(); }
看draBarUpdate
的具體實現:
drawBarUpdate() { this.drawAxis(); this.drawPoint(); this.drawTitle(); this.drawBarChart(); }
前三個函數用於基本的結構,軸、點、標題。第四個函數用來繪製圖形。主要藉助的是canvas的幾種方法fillStyle
:設置填充繪畫的顏色、漸變或模式;strokeStyle
: 設置筆觸的顏色、漸變或模型;beginPath
:開始一條路徑,或者重置當前的路徑;arc
: 用來建立弧/曲線arc(x, y, r, startAngle, endAngle, direction)
x,y分別表明圓中心的x,y座標。startAngle爲起始角,endAngle爲結束角,direction表明順時針,仍是逆時針繪圖。首先根據數據的長度,肯定每條數據的長度和座標而後使用下面操做進行繪圖。
this.ctx.beginPath(); this.ctx.arc(x, y, radius, startAngle, endAngle, direction); this.ctx.fill();
這樣就能夠繪製圖形了
SVG是一種使用XML描述2D圖形的語言。SVG基於XML,這意味着SVG DOM的每一個元素都是可用的。你能夠爲每一個元素附加javaScript事件處理器。
svg不一樣於canvas,提供了不少基本形狀。例如rect: 圓;circle: 橢圓;ellipse:直線;line: 折線;polyline:多邊形;polygon:路徑。
這裏藉助common模塊下的pie.js進行了解。
下面是使用方法:
var myPie = new Pie({ pieR: 40, // 外徑 donutR: 35, // 內徑 rotation: -90, // 旋轉到從y軸正方向起始 strokeColor: '#FFF', // 使用白色描邊 animation: true, // 啓用默認展示動畫 slices: [{ color: '#E3E3E3', // 第一切片顏色 percent: 0.1 // 第一切片面積佔比 }, { color: '#5FC2F5', // 第二切片顏色 percent: 0.2 // 第二切片面積佔比 }, { percent: 0.3 // 第三切片面積佔比 }, { percent: 0.4 // 第四切片面積佔比 }] }); $('body').append(myPie.getNode()); // 插入餅圖。
下面是效果圖
首先也是進行重置默認的參數設置,還有計算一些屬性,例
this.args = $.extend({ pieR: 100, slices: [{ percent: 1, }], }, args); $.each(this.args.slices, function(i, item) { item.angle = (item.percent || 0) * 360; })
而後設置每一個元素應該設置的路徑,是經過下面函數進行實現:
/** * @param {Number} startAngle 開始的角度 * @param {Number} angle 旋轉角度 * @param {Number} pieR 半徑 * @param {Number} donutR 環形圖所須要的參數 * @return {Object} 座標對象 */ getSectorPath(startAngle, angle, pieR, donutR) { startAngle = startAngle * Math.PI / 180; angle = angle * Math.PI / 180; var startAngleTri = { cos: Math.cos(startAngle), sin: Math.sin(startAngle) }; var angleTri = { cos: Math.cos(startAngle + angle), sin: Math.sin(startAngle + angle) }; return [ 'M', donutR * startAngleTri.cos, donutR * startAngleTri.sin, // 開始點 'L', pieR * startAngleTri.cos, pieR * startAngleTri.sin, // 開始的邊界 'A', pieR, pieR, // 外部的半徑 0, // x軸上的旋轉 Math.abs(angle) > Math.PI ? 1 : 0, // large-arc-flag 1, // sweep-flag pieR * angleTri.cos, pieR * angleTri.sin, // end point 'L', donutR * angleTri.cos, donutR * angleTri.sin, // end edge 'A', donutR, donutR, // inner arc 0, // x軸上的旋轉 Math.abs(angle) > Math.PI ? 1 : 0, // large-arc-flag 0, // sweep-flag donutR * startAngleTri.cos, donutR * startAngleTri.sin // 結束點 ].join(' '); }
繪製圖形是靠的path這個元素,下面的命令能夠用於路徑數據:
M = moveto L = lineto H = horizontal lineto V = vertical lineto C = curveto S = smooth curveto Q = quadratic Belzier curve T = smooth quadratic Belzier curveto A = elliptical Arc Z = closepath
簡便寫就能夠以下:
<path d="M250 150 L150 350 L350 350 Z" />
那麼繪製餅狀圖的就能夠以下這麼寫:
$(path).attr({ 'd': getSectorPath(startAngle, angle, pieR, donutR) }).css({ // 屬性 })
這就是svg的繪畫方式,相對canvas繪畫,svg由於提供了一些基本的圖形組件因此更好畫,可是各有優勢。若是須要製做更好的圖形庫,咱們就須要藉助繪圖引擎,就可以針對多種平臺使用不一樣的渲染方式。