學習一項新技術,首先要搞清楚它的基本設計思路,有了這個宏觀的技術架構,使用該技術起來,就會得心應手了。否則,就會不知道如何下手,即使看到人家的例子程序,可能也不知其所以然。
下面,就簡單的結合自己研究的官方文檔,對D3的使用,給其基本設計思路,做一個簡單的描述:
在html文件中加載完官方的js插件d3.v3.min.js后:
1. 設計畫布(這里主要基於SVG介紹,當然,畫布其實還有Canvas)。
a. 主要包括SVG的大小,含有width,以及height。
b. 通過d3全局對象,構建svg對象。
2. 創建視圖(D3支持的視圖很多)
1 [[bundle|捆綁布局]] - 對邊使用Holten 層次捆綁算法。 2 [[chord|弦布局]] - 從關系矩陣生成一個弦圖。 3 [[cluster|簇布局]] - 將實體聚集成樹狀圖。 4 [[force|力布局]] - 模擬物理力排放相連節點的位置。 5 [[hierarchy|層次布局]] - 這是個抽象布局,可派生一個定制的層次布局。 6 [[histogram|直方圖布局]] - 使用量化的箱計算數據的分布。 7 [[pack|包布局]] - 用遞歸的圓形包裝生成一個層次布局。 8 [[partition|分區布局]] - 遞歸地將節點樹分割為旭日狀或者冰柱狀。 9 [[pie|餅布局]] - 計算餅圖或圓環圖中弧的開始和結束角度。 10 [[stack|堆疊布局]] - 計算堆疊圖或者面積圖的基線。 11 [[tree|樹布局]] - 整齊地排列樹節點。注意簇布局不是整齊的。 12 [[treemap|矩形樹布局]] - 使用空間遞歸分區算法展示樹的節點。
例如:
var tree = d3.layout.tree();
3. 數據綁定
其實,這一步做的事情,就是一個視圖與數據的結合,視圖將數據轉化為該視圖內定的數據結構,重點是添加了一些D3功能相關的輔助參數或者變量。 例如上例中的樹視圖,數據綁定后過程如下:
1 var nodes = tree.nodes(root).reverse(), 2 var links = tree.links(nodes);
這個綁定,也可以說是數據轉化,之后,nodes對象中不僅含有root這個原始數據(用戶提供的輸入數據),還含有D3系統需要的輔助參數,比如parent,depth等。
4. 視圖數據結合
這一步,其實最能體現D3的設計思想,這一步涵蓋的內容最為豐富,但是不多講,重點介紹D3的特色操作enter,update,exit。
a. 獲取新的選擇器(SVG灌入綁定數據后的新對象)
例如:
var node = svg.selectAll("g.node").data(nodes, function(d) { return d.id || (d.id = ++i); });
b. enter/update/exit
這三個概念是什么含義呢?
如果數組為 [3, 6, 9, 12, 15],將此數組綁定到三個 p 元素的選擇集上。可以想象,會有兩個數據沒有元素與之對應,這時候 D3 會建立兩個空的元素與數據對應,這一部分就稱為 Enter。而有元素與數據對應的部分稱為 Update。如果數組為 [3],則會有兩個元素沒有數據綁定,那么沒有數據綁定的部分被稱為 Exit。
例如下圖:
對於圖形存在交互操作的情景,enter,update,以及exit都會用得到,例如我上一篇博客D3樹狀圖異步按需加載數據,里面的樹狀圖,點擊節點會有展開和收縮的效果,這個時候三者都會參與實際的邏輯處理。
Update 和 Enter 的使用
當對應的元素不足時 ( 綁定數據數量 > 對應元素 ),需要添加元素(append)。
現在 body 中有三個 p 元素,要綁定一個長度大於 3 的數組到 p 的選擇集上,然后分別處理 update 和 enter 兩部分。
1 var dataset = [ 3 , 6 , 9 , 12 , 15 ]; 2 3 //選擇body中的p元素 4 var p = d3.select("body").selectAll("p"); 5 6 //獲取update部分 7 var update = p.data(dataset); 8 9 //獲取enter部分 10 var enter = update.enter(); 11 12 //update部分的處理:更新屬性值 13 update.text(function(d){ 14 return "update " + d; 15 }); 16 17 //enter部分的處理:添加元素后賦予屬性值 18 enter.append("p") 19 .text(function(d){ 20 return "enter " + d; 21 });
- update 部分的處理辦法一般是:更新屬性值
- enter 部分的處理辦法一般是:添加元素后,賦予屬性值
Update 和 Exit 的使用
當對應的元素過多時 ( 綁定數據數量 < 對應元素 ),需要刪掉多余的元素。
現在 body 中有三個 p 元素,要綁定一個長度小於 3 的數組到 p 的選擇集上,然后分別處理 update 和 exit 兩部分。
1 var dataset = [ 3 ]; 2 3 //選擇body中的p元素 4 var p = d3.select("body").selectAll("p"); 5 6 //獲取update部分 7 var update = p.data(dataset); 8 9 //獲取exit部分 10 var exit = update.exit(); 11 12 //update部分的處理:更新屬性值 13 update.text(function(d){ 14 return "update " + d; 15 }); 16 17 //exit部分的處理:修改p元素的屬性 18 exit.text(function(d){ 19 return "exit"; 20 }); 21 22 //exit部分的處理通常是刪除元素 23 // exit.remove();
- exit 部分的處理辦法一般是:刪除元素(remove)
到此, 入門D3,了解這個基本的框架,再去細讀API文檔或者教程,相對會容易些!
最后,附帶一個簡單的例子,繪制環狀圖(顯示資源占用比例的場景,還是很有使用價值的):
1 <html> 2 <head> 3 <meta charset="utf-8"> 4 <title>環裝圖</title> 5 </head> 6 7 <style> 8 9 10 </style> 11 <body> 12 <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script> 13 <script> 14 15 var width = 400; 16 var height = 400; 17 var dataset = [ 30 , 10 , 43 , 55 , 13 , 11, 100, 99]; 18 19 var svg = d3.select("body") 20 .append("svg") 21 .attr("width", width) 22 .attr("height", height); 23 24 var pie = d3.layout.pie(); 25 26 var piedata = pie(dataset); 27 28 var outerRadius = 150; //外半徑 29 var innerRadius = 100; //內半徑,為100則中間沒有空白 30 31 var arc = d3.svg.arc() //弧生成器 32 .innerRadius(innerRadius) //設置內半徑 33 .outerRadius(outerRadius); //設置外半徑 34 35 var color = d3.scale.category20c(); 36 37 var arcs = svg.selectAll("g") 38 .data(piedata) 39 .enter() 40 .append("g") 41 .attr("transform","translate("+ (width/2) +","+ (width/2) +")"); 42 43 arcs.append("path") 44 .attr("fill",function(d,i){ 45 return color(i); 46 }) 47 .attr("d",function(d){ 48 return arc(d); 49 }); 50 51 arcs.append("text") 52 .attr("transform",function(d){ 53 return "translate(" + arc.centroid(d) + ")"; 54 }) 55 .attr("text-anchor","middle") 56 .text(function(d){ 57 return d.data; 58 }); 59 </script> 60 61 </body> 62 </html>