我們從用面向對象的方式繪製圖表,到echarts實現k線圖,我們體驗到使用echarts等可視化庫的方便之處。

今天我們就分析一個實際案例。通過可視化成績查詢系統中的一個小模塊-折線圖,讓大家感受一下實際項目中如何進行選型和實現。

業務背景:為什麼做學生成績可查

本篇我們將使用D3.js實現學生成績可查,圖表主要用來將所有測試過的技能類別,分數可視化,以此我們根據自身測試分數,做相應的查漏補缺,方便我們科學地提升自己專業能力,

技術選型:了解D3

因為canvs在數據展示方面,方便和操作難易程度上要弱於svg,所以我們選擇D3.

D3(或D3.js)是一個JavaScript庫,用於使用Web標準可視化數據。D3可幫助您使用SVG,Canvas和HTML將數據變為現實。D3將強大的可視化和交互技術與數據驅動的DOM操作方法相結合,為您提供現代瀏覽器的全部功能,並可自由地為您的數據設計正確的可視界面。

Canvas與SVG的對比

正如介紹所說,D3支持SVG與Canvas,我們看下兩者的差異:

Canvas

1)依賴解析度,

2)不支持事件處理器

3)弱的文本渲染能力

4)能夠以 .png 或 .jpg 格式保存結果圖像,

5)最適合圖像密集型的遊戲,其中的許多對象會被頻繁重繪。

SVG

1)不依賴解析度,線條顏色平滑,抗鋸齒

2)支持事件處理,便於用戶交互

3)最適合帶有大型渲染區域的應用程序(比如谷歌地圖)

4)複雜度高會減慢渲染速度(任何過度使用 DOM 的應用都不快)

5)不適合遊戲應用。

注意看SVG的第二點,數據交互這個是svg相比canvas的突出優勢,特別適合於可視化圖表製作,

svg可以用css,或者javascript操作,而且語法近似jQuery。用D3繪製SVG圖形,採用鏈式語法,大大縮短了我們的開發時間。

了解SVG

SVG元素有寬高屬性width,height表示繪製區域的寬度,高度。

SVG預定了七種元素:

  • <react>矩形,
  • <cricle>圓形,
  • <ellipse>橢圓形,
  • <line>線段,
  • <polyline>折線,
  • <polygon>多邊形,
  • <path>路徑。

1,矩形參數為6個:

  • x:矩形左上角的x坐標,
  • y:矩形左上角的y坐標,
  • width:矩形的寬度,
  • height:矩形的高度,
  • rx:對於圓角矩形,指定橢圓在x方向的半徑,
  • ry:對於圓角矩形,指定橢圓在y方向的半徑。

2,圓形和橢圓形

  • cx:圓形的x坐標,
  • cy:圓心的y坐標,
  • r:圓的半徑。

橢圓與圓的參數差別就是將r分為rx,ry,分別表示橢圓的水平半徑,垂直半徑。

3,線條的參數有四個:

  • x1:起點x坐標,
  • y2:起點y坐標,
  • x1:終點x坐標,
  • y2:終點y坐標。

4,多邊形和折線

多邊形和折線只有points參數,寫法為x,y x,y區別在於多邊形會連接起點與終點。

<polygon points="100,20 20,90 60,160 140,160 180,90">

5.路徑

<path>標籤的功能豐富,可繪製很多圖形,線條,通過給定一系列點坐標來繪製,我們在D3中也會用到。

文字

在SVG中可以使用<text>標籤繪製文字,屬性包括:

  • x:文字位置的x坐標,
  • y:文字位置的y坐標,
  • dx:相對於當前位置在x方向平移的距離,正值往右,負值往左,
  • dy:相對於當前位置在y方向平移的距離,正值往下,負值往上,
  • textLength:文字的顯示長度如果不足則拉長,否壓縮,
  • rotate:旋轉角度順時針為正,逆時針為負。

樣式

SVG中常見樣式有:

  • fill:填充色
  • stroke:描邊顏色
  • stroke-width:描邊先寬度
  • stroke-linecap:線頭端點的樣式,圓角,直角等
  • stroke-dasharray:虛線的樣式,
  • opacity:透明度
  • font-family:字體
  • font-size:字型大小
  • font-weight:字體粗細,有normal,bold,等
  • font-style:字體樣式
  • text-decoration:上畫線,下劃線等。

有了以上的SVG基礎知識我們就開始用D3繪製圖表吧。

使用D3 SVG繪製折線圖

首先我們先搭個架子給定一些樣式很簡單,注意引入了d3.v3.js:

<!DOCTYPE html>
<html>
?
<head>
<meta charset="utf-8">
<title>D3繪製折線圖</title>
<script src="https://cdn.bootcss.com/d3/3.2.2/d3.v3.js"></script>
</head>
<style type="text/css">
body {
height: 100%;
}
?
.title {
font-family: Arial, 微軟雅黑;
font-size: 20px;
text-anchor: middle;
}
?
.subTitle {
font-family: Arial, 宋體;
font-size: 14px;
text-anchor: middle;
fill: #2C3E50
}
?
.axis path,
.axis line {
fill: none;
stroke: black;
shape-rendering: crispEdges;
}
?
.axis text {
font-family: sans-serif;
font-size: 12px;
fill: #999;
}
</style>
?
<body>

