這里涉及了 HTML & CSS 的知識,比如說元素的樣式和元素塊,以后我會把相關知識補上。
繪制直線圖
條形圖實際上是矩形,而 HTML 的 div 元素是繪制矩形的最簡單手段。(對於瀏覽器來說,HTML 中的一切元素都可以用來表示矩形)。
所以我們可以定義一個叫 bar 的 div 類,用於存放圖表的公共屬性。(除了高度,其他的屬性應該是共享的)
div.bar { display: inline-block; width: 20px; height: 75px; /*最后這里會被覆寫*/ margin-right: 2px; background-color: green;
-
關於類
元素的類作為 HTML 屬性存在於標記代碼中,同時 CSS 規則也可以引用它。除了為元素設定類以外,直接給元素應用樣式也可以。(這里不太懂,下次遇到案例再寫上)
D3 有一種方法用於快速添加或者刪除元素的類:
.classed("bar",true) // 給選中的元素添加類 bar .classed("bar",false) //從元素總刪除類 bar
-
關於樣式
.style 方法用於直接為 HTML 元素應用 CSS 屬性和值。這方法執行的結果等價於在 HTML 的 style 屬性中直接寫入 CSS 規則
<div style="height: 75px;"></div>
如果要生成條形圖,每個條形圖的高度必須是對應數據值得函數,D3 代碼中可以對這個高度之進行重寫:
.style("height", function(d) {
var barHeight = d * 5; //這里是因為原始生成高度太矮了
return barHeight + "px";
});
-
關於屬性設定
attr() 用於設定HTML 元素的屬性和值。我們要給我們生成的 div 中添加 bar 類,需要這樣寫:
.attr("class","bar")

代碼如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>D3: Our first bar chart with data</title>
<script type="text/javascript" src="../d3.js"></script>
<style type="text/css">
div.bar {
display: inline-block;
width: 20px;
height: 75px; /* Gets overridden by D3-assigned height below */
margin-right: 2px;
background-color: green;
}
</style>
</head>
<body>
<script type="text/javascript">
var dataset = [ 25, 7, 5, 26, 11 ];
d3.select("body").selectAll("div")
.data(dataset)
.enter()
.append("div")
.attr("class", "bar")
.style("height", function(d) {
var barHeight = d * 5;
return barHeight + "px";
});
隨機數據
教材上面用了一個可以生成隨機數值得方法,在這里記錄一下:
這里是創建了一個名為 dataset 得空數組;
初始化一個循環25次的 for 循環,執行25次
每次生成一個介於0到30之間的隨機數
把新數值追加到數組中(push() 是數組的方法,每次執行都會把一個新值推進數組末尾)。
var dataset = []; for( var i = 0; i < 25 ;i ++){ var newNumber= Math.random() * 30; dataset.push( newNumber);}
注意:
此時 push 進去的都是浮點數,可以用 Math.round() 或者Math.floor () 方法取整。前者是將數值想上取整,后者是向下取整。
var newNumber = Math.floor(Math.random() * 30);
dataset.push( newNumber();)
繪制 SVG
SVG 元素是通過標簽中的屬性 / 值對來指定SVG元素的個各方面特征,如:
<element property = "value"></element>
因為 SVG 元素存在於 DOM 中,與其他 HTML 元素一樣,因此生成 SVG 圖形依然要使用 append() 和 attr() 方法。
創建 SGV
首先要創建一個元素,以便在其中保存所有圖形。這行代碼先找到文檔的 body 元素,然后再結束的 </body> 標簽前添加一個新的 svg 元素。
d3.select("body").append("svg");
也可以使用一種更好的方式,把append() 返回的新元素保存在了變量 svg 中。有了這個引用,將來可以少些很多代碼,從而不用總是寫 da.select("svg") ,而是只要寫 svg 即可:
var svg = d3.select("body").append("svg");
完整代碼如下,DOM 中將創建一個新的空的 SVG元素。其中高度和寬度保存於變量中,可以方便引用。
var w =500; var h = 50; var svg = d3.select("body") .append("svg") .attr("width",w) .attr("height",h);
然使用data() 迭代每個數據節點,創建一個圓形。同時創建一個新的變量保存引用
var circles = svg.selectAll("circle") .data(dataset) .enter .append("circle");
創建位置和大小信息:
circle.attr( "cx", function(d, i)){ return (i*50) +25;
// 這里是通過引用所有的圓形的變量來設置每一個圓形的屬性。(在SVG中,cx 是圓形圓心的 x 坐標,由於數據已經綁定到了圓形,所以對於每個圓形來說,都有其對應於原始數據的值。
// 並且其中的i值是自動生成的),同時,索引 i 是從function(d,i)中傳入的,使其與 d 元素一致。
}) .attr("cry", h/2) .attr("r", function(d) { return d; });
// cy 是圓形圓心的 Y 的坐標,這里把 cy 設置成了 h 的一半。由於 h 保存着整個SVG元素的高度,所以這里是將所有圓形垂直居中
// 每個圓形的半徑被設為 d,從而反映數據的大小
最后生成如圖示:

