zoukankan      html  css  js  c++  java
  • D3.js 让图表动起来

    D3 支持制作动态的图表。有时候,图表的变化需要缓慢的发生,以便于让用户看清楚变化的过程,也能给用户不小的友好感。

    一、什么是动态效果

      绘制完成后不再发生变化的,这是静态的图表。

      动态的图表,是指图表在某一时间段会发生某种变化,可能是形状、颜色、位置等,而且用户是可以看到变化的过程的。

      例如,有一个圆,圆心为 (100, 100)。现在我们希望圆的 x 坐标从 100 移到 300,并且移动过程在 2 秒的时间内发生。

      这种时候就需要用到动态效果,在 D3 里我们称之为过渡(transition)

    二、实现动态的方法

      D3 提供了 4 个方法用于实现图形的过渡:从状态 A 变为状态 B

      1、transition()

        启动过渡效果。

        其前后是图形变化前后的状态(形状、位置、颜色等等),例如:

    .attr("fill","red")         //初始颜色为红色
    .transition()               //启动过渡
    .attr("fill","steelblue")   //终止颜色为铁蓝色

        D3 会自动对两种颜色(红色和铁蓝色)之间的颜色值(RGB值)进行插值计算,得到过渡用的颜色值。我们无需知道中间是怎么计算的,只需要享受结果即可。

      2、duration()

        指定过渡的持续时间,单位为毫秒。

          如 duration(2000) ,指持续 2000 毫秒,即 2 秒。

      3、ease()

        指定过渡的方式,常用的有:

        • linear:普通的线性变化
        • circle:慢慢地到达变换的最终状态
        • elastic:带有弹跳的到达最终状态
        • bounce:在最终状态处弹跳几次

        调用时,格式形如: ease(“bounce”)。

      4、delay()

        指定延迟的时间,表示一定时间后才开始转变,单位同样为毫秒。此函数可以对整体指定延迟,也可以对个别指定延迟。例如,对整体指定时:

    .transition()
    .duration(1000)
    .delay(500)

        如此,图形整体在延迟 500 毫秒后发生变化,变化的时长为 1000 毫秒。因此,过渡的总时长为1500毫秒。

        又如,对一个一个的图形(图形上绑定了数据)进行指定时:

    .transition()
    .duration(1000)
    .delay(funtion(d,i){
        return 200*i;
    })

        如此,假设有 10 个元素,那么第 1 个元素延迟 0 毫秒(因为 i = 0),第 2 个元素延迟 200 毫秒,第 3 个延迟 400 毫秒,依次类推….整个过渡的长度为 200 * 9 + 1000 = 2800 毫秒。

    三、实现简单的动态效果

      下面将在 SVG 画布里添加三个圆,圆出现之后,立即启动过渡效果。

      1、第一个圆,要求移动 x 坐标。

    var circle1 = svg.append("circle")
            .attr("cx", 100)
            .attr("cy", 100)
            .attr("r", 45)
            .style("fill","green");
    
    //在1秒(1000毫秒)内将圆心坐标由100变为300
    circle1.transition()
        .duration(1000)
        .attr("cx", 300);

      2、第二个圆,要求既移动 x 坐标,又改变颜色。

    var circle2 = svg.append("circle")... //与第一个圆一样,省略部分代码
    
    //在1.5秒(1500毫秒)内将圆心坐标由100变为300,
    //将颜色从绿色变为红色
    circle2.transition()
        .duration(1500)
        .attr("cx", 300)
        .style("fill","red");

      3、第三个圆,要求既移动 x 坐标,又改变颜色,还改变半径。

    var circle3 = svg.append("circle")... //与第一个圆一样,省略部分代码
    
    //在2秒(2000毫秒)内将圆心坐标由100变为300
    //将颜色从绿色变为红色
    //将半径从45变成25
    //过渡方式采用bounce(在终点处弹跳几次)
    circle3.transition()
        .duration(2000)
        .ease("bounce")
        .attr("cx", 300)
        .style("fill","red")
        .attr("r", 25);

    四、给柱形图加上动态效果

      在添加文字元素和矩形元素的时候,启动过渡效果,让各柱形和文字缓慢升至目标高度,并且在目标处跳动几次。

      对于文字元素,代码如下:

    .attr("y",function(d){
        var min = yScale.domain()[0];
        return yScale(min);
    })
    .transition()
    .delay(function(d,i){
        return i * 200;
    })
    .duration(2000)
    .ease("bounce")
    .attr("y",function(d){
        return yScale(d);
    });

      文字元素的过渡前后,发生变化的是 y 坐标。其起始状态是在 y 轴等于 0 的位置(但要注意,不能在起始状态直接返回 0,要应用比例尺计算画布中的位置)。终止状态是目标值。

      对于矩形元素,思想与文字元素一样,只是在计算起始状态时要稍微复杂一些

    <html>  
    <head>  
        <meta charset="utf-8">  
        <title>让图表动起来</title>  
    
    <style>
        .axis path,
        .axis line{
            fill: none;
            stroke: black;
            shape-rendering: crispEdges;
        }
    
        .axis text {
            font-family: sans-serif;
            font-size: 11px;
        }
    
        .MyRect {
            fill: steelblue;
        }
    
        .MyText {
            fill: white;
            text-anchor: middle;
        }
    </style>
    
    </head> 
    
    <body>  
        <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>  
        <script>
    
        //画布大小
        var width = 400;
        var height = 400;
    
        //在 body 里添加一个 SVG 画布    
        var svg = d3.select("body")
            .append("svg")
            .attr("width", width)
            .attr("height", height);
    
        //画布周边的空白
        var padding = {left:30, right:30, top:20, bottom:20};
    
        //定义一个数组
        var dataset = [10, 20, 30, 40, 33, 24, 12, 5];
            
        //x轴的比例尺
        var xScale = d3.scale.ordinal()
            .domain(d3.range(dataset.length))
            .rangeRoundBands([0, width - padding.left - padding.right]);
    
        //y轴的比例尺
        var yScale = d3.scale.linear()
            .domain([0,d3.max(dataset)])
            .range([height - padding.top - padding.bottom, 0]);
    
        //定义x轴
        var xAxis = d3.svg.axis()
            .scale(xScale)
            .orient("bottom");
            
        //定义y轴
        var yAxis = d3.svg.axis()
            .scale(yScale)
            .orient("left");
    
        //矩形之间的空白
        var rectPadding = 4;
    
        //添加矩形元素
        var rects = svg.selectAll(".MyRect")
            .data(dataset)
            .enter()
            .append("rect")
            .attr("class","MyRect")
            .attr("transform","translate(" + padding.left + "," + padding.top + ")")
            .attr("x", function(d,i){
                return xScale(i) + rectPadding/2;
            } )
            .attr("width", xScale.rangeBand() - rectPadding )
            .attr("y",function(d){
                var min = yScale.domain()[0];
                return yScale(min);
            })
            .attr("height", function(d){
                return 0;
            })
            .transition()
            .delay(function(d,i){
                return i * 200;
            })
            .duration(2000)
            .ease("bounce")
            .attr("y",function(d){
                return yScale(d);
            })
            .attr("height", function(d){
                return height - padding.top - padding.bottom - yScale(d);
            });
    
        //添加文字元素
        var texts = svg.selectAll(".MyText")
            .data(dataset)
            .enter()
            .append("text")
            .attr("class","MyText")
            .attr("transform","translate(" + padding.left + "," + padding.top + ")")
            .attr("x", function(d,i){
                return xScale(i) + rectPadding/2;
            } )
            .attr("dx",function(){
                return (xScale.rangeBand() - rectPadding)/2;
            })
            .attr("dy",function(d){
                return 20;
            })
            .text(function(d){
                return d;
            })
            .attr("y",function(d){
                var min = yScale.domain()[0];
                return yScale(min);
            })
            .transition()
            .delay(function(d,i){
                return i * 200;
            })
            .duration(2000)
            .ease("bounce")
            .attr("y",function(d){
                return yScale(d);
            });
    
        //添加x轴
        svg.append("g")
            .attr("class","axis")
            .attr("transform","translate(" + padding.left + "," + (height - padding.bottom) + ")")
            .call(xAxis); 
            
        //添加y轴
        svg.append("g")
            .attr("class","axis")
            .attr("transform","translate(" + padding.left + "," + padding.top + ")")
            .call(yAxis);
    
    </script>  
    </body>  
    </html>  
  • 相关阅读:
    置换群
    背包问题
    并查集
    链式前向星
    一个简单的金额平均分配函数(C#版)
    EasyUI ComboGrid的绑定,上下键和回车事件,输入条件查询
    Oracle表解锁语句
    如何将两个json合并成一个
    textbox只能输入数字或中文的常用正则表达式和验证方法
    C#注册表的读,写,删除,查找
  • 原文地址:https://www.cnblogs.com/LO-ME/p/5387755.html
Copyright © 2011-2022 走看看