</body>
<script>
//準備構建圖表
</script>
</html>

構建SVG圖表

使用D3就像使用jQ一樣,參數我們用過一次就知道怎麼用了。

創建SVG元素插入DOM中

在<script>標籤內:

var dataset = [];//y軸數據由getData函數填充數據
var xMarks = [html, css, js, webpack, node, mongoDB];//x軸標籤的準備
var w = 700;
var h = 500;
var padding = 40;
//用一個變數存儲標題和副標題的高度,如果沒有標題什麼的,就為0
var head_height = padding;
var title = "學生成績";
var subTitle = "前端測試";
//用一個變數計算底部的高度,如果不是多系列,就為0
var foot_height = padding;
//模擬數據執行函數
getData();
//定義畫布
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);

現在我們通過D3得到了SVG對象,並且設置了寬高屬性。

添加背景

?
//添加背景
svg.append("g")
.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", w)
.attr("height", h)
.style("fill", "#FFF")
.style("stroke-width", 2)
.style("stroke", "#E7E7E7");

添加主副標題

?
//添加標題
if (title != "") {
svg.append("g")
.append("text")
.text(title)
.attr("class", "title")
.attr("x", w / 2)
.attr("y", head_height);
head_height += 30;
}
//添加副標題
if (subTitle != "") {
svg.append("g")
.append("text")
.text(subTitle)
.attr("class", "subTitle")
.attr("x", w / 2)
.attr("y", head_height);
head_height += 20;
}

設置橫縱坐標比例尺

用到我們全家變數padding,foot_height, head_height。

?
//橫坐標軸比例尺
var xScale = d3.scale.linear()
.domain([0, dataset.length - 1])
.range([padding, w - padding]);
//縱坐標軸比例尺
var yScale = d3.scale.linear()
.domain([0, d3.max(dataset)])
.range([h - foot_height, head_height]);

定義x軸,並且將考試科目按需標記

?
//定義x軸
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom").ticks(dataset.length);
//添加x坐標軸並通過編號獲取對應的x軸考試種類
var xBar = svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + (h - padding) + ")")
.call(xAxis)
.selectAll("text")
.text(function (d) {
return xMarks[d];
});

定義y軸

?
//定義y軸
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left").ticks(11);
//添加y軸
var yBar = svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(" + padding + ",0)")
.call(yAxis);

添加折線

?
//添加折線
var line = d3.svg.line()
.x(function (d, i) {
return xScale(i);
})
.y(function (d) {
return yScale(d);
});
var path = svg.append("path")
.attr("d", line(dataset))
.style("fill", "#2C3E50")
.style("fill", "none")
.style("stroke-width", 1)
.style("stroke", "#2C3E50")
.style("stroke-opacity", 0.9);

添加小圓點

?
//添加小圓點
svg.selectAll("circle")
.data(dataset)
.enter()
.append("circle")
.attr("cx", function (d, i) {
return xScale(i);
})
.attr("cy", function (d) {
return yScale(d);
})
.attr("r", 5)
.attr("fill", "#E74C3C");

動態繪製

?
//動態繪製
function drawChart() {
getData();
yBar.transition().duration(1000).call(yAxis);
//縱軸數據更新
yScale = d3.scale.linear()
.domain([0, d3.max(dataset)])
.range([h - padding, head_height]);
//重繪折線路徑
path.transition().duration(1000).attr("d", line(dataset));
//重繪圓點
svg.selectAll("circle")
.data(dataset)
.transition()
.duration(1000)
.attr("cx", function (d, i) {
return xScale(i);
})
.attr("cy", function (d) {
return yScale(d);
})
}

模擬數據

//模擬數據
function getData() {
var dataNum = 6;
dataset = [];
for (i = 0; i < dataNum; i++) {
dataset.push(Math.round(Math.random() * 100));
}
}

獲取數據按鈕

?
<p align="left">
<button onClick="javascript:drawChart();">刷新數據</button>
</p>

注意:

1.我們採用了d3的v3版本,d3版本差異還是很大的。

2.其它圖表,比如像餅圖了,雷達圖了實現方式一樣的,

? a)準備數據,實際項目中通常數據來源於後台,通過數據交互獲取

? b)做圖表

? c)加交互

3.svg和canvas沒有附屬關係,也沒有好壞之分,只是適用的場景不同。

總結

我們通過綜合案例中的一個折線圖,初步了解D3在綜合運用中用SVG的方式體現的圖表。

我們通過對比SVG與Canvas,使我們能夠在今後遇到的可視化業務中從容選擇。

d3的函數方法,我們第一次接觸可能會感覺到無從下手,一回生,二回熟嘛,多多練習就好了。

為了方便大家學習,這裡提供了個在線APID3的v3-v5的版本都在內,可自行查閱。

本篇我們只做了折線圖,常用的還有柱狀圖,扇形圖,雷達圖等,希望大家有時間,多多繪製不同圖形,提高自身能力。

下一篇我們將介紹常見的圖表庫,為大家提供更多的選擇,讓大家能夠根據不同的業務,進行最佳的技術選型。

推薦閱讀:

相关文章