【数据可视化】【1】手把手教你使用d3.js绘制折线图

1. 概要

本文主要使用的时d3.js作为绘制折线图的JavaScript库,其官方网站为d3js.org。这里引用了官方的两句话来介绍d3.js:

The JavaScript library for bespoke data visualization
Create custom dynamic visualizations with unparalleled flexibility

当前的已发布的d3.js库最新版本为v7,官方提供有两个版本,一个是完整版,一个压缩版本,分别为d3.v7.js以及d3.v7.min.js
使用d3.js必须在html中引用其js文件,在html头部添加即可。

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

注意:若要使用d3.js离线版本,需将上述js文件下载,放在项目指定文件夹并正确引用。
离线文件笔者以下载好,可在此下载:链接

2. 确定数据

提示:这里仅展示简单一维数组

接下来我们将使用下面的一维数组来绘制折线图。

const data = [3,4,6,7,8,3,9,1,5,3,8,6,4,9,3,2,6,7,5,8,9];

3. 添加画布

3.1 创建svg标签

svg是基于XML语法的图像格式,全称:Scalable Vector Graphics,即可缩放矢量图。svg可以绘制基本图形,如:直线、圆形、矩形、多边形、路径等。
使用d3画图必须要先创建一个画布,一般为svg,这里可以理解为在该svg容器中进行图表的绘制与展示。
定义一个宽度为600、高度为300的svg标签,设置id为mainsvg,以便后续通过id来查找该svg:

<svg width="600" height="300" id="mainsvg" class="svgs"></svg>

3.2 给画布添加属性

首先需要使用d3选中上述标签元素,在d3中有两种选择器,分别是

  • d3.select():默认选择所有指定元素中的第一个,该选择器一次只能选择一个标签元素。如:通过标签的id选择。
  • d3.selectAll():选择一批相同的类型的元素,可以一次选择多个标签。如:通过标签class选择。

这里我们绘制的是一个图形,所以直接使用d3.select()。选中标签后需要设置d3绘图的实际区域,该区域要比上述svg标签指定的宽度和长度要小,需要设置合适的大小。

下面写法有很多种,仅供参考:

// svg的id
var svg_id = "#mainsvg";
// 选择svg标签
const svg = d3.select(svg_id);
// 获取svg标签的宽度和长度属性用于后续计算内部宽度和长度
const width = +svg.attr('width');
const height = +svg.attr('height');

// 设置margin内部边框
const margin = {top : 60, right : 30, bottom : 60, left : 150};
// 设置内部宽度和长度,实际绘图区域
const innerWidth = width - margin.left - margin.right;
const innerHeight = height - margin.top - margin.bottom;

4. 设置比例尺

比例尺指的是实际画图中坐标轴的长度大小,以及每一个坐标单位对应的实际像素大小。绘制折线图使用到的是线性比例尺,通常线性比例尺有两个配置参数,分别为domain和range:

  • scaleLinear() 线性比例尺
  • domain() 比例尺需要映射的长度,比如数据的长度范围为10000映射到100px
  • range() 比例尺实际长度,在浏览器中实际的像素长度,如100px

分别定义两个比例尺,作为x轴和y轴的缩放比例尺

const xScale = d3.scaleLinear() // 线性比例尺
    .domain([0, data.length-1]) // 映射长度
    .range([0, innerWidth]); // 实际占用长度
const yScale = d3.scaleLinear()
    .domain([0, d3.max(data)])
    .range([innerHeight, 0]); 

注意:在定义y轴的比例尺时,range中属性的范围是由大到小。

5. 绘制轴线

5.1 添加group标签

在画布中添加一个group标签,可以设置id属性。将此group的移动合适的位置:

由于在浏览器页面中原点的位置位于左上角,x轴为水平向右,y轴为垂直向下,这点与数学中的坐标轴是不一样的。不将group进行移动的话,图形会默认紧靠着浏览器的左上角绘制,会造成展示效果不美观,部分内容显示不全。

所以需要对group进行水平和向下移动:

  • 设置transform属性,translate(${margin.left}, ${margin.top})将group向右和向下平移
