如何在嵌套树形图中显示父元素?

时间:2018-09-21 02:51:32

标签: javascript d3.js

这是我的数据:https://api.myjson.com/bins/b0m6s

我想创建一个嵌套的树形图,以显示其中的父元素和子元素,例如:https://bl.ocks.org/mbostock/911ad09bdead40ec0061

这是我当前的树形图代码:

var defaultColors = d3.scale.ordinal().range(["#00AEEF", "#8DC63F", "#FFC20E", "#F06EAA", "#AE9986", "#009BA5", "#00A651", "#F7941D", "#B656AB", "#ABA000", "#F3716D", "#8D7B6B", "#EF413D", "#AD772B", "#878787"]);
var treemap;
var h_pad = 2, // 2 pixels vertical padding
    v_pad = 4; // 4 pixels of horizontal padding (2 px at each side)
var canvas = d3
    .select(id)
    .append("svg")
    .attr("class", "chart")
    .attr("width", cfg.width + cfg.margin.left + cfg.margin.right)
    .attr("height", cfg.height + cfg.margin.top + cfg.margin.bottom)
    .attr("viewBox", "0 0 960 500")
    .attr("preserveAspectRatio", "xMidYMid meet")
    .attr("id", "canvas")

 var innercanvas = canvas
    .append("g")
    .attr("class", "innercanvas")
    .attr("transform", "translate(" + cfg.margin.left + "," + cfg.margin.top + ")");

    treemap = d3.layout
    .treemap()
    .round(false)
    .size([cfg.width, cfg.height])
    .padding(.25)
    .sticky(true)
    .nodes(data);



  var cells = innercanvas
    .selectAll(".newcell")
    .data(treemap)
    .enter()
    .append("g")
    .attr("class", function (d, i) {
      return 'newcell _' + i       // i provides a unique identifier for each node 
        + ' cell-level-' + d.depth   // cell-level-0 for root, cell-level-1, cell-level-2, etc 
        + (d.name ? ' ' + safe_name(d.name) : '') // if d.name exists, use the 'safe' version
        + (!d.children
          ? ' leaf'                  // d has no children => it's a leaf node
          : (d.depth === 0
            ? ' root'                // d.depth = 0 => it's the root node
            : ' internal '));        // has children, depth > 0 => internal node
    })

 cells
    .append("rect")
    .attr("x", function (d) {
      return d.x;
    })
    .attr("y", function (d) {
      return d.y;
    })
    .attr("id", "rectangle")
    .attr("width", function (d) {
      return d.dx;
    })
    .attr("height", function (d) {
      return d.dy;
    })
    .style("fill", function (d) {
      return d.children && d.parent ? defaultColors(d.name) : cfg.color ? cfg.color(d.name) : null;
    })
    .attr("stroke", "#000000")
    .attr('pointer-events', 'all');

 cells
    .append("text")
    .attr("x", function (d) {
      return d.x + d.dx / 2;
    })
    .attr("y", function (d) {
      return d.y + d.dy / 2;
    })
    .attr("text-anchor", "middle")
    .text(function (d) { return d.parent ? d.name : '' })


cells
      .append('title')
      .text(function (d) {
        if (d.parent) {
          return categoryKey + " : " + d.parent.name + "\n" + groupKey + " : " + d.name + "\n" + sizeKey + " : " + toCommas(d.value.toFixed(2))
        }
        return d.name;
      });

将文本包装成多行

function groupAddText(selection) {

 var v_pad = 2, // vertical padding
  h_pad = 4 // horizontal padding

selection.selectAll('.leaf text')
  .classed('groupOversize', function (d) {
    if (!d.name) {
      return false;
    }
    var bbox = this.getBBox();
    if (d.dx <= bbox.width + h_pad || d.dy <= bbox.height + v_pad) {


      d3.select(this).node().textContent = "";
      var lines = wordwrap2(d.name, d.dx).split('\n');
      for (var i = 0; i < lines.length; i++) {
        d3.select(this)
          .append("tspan")
          .attr("dy", 15)
          .attr("x", d.x + d.dx / 2)
          .text(lines[i]);

      }
      d3.selectAll(".groupOversize").attr("y", function (d) {
        return (d.y + d.dy / 2) - 20;
      })
      return true;
    }
    return false;
  });

}

function wordwrap2(str, width, brk, cut) {
brk = brk || '\n';
width = width || 75;
cut = cut || false;
if (!str) { return str; }
var regex = '.{1,' + width + '}(\\s|$)' + (cut ? '|.{' + width + '}|.+$' : '|\\S+?(\\s|$)');
return str.match(RegExp(regex, 'g')).join(brk);

}

