上一篇,我们已经构建了一个基本的平面直角坐标系。本篇主要讲讲给如何给坐标系加上数据和过渡动画。
先整理一下svg的一些基础知识点:
示例代码:
<style>
svg line {
stroke: grey;
stroke-width: 2;
}
svg circle {
stroke: red;
fill: none;
stroke-width: 2;
}
svg rect {
stroke: steelblue;
fill: none;
stroke-width: 2;
}
svg polygon {
stroke: green;
fill: none;
stroke-width: 2;
}
</style>
<script type="text/javascript">
var width = 600,
height = 500;
var svg = d3.select("body").append("svg");
svg.attr("height", height).attr("width", width);
svg
.append("line") // <-A
.attr("x1", 0)
.attr("y1", 200)
.attr("x2", 100)
.attr("y2", 100);
svg
.append("circle") // <-B
.attr("cx", 200)
.attr("cy", 150)
.attr("r", 50);
svg
.append("rect")
.attr("x", 300) // <-C
.attr("y", 100)
.attr("width", 100) // <-D
.attr("height", 100)
.attr("rx", 5); // <-E
svg.append("polygon").attr("points", "450,200 500,100 550,200"); // <-F
</script>
上面的代码可以生成这些图形:
有关SVG坐标系的小知识
SVG画布的坐标始于整个画布的左上角(0,0),而止于右下角 (width, height),即画布的宽度和高度。
line:直线元素。创建一条起点位于(x1, y1),而终点在(x2, y2)的线段(见第A行);circle:圆。append()函数可以在画布上绘制一个圆心位于(c2, cy),半径为r的源(见第B行);rect:从第C行起,我们仍然使用append()函数绘制了一个左上角未预约(x, y),宽度和高度分别为width和height的矩形。在第E行,定义了一个x方向长度和y方向长度分别为rx、``ry```的椭圆形,这个椭圆形将构成矩形的4个圆角;polygon:该元素代表一个多边形。它使用points属性对多边形的定点进行了定义,points属性是一个坐标列表,不同坐标之间用空格进行分隔。
使用线条生成器
本例实际上是实现折线图效果,需要使用到d3.js的线条生成器。其实叫它路径生成器可能更准确一点,因为它和svg:line元素没啥关系,实际上是使用svg:path元素实现的。
d3的线条生成器非常灵活,你可以用它生成各种各样的图形。但是,为了简化图形的生成,d3还提供了其它的图形生成器,这个后面应该会介绍。在本例中,我们用d2.svg.line生成器绘制多条数据驱动的线条。
根据数据绘制折线图
mock方案
此处,使用一个二维数组作为mock数据进行线条的绘制。
let data = [
[
{ x: 0, y: 5 },
{ x: 1, y: 9 },
{ x: 2, y: 7 },
{ x: 3, y: 5 },
{ x: 4, y: 3 },
{ x: 6, y: 4 },
{ x: 7, y: 2 },
{ x: 8, y: 3 },
{ x: 9, y: 2 },
],
d3.range(10).map((i) => ({ c: i, y: Math.sin(i) + 5 }))
];
其中,第一个数据序列是写死的明确的定义的数据,而第二个数据序列是通过一个函数生成的。
定义尺度
数据定义完毕,为了展示数据,我们分别定义了x坐标轴和y坐标轴的尺度。
var width = 500,
height = 500,
margin = 30,
duration = 500,
x = d3.scale.linear()
.domain([0, 10])
.range([margin, width - margin]),
y = d3.scale.linear()
.domain([0, 1])
.range([height - margin, margin]);
需要注意的是,我们将这些尺度设置得尽量宽泛一些,以便包含两个数据序列中所有的点,在值域的声明中去掉了坐标轴与画布之间的边距,并且反转了y坐标轴的值域,以确保远点位于左下角,而不是svg标准中定义的左上角。
使用线条生成器
上面的操作,定义好了mock数据和尺度。接下来的重头戏就是使用d3.svgv.line函数生成这些线条。
let line = d3.svg.line()
.x(d => x(d.x))
.y(d => y(d.y))
d3.svg.line函数将返回一个d3线条生成器函数,我们可以对这个函数进行定制。在本例中,我们只是使用先前定义的x和y坐标轴的尺度进行数据的映射。这样做既方便,也是一个公认的最佳实践。
现在我们要做的只剩下创建svg:path元素了。
svg.selectAll('path.line').data(data)
.enter()
.append('path') // < - E
.attr('class', 'line')
.attr('d', d => line(d))
绘制路径
创建路径的过程非常直接,见第E行。我们使用创建的二维数组的数据创建了两个svg:path元素,接着,又用line线条生成器处理数据中的每一个数据d(此处是作为函数的参数),并将生成的结果赋给每一个path元素的d属性。
检查元素发现,生成了svgv:path元素。
最终效果
到此,用
d3实现了完整的折线统计图。
后续文章输出安排
- 折线图-基本结构
- 折线图-过渡动画
- 折线图-线条曲度
- 面积区域图
- d3中的界面交互
......