【d3.js入门】基本面积图

663 阅读4分钟

D3.js基本面积图

D3.js (Data-Driven Documents) 是一个用于操作文档的JavaScript库,它可以通过使用HTML, SVG 和 CSS等技术在网页上动态生成数据可视化。本教程将带你了解如何使用D3.js创建一个基本的面积图。

准备工作

在开始之前,请下载最新版的D3.js。你可以直接从这里下载或者使用CDN方式加入页面中。

<script src="https://d3js.org/d3.v5.min.js"></script>

数据集定义

首先,我们需要定义好我们要展示的数据。下面我们来看一下我们将要用到的数据集:

var dataset = [
    { name: "苹果", value: 50 },
    { name: "橙子", value: 30 },
    { name: "香蕉", value: 70 },
    { name: "核桃", value: 20 },
    { name: "芒果", value: 60 },
    { name: "梨子", value: 100 },
    { name: "菠萝", value: 80 },
    { name: "葡萄", value: 90 },
    { name: "草莓", value: 35 },
    { name: "西瓜", value: 75 },
    { name: "桃子", value: 55 },
    { name: "樱桃", value: 25 }
];

该数据集包含12条数据,每条数据由水果的名称和对应的值组成。

设置画布

接下来,我们需要定义好我们将要使用的画布大小、内边距等属性。在本例中,我们将会创建一个宽度为600像素,高度为400像素,且四周留有30像素的空白的画布:

var padding = 30;
var svgWidth = 600;
var svgHeight = 400;

定义比例尺

根据数据集中的数值范围,我们需要创建与之对应的比例尺。在这个例子中,我们将使用scaleBand()和scaleLinear()两个函数分别创建x轴和y轴的比例尺:

var xScale = d3.scaleBand()
    .domain(d3.range(dataset.length))
    .range([padding, svgWidth - padding])
    .padding(0)
    .paddingInner(1)

var yScale = d3.scaleLinear()
    .domain([0, d3.max(dataset, function (d) { return d.value; })])
    .range([svgHeight - padding, padding]);

这里我们使用domain()方法来设置比例尺的输入域(即数据范围),并使用range()方法来确定输出范围(在画布上的位置)。

创建面积图

现在,我们需要生成面积图。在这个例子中,我们将使用d3.area()来创建一个面积图:

var area = d3.area()
    .x(function (d, i) { return xScale(i) + xScale.bandwidth() / 2; })
    .y0(svgHeight - padding)
    .y1(function (d) { return yScale(d.value); })
    .curve(d3.curveCardinal);

该函数创建的面积图会使用dataset中的值,将x轴和y轴上的各个点用曲线连接起来。在这里,我们通过.curve()方法指定了折线的形状。

添加SVG元素

接下来,我们需要向网页中添加一个SVG元素,并将面积图加入其中:

var svg = d3.select("body")
    .append("svg")
    .attr("width", svgWidth)
    .attr("height", svgHeight)
    .style('border', '1px solid #999999')

svg.append("path")
    .datum(dataset)
    .attr("class", "area")
    .attr("d", area)
    .attr("fill", "#69b3a2");

上述代码块首先使用.d3.select()方法选择了文档中的<body>元素,并在其中添加了一个SVG元素。接下来,我们使用svg.append()方法向SVG中添加一个路径元素(path)来展示面积图。我们需要将数据集(dataset)传递给d3.area()函数的.datum()方法,然后将它的返回值(d)传递给该路径元素的.d属性中。

为了让年月标签对齐,我们可以在x函数中将每个点的位置计算为:(i + 0.5) * xScale.bandwidth()

最后,我们还需要为这个路径设置好颜色和样式:

.attr("fill", "#69b3a2")

坐标轴设置

最后一步,我们需要添加坐标轴和数字标签,以便更好地显示数据。

var xAxis = d3.axisBottom(xScale)
   .tickFormat(function (d, i) { return dataset[i].name; });
var yAxis = d3.axisLeft(yScale);

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

svg.append("g")
    .attr("class", "y-axis")
    .attr("transform", "translate(" + padding + ",0)")
    .call(yAxis);

在这里,我们创建了两个坐标轴,并通过调用g元素上的.call()方法向画布上添加了这些坐标轴。我们还使用.transform()方法将坐标轴移动到正确的位置,并使用.tickFormat()函数向坐标轴上添加年月标签。

完整代码

// 基本面积图
var dataset = [
    { name: "苹果", value: 50 },
    { name: "橙子", value: 30 },
    { name: "香蕉", value: 70 },
    { name: "核桃", value: 20 },
    { name: "芒果", value: 60 },
    { name: "梨子", value: 100 },
    { name: "菠萝", value: 80 },
    { name: "葡萄", value: 90 },
    { name: "草莓", value: 35 },
    { name: "西瓜", value: 75 },
    { name: "桃子", value: 55 },
    { name: "樱桃", value: 25 }
];

var padding = 30;
var svgWidth = 600;
var svgHeight = 400;

var xScale = d3.scaleBand()
    .domain(d3.range(dataset.length))
    .range([padding, svgWidth - padding])
    .padding(0)
    .paddingInner(1)

var yScale = d3.scaleLinear()
    .domain([0, d3.max(dataset, function (d) { return d.value; })])
    .range([svgHeight - padding, padding]);

var area = d3.area()
    .x(function (d, i) { return xScale(i) + xScale.bandwidth() / 2; })
    .y0(svgHeight - padding)
    .y1(function (d) { return yScale(d.value); })
    .curve(d3.curveCardinal);

var svg = d3.select("body")
    .append("svg")
    .attr("width", svgWidth)
    .attr("height", svgHeight)
    .style('border', '1px solid #999999')

svg.append("path")
    .datum(dataset)
    .attr("class", "area")
    .attr("d", area)
    .attr("fill", "#69b3a2");

var xAxis = d3.axisBottom(xScale)
    .tickFormat(function (d, i) { return dataset[i].name; });
var yAxis = d3.axisLeft(yScale);

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

svg.append("g")
    .attr("class", "y-axis")
    .attr("transform", "translate(" + padding + ",0)")
    .call(yAxis);

image.png

在线地址:https://scqilin.github.io/d3js/basic-chart/index.html