d3js入門之資料繫結

來源:互聯網
上載者:User

引子

d3js 是一款上手容易的js類庫,專門用於繪製svg圖形圖表,其關鍵理念為data-join 意即資料繫結.搞清這個概念非常重要,它將以簡潔優雅的形式體現資料驅動編程.

以下是Thinking with Joins的拙譯 ,原作者Mike Bostock

假設你要用D3畫一副散佈圖,因此需要產生一些 SVG circle 元素來直觀地展現資料. 你會驚訝地發現D3沒有提供原生的產生多個DOM元素的介面,

是的,只有一個 append 方法,用於產生單個DOM元素:

svg.append("circle")    .attr("cx", d.x)    .attr("cy", d.y)    .attr("r", 2.5);

但那隻是單個圓,而你想要更多: 最好data*中每個元素對應一個圓. 在你用蠻力寫迴圈把圓畫出來之前,讓我們看看D3中的一個例子:

svg.selectAll("circle")    .data(data)  .enter().append("circle")    .attr("cx", function(d) { return d.x; })    .attr("cy", function(d) { return d.y; })    .attr("r", 2.5);

*此處 data是一個
JSON 數組,其每個元素 由 x 和 y屬性構成,
例如: [{"x": 1.0, "y":1.1},{"x": 2.0, "y":2.5},
…]
. 另,SVG circle元素用cx,cy表達圓心座標,r表達半徑長度.

這份代碼符合你的需求,即每個元素產生一個圓 , 通過xy屬性工作表達圓心的座標. 


selectAll("circle")是什麼意思,為什麼要在產生所有圓之前去選中根本不存在的元素呢?


原來事情是這樣的:告訴D3你的目標,而不要告訴它具體怎麼做.
在這個例子中,D3知道我們的意圖是,要讓選中的"circle"元素來響應資料的變化, 
selectAll即描述了這個目標;而無需一步步指揮D3產生多個圓.這個概念即data-join.


data-join的背後執行了以下步驟:

  1. selectAll("circle") 返回了一個空的選擇
  2. 空的選擇通過 data()方法將資料和DOM元素繫結,併產生三個虛擬子集: enterupdate and exitenter()方法包含了待添加的資料及相應的DOM元素的預留位置;update()包含了已與資料繫結的現有元素.剩下待移除的部分被包含在 exit ()方法中
  3. 一開始選擇的結果是空的,因此所有資料都是待添加,將全部出現在enter的結果中.
  4. 無需迴圈,通過.enter().append("circle")將待添加的元素一次性加入到SVG容器.

為什麼要這麼麻煩呢? 為什麼不直接提供原生介面? data-join的優雅之處在於抽象和解耦.上述代碼在enter()裡只是專心處理新增的元素,而update and exit分別專註於處理更新和待刪除部分.這意味著你不用把所有DOM元素刪了重繪,因此得以輕鬆應對即時變化的資料,甚至支援一些互動(如拖動)與漸層的效果!

這裡是一個處理三種狀態(增改刪)的例子:

var circle = svg.selectAll("circle")    .data(data);circle.enter().append("circle")    .attr("r", 2.5);circle    .attr("cx", function(d) { return d.x; })    .attr("cy", function(d) { return d.y; });circle.exit().remove();

如果我們重複運行代碼,它會每次重新計算 data-join. 如果新的資料集比原來的少,多餘元素會出現在 exit 中並被remove()刪除.反之亦然,新增的資料出現在enter()中通過append()添加DOM元素.若新老資料集大小不變,則所有資料只是更新座標.(譯註:上文中介於enter和exit之間的代碼,update()會被隱式調用)

以joins的方式思考同時讓你的代碼更直觀: 處理這三種狀態的代碼無需條件(if)和迴圈(for)分支,只需簡單描述讓圖形去響應資料的變化即可.如果給定的enter, update 或 exit 的選擇結果為空白,則會自動跳過相應的代碼塊,以降低效能開銷.

Joins 支援在特定狀態(增/刪/改)下執行操作.例如,可以在enter而非update代碼塊中,指定靜態attributes(例如圓的半徑,用 "r" attribute指定)
. 仰賴於精確改動目標元素和最小化DOM變更,你已經極大地提升了瀏覽器渲染的表現! 類似地,你可以在特定狀態下表現漸層等動畫效果. 例如新增的圓可以從無到有漸層(半徑從0到2.5):

circle.enter().append("circle")    .attr("r", 0)  .transition()    .attr("r", 2.5);

待刪除的圓也可以逐漸收縮直至消失:

circle.exit().transition()    .attr("r", 0)    .remove();

相信現在你已經學會用joins的方式思考了!

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.