我们的标签现在格式正确!它们标记每个月的开始,这还不错,但我们可以通过在各自的刻度之间居中月标签来提高可读性,以建议每个月从一个刻度延伸到下一个刻度。
要更改刻度标签的位置,我们首先需要选择它们。打开浏览器的检查器,仔细查看 D3 为轴生成的 SVG 元素。首先,我们有一个带有类域的路径元素,该元素在范围(或域的表示)上绘制一条水平线。此路径包括两个外部刻度,即形状两端的短垂直线,如图 4.9 所示。轴的刻度和标签由线条和文本元素组成,组织成具有刻度类的 SVG 组。这些 SVG 组沿轴平移以设置其行和文本元素的位置。轴生成器创建的元素的类型和类是 D3 公共 API 的一部分。您可以使用它们来自定义轴外观。
图 4.9 组成轴的 SVG 元素
考虑到这种结构,我们可以使用选择器选择x轴的所有标签 “.axis-x 文本” ,这意味着我们使用类轴-x抓取组中的每个文本元素。然后我们执行一些调整。首先,我们使用文本元素的 y 属性将文本元素向下移动 10px。这种增加的垂直空白将提高可读性。我们还将他们的字体系列设置为Roboto,这是我们已经在项目中使用的字体。默认情况下,D3 将轴的字体系列设置为无衬线,防止标签继承项目的字体系列。最后,我们将它们的字体大小增加到 14px。
出于关注点分离的目的,最后两个样式调整最好从CSS文件中处理。但在这里,我们使用 D3 来简化指令。
d3.selectAll(".axis-x text")
.attr("y", "10px")
.style("font-family", "Roboto, sans-serif")
.style("font-size", "14px");
为了使月份标签在其相应的刻度之间居中,我们将使用 x 属性。由于每个月都有不同的长度(在 28 到 31 天之间),我们需要为每个标签找到该月第一天和下个月第一天之间的中位数位置。请注意,D3 已在 g.axis-x 上将文本锚点属性设置为“中间”。
我们知道 D3 附加到每个标签的数据对应于该月的第一天。在下面的代码片段中,我们通过将 JavaScript 方法 getMonth() 应用于当前月份或附加到标签的值来查找下个月。此方法返回一个介于 0 和 11 之间的数字,0 表示 11 月,<> 表示 <> 月。然后,我们可以通过将年份、下个月和每月的第一天传递给 Date() 对象来创建新的 JavaScript 日期。
最后,我们使用 xScale 计算月初和下个月开始之间的中位数距离。完成后,您的轴应如图 4.10 所示。
d3.selectAll(".axis-x text")
.attr("x", d => {
const currentMonth = d;
const nextMonth = new Date(2021, currentMonth.getMonth() 1, 1);
return (xScale(nextMonth) - xScale(currentMonth)) / 2;
})
.attr("y", "10px")
.style("font-family", "Roboto, sans-serif")
.style("font-size", "14px");
图 4.10 格式化的 x 轴,月份标签在各自的刻度之间居中。
那是很多操纵!但希望它能让您了解我们可以自定义 D3 轴的不同方法。
我们现在将添加 y 轴,其步骤将更加简单。我们使用轴生成器 d3.axisLeft() ,因为我们想将 y 轴定位在图表的左侧。我们将 yScale 作为参数传递,并将轴保存在名为 leftAxis 的常量中。
const leftAxis = d3.axisLeft(yScale);
再一次,我们希望将轴附加到内部图表。我们将一个组附加到内部图表选择中,给它一个 axis-y 类并调用 leftAxis 。
const leftAxis = d3.axisLeft(yScale);
innerChart
.append("g")
.attr("class", "axis-y")
.call(leftAxis);
如果保存项目并在浏览器中查看,则会看到 y 轴已正确定位。我们所要做的就是更改标签的字体并增加它们的大小。在下面的代码片段中,我们使用类轴-y 选择组内的所有文本元素。我们使用它们的 x 属性将它们稍微向左移动以获得更好的可读性,并设置它们的字体系列和字体大小属性。
d3.selectAll(".axis-y text")
.attr("x", "-5px")
.style("font-family", "Roboto, sans-serif")
.style("font-size", "14px");
您可能已经注意到,我们必须重复代码来设置轴标签的字体系列和字体大小属性。在学习环境中,这没什么大不了的,但我们通常会尽量避免在专业项目中出现这种重复。前面提到的更好的解决方案是从CSS文件控制这些样式。另一种可能是使用组合选择器应用它们,如下所示。
d3.selectAll(".axis-x text, .axis-y text")
.style("font-family", "Roboto, sans-serif")
.style("font-size", "14px");
图 4.11 完成的 x 轴和 y 轴。
我们已经完成了我们的轴,但我们仍然应该做一件事来帮助读者理解我们的图表。x 轴上的标签是不言自明的,但 y 轴上的标签不是。我们知道它们在 0 到 90 之间变化,但我们不知道它们代表什么。
我们可以通过向轴添加标签来解决此问题。在 D3 项目中,标签只是文本元素,所以我们所要做的就是将文本元素附加到 SVG 容器中。我们将其内容设置为“温度(°F)”,并将其垂直位置设置为SVG容器原点下方20px。就是这样!您的项目现在应如图 4.12 所示。在下一节中,我们将绘制折线图。
svg
.append("text")
.text("Temperature (°F)")
.attr("y", 20);
图 4.12 完成的轴和标签。