D3.js中Treemap(矩形树图)源码详解

Treemap(矩形树图)

聊一聊Treemap,即矩形树图,树形结构非常有意思的一种展现方式,外形规整而不失表达力。

矩形树状结构图(Treemap)是一种有效的实现层次结构可视化的图表结构,简称矩形树图或树图。在矩形树图中,各个小矩形的面积表示每个子节点的大小,矩形面积越大,表示子节点在父节点中的占比越大,整个矩形的面积之和表示整个父节点。通过矩形树图及其钻取情况,我们可以很清晰地知道数据的全局层级结构和每个层级的详情。——知乎

接下来对d3.js实现treemap的过程进行解析

index.html——源码

<!DOCTYPE html>
<style>

form {
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
}

svg {
  font: 10px sans-serif;
}

</style>
<svg width="960" height="570"></svg>
<form>
  <label><input type="radio" name="mode" value="sumBySize" checked> Size</label>
  <label><input type="radio" name="mode" value="sumByCount"> Count</label>
</form>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>

// 定义svg画布
var svg = d3.select("svg"),
    // 获取svg画布宽度
    width = +svg.attr("width"),
    // 获取svg画布高度
    height = +svg.attr("height");

// 定义fader函数用来获取颜色,返回颜色字符串
// d3.interpolateCubehelix(a, b)返回a和b之间的颜色插值,0.2是修正gamma值
var fader = function(color) { return d3.interpolateRgb(color, "#fff")(0.2); },
    // d3.schemeCategory20.map(fader),将d3.schemeCategory20返回的20个颜色值通过fader函数
    // 进行映射转换,最终,生成离散颜色比例尺color函数
    color = d3.scaleOrdinal(d3.schemeCategory20.map(fader)),
    // 定义一个格式函数
    format = d3.format(",d");

// 定义一个矩形树图布局函数treemap()函数
var treemap = d3.treemap()
     // 设置tile为d3.treemapResquarify,即矩形按层排列
    .tile(d3.treemapResquarify)
     // 指定布局范围 
    .size([width, height])
     // 启用边界补偿
    .round(true)
     // 指定内部间距
    .paddingInner(1);

// 读取数据
d3.json("flare.json", function(error, data) {
  if (error) throw error;

  // 生成树形层次结构的数据
  var root = d3.hierarchy(data)
      // node.eachBefore用来前序遍历树节点,对于每一个node,计算id的格式
      .eachBefore(function(d) { d.data.id = (d.parent ? d.parent.data.id + "." : "") + d.data.name; })
      // 对节点的size属性求和
      .sum(sumBySize)
      // 对节点进行排序,按照深度或者值的大小来确定顺序
      .sort(function(a, b) { return b.height - a.height || b.value - a.value; });

  对root数据进行矩形树布局
  treemap(root);

  // 定义每个矩形的画布
  var cell = svg.selectAll("g")
    // 将叶子节点数据绑定到矩形元素上
    .data(root.leaves())
    .enter().append("g")
      // 设置矩形的位置
      .attr("transform", function(d) { return "translate(" + d.x0 + "," + d.y0 + ")"; });

  // 设置代表树节点的每个矩形的id,宽度,高度以及填充色
  cell.append("rect")
      .attr("id", function(d) { return d.data.id; })
      .attr("width", function(d) { return d.x1 - d.x0; })
      .attr("height", function(d) { return d.y1 - d.y0; })
      // 填充色通过父节点的id来计算,保证同一父节点的所有子节点的颜色相同
      .attr("fill", function(d) { return color(d.parent.data.id); });

  // 定义矩形上的文字裁剪元素
  cell.append("clipPath")
      .attr("id", function(d) { return "clip-" + d.data.id; })
    .append("use")
      .attr("xlink:href", function(d) { return "#" + d.data.id; });

  // 为矩形上的文字使用clip-path,控制文字换行
  cell.append("text")
      .attr("clip-path", function(d) { return "url(#clip-" + d.data.id + ")"; })
    .selectAll("tspan")
      .data(function(d) { return d.data.name.split(/(?=[A-Z][^A-Z])/g); })
    .enter().append("tspan")
      .attr("x", 4)
      .attr("y", function(d, i) { return 13 + i * 10; })
      .text(function(d) { return d; });

  // 为矩形绑定title属性,并设置title显示内容
  cell.append("title")
      .text(function(d) { return d.data.id + "\n" + format(d.value); });

  // 定义两个控制按钮:按照节点的size或者节点子节点的个数进行布局排列
  d3.selectAll("input")
      .data([sumBySize, sumByCount], function(d) { return d ? d.name : this.value; })
      .on("change", changed);

  // 定义定时器,默认以count为排列依据
  var timeout = d3.timeout(function() {
    d3.select("input[value=\"sumByCount\"]")
        .property("checked", true)
        .dispatch("change");
  }, 2000);

  // 当切换按钮被点击时,切换排列依据
  function changed(sum) {
    timeout.stop();
    // 以当前的sum方式来排列布局
    treemap(root.sum(sum));

    // 切换布局的过程动画
    cell.transition()
        .duration(750)
        .attr("transform", function(d) { return "translate(" + d.x0 + "," + d.y0 + ")"; })
      .select("rect")
        .attr("width", function(d) { return d.x1 - d.x0; })
        .attr("height", function(d) { return d.y1 - d.y0; });
  }
});

// 对节点的子节点个数求和
function sumByCount(d) {
  return d.children ? 0 : 1;
}
// 返回节点的size属性
function sumBySize(d) {
  return d.size;
}

</script>

至此,矩形树图的实现解释完毕,矩形树图比较简单,还是得感谢强大的d3布局,基本上帮助我们搞定绝大多数工作。

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
你好!对于Vue和D3的组件开发,你可以使用Vue的生命周期钩子函数将D3与Vue组件集成起来。以下是一个简单的示例,展示如何使用Vue和D3创建一个treemap)组件: 首先,安装必要的依赖: ```bash npm install d3 ``` 接下来,创建一个名为Treemap.vue的Vue组件,并在其引入D3库: ```vue <template> <div ref="treemap"></div> </template> <script> import * as d3 from 'd3'; export default { mounted() { this.drawTreemap(); }, methods: { drawTreemap() { // 获取DOM元素的引用 const container = this.$refs.treemap; // 创建数据数组 const data = [ { name: 'A', value: 10 }, { name: 'B', value: 20 }, { name: 'C', value: 30 }, // ... ]; // 创建treemap布局 const treemapLayout = d3.treemap() .size([500, 300]) .padding(1); // 转换数据为适用于treemap的层次结构 const root = d3.hierarchy({ children: data }) .sum(d => d.value) .sort((a, b) => b.value - a.value); // 根据treemap布局计算节点位置和大小 treemapLayout(root); // 创建矩形元素并绑定数据 const rects = d3.select(container) .selectAll('rect') .data(root.leaves()); // 更新已存在的矩形 rects.attr('x', d => d.x0) .attr('y', d => d.y0) .attr('width', d => d.x1 - d.x0) .attr('height', d => d.y1 - d.y0) .attr('fill', 'steelblue'); // 创建新的矩形 rects.enter() .append('rect') .attr('x', d => d.x0) .attr('y', d => d.y0) .attr('width', d => d.x1 - d.x0) .attr('height', d => d.y1 - d.y0) .attr('fill', 'steelblue'); // 移除多余的矩形 rects.exit().remove(); } } } </script> ``` 以上代码演示了如何使用D3的treemap布局来创建一个简单的treemap),你可以根据实际需求进行进一步的定制和样式调整。 希望这个示例能对你有所帮助!如果还有其他问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值