首页 > 其他 > 详细

数据可视化(8)--D3数据的更新及动画

时间:2014-03-02 06:58:56      阅读:500      评论:0      收藏:0      [点我收藏+]

最近项目组加班比较严重,D3的博客就一拖再拖,今天终于不用加班了,赶紧抽点时间写完~~

今天就将D3数据的更新及动画写一写~~

接着之前的博客写~~

之前写了一个散点图的例子,下面可以自己写一个柱状图的例子。

我就直接给代码了,和散点图差不多~~

bubuko.com,布布扣
var margin = {top: 20, right: 20, bottom: 30, left: 40},
    width = 960 - margin.left - margin.right,
    height = 500 - margin.top - margin.bottom;
var dataset = [ 11, 12, 15, 20, 18, 17, 16, 18, 23, 25, 8, 10, 13, 19, 21, 25, 22, 18, 15, 13];
// 使用了d3.scale.ordinal() 它支持范围分档。与定量比例尺(如d3.scale.linear())返回连续的范围值不同,序数比例尺使用的是离散范围值,也就是输出值是事先就确定好的。
// 映射范围时,可以使用range(),也可以使用rangeBands()。后者接收一个最小值和一个最大值,然后根据输入值域的长度自动将其切分成相等的块或“档”。0.2也就是档间距为每一档宽度的20%。
var x = d3.scale.ordinal()
    .domain(d3.range(dataset.length))
    .rangeBands([0, width], 0.2);

var y = d3.scale.linear()
    .domain([0, d3.max(dataset, function(d) { return d; })])
    .range([height, 0]);

var xAxis = d3.svg.axis()
    .scale(x)
    .orient("bottom");

var yAxis = d3.svg.axis()
    .scale(y)
    .orient("left");

var svg = d3.select("body").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
  .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");


svg.selectAll("rect")// 插入的不是circle了,改为rect
    .data(dataset)
    .enter()
    .append("rect")
    .attr("x", function(d,i) {
        return x(i);
    })
    .attr("y", function(d) {
        return y(d);
    })
    .attr("width", x.rangeBand())
    .attr("height", function(d) {
        return height - y(d);
    })
    .attr("fill", function(d){
      return "rgb(60, 127, " + d * 10 + ")";// 根据值的大小获取颜色
    });
svg.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0," + height + ")")
      .call(xAxis)
    .append("text")
      .attr("class", "label")
      .attr("x", width)
      .attr("y", -6)
      .style("text-anchor", "end")
      .text("X轴");

  svg.append("g")
      .attr("class", "y axis")
      .call(yAxis)
    .append("text")
      .attr("class", "label")
      .attr("transform", "rotate(-90)")
      .attr("y", 6)
      .attr("dy", ".71em")
      .style("text-anchor", "end")
      .text("Y轴");
bubuko.com,布布扣

其效果如下

bubuko.com,布布扣

坐标轴有些粗,是因为CSS没设置,如果设置上在之前博客里的CSS样式,会好看一点~~

先添加一个事件来触发数据的变化,在html中body标签里添加一个button

<button>Update</button>

为button绑定事件,并在事件中添加数据的更新,代码如下

bubuko.com,布布扣
// 单击的时候,更新数据
d3.select("button").on("click", function() {
    // 新数据集
    dataset = [ 21, 22, 25, 10, 18, 17, 6, 8, 13, 15, 15, 20, 23, 19, 11,15, 25, 8, 25, 23 ];
    // 更新所有矩形
    svg.selectAll("rect")
        .data(dataset)
        .attr("y", function(d) {
            return y(d);
        })
        .attr("height", function(d) {
            return height - y(d);
        });
});
bubuko.com,布布扣

 

运行代码,点击update按钮,chart发生变化,如下

bubuko.com,布布扣

如果你足够细心的话,就会发现,颜色跟原来的一样,没有根据长度发生变化,只要把原来针对fill 编写的代码复制到事件的代码里。

bubuko.com,布布扣
svg.selectAll("rect")
    .data(dataset)
    .attr("y", function(d) {
        return y(d);
    })
    .attr("height", function(d) {
        return height - y(d); 
    })
    .attr("fill", function(d){ 
        return "rgb(60, 127, " + d * 10 + ")";// 根据值的大小获取颜色
    });
bubuko.com,布布扣

 

是不是颜色也跟着变化了。

是不是觉得,就这么变化有些太坑了,那我们就给它加个动画,过渡一下就OK了,其实现只需简单的一行代码 .transition()

注:在方法链上,要把这个调用插到选择元素之后,改变任何属性之前