const g = svg.append('g').attr('id', 'maingroup')
    .attr('transform', `translate(${margin.left}, ${margin.top})`);

5.2 在group添加轴线

这里主要的步骤为三步:

  1. 为比例尺设置轴线及刻度
  2. 在group中调用坐标轴函数
  3. 将坐标轴进行水平或垂直方向移动(非必须,根据实际情况而定)

使用到的函数及api如下:

  • axisBottom() 参数为比例尺,添加坐标轴,将刻度设置在坐标轴下方
  • axisLeft() 参数为比例尺,添加坐标轴,将刻度设置在轴线左方
  • call() 调用定义好的的坐标轴函数

前文提到浏览器中坐标轴原点位左上角,采用默认方式,则x轴位于页面上方,为与常用数学坐标轴保持相同形式将x轴平移innerHeight的距离。这里可以按照自己的需求设置坐标轴位置。

const xAxis = d3.axisBottom(xScale);
g.append('g').call(xAxis).attr('transform', `translate(0, ${innerHeight})`);

const yAxis = d3.axisLeft(yScale);
g.append('g').call(yAxis);

6. 绘制曲线

使用d3提供的line函数,线生成器来生成线段。并设置x、y坐标访问器

var lineGenerator = d3.line()
    .x(function(d,i){return xScale(i);})
    .y(function(d){return yScale(d);});

7. 添加图表标题

为group添加text文本,并设置文本位置

g.append('text').text('折线图-test') // 添加文本信息
    .attr('font-size', '1em') // 设置字体大小
    .attr('transform', `translate(${innerWidth / 2}, ${innerHeight + 40})`) // 将文本框移动到图表下方中间位置
    .attr('text-anchor', 'middle'); // 文本居中对齐

8. 绘制图表

根据给定的data数据生成线条,设置线条的相关属性。

d3.select("g")
    .append("path")
    .attr("d",lineGenerator(data)) // 调用生成器
    .attr('fill', 'none') // 设置填充
    .attr('stroke-width', 1) // 设置线条的宽度
    .attr('stroke', 'green'); // 设置线条的颜色

9. 完整代码

绘制效果图:

完整代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="d3.v7.js"></script>
</head>
<body>
    <svg width="600" height="300" id="mainsvg" class="svgs"></svg>
    <script type="module">
        const data = [3,4,6,7,8,3,9,1,5,3,8,6,4,9,3,2,6,7,5,8,9];
        var svg_id = "#mainsvg";
        const svg = d3.select(svg_id);
        const width = +svg.attr('width');
        const height = +svg.attr('height');

        const margin = {top : 60, right : 30, bottom : 60, left : 150};
        const innerWidth = width - margin.left - margin.right;
        const innerHeight = height - margin.top - margin.bottom;

        const xScale = d3.scaleLinear()
            .domain([0, data.length-1])
            .range([0, innerWidth]);
        const yScale = d3.scaleLinear()
            .domain([0, d3.max(data)])
            .range([innerHeight, 0]);

        const g = svg.append('g').attr('id', 'maingroup')
            .attr('transform', `translate(${margin.left}, ${margin.top})`);

        const xAxis = d3.axisBottom(xScale);
        g.append('g').call(xAxis).attr('transform', `translate(0, ${innerHeight})`);

        const yAxis = d3.axisLeft(yScale);
        g.append('g').call(yAxis);

        var lineGenerator = d3.line()
            .x(function(d,i){return xScale(i);})
            .y(function(d){return yScale(d);});
            // .curve(d3.curveCardinal);

        g.append('text').text('折线图-test')
            .attr('font-size', '1em')
            .attr('transform', `translate(${innerWidth / 2}, ${innerHeight + 40})`)
            .attr('text-anchor', 'middle');

        d3.select("g")
            .append("path")
            .attr("d",lineGenerator(data))
            .attr('fill', 'none')
            .attr('stroke-width', 1)
            .attr('stroke', 'green');
    </script>
</body>
  • 29
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值