效果图
TALK IS CHEAP
源码就50多行,比较好看懂。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>svg动画</title>
<script src="https://d3js.org/d3.v4.min.js"></script>
</head>
<body>
<svg id="svg-area" width="500" height="200">
<path fill="rgba(33, 150, 243, 0.4)"></path>
<path fill="rgba(33, 150, 243, 0.6)"></path>
</svg>
<script>
//波浪动画
var svg_height = 200,
svg_width = 500,
wave_data = [[],[]],
area = d3.area().y0(svg_height).curve(d3.curveBasis), //curve会进行平滑处理
svg_paths = [];
var max = 100; //控制速度
for (var i=0; i<max; i++) {
var r = i / max * 2;
wave_data[0].push(r); //波浪一
wave_data[1].push(r + 1); //波浪二(+1代表偏移π)
}
var d = svg_width/(wave_data[0].length-1);
svg_paths.push(d3.select('#svg-area path:first-child'));
svg_paths.push(d3.select('#svg-area path:last-child'));
function area_generator(data) {
var wave_height = 0.15; //波浪高度
var area_data = data.map( function(y,i) {
return [i * d, svg_height*(1 - (wave_height*Math.sin(y*Math.PI) + 2)/3)]; //+2将范围[-1,1]转成[1,3]
} );
return function() {
return area(area_data);
};
}
function renderWave() {
svg_paths.forEach(function(svg_path,i){
svg_path.attr('d', area_generator(wave_data[i]));
wave_data[i] = getNextData(wave_data[i]);
});
requestAnimationFrame(renderWave);
}
function getNextData(data) {
var r = data.slice(1);
r.push(data[0]);
return r;
}
requestAnimationFrame(renderWave);
</script>
</body>
</html>
补充
这估计是我写得最简短的博客之一了,看到这里的同学估计是我的代码没写好,没有简单易懂,下面补充一下实现的思路和涉及到的一些知识点吧。
实现思路
因为之前画过趋势图(D3.js SVG绘图实践:趋势缩略图),所以看到波浪动画,第一想法就是,这不是两个带透明度重叠的区域嘛,让区域动起来就好。
画区域已经在上一篇博客中解决了,这次只不过加了平滑处理:
area = d3.area().y0(svg_height).curve(d3.curveBasis) //curve会进行平滑处理
重点是怎么动起来:
- 方案一:
用transform实现平移(一般思路,从左到右,然后移到与开始视觉一样时瞬间移回原点) - 方案二:
区域不动,区域上边界按照波浪的规律动,重绘区域(实现比较复杂) - 方案三:将区域数据平移,重绘区域
function getNextData(data) {
var r = data.slice(1);
r.push(data[0]);
return r;
}
一些知识点:
总结
实现上没很大的难度,但一开始因为用了Math.sin,波浪起伏的幅度较大,看着不像波浪在上下动,而是在从右往左移动,一开始都想尝试之前的方案二了,后来去看了波浪的效果,发现主要问题出在波浪本来就不是正弦图形那样的,于是改成了0.15 * Math.sin,效果就好多了。
最近在计划手上的React项目重构的事,也在看各类库的源码,希望能有更多的东西和大家分享,共勉。
264



被折叠的 条评论
为什么被折叠?