这将产生以下树状图可视化:

enter image description here

如您所见,我将单元格分为3类,root代表根节点,internal代表父母,leaf代表孩子。现在,它只是显示孩子们的行为。如何显示父元素以及嵌套在其中的子元素?

我想要这样的东西: [![在此处输入图片描述] [2]] [2]

1 个答案:

答案 0 :(得分:2)

您可以通过在树形图中添加填充来查看父单元格:

  treemap = d3.layout
    .treemap()
    .round(false)
    .size([cfg.width, cfg.height])
    .padding(20) // 20px padding all around
    .sticky(true)
    .nodes(data);

  treemap = d3.layout
    .treemap()
    .round(false)
    .size([cfg.width, cfg.height])
    .padding([20,5,5,5]) // 20px top, 5px sides and bottom
    .sticky(true)
    .nodes(data);

我做了一个小样的演示,展示了更改d3 treemap here中的填充的效果-尽管请注意这是d3 v5,所以选项略有不同。

以下是带有您的代码的演示:

var data = {"children":[{"name":"Central","children":[{"name":"Cellophane Tape","value":"419141.4728"},{"name":"File Separator","value":"327285.0157"},{"name":"Hard Cover File","value":"422707.1194"},{"name":"Highlighter","value":"488978.5362"},{"name":"Office Chair","value":"453843.621"},{"name":"Pencil","value":"416819.1027"},{"name":"Tape Dispenser","value":"393290.5862"},{"name":"File Cabinet","value":"424647.6003"},{"name":"Plastic Comb Binding","value":"230299.6657"},{"name":"White Board Markers","value":"383157.5055"},{"name":"Binder","value":"415871.6793"},{"name":"Eraser","value":"477885.9162"},{"name":"Pen","value":"444834.4362"},{"name":"Pen Set","value":"434495.1303"},{"name":"Desk","value":"247046.3919"}]},{"name":"East","children":[{"name":"Pencil","value":"441970.1055"},{"name":"White Board Markers","value":"416822.5561"},{"name":"Eraser","value":"393738.4951"},{"name":"Hard Cover File","value":"407371.1911"},{"name":"Office Chair","value":"382574.6347"},{"name":"Tape Dispenser","value":"481960.7562"},{"name":"Cellophane Tape","value":"441438.7362"},{"name":"File Cabinet","value":"333187.8858"},{"name":"Binder","value":"462926.3793"},{"name":"File Separator","value":"441311.7555"},{"name":"Plastic Comb Binding","value":"330059.7762"},{"name":"Highlighter","value":"399332.0562"},{"name":"Pen","value":"492374.2362"},{"name":"Pen Set","value":"477206.7762"},{"name":"Desk","value":"254464.9453"}]},{"name":"North","children":[{"name":"Office Chair","value":"459306.6555"},{"name":"Pencil","value":"465763.0477"},{"name":"Eraser","value":"441687.1652"},{"name":"File Cabinet","value":"463598.5893"},{"name":"File Separator","value":"430346.1162"},
{"name":"Hard Cover File","value":"346325.0175"},{"name":"Highlighter","value":"223199.4072"},{"name":"Tape Dispenser","value":"311201.7216"},{"name":"Plastic Comb Binding","value":"445513.5762"},{"name":"Binder","value":"453219.921"},{"name":"White Board Markers","value":"334737.9189"},{"name":"Cellophane Tape","value":"372554.952"},{"name":"Pen","value":"435830.2872"},{"name":"Pen Set","value":"460001.8962"},{"name":"Desk","value":"260294.2303"}]},{"name":"South","children":[{"name":"Pencil","value":"457331.6055"},{"name":"Tape Dispenser","value":"442628.4555"},{"name":"Cellophane Tape","value":"468037.3351"},{"name":"Eraser","value":"341469.2127"},{"name":"File Cabinet","value":"408198.2058"},{"name":"File Separator","value":"416543.8893"},{"name":"Office Chair","value":"466438.7227"},{"name":"Plastic Comb Binding","value":"436440.1272"},{"name":"White Board Markers","value":"437968.1344"},{"name":"Highlighter","value":"411905.4555"},{"name":"Binder","value":"456806.1151"},{"name":"Hard Cover File","value":"493053.3762"},{"name":"Pen","value":"413820.3762"},{"name":"Pen Set","value":"488299.3962"},{"name":"Desk","value":"264499.5623"}]},{"name":"West","children":[{"name":"Pencil","value":"458648.3055"},{"name":"Cellophane Tape","value":"299045.7162"},{"name":"File Cabinet","value":"386045.352"},{"name":"File Separator","value":"435098.0403"},{"name":"Highlighter","value":"457454.0701"},{"name":"Office Chair","value":"262021.1055"},{"name":"Plastic Comb Binding","value":"413222.1555"},{"name":"Eraser","value":"449997.2978"},{"name":"Hard Cover File","value":"364335.5793"},{"name":"Binder","value":"467389.3801"},{"name":"Tape Dispenser","value":"394066.5845"},{"name":"White Board Markers","value":"408833.4789"},{"name":"Pen","value":"481281.6162"},{"name":"Pen Set","value":"398652.9162"},{"name":"Desk","value":"229482.2954"}]}]};
data.name = 'root'
var defaultColors = d3.scale.ordinal().range(["#00AEEF", "#8DC63F", "#FFC20E", "#F06EAA", "#AE9986", "#009BA5", "#00A651", "#F7941D", "#B656AB", "#ABA000", "#F3716D", "#8D7B6B", "#EF413D", "#AD772B", "#878787"]);
var treemap;
var h_pad = 2, // 2 pixels vertical padding
    v_pad = 4; // 4 pixels of horizontal padding (2 px at each side)
