前端編程提高之旅(八)----D3.js數據可視化data join解析

   D3.js作爲一門輕型的可視化類庫,非常便於將數據與web界面元素綁定,實現可視化。樂帝d3.js入門是大體看了一遍《d3js數據可視化實戰》這本書,D3操作非常類似於jquery的使用,具體體現在兩點:

  • 選擇器模塊都採用CSS3標準
  • 方法可以鏈式調用
   有了jquery使用基礎,相信再加上以上書籍的例子,調試很容易上手使用D3.js,樂帝目前認爲D3.js與jquery區別在於:D3.js獨有的數據結構概念及對SVG操作方便的實現。而深入理解D3原理,以上皮毛的理解就不夠用了。
   通過閱讀上述書籍樂帝將D3內容劃了幾大塊來分開理解:
   DOM操作包括:
  • 選擇器模塊(select、selectAll等方法)及如何實現鏈式調用。
  • 節點模塊(append、remove等方法實現)
  • 樣式模塊(attr、style等方法實現)
  數據綁定相關方法:
  • data方法
  • enter、exit等方法
   比例尺:
  • 值域與輸出域的實現
   更新、過渡、動畫方法:
  • transition方法及連帶duration、ease、delay等方法
   事件:
  • 即綁定事件
  而後通讀API發現對於理解D3.js實現機理有一些關鍵概念,這裏關鍵概念涉及selection、data join、group、transition等。而樂帝讀API最大心得在於,在沒有一個大體概念時,千萬不要去觸碰源碼,還是按部就班讀API吧,讀不懂把文檔翻譯一遍就懂了,樂帝是這麼做的。
   這篇文章樂帝主要想討論data join,但在討論之前,還是需要補充下基本概念。
   D3.js獨有關鍵概念是selection,樂帝將其翻譯成元素集。它表示從當前文檔獲取的元素數組。它定義了一種數據結構,或者說是對原有dom文檔數據結構的修改。有了元素集之後,就可以對元素執行常規操作了,諸如屬性、樣式、參數、文檔內容等。
   selection存在的意義在於,是它將頁面元素與數據實現綁定連接,連接的數據又可以產生enter和exit子元素集,因此能夠反映數據的變化,用於添加或移除元素。
   D3支持方法鏈,操作方法返回值是元素集,從這一句話,我們知道不管如何具體實現鏈式操作,我們知道返回的是元素集就夠了。
   樂帝最近思考,整個web世界甚至整個世界,由兩種力量驅動:數據與人。而某些高深思想或許能把人也歸結爲數據。D3是這兩種力量的典型,數據驅動展現,人驅動交互。脫離人與數據,D3的代碼,只是一堆分離的函數而已。D3緊緊擁抱數據,這就是其最大特點。
   selection介紹完了,我們開始介紹data join概念。
   由上所述,D3是數據驅動,而元素集是溝通數據與元素的集合,而data join的概念又是代表數據與元素結合三種狀態的概念,由此看來,data join在D3中屬於核心概念。
   《以data join概念思考》這篇文章給出了對data join比較簡明易懂的陳述。
   在D3中任何時候,數據與頁面元素都有三種關係:數據與元素綁定時,即一一對應,這樣構成的selection狀態叫update selection;沒有元素與之對應的數據構成的selection叫enter selection;沒有數據與之對應的元素構成的selection叫exit selection,它代表將要被移除的元素集。
   如下圖:


   從字面上理解,D3對數據的推崇可謂毫無節操,有數據沒元素叫enter,有元素沒數據叫exit,代表要被踢出去的元素。
   下面來看一段代碼例子:
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);

         首先來看第一句svg.selectAll("circle"),它返回空的元素集,因爲SVG容器是空的。
   
   
   然後上述空元素集與數據結合,構成新的元素集,包含enter、update、exit三種狀態。因爲元素集是空的,所以update和exit元素集爲空,而enter狀態的元素集,則包括五個佔位符元素。

   selection.enter後,返回enter元素集,此時爲五個綁定數據的對象。
 
    最後append("circle")一步,使得enter元素集實現與元素一一對應,沒錯構造成了上述的update元素集狀態。
    由上述例子不難看出,給頁面對象添加子對象不用for循環,而是採取data join的概念,用意在於,在靜態展現的基礎上,對update及exit做微小改動,就可以使它實現動態展現。這就意味着你可以看實時數據,允許數據集合的交互行爲及溫和過渡效果展現。
   任何時候運行代碼,都會重新計算data join,從而保證數據與元素預期的關係。
  data join允許我們隊指定狀態進行操作,比如,可是設置常數值在enter上,而不是update上,通過重新選擇元素最小化改變原有dom,大大提升渲染效率。
   下面樂帝展示一個對各個狀態data join操作的例子:
    起始HTML:
<div>update</div>
<div>exit</div>

         起始D3代碼:
var dataset =["enter", "hello"];
var key = function(d) { 
  return d || this.textContent;
}
var duration = 750;
var div = d3.select("body").selectAll("div")
    .data(dataset,key);

      此時data join 三個狀態:



   如上圖,不難分析得到,此時data join三狀態:update元素集爲空,enter元素集已經有數據綁定,exit元素集有兩個div元素,在第二張圖中innerHTML屬性中,發現恰恰是初始化HTML的兩個div元素,這裏採用了鍵函數(key)方法,鍵函數被調用了四次,前兩次調用的是已有的div數據調用,後兩次則是enter狀態元素集數據調用。
   接下來對exit元素集操作:
// // 1. exit
var exitTransition = d3.transition().duration(750).each(function() {
  div.exit()
      .style("background", "red")
    .transition()
      .style("opacity", 0)
      .remove();//移除節點
});


   不難得出結論,是原有兩個div將要被移除,在頁面及內存中清除。
   接下來對enter的操作,這裏update爲空,故第二步update操作並沒有實際意義。
// 2. update
var updateTransition = exitTransition.transition().each(function() {
  div.transition()
      .style("background", "orange");
});
// 3. enter
var enterTransition = updateTransition.transition().each(function() {
  div.enter().append("div")
      .text(function(d) { return d; })
      .style("opacity", 0)
    .transition()
      .style("background", "green")
      .style("opacity", 1);
});
   第三步對enter元素集的操作,使其與元素綁定,並設置成綠色。
   樂帝在調試期間還發現了另外的情況:
   一開始js代碼是這樣的:
var dataset =["enter", "update"];
var key = function(d) { 
  return d || this.textContent;
}
var duration = 750;
var div = d3.select("body").selectAll("div")
    .data(dataset,key);

   即dataset有一個元素與已存在的div文本內容相同,又由於鍵函數是處理的是dataset與div文本內容的集合,經過運行如下:

      與之上比較不難發現,這裏update元素集有一個元素,enter元素集有一個enter狀態元素。另看exit元素集:

   exit及enter都少了一個對應狀態的對象,這裏樂帝猜測d3應該是將每個鍵值函數返回數據進行了查重操作,將兩個“update”文本數據合併成一個update狀態元素了。
   執行1.exit代碼,此時只有exit文本的div被移除。執行2.update代碼時,update文本的div被設置爲背景爲橘黃色。最後執行3.enter代碼時,背景色爲綠色的div被加入到文檔。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章