基于 Vue,使用 D3.js 画一个疫情趋势折线图

2022-12-17 10:01:51 浏览数 (1)

在过去的两年里,我们看到很多数据可视化基于新冠疫情开展研究工作。这些可视化图表通过为我们提供有关特定城市/地区病例数的信息,帮助人们更快捷地理解疫情的发展情况。

除此之外,数据可视化也在帮助我们更好地理解数字。因为视觉本身不是执行复杂的计算,而是帮助人脑更快地感知信息。此外,与充满数字的电子表格相比,它们看起来也更有趣。

在本文中,我们将使用 D3.js 和 Vue.js 创建折线图,并勾画一个疫情趋势。

D3.js

D3 是一个开源 JavaScript 库,用于在 Web 浏览器中创建交互式数据可视化。D3 可用于操作 DOM 对象和 HTML、SVG 或 Canvas 元素以可视化数据。

目前, D3 在 GitHub 上拥有超过 102k star。

根据官方文档所介绍的:

D3 帮助用户使用 HTML、SVG 和 CSS 将数据变为现实。D3 对 Web 标准的重视为用户提供了现代浏览器的全部功能,而无需将自己束缚于专有框架,结合了强大的可视化组件和数据驱动的 DOM 操作方法。

除了作为创建视觉效果的强大工具外,D3 还拥有庞大的开源社区。这也是它如此受欢迎的原因之一。废话不多说,下面我们进入到实战正题。

开始

我们首先在终端中运行以下命令来创建一个新的 Vue 应用程序:

代码语言:javascript复制
npm init vue@2.7.4

接下来,导航到项目根目录并安装必要的依赖项:

代码语言:javascript复制
cd vue-project
npm install

接着安装 D3:

代码语言:javascript复制
npm i d3

使用 D3.js 构建折线图

前面我们了解了 D3 是什么,现在让我们通过创建折线图来学习如何使用它。

首先要做的是定义我们将在其中呈现图表的 HTML 模板。本文中,我们将使用 SVG 呈现图表:

代码语言:javascript复制
<template>
  <div>
    <h2>Vue.js and D3 Line Chart</h2>
    <svg></svg>
  </div>
</template>

接下来,我们定义要在图表上显示的数据。我们将在此示例中使用虚拟数据,但在实际应用程序中,我们很可能会使用实时数据:

代码语言:javascript复制
<script>
  const data = [
    { date: "2022-07-01", amount: 29 },
    { date: "2022-07-02", amount: 56 },
    { date: "2022-07-03", amount: 43 },
    { date: "2022-07-04", amount: 32 },
    { date: "2022-07-05", amount: 66 },
    { date: "2022-07-06", amount: 61 },
    { date: "2022-07-07", amount: 55 },
    { date: "2022-07-08", amount: 31 },
    { date: "2022-07-09", amount: 22 },
    { date: "2022-07-10", amount: 26 },
    { date: "2022-07-11", amount: 21 },
    { date: "2022-07-12", amount: 12 },
    { date: "2022-07-13", amount: 10 },
  ];
<script/>

创建图表

接着,开始创建图表。

