iT邦幫忙

2021 iThome 鐵人賽

DAY 10
0
Modern Web

從原料到燃料,從資料到預料—資料駕馭網頁之理科的美學系列 第 10

D3JsDay10 遇到元素資料不相等,用函式解決高人一等

綁定的資料和畫面上的元素不相等

enter()函式—沒放入元素的資料

先看以下程式碼

<body>
  <div></div>
  <div></div>
  <script>
    const arr = [13,6,2,34,23];
    const div = d3.select("body").selectAll("div");
    console.log(div.data(arr));
    div.data(arr).text(function(d) { return d});
  </script>
</body>

這時候你嘗試著開啟開發者人工具的會發現有一個叫做_enter的陣列裡面元素前兩個是empty和後面三個Ut的物件,由於你所選取的div只有兩個,當資料被添加進去div的時候會有兩個如願地加進div然而剩下三個並沒有被加入進去的就會在_enter陣列裡面呈現。

畫面如下圖
https://ithelp.ithome.com.tw/upload/images/20210925/20125095gqrV3Nvaqi.png

這時候你可以發現網頁只有前兩個資料被顯示在畫面上

https://ithelp.ithome.com.tw/upload/images/20210925/20125095dGlja4bl0r.png

因此這時候我們可以使用enter()這個方法來獲取那些未被添加至div的資料進行操作,我們嘗試著將程式碼改成以下片段

const arr = [13,6,2,34,23];
const div =d3.select("body").selectAll("div");
div.data(arr).enter().append("div").text(function(d) { return d});

這個時候畫面可以渲染出未被放入起始div的資料

https://ithelp.ithome.com.tw/upload/images/20210925/20125095UNs8EHlMkH.png

因此我們將程式碼改成如下

let arr = [13,6,2,34,23];
let div =d3.select("body").selectAll("div");
div.data(arr).text(function(d){return d});
div.data(arr).enter().append("div").text(function(d) { return d});

原先的程式碼將在div.data(arr)添加enter()的方法後再添加div最後同樣地用text()把資料顯示在畫面上,如下圖
https://ithelp.ithome.com.tw/upload/images/20210925/20125095CFm3zSYvLP.png
因此我們可以結合上面的程式碼就能正確的渲染出畫面

我們可以看下圖一般使用data()綁定元素的時候如果原先畫面有div會被正確對應,如果沒有被對應到的會被歸類到enter裡面,這時候我們就用enter函式來append div元素就可以渲染出整個畫面

https://ithelp.ithome.com.tw/upload/images/20210925/201250958QGrq3LcXd.png

另外官方API文件enter()的說明有提到可以使用merge()合併,下個部分會提到關於merge()的應用。

https://ithelp.ithome.com.tw/upload/images/20210925/201250953SnD9KFOCh.png

官方enter()文件參考

merge()函式—合併

使用merge把原先body裡面有的div和後來透過append()添加的div進行合併,我們宣告一個merge做為起點來操作畫面,如下程式碼

let arr = [13,6,2,34,23];
let div =d3.select("body").selectAll("div");
let merge = div.data(arr)
               .merge(
                 div.data(arr)
                 .enter()
                 .append("div")
                );
  console.log(merge);
  merge.text(function(d) {return d});

這時候你開啟開發人員工具的時候就比較像是當初你在body擁有5個div一樣了,此時我們加入text()函式就能完整的顯示出arr陣列裡面的內容在網頁上。

https://ithelp.ithome.com.tw/upload/images/20210925/20125095WkQPM1T3gQ.png

exit()函式—沒資料放入的元素

前面的例子提到當資料大於畫面中的元素時候使用enter()選取來補足,反之如果當資料量小於畫面中的元素的時候,我們可以使用exit()函式來選取通常也伴隨著remove()函式來移除多餘的這些元素,來看以下的例子。

<body>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
<script>
  const arr = [13,6,2,34,23];
  const div =d3.select("body").selectAll("div");
  const dataInDiv = div.data(arr);
  dataInDiv.text(function(d){return d})
  dataInDiv.exit().remove();
</script>

exit()官方API文件
可以參照官方API文件說明

這時候你開啟開發者人員工具可以發現原本你寫六個div,因為撰寫了dataInDiv.exit().remove(),把沒有綁定資料的div給移除了。

https://ithelp.ithome.com.tw/upload/images/20210925/20125095HPuYeQrL3E.png

如下圖如果資料綁定的過程當中有多餘的元素時會被歸類在exit裡面,這時候可以使用remove來移除多餘的元素。

https://ithelp.ithome.com.tw/upload/images/20210925/20125095SFVb4ckczG.png

join()函式—三個願望一次滿足

由於我們可能不確定元畫面上的元素和資料哪個數量比較大,因此在撰寫資料到元素時,我們會用上述的方法來確保的數量是相等,不會有元素大於資料或者資料大於元素的情況,參照以下程式碼

<body>
  <div></div>
  <div></div>
  <script>
    const arr = [13, 6, 2, 34, 23];
    const div = d3.select("body").selectAll("div");
    const dataInDiv = div.data(arr);
    const merge = div.data(arr)
                   .merge(dataInDiv.enter()
                                   .append("div")
                          );
    merge.text(function (d) {
      return d;
    });
    dataInDiv.exit().remove();
  </script>
</body>

撰寫如上述的程式碼後,無論畫面上原本的div數量是兩個或是六個並不會造成資料缺失或是元素過多的情形。
然而這些操作對於新手不友善,並且繁瑣,所幸後來的版本增加了一個函式叫做join()接下來你可以嘗試著使用下列程式碼。

  let arr = [13, 6, 2, 34, 23];
  let div = d3.select("body").selectAll("div");
  let dataInDiv = div.data(arr);
  let join = dataInDiv.join("div");
  join.text(function (d) { return d});

頓時你會覺得世界的美好,官方API說明他將會合併enter和綁定資料的selection甚至移除多餘的部分

官方API文件JOIN()

參考以下官方API截圖
https://ithelp.ithome.com.tw/upload/images/20210925/20125095fYdmGLqKnm.png


上一篇
D3JsDay09 資料元素來綁定,讓你元素有內定—資料綁定
下一篇
D3JsDay11 觀測時候別鐵齒,拿出你的比例尺
系列文
從原料到燃料,從資料到預料—資料駕馭網頁之理科的美學30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言