\

In the cone of light, all is fate

用D3js的区域生成器实现简单波浪图

最近做控件遇到含有波浪图的图表,一开始用Echarts虽然很快完成了,但Echarts的波浪图与其他图表的响应式不同步,于是学习了D3js,D3js写起来确实复杂一些,但能够实现的效果也更丰富,做的时候查了不少资源,讲真的,网上教程挺少的,很多都重复,我分享下我的方法。

先看一下效果:
water

我只做了简单的效果,想控制波浪的流速、高度就跟据应用场景自己设计,我在控件中是用比例尺。
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次明显的跳动,二是如果上升或下降的速度太快,过程中液面是倾斜的,三是双层液面时同样的值会有不一样的速度,需要自己调试。

posted @ 2019-11-01 13:01  Ymrt  阅读(1200)  评论(0编辑  收藏  举报