說到數據可視化,我們會行到很多優秀的框架,像echarts、highcharts,這些框架很優雅,健壯,能滿足我們對可視化的大部分需求,但是缺點也很明顯,就是這些框架幾乎是不可定制化的,當遇到特殊的需求,那就太難了。這個時候,聰明的小伙伴會轉而學習一些基礎的,定制化程度更高的框架,而其中最杰出的就是D3.js,由于我是專為北京地鐵定制化軟件,經常會用到數據可視化,廢話不多說先上北京地鐵路網,因為今天是入門教程,但是我不想講svg基礎知識,只講一點基礎內容餅圖,大佬請繞行。
1.繪制餅圖的預備知識
- 1.比例尺的使用
- 2.餅圖布局的使用
- 3.弧生成器的使用
1.比例尺的使用
d3中有很多種比例尺,其中有四種經常使用,分別是scaleLinear線性比例尺,scaleOrdinal序數比例尺,scaleBand序數段比例尺,scaleTime時間比例尺。今天我們只介紹序數比例尺。
const colorList = ["#ffa39e", "#eaff8f", "#87e8de", "#ffd591", "#91d5ff", "#ffadd2", "#ffe58f"]; const color = d3.scaleOrdinal().domain(colorList.map((d,i) => i)).range(colorList)
使用序數比例尺將索引和顏色對應,如color(1) --> "#eaff8f"
2.餅圖布局的使用
d3中同樣有很多種布局,布局并沒有繪制的作用,他只是將原始數據轉換成繪制圖形所需要的數據的方法。餅圖布局就是將數據轉換成繪制餅圖所需要的數據,如startAngle,endAngle,index,data等數據。
let pie = d3.pie().sort(null).value(d => d.number);
sort方法是先將傳入方法的數據做排序處理,默認降序,null參數,即保留原數據局順序。
value方法是選擇布局要處理的數據,即按照傳入對象的number屬性值排序。既然布局是一個方法,那么試用起來非常簡單
var pieData = pie(dataset);
這里pieData就是我們需要的數據
3.弧生成器的使用
d3中大部分圖形都是通過path繪制的,弧生成器,就是將數據繪制出path的d屬性。
let arc = d3.arc().innerRadius(100).outerRadius(200);
innerRadius為繪制弧的內徑,outerRadius為繪制弧的內徑,使用方式如下
arc({startAngle: 0, endAngle: 2})
因為我們的布局就是將數據處理成startAngle,endAngle這種形式,那么畫出餅圖就變得非常簡單
selection.data(pieData).enter().append('path').attr('d', (d) => arc(d))
這就生成了一個餅圖。
2.完整的畫一個餅圖
1.分組
想做好一個d3的項目,分析必不可少,好的分組能代碼更簡潔優雅。餅圖大致分四個部分
- 弧形部分
- 虛線部分
- 文字部分
- 中心詳情部分
group.append('g').attr('class', 'pies'); group.append('g').attr('class', 'lines'); group.append('g').attr('class', 'texts'); const centersT = group.append('g').append('text').attr('x', 0).attr('y', 0).attr('text-anchor', 'middle').attr('dy', '-1.6em').attr('font-size', 30).attr('fill', 'none').attr('stroke', '#888').text(''); const centersC = group.append('g').append('text').attr('x', 0).attr('y', 0).attr('text-anchor', 'middle').attr('dy', '0em').attr('font-size', 30).attr('fill', 'none').attr('stroke', '#888').text(''); const centersB = group.append('g').append('text').attr('x', 0).attr('y', 0).attr('text-anchor', 'middle').attr('dy', '1.6em').attr('font-size', 30).attr('fill', 'none').attr('stroke', '#888').text('');
這里中心詳情部分我為了簡單就沒有分組。只把三大塊分了組。
2.生成數據方法
const initData = () => {dataset = dataset.map( d => {return {name: d.name,number: Math.floor(Math.random() * 1000 + 100)}}) }
3.使用merge()方法將數據更新。
merge()方法可以把update和enter部分的操作合一,更加方便數據更新。
let pathUpdate = group.select('.pies').selectAll('path.pie').data(pieData) let pathEnter = pathUpdate.enter().append('path'); pathEnter.merge(pathUpdate).attr('fill', (d,i) => color(i)).attr('class', 'pie').attrTween('d', function (d) {return arc(d)})
4.繪制折線
因為每次數據的變化勢必會影響折線的位置,這里要做一些計算
let polylineUpdate = group.select('.lines').selectAll('polyline').data(pieData); let polylineEnter = polylineUpdate.enter().append('polyline');polylineEnter.merge(polylineUpdate).attr('fill', 'none').attr('stroke', '#333').attr('stroke-dasharray', '5,5').attr('points', d => {let direction = (d.startAngle + d.endAngle < Math.PI * 2 ? 1 : -1);return [arc.centroid(d), arc.centroid(d)[0] * 1.6, arc.centroid(d)[1] * 1.6, (innerRadius + outerRadius) * direction, arc.centroid(d)[1] * 1.6]})
這里的arc.centroid(d)為當前扇形的中心坐標,arc.centroid(d)[0]為x坐標,arc.centroid(d)[1]為y坐標。
(d.startAngle + d.endAngle < Math.PI * 2 ? 1 : -1);
這段代碼是判斷扇形是屬于左半面還是右半面。
5.加入一些動畫。
transition(動畫)能讓圖形更加優雅的變化。這里主要是學習一下attrTween,直接看文檔我就不多說了。具體代碼請移步至餅圖。
后續將發布更多的教程。
?
原創博客:轉載請注明d3.js 入門指南
?
?