zoukankan      html  css  js  c++  java
  • d3.js之树形折叠树

    1.效果

    children和_children

    2.技术分解

    2.1折叠函数

    // (1) 递归调用,有子孙的就把children(显示)给_children(不显示)暂存,便于折叠,
    function collapse(d) {
        if (d.children) {  console.log(d);
            d._children = d.children;
            d._children.forEach(collapse);
            d.children = null;
        }
    }
    // 折叠根节点的每个孩子
    root.children.forEach(collapse);
    // 折叠之后要重绘
    update(root);
    

      

    2.2 根据交互的情况更新布局并输出

    function update(source) {
      // (2-1) 计算新树的布局
      var nodes = tree.nodes(root).reverse(),
          links = tree.links(nodes);
      
      // (2-2) 树的深度这里树d.y。树的宽度最大720,要分四层,所以每层就乘180
      nodes.forEach(function(d) { 
        d.y = d.depth * 180;// 树的x,y倒置了,所以这里Y其实是横向的
      });
    
      // (2-3) 数据连接,根据id绑定数据
      var node = svg.selectAll("g.node")
          .data(nodes, function(d) {
            return d.id //最初新点开的节点都没有id
            || (d.id = ++i); //为没有id的节点添加上ID
          });
    
      // (2-4) 点击时增加新的子节点
      var nodeEnter = node.enter().append("g")
          .attr("class", "node")
          .attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; })
          .on("click", click);
      nodeEnter.append("circle")
          .attr("r", 1e-6)
          .style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; });
      nodeEnter.append("text")
          .attr("x", function(d) { return d.children || d._children ? -10 : 10; })
          .attr("dy", ".35em")
          .attr("text-anchor", function(d) { return d.children || d._children ? "end" : "start"; })
          .text(function(d) { return d.name; })
          .style("fill-opacity", 1e-6);
      
      // (2-5) 原有节点更新到新位置
      var nodeUpdate = node.transition()
          .duration(duration)
          .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; });
      nodeUpdate.select("circle")
          .attr("r", 4.5)
          .style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; });
      nodeUpdate.select("text")
          .style("fill-opacity", 1);
      
      // (2-6) 折叠节点的子节点收缩回来
      var nodeExit = node.exit().transition()
          .duration(duration)
          .attr("transform", function(d) { 
            return "translate(" + source.y + "," + source.x + ")"; 
           })
          .remove();
      nodeExit.select("circle")
          .attr("r", 1e-6);
      nodeExit.select("text")
          .style("fill-opacity", 1e-6);
      
      // (2-7) 数据连接,根据目标节点的id绑定数据
      var link = svg.selectAll("path.link")
          .data(links, function(d) { return d.target.id; });
      
      // (2-8) 增加新连接
      link.enter().insert("path", "g")
          .attr("class", "link")
          .attr("d", function(d) {
            var o = {x: source.x0, y: source.y0};
            return diagonal({source: o, target: o});
          });
      
      // (2-9) 原有连接更新位置
      link.transition()
          .duration(duration)
          .attr("d", diagonal);
      
      // (2-10) 折叠的链接,收缩到源节点处
      link.exit().transition()
          .duration(duration)
          .attr("d", function(d) {
            var o = {x: source.x, y: source.y};
            return diagonal({source: o, target: o});
          })
          .remove();
      // 把旧位置存下来,用以过渡
      nodes.forEach(function(d) {
        d.x0 = d.x;
        d.y0 = d.y;
      });
    }

     2.3 点击时切换折叠

    // (3) 切换折叠与否
    function click(d) {
      if (d.children) {
        d._children = d.children;
        d.children = null;
      } else {
        d.children = d._children;
        d._children = null;
      }
      update(d);// 重新渲染
    }
    

    3.完整代码

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>testD3-26-CollapsibleTree.html</title>
    <script type="text/javascript" src="d3.js"></script>
    <style>
    
    .node circle {
      fill:yellow ;
      stroke: red;
      stroke- 1.5px;
    }
    
    .node {
      font: 10px sans-serif ;
    }
    
    .link {
      fill: green;
      stroke: #ccc;
      stroke- 1.5px;
    }
    
    </style>
    </head>
    <body>
    <script type="text/javascript">
            //位置参数
    var margin = {top: 20, right: 120, bottom: 20, left: 120},
        width = 960 - margin.right - margin.left,
        height = 800 - margin.top - margin.bottom;
        
    var i = 0,
        duration = 750,
        root;
    // 声明树布局
    var tree = d3.layout.tree()
        .size([height, width]);
    // 指定为横向布局
    var diagonal = d3.svg.diagonal()
        .projection(function(d) { return [d.y, d.x]; });
    
    var svg = d3.select("body").append("svg")
        .attr("width", width + margin.right + margin.left)
        .attr("height", height + margin.top + margin.bottom)
      .append("g")
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
    
    d3.json("tree.json", function(error, flare) {
        // 根节点和位置
        root = flare;
        root.x0 = height / 2;
        root.y0 = 0;
        //(1) 折叠函数,递归调用,有子孙的就把children(显示)给_children(不显示)暂存,便于折叠,
        function collapse(d) {
            if (d.children) {  console.log(d);
                d._children = d.children;
                d._children.forEach(collapse);
                d.children = null;
            }
        }
        // 折叠根节点的每个孩子
        root.children.forEach(collapse);
        // 折叠之后要重绘
        update(root);
    });
    
    //(2) 更新布局
    function update(source) {
      // (2-1) 计算新树的布局
      var nodes = tree.nodes(root).reverse(),
          links = tree.links(nodes);
      
      // (2-2) 树的深度这里树d.y。树的宽度最大720,要分四层,所以每层就乘180
      nodes.forEach(function(d) { 
        d.y = d.depth * 180;// 树的x,y倒置了,所以这里Y其实是横向的
      });
    
      // (2-3) 数据连接,根据id绑定数据
      var node = svg.selectAll("g.node")
          .data(nodes, function(d) {
            return d.id //最初新点开的节点都没有id
            || (d.id = ++i); //为没有id的节点添加上ID
          });
    
      // (2-4) 点击时增加新的子节点
      var nodeEnter = node.enter().append("g")
          .attr("class", "node")
          .attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; })
          .on("click", click);
      nodeEnter.append("circle")
          .attr("r", 1e-6)
          .style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; });
      nodeEnter.append("text")
          .attr("x", function(d) { return d.children || d._children ? -10 : 10; })
          .attr("dy", ".35em")
          .attr("text-anchor", function(d) { return d.children || d._children ? "end" : "start"; })
          .text(function(d) { return d.name; })
          .style("fill-opacity", 1e-6);
      
      // (2-5) 原有节点更新到新位置
      var nodeUpdate = node.transition()
          .duration(duration)
          .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; });
      nodeUpdate.select("circle")
          .attr("r", 4.5)
          .style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; });
      nodeUpdate.select("text")
          .style("fill-opacity", 1);
      
      // (2-6) 折叠节点的子节点收缩回来
      var nodeExit = node.exit().transition()
          .duration(duration)
          .attr("transform", function(d) { 
            return "translate(" + source.y + "," + source.x + ")"; 
           })
          .remove();
      nodeExit.select("circle")
          .attr("r", 1e-6);
      nodeExit.select("text")
          .style("fill-opacity", 1e-6);
      
      // (2-7) 数据连接,根据目标节点的id绑定数据
      var link = svg.selectAll("path.link")
          .data(links, function(d) { return d.target.id; });
      
      // (2-8) 增加新连接
      link.enter().insert("path", "g")
          .attr("class", "link")
          .attr("d", function(d) {
            var o = {x: source.x0, y: source.y0};
            return diagonal({source: o, target: o});
          });
      
      // (2-9) 原有连接更新位置
      link.transition()
          .duration(duration)
          .attr("d", diagonal);
      
      // (2-10) 折叠的链接,收缩到源节点处
      link.exit().transition()
          .duration(duration)
          .attr("d", function(d) {
            var o = {x: source.x, y: source.y};
            return diagonal({source: o, target: o});
          })
          .remove();
      // 把旧位置存下来,用以过渡
      nodes.forEach(function(d) {
        d.x0 = d.x;
        d.y0 = d.y;
      });
    }
    
    // (3) 切换折叠与否
    function click(d) {
      if (d.children) {
        d._children = d.children;
        d.children = null;
      } else {
        d.children = d._children;
        d._children = null;
      }
      update(d);// 重新渲染
    }
    </script>
    </body>
    </html>

      

  • 相关阅读:
    Atitit sql计划任务与查询优化器统计信息模块
    Atitit  数据库的事件机制触发器与定时任务attilax总结
    Atitit 图像处理知识点体系知识图谱 路线图attilax总结 v4 qcb.xlsx
    Atitit 图像处理 深刻理解梯度原理计算.v1 qc8
    Atiti 数据库系统原理 与数据库方面的书籍 attilax总结 v3 .docx
    Atitit Mysql查询优化器 存取类型 范围存取类型 索引存取类型 AND or的分析
    Atitit View事件分发机制
    Atitit 基于sql编程语言的oo面向对象大规模应用解决方案attilax总结
    Atitti 存储引擎支持的国内点与特性attilax总结
    Atitit 深入理解软件的本质 attilax总结 软件三原则"三次原则"是DRY原则和YAGNI原则的折
  • 原文地址:https://www.cnblogs.com/wanyong-wy/p/7603123.html
Copyright © 2011-2022 走看看