上一章:《【D3.js 入門系列一】從零開始繪製一個柱形圖》 html
聲明:本教程針對D3.js v3版本進行講解。git
Update、Enter、Exit 是 D3 中三個很是重要的概念,它處理的是當選擇集和數據的數量關係不肯定的狀況。github
前面章裏,反覆出現了形如如下的代碼。api
svg.selectAll("rect") //選擇svg內全部的矩形
.data(dataset) //綁定數組
.enter() //指定選擇集的enter部分
.append("rect") //添加足夠數量的矩形元素
複製代碼
前面提到,這段代碼使用的狀況是當如下狀況出現的時候:數組
有數據,而沒有足夠圖形元素的時候,使用此方法能夠添加足夠的元素。app
當時並無深究這段代碼是什麼意思,本章將對此進行講解。可是,因爲此問題相對複雜,本章只進行最初步的介紹。less
假設,在 body 中有三個 p 元素,有一數組 [3, 6, 9],則能夠將數組中的每一項分別與一個 p 元素綁定在一塊兒。可是,有一個問題:當數組的長度與元素數量不一致(數組長度 > 元素數量 or 數組長度 < 元素數量)時呢?這時候就須要理解 Update、Enter、Exit 的概念。dom
若是數組爲 [3, 6, 9, 12, 15],將此數組綁定到三個 p 元素的選擇集上。能夠想象,會有兩個數據沒有元素與之對應,這時候 D3 會創建兩個空的元素與數據對應,這一部分就稱爲 Enter。而有元素與數據對應的部分稱爲 Update。若是數組爲 [3],則會有兩個元素沒有數據綁定,那麼沒有數據綁定的部分被稱爲 Exit。示意圖以下所示。 svg
看到這,我想你們能體會到爲何本節最開始處的代碼可以給 SVG 內添加足夠數量的元素了吧。它的意思實際上是:函數
此時 SVG 裏沒有 rect 元素,即元素數量爲 0。有一數組 dataset,將數組與元素數量爲 0 的選擇集綁定後,選擇其 Enter 部分(請仔細看上圖),而後添加(append)元素,也就是添加足夠的元素,使得每個數據都有元素與之對應。
當對應的元素不足時 ( 綁定數據數量 > 對應元素 ),須要添加元素(append)。
如今 body 中有三個 p 元素,要綁定一個長度大於 3 的數組到 p 的選擇集上,而後分別處理 update 和 enter 兩部分。
var dataset = [ 3 , 6 , 9 , 12 , 15 ];
//選擇body中的p元素
var p = d3.select("body").selectAll("p");
//獲取update部分
var update = p.data(dataset);
//獲取enter部分
var enter = update.enter();
//update部分的處理:更新屬性值
update.text(function(d){
return "update " + d;
});
//enter部分的處理:添加元素後賦予屬性值
enter.append("p")
.text(function(d){
return "enter " + d;
});
複製代碼
結果以下圖,update 部分和 enter 部分被綁定的數據很清晰地表示了出來。
請你們記住:
當對應的元素過多時 ( 綁定數據數量 < 對應元素 ),須要刪掉多餘的元素。
如今 body 中有三個 p 元素,要綁定一個長度小於 3 的數組到 p 的選擇集上,而後分別處理 update 和 exit 兩部分。
var dataset = [ 3 ];
//選擇body中的p元素
var p = d3.select("body").selectAll("p");
//獲取update部分
var update = p.data(dataset);
//獲取exit部分
var exit = update.exit();
//update部分的處理:更新屬性值
update.text(function(d){
return "update " + d;
});
//exit部分的處理:修改p元素的屬性
exit.text(function(d){
return "exit";
});
//exit部分的處理一般是刪除元素
// exit.remove();
複製代碼
結果以下,請你們區分好 update 部分和 exit 部分。這裏爲了代表哪一部分是 exit,並無刪除掉多餘的元素,但實際上 exit 部分的絕大部分操做是刪除。
請你們記住:
D3 支持製做動態的圖表。有時候,圖表的變化須要緩慢的發生,以便於讓用戶看清楚變化的過程,也能給用戶不小的友好感。
前面一章製做的圖表是一蹴而就地出現,而後繪製完成後再也不發生變化的,這是靜態的圖表。
動態的圖表,是指圖表在某一時間段會發生某種變化,多是形狀、顏色、位置等,並且用戶是能夠看到變化的過程的。
例如,有一個圓,圓心爲 (100, 100)。如今咱們但願圓的 x 座標從 100 移到 300,而且移動過程在 2 秒的時間內發生。
這種時候就須要用到動態效果,在 D3 裏咱們稱之爲過渡(transition)。
D3 提供了 4 個方法用於實現圖形的過渡:從狀態 A 變爲狀態 B。
transition()
啓動過渡效果。
其先後是圖形變化先後的狀態(形狀、位置、顏色等等),例如:
.attr("fill","red") //初始顏色爲紅色
.transition() //啓動過渡
.attr("fill","steelblue") //終止顏色爲鐵藍色
複製代碼
D3 會自動對兩種顏色(紅色和鐵藍色)之間的顏色值(RGB值)進行插值計算,獲得過渡用的顏色值。咱們無需知道中間是怎麼計算的,只須要享受結果便可。
duration()
指定過渡的持續時間,單位爲毫秒。
如 duration(2000) ,指持續 2000 毫秒,即 2 秒。
ease()
指定過渡的方式,經常使用的有:
調用時,格式形如: ease(「bounce」)。
delay()
指定延遲的時間,表示必定時間後纔開始轉變,單位一樣爲毫秒。此函數能夠對總體指定延遲,也能夠對個別指定延遲。
例如,對總體指定時:
.transition()
.duration(1000)
.delay(500)
複製代碼
如此,圖形總體在延遲 500 毫秒後發生變化,變化的時長爲 1000 毫秒。所以,過渡的總時長爲1500毫秒。
又如,對一個一個的圖形(圖形上綁定了數據)進行指定時:
.transition()
.duration(1000)
.delay(funtion(d,i){
return 200*i;
})
複製代碼
如此,假設有 10 個元素,那麼第 1 個元素延遲 0 毫秒(由於 i = 0),第 2 個元素延遲 200 毫秒,第 3 個延遲 400 毫秒,依次類推….整個過渡的長度爲 200 * 9 + 1000 = 2800 毫秒。
下面將在 SVG 畫布裏添加三個圓,圓出現以後,當即啓動過渡效果。
第一個圓,要求移動 x 座標。
var circle1 = svg.append("circle")
.attr("cx", 100)
.attr("cy", 100)
.attr("r", 45)
.style("fill","green");
//在1秒(1000毫秒)內將圓心座標由100變爲300
circle1.transition()
.duration(1000)
.attr("cx", 300);
複製代碼
第二個圓,要求既移動 x 座標,又改變顏色。
var circle2 = svg.append("circle")... //與第一個圓同樣,省略部分代碼
//在1.5秒(1500毫秒)內將圓心座標由100變爲300,
//將顏色從綠色變爲紅色
circle2.transition()
.duration(1500)
.attr("cx", 300)
.style("fill","red");
複製代碼
第三個圓,要求既移動 x 座標,又改變顏色,還改變半徑。
var circle3 = svg.append("circle")... //與第一個圓同樣,省略部分代碼
//在2秒(2000毫秒)內將圓心座標由100變爲300
//將顏色從綠色變爲紅色
//將半徑從45變成25
//過渡方式採用bounce(在終點處彈跳幾回)
circle3.transition()
.duration(2000)
.ease("bounce")
.attr("cx", 300)
.style("fill","red")
.attr("r", 25);
複製代碼
在上一章完整柱形圖的基礎上稍做修改,便可作成一個帶動態效果的、有意思的柱形圖。
在添加文字元素和矩形元素的時候,啓動過渡效果,讓各柱形和文字緩慢升至目標高度,而且在目標處跳動幾回。
對於文字元素,代碼以下:
.attr("y",function(d){
var min = yScale.domain()[0];
return yScale(min);
})
.transition()
.delay(function(d,i){
return i * 200;
})
.duration(2000)
.ease("bounce")
.attr("y",function(d){
return yScale(d);
});
複製代碼
文字元素的過渡先後,發生變化的是 y 座標。其起始狀態是在 y 軸等於 0 的位置(但要注意,不能在起始狀態直接返回 0,要應用比例尺計算畫布中的位置)。終止狀態是目標值。
對於矩形元素,思想與文字元素同樣,只是在計算起始狀態時要稍微複雜一些,請讀者自行研讀頁面底部的示例代碼地址中的代碼。
與圖表的交互,指在圖形元素上設置一個或多個監聽器,當事件發生時,作出相應的反應。
交互,指的是用戶輸入了某種指令,程序接受到指令以後必須作出某種響應。對可視化圖表來講,交互能使圖表更加生動,能表現更多內容。例如,拖動圖表中某些圖形、鼠標滑到圖形上出現提示框、用觸屏放大或縮小圖形等等。
用戶用於交互的工具通常有三種:鼠標、鍵盤、觸屏。
對某一元素添加交互操做十分簡單,代碼以下:
var circle = svg.append("circle");
circle.on("click", function(){
//在這裏添加交互內容
});
複製代碼
這段代碼在 SVG 中添加了一個圓,而後添加了一個監聽器,是經過 on() 添加的。在 D3 中,每個選擇集都有 on() 函數,用於添加事件監聽器。
on() 的第一個參數是監聽的事件,第二個參數是監聽到事件後響應的內容,第二個參數是一個函數。
鼠標經常使用的事件有:
鍵盤經常使用的事件有三個:
觸屏經常使用的事件有三個:
當某個事件被監聽到時,D3 會把當前的事件存到 d3.event 對象,裏面保存了當前事件的各類參數,請你們好好參詳。若是須要監聽到事件後馬上輸出該事件,能夠添加一行代碼:
circle.on("click", function(){
console.log(d3.event);
});
複製代碼
將【D3.js 入門系列一】的部分代碼修改爲以下代碼。
var rects = svg.selectAll(".MyRect")
.data(dataset)
.enter()
.append("rect")
.attr("class","MyRect") //把類裏的 fill 屬性清空
.attr("transform","translate(" + padding.left + "," + padding.top + ")")
.attr("x", function(d,i){
return xScale(i) + rectPadding/2;
} )
.attr("y",function(d){
return yScale(d);
})
.attr("width", xScale.rangeBand() - rectPadding )
.attr("height", function(d){
return height - padding.top - padding.bottom - yScale(d);
})
.attr("fill","steelblue") //填充顏色不要寫在CSS裏
.on("mouseover",function(d,i){
d3.select(this)
.attr("fill","yellow");
})
.on("mouseout",function(d,i){
d3.select(this)
.transition()
.duration(500)
.attr("fill","steelblue");
});
複製代碼
這段代碼添加了鼠標移入(mouseover),鼠標移出(mouseout)兩個事件的監聽器。監聽器函數中都使用了 d3.select(this),表示選擇當前的元素,this 是當前的元素,要改變響應事件的元素時這麼寫就好。
mouseover 監聽器函數的內容爲:將當前元素變爲黃色
mouseout 監聽器函數的內容爲:緩慢地將元素變爲原來的顏色(藍色)
代碼示例地址:github.com/legend-li/D…
未完待續~
參考資料:www.ourd3js.com/
D3.js(v3)中文api:github.com/d3/d3/wiki/…