也可以在上面添加色彩:
色彩填充( fill )和描邊( stroke )同樣也是屬性,所以也可以通過attr()方法來設定。
.attr("fill", "yellow")
.attr("stroke", "orange")
.attr("stroke-width", function(d) {
return d/2;}
最后圖像如下:

源代碼為:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>D3: Using color in SVG</title>
<script type="text/javascript" src="../d3.js"></script>
<style type="text/css">
/* No style rules here yet */
</style>
</head>
<body>
<script type="text/javascript">
//Width and height
var w = 500;
var h = 100;
//Data
var dataset = [ 5, 10, 15, 20, 25 ];
//Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
var circles = svg.selectAll("circle")
.data(dataset)
.enter()
.append("circle");
circles.attr("cx", function(d, i) {
return (i * 50) + 25;
})
.attr("cy", h/2)
.attr("r", function(d) {
return d;
})
.attr("fill", "yellow")
.attr("stroke", "orange")
.attr("stroke-width", function(d) {
return d/2;
});
</script>
</body>
</html>
關於繪制條形圖的改進:
我們也可以通過 SVG 的方式來繪制條形圖:
首先確定 SVG 的大小:
var w = 500; var h = 500;
然后讓 D3 創建一個空元素,將其添加到 DOM 中.復習一下,這些代碼會在結束的</body>標簽前面插入新的 svg 元素,並將結果保存在了變量 svg 中,因此以后可以方便引用這個 sv g元素,而不用每次再使用 select() 之類的代碼重新選擇。
var svg = d3.select("body") .append("svg") .attr("width",w) .attr("height",h);
然后不創建 div,而是生成矩形元素 rect 並將其添加到 svg 中。
這段代碼選擇了 svg 中所有的矩形。但是,現在什么也沒有,所以會返回一個空的元素集。
接下來 data(dataset) 看到了數據集中有20個值,就把這些值交給了 enter() 處理。每個rect 必須有 x, y width 和 height 屬性。這里就是用 attr() 為每個新創建的 rect 設置了這些屬性。但是這樣會出現一個問題,就是所有的條形生成以后就重疊在了一起,而且此時並沒有反映數據。
svg.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("x",0)
.attr("y",0)
.attr("width",20)
.attr("height",100);
為了解決重疊問題們同樣需要使用 function() 函數:
.attr("x",function(d,i)) {
return i*21; //由於矩形寬20像素,所以外加一個像素作為間距。
};
動態縮放:
當數據比較多的時候,最右邊的矩形很有可能跑到 SVG 外面去,這時候就需要使用靈活、動態的坐標方案了。
首先,從改進設置每條矩陣 x 坐標的那行代碼進行修改,這樣的話,每個矩形就會進行縮放生成。當數據密的時候就會密集,當數據稀疏的時候間距就會拉大。
.attr("x",function(d,i) {
return i * (w / dataset.length);
})
以圖為例:
當數據密集的時候:

當數據稀疏的時候:

這種解決方式並不好看。為了更加的美觀,可以將矩形的寬度也成比例的縮放。
var w = 500; var h = 100; var barPadding = 1; //這里的變量是減去的間距的值
.attr("width",w / dataset.length - Padding)
然后再讓數據值決定條形高度:
.attr("height",function(d)){
return d*4; // 放大四倍
});
結果如圖所示:
由於 SVG 在繪制時,x 和 y 值指定的是它們左上角的坐標,所以 SVG 支持的只有左上角坐標系。如果我們需要改成一般的矩形圖,就需要將每個圖形的“下沿”與 SVG 的下沿對齊,每個 rect 的 height可以就設置為數據值的本身。

.attr("y", function(d){
return h - d;
})
.attr("height",function(d){
return d;
});
結果如圖示:

上色
使用 fill 屬性可以對其添加顏色:
.attr(" fill", "teal");
我們也可以讓顏色反映數據的某些特性,對着條形圖而言,這樣做叫做雙重編碼,即同樣的數據值可以被編碼成倆種可以見的特性:條形高度和顏色。
.attr( "fill", function(d){ return "rgb( 0, 0, "+(d * 10) +" )";
附錄:關於多值映射
D3 擁有多值映射機制,從而可以一次性設置多個值。而且依然是用 attr( ) 方法。假設要把一個圓形平移到 SVG 左上角,再設置成紅色,可以每次單獨調用 attr( ) :
svg.select("circlr")
.attr("cx",0)
.attr("cy",0)
.attr( "fill", "red")
也可以把這三個屬性的值都封裝在一個對象中,然后統一交給 attr( ) :
svg.select("circlr")
.attr({
cx: 0;
cy: 0;
fill: "red"
});
源代碼為:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>D3: Adding dynamic color, based on data</title>
<script type="text/javascript" src="../d3.js"></script>
<style type="text/css">
/* No style rules here yet */
</style>
</head>
<body>
<script type="text/javascript">
//Width and height
var w = 500;
var h = 100;
var barPadding = 1;
var dataset = [ 5, 10, 13, 19, 21, 25, 22, 18, 15, 13,
11, 12, 15, 20, 18, 17, 16, 18, 23, 25 ];
//Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
svg.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("x", function(d, i) {
return i * (w / dataset.length);
})
.attr("y", function(d) {
return h - (d * 4);
})
.attr("width", w / dataset.length - barPadding)
.attr("height", function(d) {
return d * 4;
})
.attr("fill", function(d) {
return "rgb(0, 0, " + Math.round(d * 10) + ")";
});
</script>
</body>
</html>
