數據可視化實踐

數據可視化的目的其實就是直觀地展示數據,例如讓花費數小時甚至更久才能概括的數據量,轉化成一眼就能讀懂的指標;經過加減乘除、各種公式權衡計算獲得的兩組數據差別,在圖中顏色敏感、長短大小即能造成對比;數據可視化是一個溝通複雜信息的強大武器。經過可視化信息,咱們的大腦可以更好地抓取和保存有效信息,增長信息的印象。但若是數據可視化作的較弱,反而會帶來負面效果;錯誤的表達每每會損害數據的傳播,徹底曲解和誤導用戶,因此更須要咱們多維的展示數據,就不只僅是單一層面,
目前有多種第三方庫來實現數據的可視化:Highcharts, Echarts, Chart.js, D3.js等。
總的來講,如今的第三方庫都是基於這兩種瀏覽器圖形渲染技術實現的:Canvas和SVG。canvas和webGL都是基於openGL來進行封裝。可是webGL因爲更貼近openGL因此學習曲線較陡,這裏就講解Canvas和SVG兩種。
下面是兩種圖形渲染技術的對比javascript

SVG Canvas
不依賴分辨率 依賴分辨率
支持事件處理器 不支持事件處理器
最適合帶有大型渲染區域的應用程序 弱的文本渲染能力
複雜度高會減慢渲染速度(任何過分使用 DOM 的應用都不快) 可以以 .png 或 .jpg 格式保存結果圖像
不適合遊戲應用 最適合圖圖像密集型的遊戲
能夠爲某個元素附加 JavaScript 事件處理器。在 SVG 中,每一個被繪製的圖形均被視爲對象。 一旦圖形被繪製完成,它就不會繼續獲得瀏覽器的關注。若是其位置發生變化,那麼整個場景都須要從新繪製。

Echarts

是百度的一個開源的數據可視化工具,一個純 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

如何支持多種渲染方式

echarts支持svg、canvas、vml等底層技術
echarts會根據具體的渲染平臺去作不一樣的渲染實現,底層是一個叫路徑代理PathProxy的類,它會負責這個底層的繪製指令。根據不一樣的渲染器,底層進行不一樣的實現。html

const rect = new zrender.Rect({
  shape: {
    x: 10,
    y: 10,
    width: 80,
    height: 80
  }
});

如何支持事件處理

在canvas不可以爲某個元素綁定事件,因此採用給整個圖表容器綁定事件。當進行事件處理的時候,先判斷鼠標是否在圖形之內。由於圖形通過旋轉和縮放,因此須要將鼠標座標切換到圖形座標系。獲取到圖形座標系之後,就能夠知道鼠標和圖形之間的關係,就能夠進行相應的事件處理。java

SVG渲染如何部分更新

在渲染的時候canvas一旦改變就徹底重繪,可是效率很高。對於SVG而言,假如說散點圖有一千個,那麼DOM就有一千個節點。若是每一幀都須要把DOM元素進行刪除而後添加,效率是很是低的。因此這裏但是使用virtual-Dom的方法,經過維護一個渲染對象列表,每幀將新的渲染對象列表與上一幀的進行diff,得到新增、修改、刪除的渲染對象列表,在根據列表對DOM相關節點進行調整。web

數據可視化的具體實現

這裏基於兩種實現方式,一種canvas一種svg。chrome

Canvas

在這裏實現了一個簡單的庫,能夠繪製柱狀圖、餅狀圖、折線圖、雷達圖。
下面是使用方法: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

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由於提供了一些基本的圖形組件因此更好畫,可是各有優勢。若是須要製做更好的圖形庫,咱們就須要藉助繪圖引擎,就可以針對多種平臺使用不一樣的渲染方式。

相關文章
相關標籤/搜索