• 用D3.js画树状图


    做项目遇到一个需求,将具有层级关系的词语用树状图的形式展示它们之间的关系,像这样:

    或者是这样:

    上面的图片只是样例,跟我下面的代码里面用的数据不同

    网上有很多这种数据可视化展示的js控件,我这里选择了D3.js。

    首先在html页面需要包含D3的js文件,其次我们需要将数据构造成json格式,然后存入到一个d3.json文件

    {
    "name":"如何学习D3",
    "children":
    [
        { 
          "name":"预备知识" , 
            "children":
            [
                    {"name":"HTML & CSS" },
                    {"name":"JavaScript" },
                    {"name":"DOM" },
                    {"name":"SVG" }
            ] 
          },
          
        { 
            "name":"安装" , 
            "children":
            [
                {
                    "name":"记事本软件",
                    "children":
                    [
                        {"name":"Notepad++"},
                        {"name":"EditPlus"},
                        {"name":"Sublime Text"}
                    ]
                },
                {
                    "name":"服务器软件",
                    "children":
                    [
                        {"name":"Apache Http Server"},
                        {"name":"Tomcat"}
                    ]
                },
                {"name":"下载D3.js"}
            ] 
        },
        
        { 
            "name":"入门",
            "children":
            [
                {
                    "name":"选择集",
                    "children":
                    [
                        {"name":"select"},
                        {"name":"selectAll"}
                    ]
                },
                {
                    "name":"绑定数据",
                    "children":
                    [
                        {"name":"datum"},
                        {"name":"data"}
                    ]
                },
                {"name":"添加删除元素"},
                {
                    "name":"简单图形",
                    "children":
                    [
                        {"name":"柱形图"},
                        {"name":"折线图"},
                        {"name":"散点图"}
                    ]
                },
                {"name":"比例尺"},
                {"name":"生成器"},
                {"name":"过渡"}
            ] 
        },
        
        { 
            "name":"进阶" , 
            "children":
            [
                {
                    "name":"布局的应用",
                    "children":
                    [
                        {"name":"饼状图"},
                        {"name":"树状图"},
                        {"name":"矩阵树图"}
                    ]
                },
                {"name":"地图"}
            ]
        }
    ]
    }

    然后开始编写JavaScript代码:

    横向树状图:

    var width = 700,
        height = 700;
    
    var cluster = d3.layout.cluster()
        .size([width, height - 200]);
    
    var diagonal = d3.svg.diagonal()
        .projection(function(d) { return [d.y, d.x]; });
    
    var svg = d3.select("body").append("svg")
        .attr("width", width)
        .attr("height", height)
      .append("g")
        .attr("transform", "translate(40,0)");
        
    
    
    d3.json("d3.json", function(error, root) {
        
      var nodes = cluster.nodes(root);
      var links = cluster.links(nodes);
      
      console.log(nodes);
      console.log(links);
    
      var link = svg.selectAll(".link")
          .data(links)
          .enter()
          .append("path")
          .attr("class", "link")
          .attr("d", diagonal);
    
      var node = svg.selectAll(".node")
          .data(nodes)
          .enter()
          .append("g")
          .attr("class", "node")
          .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; })
    
      node.append("circle")
          .attr("r", 4.5);
    
      node.append("text")
          .attr("dx", function(d) { return d.children ? -8 : 8; })
          .attr("dy", 3)
          .style("text-anchor", function(d) { return d.children ? "end" : "start"; })
          .text(function(d) { return d.name; });
    });

    圆形树状图(这个需要用到投影,稍微麻烦一点,不详细解释了):

    //图像区域大小
        var R = 600;
    
        //定义一个Tree对象,定义旋转角度和最大半径
        var tree = d3.layout.tree()
            .size([360,R/2-120])
            .separation(function(a,b) { return a.parent == b.parent ? 1 : 2;});
    
        //定义布局方向
        var diagonal = d3.svg.diagonal()  
            .projection(function(d) { 
                var r = d.y, a = (d.x-90) / 180 * Math.PI;
                  return [r * Math.cos(a), r * Math.sin(a)];
         }); 
    
        //新建画布,移动到圆心位置
        var svg = d3.select("#showTree").append("svg")
            .attr("width", R)
            .attr("height", R)
            .append("g")
            .attr("transform", function(d){ return "translate("+R/2+"," + R/2 + ")";});
    
            //根据JSON数据生成树
            d3.json("d3.json", function(error, data) {
          
          //根据数据生成nodes集合
          var nodes = tree.nodes(data);
          
          //获取node集合的关系集合
          var links = tree.links(nodes);
          
          //为关系集合设置贝塞尔曲线连接
          var link=svg.selectAll(".link")
              .data(links)
              .enter()
              .append("path")
              .attr("class", "link")
              .attr("d",diagonal);
          
          //根据node集合生成节点
          var node = svg.selectAll(".node")
              .data(nodes)
              .enter()
              .append("g")
              .attr("class", "node")
              .attr("transform",function(d){return "rotate(" + (d.x-90) + ")translate(" + d.y + ")"; });
          
          //为节点添加圆形标记,如果有子节点为红色,否则绿色
          node.append("circle")      
              .attr("fill",function(d){return d.children==null?"#0F0":"#F00";})
              .attr("r", 5);
          
          //为节点添加说明文字
          node.append("text")
            .attr("dy", ".4em")
            .text(function(d){return d.name;})
            .attr("text-anchor", function(d) { return d.x < 180 ? "start" : "end"; })
            .attr("transform", function(d) { return d.x < 180 ? "translate(8)" : "rotate(180)translate(-8)"; });
        });    

    D3的d3.json(url,callback)方法可以读取json文件,然后构造树状图。

    如果不想把数据写入json文件,直接在后台构造好json数据结构然后传到前台要怎么弄?

    其实d3.json(url,callback)方法的url是发起一个get请求,返回一个json字符串,然后进入callback进行处理,本质上跟ajax差不多

    所以当我们不想读取文件时,修改一下d3.json(url,callback)的url参数,发起一个get请求到控制器,然后你在控制器里面构造相应的json数据结构,然后返回过来就可以了

    但是这里的url不能直接带中文参数,比如:

    url = "json.html?word=关键词";

    这样的请求发到后台,后台接收的是这样的一段乱码字符串:

    关键è¯

    那有人说先将这个中文做一次编码,然后在传到后台不就行了?

    确实,我们一般在js里面如果要传中文参数到后台都会先进行编码然后再传的,所以我当时也是这么想的,心想这下应该不会出问题了吧,然并卵,后台接收然后解码得到的依然是那串乱码,然后没办法,我只能进d3.js的文件去查看源码,奈何才疏学浅,压根看不懂,也没找到它哪里对这个url做了什么编码或解码操作。后来想到以前见到过在前台进行多次编码然后再传到后台的,我也尝试了一下在js里面进行了两次编码,然后再传到后台,到后台接收然后解码一次,发现能够得到正确的中文参数

     第一行是后台接收的参数,第二行是对参数解码一次得到的结果。

    问题是解决了,但是我还是不知道这是为什么,只注意到d3.json这个方法里面发送的是get请求,后来查资料还有问其他人才知道在浏览器地址栏里,浏览器认为%是个转义字符,浏览器会把%与%之间的编码,两位两位取出后进行解码,然后再传递给处理页面,然后由处理页面进行再次解码,而get请求的中文参数就是显示在浏览器地址栏,所以在js里面参数只进行一次编码的话,参数经过浏览器的解码,传到后台的就是没编码的中文,这个当然就会变成乱码,所以在js里面对中文做两次编码然后通过get请求传到后台,后台只需做一次解码就能得到正确的中文参数

  • 相关阅读:
    The requested resource (/) is not available解决办法
    字符问题
    Unknown column in 'field list'
    table 和 div 简单布局
    css简介
    div 与 table 的优点
    瞎搞
    html
    小计--关联 复制表结构
    ddl dml dcl
  • 原文地址:https://www.cnblogs.com/quyixuanblog/p/5742467.html
Copyright © 2020-2023  润新知