【D3.js开发入门2:绘制图表】动态图表

已被阅读 673 次 | 文章分类:javascript | 2022-05-04 01:19

d3.js的最大特征是所有图表元素都是一个单独对象,可以组合使用;有很高的自由度,比如增删改查等等

1 延时动画

初始化图表的时候,让图表有个延迟和缓冲的动画效果;

                                            
这里使用delay()函数和duration()函数;
                                            
                                        

实现效果如下:

/net/upload/image/20220504/429ca182baee4f0d9bfe5b9a92a11ee0.gif

如图有两部分,矩形和文字两种类型;原理就是让每个矩形和文字依次延迟出现;核心代码如下:

                                            
// 添加文字元素
      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(1000)
        .ease('bounce')
        .attr('y', function (d) {
          return yScale(d);
        });
                                            
                                        

2 鼠标悬浮交互

鼠标悬浮更改图表某些属性,比如尺寸或者颜色等;

                                            
通过on函数注册对应的事件即可;
                                            
                                        

这里演示鼠标悬浮事件更改颜色的效果

/net/upload/image/20220504/5c00594d0e1049e8a2d4fa13215a4fee.gif

代码如下:

                                            
// 添加矩形元素
      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('y', function (d) {
          return yScale(d);
        })
        .attr('width', xScale.rangeBand() - rectPadding)
        .attr('height', function (d) {
          return height - padding.top - padding.bottom - yScale(d);
        })
        .attr('fill', 'steelblue') //填充颜色不要写在CSS里
        .on('mouseover', function (d, i) {
          d3.select(this).attr('fill', 'yellow');
        })
        .on('mouseout', function (d, i) {
          d3.select(this).transition().duration(500).attr('fill', 'steelblue');
        });
                                            
                                        

3 拖拽交互(力导向图)

力导向图绘制的关键是节点和连线之间的关系;不过D3为我们提供了对应的api;这个不需要我们去关心;只需要组织好数据结构,将数据传进去即可;实现下面一个效果:

/net/upload/image/20220504/aacc70be2033476196c3ebf876a095df.gif

节点和连线的关系用下面两个数组:

                                            
var nodes = [

        { name: '桂林' },

        { name: '广州' },

        { name: '厦门' },

        { name: '杭州' },

        { name: '上海' },

        { name: '青岛' },

        { name: '天津' },

      ];

      var edges = [

        { source: 0, target: 1 },

        { source: 0, target: 2 },

        { source: 0, target: 3 },

        { source: 1, target: 4 },

        { source: 1, target: 5 },

        { source: 1, target: 6 },

      ];
                                            
                                        
                                            
这里我们使用d3.layout()方法绘制力导向图;
                                            
                                        

首先创建一个力导向图的元素布局;

                                            
var width = 500;
      var height = 500;
      var svg = d3
        .select('body')
        .append('svg')
        .attr('width', width)
        .attr('height', height);
 
      var force = d3.layout
        .force()
        .nodes(nodes) //指定节点数组
        .links(edges) //指定连线数组
        .size([width, height]) //指定范围
        .linkDistance(150) //指定连线长度
        .charge(-400); //相互之间的作用力
 
      force.start(); //开始作用
 
      console.log(nodes);
      console.log(edges);
 
      // 添加连线
      var svg_edges = svg
        .selectAll('line')
        .data(edges)
        .enter()
        .append('line')
        .style('stroke', '#ccc')
        .style('stroke-width', 1);
 
      var color = d3.scale.category20();
 
      // 添加节点
      var svg_nodes = svg
        .selectAll('circle')
        .data(nodes)
        .enter()
        .append('circle')
        .attr('r', 20)
        .style('fill', function (d, i) {
          return color(i);
        })
        .call(force.drag); //使得节点能够拖动
 
      // 添加描述节点的文字
      var svg_texts = svg
        .selectAll('text')
        .data(nodes)
        .enter()
        .append('text')
        .style('fill', 'black')
        .attr('dx', 20)
        .attr('dy', 8)
        .text(function (d) {
          return d.name;
        });
                                            
                                        

