D3 - 动态图绘制(详解)(D3.v5)

文章目录

      • 1. 再谈“数据绑定”
        • 1.1 选择元素
        • 1.2 添加、插入和删除
        • 1.3 数据绑定
      • 2. 过渡效果
        • 2.1 过渡启动
        • 2.2 过渡属性
      • 3. 定时器
      • 4. 简单动画制作
        • 4.1 动态绘制circle
        • 4.2 动态绘制rect

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 数组元素 < 元素数量
    D3 - 动态图绘制(详解)(D3.v5)_第1张图片
    通常比较常用的方法是利用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中数据显示为:
D3 - 动态图绘制(详解)(D3.v5)_第2张图片
随后对数据进行更新:

    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中的元素变为:
D3 - 动态图绘制(详解)(D3.v5)_第3张图片
可以看到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

D3 - 动态图绘制(详解)(D3.v5)_第4张图片

动态条形图代码:

        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);

你可能感兴趣的:(#,D3)