bubuko.com,布布扣
svg.selectAll("rect")
    .data(dataset)
    .transition() // <-- 这是新代码,其他都保持不变。
    .attr("y", function(d) {
        return y(d);
    })
    .attr("height", function(d) {
        return height - y(d);
    })
    .attr("fill", function(d){
        return "rgb(60, 127, " + d * 10 + ")";// 根据值的大小获取颜色
    });
bubuko.com,布布扣

 

是不是有了动画,就不会觉得变化有些突然了~~

之后,我觉得想控制一下动画的时间,要让他快一点或者慢一点,其实现也只需要一行代码 .duration(2000) 

bubuko.com,布布扣
svg.selectAll("rect")
    .data(dataset)
    .transition()
    .duration(2000) // <-- 这是新代码,其他都保持不变。2000 毫秒,即2 秒
    .attr("y", function(d) {
        return y(d);
    })
    .attr("height", function(d) {
        return height - y(d);
    })
    .attr("fill", function(d){
        return "rgb(60, 127, " + d * 10 + ")";// 根据值的大小获取颜色
    });
bubuko.com,布布扣

 

你延长了一下动画时间,发现它的动画一开始非常慢,然后逐渐加速,最后在达到预定高度之前速度再次慢了下来。换句话说,动画的速度不是线性不变的,而是有加减速变化的。

如果,我想要均匀的变化怎么办?

在D3 中,可以使用ease() 指定不同的缓动类型。默认的缓动效果是"cubic-inout",产生的就是我们刚刚看到的那种逐渐加速然后再逐渐减速的效果。

所以我们只需要设置一下ease("linear")就可以了。我们要在transition() 之后、attr() 之前指定ease()。事实上,ease()在duration() 之前之后都没问题,但先过渡再设置缓动似乎更顺理成章。

... // 选择元素的代码
.transition()
.duration(2000)
.ease("linear")
... //attr() 的代码

 

linear是线性缓动,就是没有逐渐加速和减速的变化,所有元素都按照一个速度变化,变化到最终值时戛然而止。

除此之外,还有很多缓动函数可供选择。下面只是几个,不是全部
? circle
逐渐进入并加速,然后突然停止。
? elastic
描述这个效果的一个最恰当的词是“有弹性”。
? bounce
像皮球落地一样反复弹跳,慢慢停下来。

详细可以查看:https://github.com/mbostock/d3/wiki/Transitions#wiki-d3_ease

我们再来想一下,如果这个动画,我不想让它一开始就跑起来,我想让它晚点跑起来,比如说2秒后。

那我们只需要在添加一个方法.delay(2000),就OK了

...
.transition()
.delay(2000) //2000 毫秒,即2 秒
.duration(2000) //2000 毫秒,即2 秒
...

与使用duration() 和ease() 一样,把delay() 放到哪里并没有十分严格的限制,但我更喜欢把它放在duration() 前面。因为是先设定延迟时间,然后过渡动画才开始计时,这样比较符合逻辑。

上面的代码是静态延时,静态延迟时间只是一种延迟方式,更有意思的是可以动态计算延迟时间。动态延迟的一个常见用途就是创建交错延迟的效果,让某些过渡在另一个过渡之前发生。交错延迟对人的感知有利,因为当相邻元素的变化不那么同步时,人眼更容易注意到每个元素的变化。要设置动态延迟,就别给delay() 传递静态值,而是给它传入一个函数,按照D3 的惯例……对,就是传入一个匿名函数。

bubuko.com,布布扣
...
.transition()
.delay(function(d, i) {
    return i * 100;
})
.duration(500)
...
bubuko.com,布布扣

 

在匿名函数中,与当前元素绑定的数据值是以d 传入的,而这个元素的位置是以i传入的。因此,这里的意思是让D3 循环遍历每个元素,把它们的动画延迟时间设定为i * 100,也就是后一个元素的动画开始时间总比前一个元素晚100 毫秒。

到这里,也许你会提出一个疑问,如果变化的时候数据超出了原来的范围,怎么办?

那我们就需要更新比例尺了,更新比例尺的代码很简单。

// 更新比例尺的值域
y.domain([0, d3.max(dataset)]);

 

 

今天就先到这里,写博客时间长了,觉得有点腰疼。

等有时间再继续更新吧~~

数据可视化(8)--D3数据的更新及动画,布布扣,bubuko.com

数据可视化(8)--D3数据的更新及动画

原文:http://www.cnblogs.com/CraryPrimitiveMan/p/3556765.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!