代码语言:javascript复制
<script>
  import * as d3 from 'd3'

  data = [//前面定义的数据]

  mounted(){
    const width = 800;
    const height = 500;
    const svg = d3.select("svg").attr("width", width).attr("height", height);
    const g = svg.append("g");
  }
<script/>

在上面的代码中,我们从 D3 库中导入了 d3 并定义了图表的宽度和高度。然后,我们使用 d3.select() 方法选择了我们之前定义的 SVG 元素,并将其存储为一个名为 svg 的常量。此方法将选择 DOM 中匹配的第一个元素。

接下来,我们使用 D3 的 attr() 方法将宽度和高度属性添加到 svg,然后将 g(SVG 元素)附加到 svg。SVG <g> 元素是用于对其他 SVG 元素进行分组的容器。

目前,我们数据数组中的日期是字符串格式。因此,我们的下一步是将字符串数据中的日期解析为 JavaScript 日期对象。

D3 有一个 d3-time-format 模块,其中包含几种解析和格式化日期的方法:

代码语言:javascript复制
const parseTime = d3.timeParse("%d-%b-%y");

创建图表轴

我们想在 x 轴上绘制日期,在 y 轴上绘制数量。

D3 有一个 d3-scale 模块,我们将使用它来将数据值转换为像素。

d3-scale 需要两条信息:域和范围。简单来说,域就是我们给的输入,范围就是我们想要的输出:

代码语言:javascript复制
const x = d3
      .scaleTime()
      .domain(
        d3.extent(data, function (d) {
          return parseTime(d.date);
        })
      )
      .rangeRound([0, width]);

const y = d3
      .scaleLinear()
      .domain(
        d3.extent(data, function (d) {
          return d.amount;
        })
      )
      .rangeRound([height, 0]);

在这里,我们执行以下操作:

我们在 x 轴上使用了 d3.scaleTime() 刻度,因为我们正在处理日期对象,这是知道如何处理日期对象的刻度。然后,我们在 y 轴上使用了 d3.scaleLinear() 刻度,因为 y 轴上的值是线性增加的数字。

创建折线

D3 提供了一个 d3-shape 模块,我们可以使用它来创建复杂的形状,例如符号、线条和圆弧。我们正在创建一个折线图,因此我们将使用 d3.line() 方法。

d3.line() 方法创建一个遵循一系列点的形状:

代码语言:javascript复制
const line = d3.line()
  .x(function (d) {
    return x(parseTime(d.date));
  })
  .y(function (d) {
    return y(d.amount);
  });

在这里,我们通过传入匿名函数并返回日期对象和每个日期对应的数量来定义行的 x 轴和 y 轴属性。

将轴附加到图表

现在,我们需要将 xy 轴附加到图表上,如下所示:

代码语言:javascript复制
g.append("g")
      .attr("transform", "translate(0,"   height   ")")
      .call(d3.axisBottom(x));

    g.append("g")
      .call(d3.axisLeft(y))
      .append("text")
      .attr("fill", "#000")
      .attr("transform", "rotate(-90)")
      .attr("y", 6)
      .attr("dy", "0.71em")
      .attr("text-anchor", "end")
      .text("病例数");

对于 x 轴,我们调用 d3.axisBottom() 因为我们需要将它对齐到画布的底部。对于 y 轴,我们调用 d3.axisLeft() 因为我们想将它对齐到画布的左侧。

将路径附加到图表

最后,我们将路径附加到图表。这个路径实际上会根据数据的值绘制折线图:

代码语言:javascript复制
g.append("path")
      .datum(data)
      .attr("fill", "none")
      .attr("stroke", "steelblue")
      .attr("stroke-width", 1.5)
      .attr("d", line);

在这里,我们执行以下操作:

  • 使用 datum 方法传递数据数组
  • 设置填充颜色、描边颜色、描边宽度的属性
  • 设置 d 的属性,该属性指示 SVG 路径关于在何处连接路径的点

有了这个,我们看到折线图出现在浏览器中。

image.png

完整代码

这是折线图的最终代码:

代码语言:javascript复制
<template>
  <div>
    <h2>Vue.js and D3 Line Chart</h2>
    <svg></svg>
  </div>
</template>
<script>
import * as d3 from "d3";
export default {
  data() {
    return {};
  },
  mounted() {
    const width = 800;
    const height = 500;
    const data = [
    { date: "2022-07-01", amount: 29 },
    { date: "2022-07-02", amount: 56 },
    { date: "2022-07-03", amount: 43 },
    { date: "2022-07-04", amount: 32 },
    { date: "2022-07-05", amount: 66 },
    { date: "2022-07-06", amount: 61 },
    { date: "2022-07-07", amount: 55 },
    { date: "2022-07-08", amount: 31 },
    { date: "2022-07-09", amount: 22 },
    { date: "2022-07-10", amount: 26 },
    { date: "2022-07-11", amount: 21 },
    { date: "2022-07-12", amount: 12 },
    { date: "2022-07-13", amount: 10 },
  ];

    const svg = d3.select("svg").attr("width", width).attr("height", height);
    const g = svg.append("g");

    // 解析日期
    const parseTime = d3.timeParse("%d-%b-%y");

    // 创建图表轴
    const x = d3
      .scaleTime()
      .domain(
        d3.extent(data, function (d) {
          return parseTime(d.date);
        })
      )
      .rangeRound([0, width]);

    const y = d3
      .scaleLinear()
      .domain(
        d3.extent(data, function (d) {
          return d.amount;
        })
      )
      .rangeRound([height, 0]);

    // 创建折线
    const line = d3
      .line()
      .x(function (d) {
        return x(parseTime(d.date));
      })
      .y(function (d) {
        return y(d.amount);
      });

    // 将轴附加到图表上
    g.append("g")
      .attr("transform", "translate(0,"   height   ")")
      .call(d3.axisBottom(x));

    g.append("g")
      .call(d3.axisLeft(y))
      .append("text")
      .attr("fill", "#000")
      .attr("transform", "rotate(-90)")
      .attr("y", 6)
      .attr("dy", "0.71em")
      .attr("text-anchor", "end")
      text("病例数");

    // 将路径附加到图表上
    g.append("path")
      .datum(data)
      .attr("fill", "none")
      .attr("stroke", "steelblue")
      .attr("stroke-width", 1.5)
      .attr("d", line);
  },
};
</script>

结尾

D3 是一个庞大的库,尽管我们涵盖了很多内容,但这只是基础知识。我们可以使用 D3 创建不同类型的图表。希望这一个入门能帮助到你!

0 人点赞