携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第 36 天,点击查看活动详情
前因
在前一节中,我们通过一个散点图的案例加强了对 D3
中 Data - Join
的学习和理解。这一节我们继续来盘一下 D3
中一个很重要的属性 Path
,让我们开始吧!
什么是 Path
?
path
元素是 SVG
基本形状中最强大的一个,它不仅能创建一些基本形状,还能创建更多不规则的图形。通过使用 path
元素可以绘制矩形、圆形、椭圆、折线形或多边形,以及一些其它的曲线。例如贝塞尔曲线、二次曲线等。
path
元素的形状是通过属性 d 来定义的,属性 d 的值是一个 “命令 + 参数” 的序列。
我们先来看一下关于 path
中 d 基础属性的相关内容,可以分为以下几点:
- M = moveto(M X, Y): 将画笔移动到指定的坐标位置
- L = lineto(L X, Y): 画直线到指定的坐标位置
- H = horizontal lineto(H X): 画水平线到指定的 X 坐标位置
- V = vertical lineto(V Y): 画垂直线到指定的 Y 坐标位置
- Z = closepath(): 关闭路径
上述所有指令均允许小写字母。大写表示绝对定位,小写表示相对定位。
我们可以通过一个案例来了解一下,以下为相关代码:
<svg width="100px" height="100px">
<path d="M 0 0 H 90 V 90 H 10 L 10 10" />
</svg>
通过 path
我们绘制了一个正方形,具体如下图所示:
因为 path
属性是 SVG
中最强大的一个元素,因此我们才有必要了解 path
是什么,以及它能做什么,不过我们在使用 D3
的过程中不需要自己编写 path
的相关代码,D3
已经替我们封装好了,因此我们只需要知道 path
的相关属性即可。
D3.js Path生成器
在上面我们介绍了 path
的基本属性,在使用 D3
的开发中,它已经替我们封装好了相关的方法,我们只需要调用 D3
提供的方法即可。
简单列一下 D3 提供的相关方法:
- d3.line(...).x(...).y(...):用于折线图
- d3.gepPath().projection():用于地图
- d3.area():用于主题河流
- d3.arc(...).innerRadius(...).outerRadius(...):用于饼图
- d3.lineReadial().angle(...).radius(...):用于极坐标
下面我们通过一个实例来学习一下使用 D3
中提供的 Path
生成器。
动态折线图
在前面我们已经介绍了 SVG
中的 path
属性,以及 D3
中提供的相关 path
方法,下面我们就开始实例编码吧,用于加强对 path
的学习。
首先还是需要先有一个最基础的 svg
画布,代码如下:
<svg width="1600" height="800" class="svgs"></svg>
并且我们需要设置相关的基础属性,在前面的章节中已经介绍过,这里就不做过多的赘述,直接上代码,如下:
const svg = d3.select('.svgs');
const width = +svg.attr('width');
const height = +svg.attr('height');
const margin = {top: 120, right: 50, bottom: 50, left: 120};
const innerWidth = width - margin.left - margin.right;
const innerHeight = height - margin.top - margin.bottom;
const g = svg.append('g').attr('id', 'maingroup').attr('transform',`translate(${margin.left}, ${margin.top})`);
const xValue = (datum) => {return datum['日期']};
const yValue = (datum) => {return datum['现有确诊']};
let xSacle, yScale;
let alldates;
let allkeys;
上面的内容都是很基础的属性设置,在前面的章节中都介绍过,不记得可以看前面的章节。
接下来我们要获取数据,这里是直接读取本地的一个 csv 文件里面的数据来展示,实际开发中我们还是需要通过与后端的交互获取到真实的数据,大致的代码如下:
d3.csv("./static/data/province.csv").then(data => {
// ...data
});
关于 d3.csv
读取本地 csv 内容的介绍,在前一节里面讲过,这里直接借用前一节中的相关代码。
获取到数据后,我们需要对数据进行部分加工,因为获取到的数据中包含 总计 字段,但是我们做可视化动态折线图是不需要总计的,因此需要处理掉。大致代码如下:
data = data.filter( d => d['省份'] !== '总结');
data = data.filter( d => d['省份'] !== '湖北');
alldates = Array.from(new Set( data.map( d => xValue(d); )));
data.forEach( d => {
d['现有确诊'] = +(d['现有确诊']);
d['日期'] = new Date();
})
接下来我们还需要将每个省份单独拎出来,用于坐标轴的生成,大致代码如下:
let provinces = {};
allkeys = Array.from(new Set( data.map( d => d['省份']; )));
allkeys.forEach( key => { provinces[key] = []; });
data.forEach( d => { provinces[d['省份']].push(d); });
allkeys.forEach( key => provinces[key].sort((b, a) => {
return b['日期']) - new Date(a['日期'];
}));
上述的代码最终执行的效果如下图所示:
通过从 csv 中获取的数据,我们在画布中生成了横坐标和纵坐标,接下来我们需要通过一个定时器不断的更新数据,并将数据动态的更新在画布中,从而形成一个动态的折线图,代码如下:
const render_update_alter = function (data) {
const line = d3.line()
.x((d) => {
// x 坐标
return xScale(xValue(d));
})
.y((d) => {
// y 坐标
return yScale(yValue(d));
})
.curve(d3.curveCardinal.tension(0.5));
// 在这里画折线图
d3.select("#alterPath")
.datum(data)
.attr("class", "datacurve")
.attr("fill", "none")
.attr("stroke", "green")
.attr("stroke-width", 2.5)
.transition()
.duration(2000)
.attr("d", line); // d3 中直接使用 d 属性,用于画线
};
最终的执行效果,可以狠戳这里。
最后
这一小节我们主要介绍了 SVG
中的 path
属性,并且介绍了 D3
中的 path
生成器,最后通过一个实例演示了如果通过 D3
来创建一个动态折线图。当然,这一节介绍的也较为简单,如果要加强对 D3 的学习,还是需要多看官方文档。让我们一起加油吧!
最后,如果这篇文章有帮助到你,❤️关注+点赞❤️鼓励一下作者,谢谢大家