d3數據綁定與selection實踐

本篇blog的使用的d3版本爲d3.js v5.9.2
將按照簡要介紹、實驗及意義進行html

簡要

d3.js經過data join(數據綁定)建立,更新及銷燬元素,如何操做元素則是經過selection。總結以下
clipboard.pnggit

其中,selection的三種狀態就將data與elements結合在一塊兒,進行對元素的控制
他們以前的關係如圖所示(圖片來源:Thinking with Joins
clipboard.png
接下來用實驗進一步說明區別吧github

實驗

主要會用到如下幾個API:
selection.data():返回表明update的selection,同時定義enter selectionexit selection,update按上圖理解表示又有數據又有元素 編程

selection.enter():返回enter selection,enter中文爲「進入」,我理解爲有數據但無元素,能夠進入圖表 數組

selection.exit():返回exit selection,exit中文爲「退出」,我理解爲無數據綁定的元素,能夠退出圖表 app

selection.join():對已綁定數據的元素作插入,移除多餘,更新數據,能夠簡化操做函數式編程

初始HTML及CSS

HTML以下函數

<div class="chart"></div>

CSS以下動畫

.chart div{
    font: 10px sans-serif;
    background-color: steelblue;
    text-align: right;
    padding: 3px;
    margin: 1px;
    color: white;
}

接下來以四種狀況熟悉enter,update與exit:spa

  • chart下無子元素
  • chart下子元素少於數據(其實和上一種差很少,但爲了方便觀察列出來)
  • chart下子元素數量等於數據
  • chart下子元素數量多於數據

chart下無子元素

<div class="chart"></div>

數據及JS代碼以下

const data = [10,55,33];
let selection = d3.select('.chart')
    .selectAll('div')
    .data(data);
console.log(selection);

clipboard.png

(注意這裏每個selection是一個數組對象,每個元素爲一個數組)

_groups:這裏是表明update的selection,既有數據,又有元素;無元素的數據則用empty表示

enter:有數據,無元素

exit:無數據,有元素

對於enter,可經過selection.enter()進行操做

let enterSelection = selection.enter();
console.log(enterSelection);

enterSelection.append('div')
    .style('width', d => d * 10 + 'px')
    .text(d => d);

clipboard.png

chart下子元素少於數據

<div class="chart">
    <div></div>
</div>
const data = [10,55,33];
let selection = d3.select('.chart')
    .selectAll('div')
    .data(data);
    // .style('width', d => d * 10 + 'px') //註釋去掉就會設置第一個div的width
    // .text(d => d);
console.log(selection);

let enterSelection = selection.enter();
console.log(enterSelection);

enterSelection.append('div')
    .style('width', d => d * 10 + 'px')
    .text(d => d);

console.log(selection)顯示以下:
clipboard.png

enter:.chart下有一個div,且這個div有數據綁定,故enter的第一個元素用empty表示,三個數據剩下兩個用EnterNode表示

exit:.chart下有一個div,但他有數據綁定,因此exit中這個div用一個empty表示

_groups(這裏表示update selection):.chart下的有一個div而且綁定上了數據,剩餘兩個數據沒有元素綁定,故用empty表示

chart下子元素數量等於數據

<div class="chart">
    <div></div>
    <div></div>
    <div></div>
</div>
const data = [10,55,33];
let selection = d3.select('.chart')
    .selectAll('div')
    .data(data);
    // .style('width', d => d * 10 + 'px')
    // .text(d => d);
console.log(selection);

clipboard.png

道理同上

chart下子元素數量多於數據

<div class="chart">
    <div></div>
    <div></div>
    <div></div>
    <div></div>
</div>
const data = [10,55,33];
let selection = d3.select('.chart')
    .selectAll('div')
    .data(data);
    // .style('width', d => d * 10 + 'px')
    // .text(d => d);
console.log(selection);

clipboard.png
clipboard.png
可見exit下多了最後一個未綁定數據的元素,即對應圖片中的最後一個元素
可經過selection.exit()對其進行操做

let exitSelection = selection.exit();
console.log(exitSelection);

exitSelection.remove();

clipboard.png

selection.join()簡化操做

以前不管是對enter,exit以及update的操做可能都須要經過selection.enter()及selection.exit()等API獲取selection,使用selection.join()能夠極大地簡化操做,同時局部渲染提升了效率
如下根據以前的例子簡單舉例

子元素少於數據或無子元素

<div class="chart">
    <div></div>
</div>
let selection = d3.select('.chart')
    .selectAll('div')
    .data(data).join('div')
    .style('width', d => d * 10 + 'px')
    .text(d => d);

子元素多於數據

<div class="chart">
    <div></div>
    <div></div>
    <div></div>
    <div></div>
</div>
let selection = d3.select('.chart')
    .selectAll('div')
    .data(data).join('div')
    .style('width', d => d * 10 + 'px')
    .text(d => d);

js是一樣的代碼,同時把多餘的元素刪去了

data join意義

1.有利於動態數據的可視化編程

以上僅僅只是靜態數據,但咱們能夠擴展到動態的數據,如data數組元素增長或減小,三種狀態使得咱們便於操做數據,僅僅只需使用selection.join()或者selection.remove()等等

2.編程更偏向聲明式

當數據大小改變,或數據量增多減小時,不須要使用if或者for等語法。update,enter及exit三種狀態結合API使得語法簡練,大幅度提高編程效率

3.方便添加動畫效果

其實意義同第一條很相像,三種狀態能夠方便咱們對進入圖表或退出圖表的元素建立動畫,例子以下

<div class="chart"></div>
const data = [10,55,33];
const t = d3.transition()//定義動畫變換
    .duration(500)
    .ease(d3.easeLinear);
    
let selection = d3.select('.chart')
    .selectAll('div')
    .data(data).join('div').style('width', 0).
    transition(t) //使用動畫變換
    .style('width', d => d * 10 + 'px')
    .text(d => d);

這樣就會有動畫效果了

總結

解決了一直好奇的問題,初步入門,有不對或建議請大佬指正

參考資料

Thinking with Joins
編程範式:命令式編程(Imperative)、聲明式編程(Declarative)和函數式編程(Functional)
selection.data()
selection.enter()
selection.exit()
selection.join()

相關文章
相關標籤/搜索