为集合中的每个数据点创建一个数据条 & 动态设置每个 Bar 的坐标

51 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的18天,点击查看活动详情

为集合中的每个数据点创建一个数据条

介绍

上篇文章在 svg 中添加了一个矩形来表示数据条。 接下来你将结合到目前为止所学的关于 data()enter() 和 SVG 图形的知识,为 dataset 中的每一个数据点创建并且添加一个矩形。

之前的挑战展示了如何为 dataset 中的每个对象创建并添加一个 div

d3.select("body").selectAll("div")
  .data(dataset)
  .enter()
  .append("div")

操作 rect 元素和 div 元素有一些不同。 rect 元素必须添加在 svg 元素内,而不能直接添加在 body 内。 同时,你需要告诉 D3 将 rect 放在 svg 区域的哪个位置。 条形的放置会在下一个挑战中讲到。

实战

data()enter()append() 方法为 dataset 中的每一个对象创建并添加一个 rect 。 每个数据条都将直接显示在上一个数据条的上面,这一点将在下一个挑战中实现。

  1. 应该包含 9 个 rect 元素。
  2. 应该使用 data() 方法。
  3. 应该使用 enter() 方法。
  4. 应该使用 append() 方法。
<body>
  <script>
    const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];

    const w = 500;
    const h = 100;

    const svg = d3.select("body")
                  .append("svg")
                  .attr("width", w)
                  .attr("height", h);

    svg.selectAll("rect")
       
        .data(dataset)
        .enter()
        .append("rect")
       
       .attr("x", 0)
       .attr("y", 0)
       .attr("width", 25)
       .attr("height", 100);
  </script>
</body>

动态设置每个 Bar 的坐标

介绍

上个挑战在 svg 元素中为 dataset 的每一个数据点创建并且添加了一个矩形,其中一个矩形表示一组, 但是它们相互重叠。

矩形的位置是由 xy 属性决定的。 它们告诉 D3 在 svg 区域的哪个位置开始绘制图形。 上个挑战将它们都设置为 0,因此所有条形都在左上角。

对于条形图,所有条形应该处于相同的垂直线上,也就是说所有条形的 y 值相同(为 0), 但是 x 值需要随着增添新的条形而变化。 注意 x 值越大,图形就越靠近右边。 所以当遍历 dataset 中的数组元素时,x 的值应该递增。

D3 的 attr() 方法可接收一个回调函数来动态设置属性。 这个回调函数有两个参数,一个是数据点本身(通常是 d),另一个是该数据点在数组中的下标, 这个参数是可选的。 下面是其格式:

selection.attr("property", (d, i) => {

})

值得注意的是,你不需要写 for 循环或者用 forEach() 迭代数据集中的对象。 data() 方法会解析数据集,任何链接在 data() 后面的方法都会为数据集中的每个对象运行一次。

实战

改变 x 属性的回调函数,让它返回下标乘以 30 的值。

注意: 每组的宽为 25,所以每次 x 增加 30,可在每组之间留出一些空隙。 在这个例子中任何比 25 大的数也同样适用。

  1. 第一个 rectx 值应该为 0
  2. 第二个 rectx 值应该为 30
  3. 第三个 rectx 值应该为 60
  4. 第四个 rectx 值应该为 90
  5. 第五个 rectx 值应该为 120
  6. 第六个 rectx 值应该为 150
  7. 第七个 rectx 值应该为 180
  8. 第八个 rectx 值应该为 210
  9. 第九个 rectx 值应该为 240
<body>
  <script>
    const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];

    const w = 500;
    const h = 100;

    const svg = d3.select("body")
                  .append("svg")
                  .attr("width", w)
                  .attr("height", h);

    svg.selectAll("rect")
       .data(dataset)
       .enter()
       .append("rect")
       .attr("x", (d, i) => {

          return 30 * i

       })
       .attr("y", 0)
       .attr("width", 25)
       .attr("height", 100);
  </script>
</body>