其次在鼠标拖拽的时候,实现实时更新所有节点、文字、连线的位置;代码如下

                                            
force.on('tick', function () {
        // 对于每一个时间间隔
        // 更新连线坐标
        svg_edges
          .attr('x1', function (d) {
            return d.source.x;
          })
          .attr('y1', function (d) {
            return d.source.y;
          })
          .attr('x2', function (d) {
            return d.target.x;
          })
          .attr('y2', function (d) {
            return d.target.y;
          });
 
        // 更新节点坐标
        svg_nodes
          .attr('cx', function (d) {
            return d.x;
          })
          .attr('cy', function (d) {
            return d.y;
          });
 
        // 更新文字坐标
        svg_texts
          .attr('x', function (d) {
            return d.x;
          })
          .attr('y', function (d) {
            return d.y;
          });
      });
                                            
                                        

4 动态添加组合实体

将多个元素放到一个组,然后整体添加;

效果如下

/net/upload/image/20220504/fab3848081514c1fb1be2dac73530453.gif

代码如下:

                                            
<!DOCTYPE html>
<html lang="en">
  <head>   
    <meta charset="UTF-8">   
    <title>创建组合元素</title>
    <style>
      .Main_tool{
        margin-bottom: 10px;
      } 
       .node{
        cursor: pointer;
      }
    </style>
  </head>
  <body>
    <div id="Main">
      <div class="Main_tool" id="Tool">
        <input id="labeltext_Entity" type="text" />
        <input id="addEntity" type="button" value="添加实体" />
 
        <br />
 
        <input id="labeltext_Field" type="text" />
        <input id="addField" type="button" value="添加字段" />
      </div>
      <div id="svgContent">
 
      </div>
    </div>
      <script src="../d3/d3.v3.min.js"></script>
    <script>   
      //初始化实体参数,创建一个svg对象,定义宽高、背景颜色
      var w =1000,h = 500,  x=50,y=50,radius=50,radius1=30;    
      var svg = d3.select("#svgContent").append("svg")            
        .attr("width",w)            
        .attr("height",h)
        .style("background-color", "white")
        .style("border","solid 1px green");
 
        var circles = [];
        var circles1 = [];
       function drawEntites(_circleArr){
         // 创建一个组   
          var elem = svg.selectAll("g")
              .data(_circleArr)
              console.log("3. elem",elem);
          /* 拖曳实体函数 -start */   //拖曳有两种方式,都是获取鼠标的像素位置更新;一种更新x、y坐标;一种更新偏移量
          var drag=d3.behavior.drag().on("drag",dragmove)
            function dragmove(d) {
                d3.select(this)
                .attr("transform","translate("+d3.event.x+","+d3.event.y+")");
            }
          /* 拖曳实体函数 -end */
          var elemEnter = elem.enter()
              .append("g")
              .attr("class", "node")
              .attr("transform", function(d){return "translate("+d.cx+","+d.cy+")"}).call(drag);
 
          /*创建圆*/
          var circle = elemEnter.append("circle")
              .attr("r", function(d){return d.r} )
              .attr("stroke","black")
              .attr("fill",function(d){
                console.log("4.d",d);
                var name=d.name;//文字颜色
                console.log("5.name",name);
                switch(name){
                  case "entity":
                    color="green";
                    break;
                  case "field":
                    color="orange";
                    break;
                  default:
                    color="red";
                }
                return color;
              });
 
          /* 创建文本*/
          elemEnter.append("text")
              .text(function(d){return d.label})  //text 显示标注
              .attr("text-anchor", "middle")      //text相对块居中
              .attr("fill","white")
        }
      /* tool事件 -start */
      document.getElementById('addEntity').addEventListener('click',function(){
        circles.push( {cx:x, cy:y, r:radius,label:document.getElementById("labeltext_Entity").value.toString().trim(),name:"entity"});
        drawEntites(circles);
      });
      document.getElementById('addField').addEventListener('click',function(){
        circles1.push( {cx:x, cy:y, r:radius1,label:document.getElementById("labeltext_Field").value.toString().trim(),name:"field"});
        drawEntites(circles1);
      })
      /* tool事件 -end */
    </script>
  </body>
</html>
                                            
                                        

QQ:3410192267 | 技术支持 微信:popstarqqsmall

Copyright ©2017 xiaobaigis.com . 版权所有 鲁ICP备17027716号