D3 - 動態圖繪製(詳解)(D3.v5)

1. 再談“數據綁定”

1.1 選擇元素

D3中,選擇元素的函數有兩個selectselectAll,兩種方法都很常用,select返回匹配選擇器的第一個元素,而selectAll返回匹配選擇器的所有元素。
選擇所需元素的方法:

d3.select("body"); //選擇body元素
d3.select("#tp1"); //選擇id爲tp1的元素
d3.select(".tp2"); //選擇類爲tp2的元素

當然,也可以對選擇集中的元素再進行選擇:

d3.select("body")
  .selectAll("p");

1.2 添加、插入和刪除

d3.selectd3.selectAll所返回的對象稱爲選擇集 selection
利用 selection.attr(name,[]) 來設置或獲取選擇集的屬性。
利用 selection.text([]) 設定或獲取選擇集的文本內容。

添加元素的方法爲 selection.append(name) ,在選擇集的末尾添加一個元素,name爲元素的名稱。
插入元素的方法爲 selection.insert(name, [before]) ,name是插入元素的名稱,before爲CSS選擇器的名稱,將元素插入到指定元素之前

刪除選擇集中的元素 selection.remove()

1.3 數據綁定

對於d3.selectd3.selectAll 返回的選擇集是沒有數據的。數據綁定的過程就是讓這些被選擇的元素中 “含有” 數據。

selection.datum(value)
選擇集中的每個元素都綁定相同的數據value。
selection.data(values, [key])
選擇集中的每一個元素分別綁定數組values中的每一項,key爲鍵值函數,用於指定綁定時的對應規則。

在data綁定之後,有三種情況,分別按駐足長度和元素數量的關係如下:

  • update 數組長度 = 元素數量
  • enter 數組元素 > 元素數量
  • exit 數組元素 < 元素數量
    在這裏插入圖片描述
    通常比較常用的方法是利用selectAll選取一個空集,隨後再對enter() 部分添加元素append,即
d3.selectAll("p")
  .data(d)
  .enter()
  .append("p")

鍵函數key:
只有在選擇集原來已經有數據的情況下,使用鍵函數纔有效果!
比如有如下內容:

<body>
<p></p>
<p></p>
<p></p>
<script src="https://d3js.org/d3.v5.js"></script>
<script>
    let Data = [{name: "p1", data: 12}, {name: "p2", data: 17}, {name: "p3", data: 14}];

    let p = d3.select("body").selectAll("p")
        .data(Data)
        .text(function (d) {
            return d.name + ':' + d.data;
        });
</script>
</body>

此時p中數據顯示爲:
在這裏插入圖片描述
隨後對數據進行更新:

    let DataEntry = [{name: "p5", data: 17}, {name: "p4", data: 14}, {name: "p6", data: 12}];

    p.data(DataEntry, d => d.data)
        .text(function (d) {
            return d.name + ':' + d.data;
        });

可以看到此時p中的元素變爲:
在這裏插入圖片描述
可以看到data作爲鍵值,並沒有按照DataEntry中的順序進行依次綁定,而是保持原本順序不變,使鍵值對應的數據作出更新。可以利用這一性質在製作動態圖時更新數據。

2. 過渡效果

2.1 過渡啓動

d3.transition() 創建一個過渡效果。對於每個選擇集都可以使用**transition()**方法創建過渡。
transition.delay([value]) 設定延遲時間。過渡經過一段時間後才發生,單位是毫秒。
transition.duration([value]) 設定過渡的持續時間。單位爲毫秒。
默認情況下,如果不設置時間的話delay爲0ms,duration爲250ms。
transition.ease(value,[]) 設定過渡樣式、在目標處彈跳幾次等方式。

2.2 過渡屬性

過渡前後的狀態不同,因此需要指定過渡前後元素的不同屬性。
transition.attr(name,value) 屬性name過渡到目標值value,value可以是一個函數。
例如如下代碼:

        .attr("r", function (d) {
            //...
        })
        .attr("cx", function (d) {
            //...
        })
        .attr("cy", function (d) {
            //...
        })
        .transition()
        .delay(3000)
        .duration(2000)
        .attr("r", function (d) {
            //...
        })
        .attr("fill", function (d) {
            //...
        });

transition.attrTween(name, tween()) 將屬性 name 使用差值函數 tween() 。
例如:

    svg.transition()
        .duration(2000)
        .attrTween("width", function (d,i,a) {
            return function (t) {
                return parseInt(a + t * 300);
            }
        })

d是被綁定的數據,i是索引號,a是width的屬性初始值。

3. 定時器

setInterval(code, millisec) 以指定的週期來執行代碼,直到 clearInterval() 被調用或者窗口被關閉。
例如:

	// 調用更新函數,每0.7s更新一次
    setInterval(function () {
        update((++idx) % 12);
    }, 700);

刪除方法:

    let id = setInterval(function () {
        update((++idx) % 12);
    }, 700);

	//...
	clearInterval(id);

4. 簡單動畫製作

4.1 動態繪製circle

效果圖(含實時更新的情況):
在這裏插入圖片描述

    let circles = svg.selectAll("circle")
        .data(DataLine)
        .enter()
        .append("circle")
        .attr("r", function (d) {
            return 1;
        })
        .attr("cx", function (d) {
            return w - inner.right - (d.longitude * (-1) - 60) / 70 * W;
        })
        .attr("cy", function (d) {
            return h - inner.bottom - (d.latitude - 25) / 30 * H;
        });


    circles.transition()
        .delay(3000)
        .duration(2000)
        .attr("r", function (d) {
            return d.PRCP * 5;
        })
        .attr("fill", function (d) {
            return 'rgba(0,' + Math.max(0, (175 - parseInt(d.WSF5))) + ',' + (255) + ',0.8)';
        });
        
    setInterval(function () {
        add1day(); //更新idx的函數
        update(idx);
    }, 2000);

    function update(t) {
        comment.text(idx);
        updateElement();
    }

    function updateElement() {

        svg.selectAll("circle")
            .data(DataEntry[sce], d => d.station)
            .transition()
            .duration(2000)
            .attr("r", function (d) {
                return d.PRCP * 5;
            })
            .attr("fill", function (d) {
                return 'rgba(0,' + Math.max(0, (175 - parseInt(d.WSF5))) + ',' + (255) + ',0.8)';
            });
    }

4.2 動態繪製rect

在這裏插入圖片描述

動態條形圖代碼:

        let rects = groups.data(DataEntry)
            .enter().append("rect")
            .attr("x", inner.left)
            .attr("height", H * 0.65)
            .attr("fill", function (d, i) {
                return Color[i];
            })
            .attr("width", function (d) {
                return xScale(d.sunshine);
            });
            
        // 設定更新函數
        function UpdateElement() {

            rects.data(DataEntry, d => d.city)
                .transition()
                .duration(600)
                .attr("y", function (d, i) {
                    return i * H + inner.bottom;
                })
                .attr("width", function (d) {
                    return xScale(d.sunshine);
                });
        }

        UpdateElement();

        // 更新函數
        function update(t) {
        	//...
            comment.text(DataEntry[0].month);
            UpdateElement();
        }

        // 調用更新函數,每0.7s更新一次
        setInterval(function () {
            update((++idx) % 12);
        }, 700);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章