SOURCE

console 命令行工具 X clear

                    
>
console
 // 嗯,这是最初的数据。
    var treeData = {
    "name": "心血管中心",
    "children": [
        {
            "name": "浙江CDC",
            "children": [
                {
                    "name": "杭州",
                    "children": [
                        {
                            "name": "东湖南路社区服务中心",
                            "children": [
                                {
                                    "name": "张医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "张医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                }
                            ]
                        },
                        {
                            "name": "解放北路社区服务中心",
                            "children": [
                                {
                                    "name": "张医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                }
                            ]
                        },
                        {
                            "name": "东湖南路社区服务中心",
                            "children": [
                                {
                                    "name": "张医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "张医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                }
                            ]
                        },
                        {
                            "name": "解放北路社区服务中心",
                            "children": [
                                {
                                    "name": "张医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                }
                            ]
                        },
                        {
                            "name": "解放北路社区服务中心",
                            "children": [
                                {
                                    "name": "张医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                }
                            ]
                        },
                        {
                            "name": "东湖南路社区服务中心",
                            "children": [
                                {
                                    "name": "张医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "张医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                }
                            ]
                        },
                        {
                            "name": "解放北路社区服务中心",
                            "children": [
                                {
                                    "name": "张医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                }
                            ]
                        }
                    ]
                },
                {
                    "name": "宁波",
                    "children": [
                        {
                            "name": "东湖南路社区服务中心",
                            "children": [
                                {
                                    "name": "张医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "张医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                }
                            ]
                        },
                        {
                            "name": "解放北路社区服务中心",
                            "children": [
                                {
                                    "name": "张医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                }
                            ]
                        },
                        {
                            "name": "东湖南路社区服务中心",
                            "children": [
                                {
                                    "name": "张医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "张医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                }
                            ]
                        },
                        {
                            "name": "解放北路社区服务中心",
                            "children": [
                                {
                                    "name": "张医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                }
                            ]
                        },
                        {
                            "name": "解放北路社区服务中心",
                            "children": [
                                {
                                    "name": "张医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                }
                            ]
                        },
                        {
                            "name": "东湖南路社区服务中心",
                            "children": [
                                {
                                    "name": "张医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "张医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                }
                            ]
                        },
                        {
                            "name": "解放北路社区服务中心",
                            "children": [
                                {
                                    "name": "张医生"
                                },
                                {
                                    "name": "李医生"
                                },
                                {
                                    "name": "李医生"
                                }
                            ]
                        }
                    ]
                }
            ]
        }
    ]
}
;;


    /********************* 1. 初始化D3基本能力(设置宽高等) *********************/
    // 设置图表的宽高和Margin
    var margin = {
        top: 20,
        right: 90,
        bottom: 30,
        left: 90
      },
      width = 1220 - margin.left - margin.right,
      height = 900 - margin.top - margin.bottom;

    // 这里我们将svg元素,和子group元素拆分
    var svg = d3
      .select("body")
      // 在页面的body里添加svg对象
      .append("svg")
      // 设置svg宽高
      .attr("width", width + margin.right + margin.left)
      .attr("height", height + margin.top + margin.bottom);

    // 子group元素存为view变量
    var view = svg
      // 在svg里添加group元素
      .append("g")
      // 将group放置在左上方
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    // 创建zoom操作
    var zoom = d3
      .zoom()
      // 设置缩放区域为0.1-100倍
      .scaleExtent([0.1, 100])
      .on("zoom", () => {
        // 子group元素将响应zoom事件,并更新transform状态
        view.attr(
          "transform",
          "translate(" +
          (d3.event.transform.x + margin.left) +
          "," +
          (d3.event.transform.y + margin.top) +
          ") scale(" +
          d3.event.transform.k +
          ")"
        );
      });

    // svg层绑定zoom事件,同时释放zoom双击事件
    svg.call(zoom).on("dblclick.zoom", () => {});

    var i = 0,
      duration = 750,
      root;

    // 定义菜单选项
    var userMenuData = [
      [{
          text: "菜单1",
          func: function () {
            // id为节点id
            var id = Number($(this).attr("id"))
            alert("菜单1", id)
          }
        },
        {
          text: "菜单2",
          func: function () {
            var id = Number($(this).attr("id"))
            alert("菜单1", id)
          }
        }
      ]
    ];
    // 事件监听方式添加事件绑定
    // $("body").smartMenu(userMenuData, {
    //   name: "chatRightControl",
    //   container: "g.node"
    // });


    initData();

    /********************* 2. 数据初始化绑定(包括数据更新) *********************/
    function initData() {
      // 计算父节点、字节点、高度和深度(parent, children, height, depth)
      root = d3.hierarchy(treeData, function (d) {
        return d.children;
      });
      // 设置第一个元素的初始位置
      root.x0 = height / 2;
      root.y0 = 0;

      // 第二层以上元素收起
      //root.children.forEach(collapse);

      // 更新节点状态
      updateChart(root);

    }



    /********************* 3. 数据更新绑定  *********************/
    function updateChart(source) {
              let levelWidth = [1];
        let childCount = function (level, n) {

            if (n.children && n.children.length > 0) {
                if (levelWidth.length <= level + 1) levelWidth.push(0);

                levelWidth[level + 1] += n.children.length;
                n.children.forEach(function (d) {
                    childCount(level + 1, d);
                });
            }
        };
        childCount(0, root);
        let newHeight = d3.max(levelWidth) * 25; // 25 pixels per line
      // 大致计算需要放大的倍数
      var scale =
        (getDepth(root) / 8 || 0.5) +
        (getMax(root) / 12 || 0.5);
      // 定义Tree层级,并设置宽高
      var treemap = d3.tree().size([height * scale, width]);
      // 设置节点的x、y位置信息
      var treeData = treemap(root);

      // 计算新的Tree层级
      var nodes = treeData.descendants(),
        links = treeData.descendants().slice(1);

      // 设置每个同级节点间的y间距为180
      nodes.forEach(function (d) {
        d.y = d.depth * 180;
      });

      // node交互和绘制
      updateNodes(source, nodes);
      // link交互和绘制
      updateLinks(source, links);

      // 为动画过渡保存旧的位置
      nodes.forEach(function (d) {
        d.x0 = d.x;
        d.y0 = d.y;
      });

    }


    /********************* 4. node交互和绘制  *********************/
    function updateNodes(source, nodes) {
      // 给节点添加id,用于选择集索引
      var node = view.selectAll("g.node").data(nodes, function (d) {
        return d.id || (d.id = ++i);
      });

      // 添加enter操作,添加类名为node的group元素
      var nodeEnter = node
        .enter()
        .append("g")
        .attr("class", "node")
        .attr("id", d => d.id)
        // 默认位置为当前父节点的位置
        .attr("transform", function (d) {
          return "translate(" + source.y0 + "," + source.x0 + ")";
        })
        // 添加mouseover事件
        .on("mouseover", d => {
          // 从d3.event获取鼠标的位置
          var transform = d3.event;
          var yPosition = transform.offsetY + 20;
          var xPosition = transform.offsetX + 20;

          // 将浮层位置设置为鼠标位置
          var chartTooltip = d3
            .select(".chartTooltip")
            .style("left", xPosition + "px")
            .style("top", yPosition + "px");

          // 更新浮层内容
          chartTooltip.select(".name").text(d.data.name);

          // 移除浮层hidden样式,展示浮层
          chartTooltip.classed("hidden", false);
        })
        // 添加mouseover事件
        .on("mouseout", () => {
          // 添加浮层hidden样式,隐藏浮层
          d3.select(".chartTooltip").classed("hidden", true);
        })
        // 给每个新加的节点绑定click事件
        .on("click", click)
        // 给每个新加的节点绑定dbclick事件
        .on("dblclick", dblclick);

      // 给每个新加的group元素添加cycle元素
      nodeEnter
        .append("circle")
        .attr("class", "node")
        .attr("r", 1e-6)
        // 如果元素有子节点,且为收起状态,则填充浅蓝色
        .style("fill", function (d) {
          return d._children ? "lightsteelblue" : d.data.children ? "#fff" : "#aaa";
        });

      // 给每个新加的group元素添加文字说明
      nodeEnter
        .append("text")
        .attr("dy", ".35em")
        .attr("x", function (d) {
          return d.children || d._children ? -13 : 13;
        })
        .attr("text-anchor", function (d) {
          return d.children || d._children ? "end" : "start";
        })
        .text(function (d) {
          return d.data.name;
        });

      // 获取update集
      var nodeUpdate = nodeEnter.merge(node);

      // 设置节点的位置变化,添加过渡动画效果
      nodeUpdate
        .transition()
        .duration(duration)
        .attr("transform", function (d) {
          return "translate(" + d.y + "," + d.x + ")";
        });

      // 更新节点的属性和样式
      nodeUpdate
        .select("circle.node")
        .attr("r", 10)
        .style("fill", function (d) {
          return d._children ? "lightsteelblue" : d.data.children ? "#fff" : "#aaa";
        })
        .attr("cursor", "pointer");

      // 获取exit操作
      var nodeExit = node
        .exit()
        // 添加过渡动画
        .transition()
        .duration(duration)
        .attr("transform", function (d) {
          return "translate(" + source.y + "," + source.x + ")";
        })
        // 移除元素
        .remove();

      // exit集中节点的cycle元素尺寸变为0
      nodeExit.select("circle").attr("r", 1e-6);

      // exit集中节点的text元素可见度降为0
      nodeExit.select("text").style("fill-opacity", 1e-6);
    }



    /********************* 5. link交互和绘制  *********************/
    function updateLinks(source, links) {
      // 更新数据
      var link = view.selectAll("path.link").data(links, function (d) {
        return d.id;
      });

      // 添加enter操作,添加类名为link的path元素
      var linkEnter = link
        .enter()
        .insert("path", "g")
        .attr("class", "link")
        // 默认位置为当前父节点的位置
        .attr("d", function (d) {
          var o = {
            x: source.x0,
            y: source.y0
          };
          return diagonal(o, o);
        });

      // 获取update集
      var linkUpdate = linkEnter.merge(link);

      // 更新添加过渡动画
      linkUpdate
        .transition()
        .duration(duration)
        .attr("d", function (d) {
          return diagonal(d, d.parent);
        });

      // 获取exit集
      var linkExit = link
        .exit()
        // 设置过渡动画
        .transition()
        .duration(duration)
        .attr("d", function (d) {
          var o = {
            x: source.x,
            y: source.y
          };
          return diagonal(o, o);
        })
        // 移除link
        .remove();
    }


    /********************* 6. 单击节点事件处理  *********************/
    // 当点击时,切换children,同时用_children来保存原子节点信息
    function click(d) {
      if (d._clickid) {
        // 若在200ms里面点击第二次,则不做任何操作,清空定时器
        clearTimeout(d._clickid);
        d._clickid = null;
      } else {
        // 首次点击,添加定时器,350ms后进行toggle
        d._clickid = setTimeout(() => {
          if (d.children) {
            d._children = d.children;
            d.children = null;
          } else {
            d.children = d._children;
            d._children = null;
          }
          updateChart(d);
          d._clickid = null;
        }, 350);
      }
    }



    /********************* 7. 双击获取子节点事件处理  *********************/
    // 将获取到的节点,添加进data对象中,同时若已获取过不再获取
    function dblclick(d) {
      // 若无d.data.children,则视为未获取
      if (!(d.data && d.data.children)) {
        // 这里模拟请求,1.json - 5.json 随机获取数据
        var randomNum = Math.floor(Math.random() * 5) + 1;
                  // 给子节点绑定父节点
          var children = {
  "name": "Test 1",
  "children": [
    {
      "name": "解放北路社区服务中心A" + randomNum
    },
    {
      "name": "解放北路社区服务中心B" + randomNum
    },
    {
      "name": "解放北路社区服务中心C" + randomNum
    },
    {
      "name": "解放北路社区服务中心D" + randomNum
    },
    {
      "name": "解放北路社区服务中心E" + randomNum
    },
    {
      "name": "解放北路社区服务中心F" + randomNum
    }
  ]
}
.children.map(x => {
            return {
              name: x.name,
              parent: d,
              depth: d.depth + 1,
              data: {
                ...x
              }
            }
          });
          // 将子节点数据绑定在d节点上
          if (children.length) d.children = children;
          // 同时也绑到data上
          d.data.children = children;
          updateChart(d);
      }
    }


    // collapse方法,切换子节点展开收起
    function collapse(d) {
      if (d.children) {
        d._children = d.children;
        d._children.forEach(collapse);
        d.children = null;
      }
    }

    // 添加贝塞尔曲线的path,衔接与父节点和子节点间
    function diagonal(s, d) {
      path =
        `M ${s.y} ${s.x}
              C ${(s.y + d.y) / 2} ${s.x},
                ${(s.y + d.y) / 2} ${d.x},
                ${d.y} ${d.x}`;

      return path;
    }

    // 获取最多的子节点数
    function getMax(obj) {
      let max = 0;
      if (obj.children) {
        max = obj.children.length;
        obj.children.forEach(d => {
          const tmpMax = this.getMax(d);
          if (tmpMax > max) {
            max = tmpMax;
          }
        });
      }
      return max;
    }

    // 获取最深层级数
    function getDepth(obj) {
      var depth = 0;
      if (obj.children) {
        obj.children.forEach(d => {
          var tmpDepth = this.getDepth(d);
          if (tmpDepth > depth) {
            depth = tmpDepth;
          }
        });
      }
      return 1 + depth;
    }
<div class="chartTooltip hidden">
  <p>
    <strong class="name"></strong>
  </p>
</div>
  <script src="https://d3js.org/d3.v5.min.js"></script>

@charset "utf-8";
/* smartMenu.css	by zhangxinxu */
.smart_menu_box{display:none; width:300px; position:absolute; z-index:201105;}
.smart_menu_body{padding:1px; border:1px solid #B8CBCB; background-color:#fff; -moz-box-shadow:2px 2px 5px #666; -webkit-box-shadow:2px 2px 5px #666; box-shadow:2px 2px 5px #666;}
.smart_menu_ul{margin:0; padding:0; list-style-type:none;}
.smart_menu_li{position:relative;}
.smart_menu_a{display:block; height:25px; line-height:24px; padding:0 5px 0 25px; color:#000; font-size:12px; text-decoration:none; overflow:hidden;}
.smart_menu_a:hover, .smart_menu_a_hover{background-color:#348CCC; color:#fff; text-decoration:none;}
.smart_menu_li_separate{line-height:0; margin:3px; border-bottom:1px solid #B8CBCB; font-size:0;}
.smart_menu_triangle{width:0; height:0; border:5px dashed transparent; border-left:5px solid #666; overflow:hidden; position:absolute; top:7px; right:5px;}
.smart_menu_a:hover .smart_menu_triangle, .smart_menu_a_hover .smart_menu_triangle{border-left-color:#fff;}
.smart_menu_li_hover .smart_menu_box{top:-1px; left:130px;}
.smart_menu_li:first-child a, .smart_menu_li:nth-child(2) a, .smart_menu_li:nth-child(3) a, .smart_menu_li:nth-child(4) a{
    cursor: default;
}

 .node circle {
    fill: #fff;
    stroke: steelblue;
    stroke-width: 3px;
  }

  .node text {
    font: 12px sans-serif;
  }

  .link {
    fill: none;
    stroke: #ccc;
    stroke-width: 2px;
  }

  .chartTooltip {
    position: absolute;
    width: 200px;
    height: auto;
    padding: 10px;
    box-sizing: border-box;
    background-color: white;
    border-radius: 5px;
    box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.4);
    pointer-events: none;
  }

  .chartTooltip.hidden {
    display: none;
  }

  .chartTooltip p {
    margin: 0;
    font-size: 14px;
    line-height: 20px;
    word-wrap: break-word;
  }