var id = 'treemap';
var cfg = { width: 960, height: 500, margin: { left: 10, right: 10, bottom: 10, top: 10 }, color: d3.scale.category20() }
var canvas = d3
    .select('#' + id)
    .append("svg")
    .attr("class", "chart")
    .attr("width", cfg.width + cfg.margin.left + cfg.margin.right)
    .attr("height", cfg.height + cfg.margin.top + cfg.margin.bottom)
    .attr("viewBox", "0 0 960 500")
    .attr("preserveAspectRatio", "xMidYMid meet")
    .attr("id", "canvas")

 var innercanvas = canvas
    .append("g")
    .attr("class", "innercanvas")
    .attr("transform", "translate(" + cfg.margin.left + "," + cfg.margin.top + ")");

  treemap = d3.layout
    .treemap()
    .round(false)
    .size([cfg.width, cfg.height])
    .padding([20,5,5,5])
    .sticky(true)
    .nodes(data);

  var cells = innercanvas
    .selectAll(".newcell")
    .data(treemap)
    .enter()
    .append("g")
    .attr("class", function (d, i) {
      return 'newcell _' + i       // i provides a unique identifier for each node 
        + ' cell-level-' + d.depth   // cell-level-0 for root, cell-level-1, cell-level-2, etc 
        + (d.name ? ' ' + d.name : '') // if d.name exists, use the 'safe' version
        + (!d.children
          ? ' leaf'                  // d has no children => it's a leaf node
          : (d.depth === 0
            ? ' root'                // d.depth = 0 => it's the root node
            : ' internal '));        // has children, depth > 0 => internal node
    })

 cells
    .append("rect")
    .attr("x", function (d) {
      return d.x;
    })
    .attr("y", function (d) {
      return d.y;
    })
    .attr("id", function(d,i){ return 'rect_' + i; })
    .attr("width", function (d) {
      return d.dx;
    })
    .attr("height", function (d) {
      return d.dy;
    })
    .style("fill", function (d) {
      return d.children && d.parent ? defaultColors(d.name) : cfg.color ? cfg.color(d.name) : null;
    })
    .attr("stroke", "#000000")
    .attr('pointer-events', 'all');

cells.append("clipPath")
    .attr("id", function(d,i) { return "clip_" + i ; })
    .append("use")
    .attr("xlink:href", function(d,i) { 
       return "#rect_" + i;
    });

cells
    .append("text")
    .attr("clip-path", function(d,i) { return "url(#clip_" + i })
    .attr("x", function (d) {
      return d.x + d.dx / 2;
    })
    .attr("y", function (d) {
      return d.children ? d.y + 12 : d.y + d.dy / 2 ;
    })
    .attr("text-anchor", "middle")
    .text(function (d) { return d.name })


cells
    .append('title')
    .text(function (d) {
      if (d.parent) {
        return "categoryKey : " + d.parent.name + "\ngroupKey : " + d.name + "\nsizeKey : " + d.value.toFixed(2)
      }
        return d.name;
    });
    
svg text {
  font-size: 10px;
}
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.js"></script><div id="treemap"></div>