用D3js的区域生成器实现简单波浪图
最近做控件遇到含有波浪图的图表,一开始用Echarts虽然很快完成了,但Echarts的波浪图与其他图表的响应式不同步,于是学习了D3js,D3js写起来确实复杂一些,但能够实现的效果也更丰富,做的时候查了不少资源,讲真的,网上教程挺少的,很多都重复,我分享下我的方法。
先看一下效果:
我只做了简单的效果,想控制波浪的流速、高度就跟据应用场景自己设计,我在控件中是用比例尺。
D3中有一种叫区域生成器的东西,可以生成一个上方是不规则形状,其余三边都是直线的区域,主要就围绕这个来做。
先定义一个画布
var width = 200;
var height = 500;
var svg = d3.select("#body")
.append("svg")
.attr("width", width)
.attr("height", height)
然后用数组控制波浪的形状
var values = 0
var dataList0 = [values - 2, values - 3, values - 4, values - 3, values - 2, values - 1, values, values - 1]
网上的50行代码的版本大家应试都看到过,是将数组的每一个数组放到最后,循环这个操作就可以了,本人比较小白,有几个地方看不懂,所以用了比较直观的方法,多定义些数组
var values = 0
var dataList0 = [values - 2, values - 3, values - 4, values - 3, values - 2, values - 1, values, values - 1]
var dataList1 = [values - 3, values - 4, values - 3, values - 2, values - 1, values, values - 1, values - 2]
var dataList2 = [values - 4, values - 3, values - 2, values - 1, values, values - 1, values - 2, values - 3]
var dataList3 = [values - 3, values - 2, values - 1, values, values - 1, values - 2, values - 3, values - 4]
var dataList4 = [values - 2, values - 1, values, values - 1, values - 2, values - 3, values - 4, values - 3]
var dataList5 = [values - 1, values, values - 1, values - 2, values - 3, values - 4, values - 3, values - 2]
var dataList6 = [values, values - 1, values - 2, values - 3, values - 4, values - 3, values - 2, values - 1]
var dataList7 = [values - 1, values - 2, values - 3, values - 4, values - 3, values - 2, values - 1, values]
现在我们把区域生成器放上去,网上很多教程都是v3的,生成时用的 d3.svg.area() ,新版本是 d3.area() 曲线用的是 .interpolate("basis") ,新的版本是 .curve(d3.curveBasis)
var areaPath = d3.area()
.x(function (d, i) { return i * 20 })
.y0(function (d, i) { return height / 2 })
.y1(function (d, i) { return - d })
.curve(d3.curveBasis)
最后加属性,并让数组波浪起来
function run() {
svg.append("path")
.attr("d", areaPath(dataList0))
.attr("fill", "rgba(0,118,184,.4)")
.transition().duration(100).delay(0).ease(d3.easeLinear)
.attr("d", areaPath(dataList1))
.transition().duration(100).delay(0).ease(d3.easeLinear)
.attr("d", areaPath(dataList2))
.transition().duration(100).delay(0).ease(d3.easeLinear)
.attr("d", areaPath(dataList3))
.transition().duration(100).delay(0).ease(d3.easeLinear)
.attr("d", areaPath(dataList4))
.transition().duration(100).delay(0).ease(d3.easeLinear)
.attr("d", areaPath(dataList5))
.transition().duration(100).delay(0).ease(d3.easeLinear)
.attr("d", areaPath(dataList6))
.transition().duration(100).delay(0).ease(d3.easeLinear)
.attr("d", areaPath(dataList7))
.transition().duration(100).delay(0).ease(d3.easeLinear)
.attr("d", areaPath(dataList0))
.remove()
.on('end', run)
}
requestAnimationFrame(run);
不建议用计时器, requestAnimationFrame(run) 配合 on('end', run) 的效果更好,.remove() 是让删除之前的动画,ease(d3.easeLinear) 一定要加,会让动画看上去更流畅,不加就是幻灯片-_-b
用同样的方式再做一个,设置不同透明度即可完效果,如果让液位高度变化,可在y1()中加入三元运算,不过这个方法有三个缺点,一是会有2次明显的跳动,二是如果上升或下降的速度太快,过程中液面是倾斜的,三是双层液面时同样的值会有不一样的速度,需要自己调试。