发布于 2026-01-06 0 阅读
0

一个简单的 D3.js 面积图

一个简单的 D3.js 面积图

我们来看:

X
0 10
1 15
2 35
3 20

并制作:

D3.js 面积图

D3.js 非常复杂,我觉得 D3.js wiki 上的示例解释得太少,内容又太多。在这个示例中,我将向您展示如何创建一个我能想到的最简单的面积图。如果您想直接查看“答案”,请参阅完整的 JavaScript 代码

D3.js 不是一个图表库,而是一个图表组件库。这个库感觉像是 SVG 和数据操作的混合体,并添加了一些额外的功能。虽然它非常灵活,但这种灵活性是以复杂性为代价的。让我们深入了解一下。

要构建图表,我们需要:数据、SVG 容器、边距、X 轴、Y 轴、区域形状本身,以及一些 CSS 来使其看起来美观。

数据

我们不会使用 TSV 或 CSV 加载器,也不会使用任何回调函数。数据就在这里,简单明了。

var data = [
    { x: 0, y: 10, },
    { x: 1, y: 15, },
    { x: 2, y: 35, },
    { x: 3, y: 20, },
];
Enter fullscreen mode Exit fullscreen mode

SVG

D3 使用 SVG(可缩放矢量图形)来绘制形状。虽然可以<svg>动态创建新标签,但我还是将以下代码添加到了 HTML 源代码中。

<svg id="area" />
Enter fullscreen mode Exit fullscreen mode

边际

D3 中的图表没有边距,但 D3 的主要作者经常提到定义常规边距。其思路是设置一些边距,并定义一个 SVG 组(即 `<div>`g标签),将其设置为与这些边距边界相符。代码仅将 `<div>` 组标签视为可绘制区域。

var margin = {top: 20, right: 20, bottom: 40, left: 50},
    width = 575 - margin.left - margin.right,
    height = 350 - margin.top - margin.bottom;
Enter fullscreen mode Exit fullscreen mode

为了以可缩放的方式绘制数据,D3 需要能够将数据(例如,x=0,y=10)映射到像素位置。我们必须获取 X 轴数据并将其设置到坐标轴上,使得 X 轴的最大值(即 3)与图表区域的像素宽度相匹配。由于 D3 具有很高的灵活性,这意味着 X 轴和 Y 轴必须独立定义。

在数学课上,你可能学过 X 代表定义域,Y 代表值域。遗憾的是,D3 也把定义域/值域的概念应用到了坐标轴上。我们需要把 X 轴的数据(0-3)看作是定义域,把图表的水平方向(0- width)看作是值域。同样的道理也适用于 Y 轴(0-35 应用于图表的垂直方向)。

x你可以把 ` and`变量看作y是转换函数,它们接受一个域值并将其转换为像素大小。`and`xAxis和 `or`yAxis则指示坐标轴应该放在哪里。

var x = d3.scale.linear()
    .domain([0, d3.max(data, function(d) { return d.x; })])
    .range([0, width]);

var y = d3.scale.linear()
    .domain([0, d3.max(data, function(d) { return d.y; })])
    .range([height, 0]);

var xAxis = d3.svg.axis()
    .scale(x)
    .orient("bottom");

var yAxis = d3.svg.axis()
    .scale(y)
    .orient("left");
Enter fullscreen mode Exit fullscreen mode

区域

面积函数将每个数据点(例如 (2, 35))转换为描述形状的信息。每个数据点对应一个 x 坐标、一个上 y 坐标y1和一个下 y 坐标y0。这里比较特殊的是,下 y 坐标y0被设置为常量height。当你了解 SVG 是相对于图形左上角定位时,这一点就很容易理解了。任何“向下”的距离都是正数,因此正数height表示图形的底部。

var area = d3.svg.area()
    .x(function(d) { return x(d.x); })
    .y0(height)
    .y1(function(d) { return y(d.y); });
Enter fullscreen mode Exit fullscreen mode

把所有东西整合起来

到目前为止,我们除了定义一些数据和函数之外,什么都没做。现在我们需要让这些函数发挥作用。

var svg = d3.select("svg#area")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
  .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

svg.append("path")
    .datum(data)
    .attr("class", "area")
    .attr("d", area);

svg.append("g")
    .attr("class", "x axis")
    .attr("transform", "translate(0," + height + ")")
    .call(xAxis);

svg.append("g")
    .attr("class", "y axis")
    .call(yAxis);
Enter fullscreen mode Exit fullscreen mode

变量定义会svg获取svg具有指定 ID 的标签area,并添加一个组标签 `<group> g` 来定义 SVG 内的边距。所有绘制操作都将在该g标签内进行。

下一部分添加了一个path。这是数据和面积函数交汇的地方,也是整个示例的关键所在。D3使用每个数据点并将其传递给该area函数。该area函数将数据转换为 SVG 路径上的位置。结果如下:

<path class="area" d="M0,214.28571428571428L168.33333333333331,
171.42857142857142L336.66666666666663,0L505,128.57142857142858L505,
300L336.66666666666663,300L168.33333333333331,300L0,300Z"/>
Enter fullscreen mode Exit fullscreen mode

最后两部分为SVG添加了坐标轴。关于这两部分没什么好说的。

把它弄漂亮

在“整合所有内容”部分,我忽略了.attr("class", "area")解释。D3 可以使用 `<div>` 标签添加任何属性attr()。我添加了一些class属性,以便可以设置图表的样式。SVG 使用的属性与标准 HTML 标签不同,但下面的样式使图表看起来简洁明了。

svg { border: 1px solid #dedede; }

.axis path, .axis line {
  fill: none;
  stroke: #000;
  shape-rendering: crispEdges;
}

.area { fill: #4ca3bd; }
Enter fullscreen mode Exit fullscreen mode

本文最初发表于mattlayman.com

文章来源:https://dev.to/mblayman/a-simple-d3-js-area-chart-4bkf