D3.js 实现可拓展的层级二叉树(Vue)

1,433 阅读1分钟

引言

项目需要在实现一个点击可拓展的用户关系树,框架是Vue

网上找了一下,d3和echarts的Hierarchy Tree实例代码都是一次加载所有用户数据,因为d3的可配置Dom所以选择了d3

d3的collapsible Tree示例

d3部分示例代码


    const nodeEnter = node.enter().append("g")
        .attr("transform", d => `translate(${source.y0},${source.x0})`)
        .attr("fill-opacity", 0)
        .attr("stroke-opacity", 0)
        .on("click", d => {
          d.children = d.children ? null : d._children;
          update(d);
        });

主要修改的就是click函数

d.children存在时要展示节点的数据,否则发送请求在数据源中插入数据并重新渲染树

实现步骤


  1. d.children存在时用 this.showInfo 控制数据的展示
  2. 如果不存在,发送数据请求并获取点击的节点在数据源中的索引列表
  3. 根据索引列表获取点击的节点在数据源中的引用,再插入请求获得的后代用户数据,如果请求到的数据为空则展示该节点的用户数据
  4. 更新viewBox的宽高,重新渲染树

### 获取节点在数据源中的索引列表 - - - ``` javascript // d代表点击的节点 getIndexList(d) { let indexList = []; let item = ''; // d.depth 节点深度,根节点到该节点的距离 const depth = d.depth; for (let i = 0; i < depth; i++) { // d.y <= d.parent.y ,代表d在父节点的左区,index为0 let index = d.y <= d.parent.y ? 0 : 1; indexList.unshift(index); d = d.parent; } console.log('indexList-----',indexList); return indexList; } ```

获取点击的节点在this.treeData中的引用


    insertSourceData(d) {
      let indexList = this.getIndexList(d);
      let tree = this.treeData;
      for (let e = 0; e < indexList.length; e++) {
        this.clickItem = tree.children[indexList[e]];
        tree = tree.children[indexList[e]];
      }
      console.log('clickItem-------',this.clickItem);
    },

更新viewBox的宽高,重新渲染树


    let list = [];
    let yList = [];
    const root = d3.hierarchy(this.treeData);
    // 更新root的后代
    root.descendants().forEach((d, i) => {
      d.ID = d.data.id;;
      list.push(d);
    });
    this.root = root;

    // 更新svg height
    let svgHeight = root.height*this.nodeSizeY + 130;
    this.height = svgHeight > this.height ? svgHeight : this.height;

    // 更新树
    this.update(d);

    // 更新svg width (x y 反转)
    list.forEach(d => {
      d.y ? yList.push(d.y): ''
    })
    let max = Math.max(...yList)
    let min = Math.min(...yList)
    let width =  (max + min >= 0 ? max*2+200 : -min*2+200);
    this.width = width > this.width ? width : this.width;