D3 从入门到实战 - 3

569 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第 27 天,点击查看活动详情

前因

上一节中,我们讲解了关于 SVG 相关的基本操作,并且在最后留了一个示例,通过 D3 实现了 柱状图 ,这一节我们就继续来学习关于 SVG 相关的操作。

柱状图

首先我们还是接着上一节结尾的 柱状图 来继续学习,我们要生成一个 柱状图 ,就需要先准备相关的数据,类似下面这样:

interface BarChartType {
    name: string;
    value: number;
}
const data: BarChartType[] = [
    {name: 'ShaoKei1', value: 6},
    {name: 'ShaoKei2', value: 6},
    {name: 'ShaoKei3', value: 13},
    {name: 'ShaoKei4', value: 8},
    {name: 'ShaoKei5', value: 20},
    ...
];

有了数据后,我们需要选择将要操作的元素,就需要使用 select 来获取元素的索引,如下:

const svg = d3.select('#svg');

我们要创建一个 柱状图,就需要定义 柱状图 中的横坐标比例尺纵坐标比例尺,关于比例尺在上一节做了简单的介绍,这里只要知道我们是要获取横坐标和纵坐标的数据即可,代码如下:

// 需要获取到画布的宽高
const width = +svg.attr('width');
const height = +svg.attr('height');

const xScale = d3.scaleLinear()
    .domain()
    .range();

const yScale = d3.scaleBand()
    .domain()
    .range();

我们在前面已经了解过,如果要给一个元素设置属性,就需要用到attr,当然attr这个API不仅可以用于设置值,也可以用于获取值,只需要在最前面添加+号,并且attr的参数只设置第一个,就可以获取到对应的值,如上所示。

当然,我们虽然获取到了画布的宽高,但是为了防止将坐标轴画到画布的外面,我们就需要设置相关的起点,如下:

const margin = { top: 60, right: 40, bottom: 60, left: 40 };

因为我们设置了相关的起点,所以我们真正能够画图的区域就缩小了,如下所示:

const iWidth = width - margin.left - margin.right;
const iHeight = height - margin.top - margin.bottom;

当我们设置好相关的位置后,我们就可以设置比例尺中的相关数据了,如下:

const xScale = d3.scaleLinear()
    .domain([0, d3.max(data, (item: BarChartType) => item.value)])
    .range([0, innerWidth]);

const yScale = d3.scaleBand()
    .domain(data.map((item: BarChartType) => item.name))
    .range([0, innerHeight])
    .padding(0.1);

在上述的代码中,我们通过range设置坐标轴的起点和终点,起点是0,终点就是我们前面计算的可以实际操作的画布的大小。然后在domain中是我们需要设置的数据,也就是这个 柱状图 实际的值展示出来后的样子,在 D3 中有一些数组的静态方法,d3.max 就是用于获取数组中最大的值,通过这个 API,我们就能拿到数组用最大的值。

我们需要将坐标画在画布上,就需要先创建相关的标签,然后进行统一的设置,代码如下:

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

当我们已经将 柱状图 中的横纵坐标的数据都准备后,我们就可以在画布中根据前面的 data 数据来画图了,这时候就需要先计算出相关的坐标位置,代码如下:

const yAxis = d3.axisLeft(yScale);

g.append('g').call(yAxis);

上述的代码中,通过 d3.axisLeft 设置左侧纵坐标的位置,最终的效果如下图所示:

image.png

有了纵坐标,那么我们还需要将横坐标也展示出来,代码如下:

const xAxis = d3.axisBottom(xScale);

g.append('g').call(xAxis).attr('transform', `translate(0, ${iHeight})`);

设置完横纵坐标后,最终的效果如下图所示:

image.png

我们在上面已经完成了坐标轴的渲染,接下来我们就需要将 data 中的数据通过循环画到画布上,具体代码如下:

data.forEach((item: BarChartType) => {
    g.append('rect')
    .attr('width', xScale(item.value))
    .attr('height', yScale.bandwidth())
    .attr('fill', 'pink')
    .attr('y', yScale(item.name));
});

通过 append 创建一个 rect 元素,然后给它设置相关的属性,最终展示如下图所示:

image.png

当然,左侧的纵坐标的文字太小了,我们需要修改一下,但 D3 是不支持直接修改文字大小的,我们可以通过选取到这些文字所在的标签进行修改,如下所示:

d3.selectAll('.tick text').attr('font-size', '2em');

我们还添加一个 柱状图 的标题,这个示例就完成了,代码如下:

g.append('text').text('Bar Chart')
.attr('font-size', '3em')
.attr('transform', `translate(${iWidth / 2}, 0)`)
.attr('text-anchor', 'middle');

完成后的最终样式如下图所示:

image.png

你可以狠戳这里进行代码的查看。

最后

我们在这一节继续加深了对 SVG 操作的学习,并且将上一节中最后留的案例进行了拆分讲解,相信通过这两节基本操作的学习,我们已经学会了使用 D3 对 SVG 进行操作,并完成相关的案例,我们一起加油吧!

未完待续...

最后,如果这篇文章有帮助到你,❤️关注+点赞❤️鼓励一下作者,谢谢大家

往期回顾

D3 从入门到实战 - 1

D3 从入门到实战 - 2