svg水纹波效果
记得引用snap.svg脚本
<svg id="cloud" width="800" height="70"></svg> <svg id="wave" width="800" height="360"> </svg> <button id="weather">切换天气</button> body{ padding:0;margin:0;} #cloud{ position: absolute; left: 50%; margin-left: -400px; } #wave{ margin:0 auto; display: block; } /** * 作者: luxueyan * 博客: http://hi.gitcafe.io * 参考: http://gamedev.stackexchange.com/questions/44547/2d-water-with-dynamic-waves * 注: 原文包含lua和prosessing.js */ var s = Snap('#wave'); //波预设 var wave = s.paper.path('').attr({ stroke: 'Cyan', fill: 'Cyan' }); //雨滴 // var rains = makeRains(); //河岸 var bank = s.paper.path('M50 150 H100 V350H700V150H750').attr({ stroke: 'silver', strokeWidth: 5, fill: 'none', strokeLinejoin: 'round' }); var lastUpdate = +new Date; // rain count var RAIN_COUNT = 6; // Resolution of simulation var NUM_POINTS = 180; // Width of simulation var WIDTH = 600; // Horizonal Position var X_OFFSET = 100; // Spring constant for forces applied by adjacent points var SPRING_CONSTANT = 0.005; // Sprint constant for force applied to baseline var SPRING_CONSTANT_BASELINE = 0.005; // Vertical draw offset of simulation var Y_OFFSET = 200; // Damping to apply to speed changes var DAMPING = 0.99; // Number of iterations of point-influences-point to do on wave per step // (this makes the waves animate faster) var ITERATIONS = 5; // A phase difference to apply to each sine var offset = 0; var NUM_BACKGROUND_WAVES = 7; var BACKGROUND_WAVE_MAX_HEIGHT = 5; var BACKGROUND_WAVE_COMPRESSION = 1 / 10; // Amounts by which a particular sine is offset var sineOffsets = []; // Amounts by which a particular sine is amplified var sineAmplitudes = []; // Amounts by which a particular sine is stretched var sineStretches = []; // Amounts by which a particular sine's offset is multiplied var offsetStretches = []; // Set each sine's values to a reasonable random value var tableContent = ""; var rainState; var wavePoints = makeWavePoints(NUM_POINTS); function init() { for (var i = -0; i < NUM_BACKGROUND_WAVES; i++) { var sineOffset = -Math.PI + 2 * Math.PI * Math.random(); sineOffsets.push(sineOffset); var sineAmplitude = Math.random() * BACKGROUND_WAVE_MAX_HEIGHT; sineAmplitudes.push(sineAmplitude); var sineStretch = Math.random() * BACKGROUND_WAVE_COMPRESSION; sineStretches.push(sineStretch) var offsetStretch = Math.random() * BACKGROUND_WAVE_COMPRESSION; offsetStretches.push(offsetStretch); } //cloud var c = Snap('#cloud'); c.paper.path('M100.063,20c0,0-49.649-28.854,85.269-19.895c31.768-24.37,130.412-9.946,130.412-9.946c42.981-8.315,170.958-20.393,147.551,13.429c-8.247,11.914,38.582-3.945,57.264,8.454c30.454,20.216,2.868,23.573-44.308,23.252c-30.094,9.155-41.798,4.974-41.798,4.974c-75.237,14.051-29.94-6.469-96.172,1.119c-56.335,6.454-48.23,0.885-134.444,0.688c-81.296-0.184-53.616-6.159-80.366-7.154c2.579,9.812,-5.063,-6.227,-10.063,-10.227z').attr({stroke:'#A7A9AC', fill:"#A7A9AC"}); c.paper.path('M280.063,20c0,0-49.649-28.854,85.269-19.895c31.768-24.37,130.412-9.946,130.412-9.946c42.981-8.315,170.958-20.393,147.551,13.429c-8.247,11.914,38.582-3.945,57.264,8.454c30.454,20.216,2.868,23.573-44.308,23.252c-30.094,9.155-41.798,4.974-41.798,4.974c-75.237,14.051-29.94-6.469-96.172,1.119c-56.335,6.454-48.23,0.885-134.444,0.688c-81.296-0.184-53.616-6.159-80.366-7.154c2.579,9.812,-5.063,-6.227,-10.063,-10.227z').attr({stroke:'#A7A9AC', fill:"#A7A9AC"}); } // Make points to go on the wave function makeWavePoints(numPoints) { var t = []; for (var n = 0; n < numPoints; n++) { // This represents a point on the wave var newPoint = { x: n / numPoints * WIDTH + X_OFFSET, y: Y_OFFSET, spd: { y: 0 }, // speed with vertical component zero mass: 1 } t.push(newPoint); } return t } // This function sums together the sines generated above, // given an input value x function overlapSines(x) { var result = 0; for (var i = 0; i < NUM_BACKGROUND_WAVES; i++) { result = result + sineOffsets[i] + sineAmplitudes[i] * Math.sin(x * sineStretches[i] + offset * offsetStretches[i]); } return result; } // Update the positions of each wave point function updateWavePoints(points, dt) { for (var i = 0; i < ITERATIONS; i++) { for (var n = 0; n < points.length; n++) { var p = points[n]; // force to apply to this point var force = 0; // forces caused by the point immediately to the left or the right var forceFromLeft, forceFromRight; if (n == 0) { // wrap to left-to-right var dy = points[points.length - 1].y - p.y; forceFromLeft = SPRING_CONSTANT * dy; } else { // normally var dy = points[n - 1].y - p.y; forceFromLeft = SPRING_CONSTANT * dy; } if (n == points.length - 1) { // wrap to right-to-left var dy = points[0].y - p.y; forceFromRight = SPRING_CONSTANT * dy; } else { // normally var dy = points[n + 1].y - p.y; forceFromRight = SPRING_CONSTANT * dy; } // Also apply force toward the baseline var dy = Y_OFFSET - p.y; forceToBaseline = SPRING_CONSTANT_BASELINE * dy; // Sum up forces force = force + forceFromLeft; force = force + forceFromRight; force = force + forceToBaseline; // Calculate acceleration var acceleration = force / p.mass; // Apply acceleration (with damping) p.spd.y = DAMPING * p.spd.y + acceleration; // Apply speed p.y = p.y + p.spd.y; } } } // Callback for drawing function drawWave(dt) { offset = offset + 1; // Update positions of points updateWavePoints(wavePoints, dt) var path = []; //构造路径 for (var n = 0; n < wavePoints.length; n++) { var p = wavePoints[n]; if (n == 0) { path.push('M' + p.x + ' ' + (p.y + overlapSines(p.x, 0, 0))); } else { path.push(p.x + ' ' + (p.y + overlapSines(p.x))); } } path.push('V350H100V150'); wave.attr({ path: path }); } //make rains function makeRains() { var rains = []; for (var n = 0; n < RAIN_COUNT; n++) { rains.push([X_OFFSET + WIDTH * Math.random(), 50 * Math.random(), 1, 3]); } return rains; } //获取雨点对应点的index function getClosestPointIndex(cx) { var left = parseInt((cx - X_OFFSET) / (WIDTH / NUM_POINTS) - 1); return left + (Math.abs(wavePoints[left].x - cx) > Math.abs(wavePoints[left + 1].x - cx)); // var high = NUM_POINTS - 1; // var low = 0; // var mid = 0; // var index, x; // while (low <= high) { // mid = parseInt((high + low)/2); // x = wavePoints[mid].x; // if (x == cy) { // index = mid; // break; // } else if (high - low = 1) { // index = Math.abs(wavePoints[high].x - cy) > Math.abs(wavePoints[low].x - cy) ? high : low; // break; // } else if (x > cy) { // high = mid - 1; // } else if (x < cy) { // low = mid + 1; // } // } // return index; } function updateRains(now) { var rains = s.selectAll('ellipse'); rains.forEach(function(e, i) { var cx = parseInt(e.attr('cx')); var closestPointIndex = parseInt(e.attr('data-cp-index')); var cy = parseInt(e.attr('data-start-y')) + 0.5 * Math.pow((now - parseInt(e.attr('data-start-time'))) / 50, 2); if (wavePoints[closestPointIndex].y <= cy) { wavePoints[closestPointIndex].y = Y_OFFSET + 10; e.remove(); } else { e.attr({ cy: cy }); } }); } function drawRains() { var rains = makeRains(); var l = rains.length; // var g = s.g(); var now = +new Date; for (var n = 0; n < l; n++) { s.paper.ellipse(rains[n][0], rains[n][1], rains[n][2], rains[n][3]).attr({ 'data-start-time': now, 'fill': 'Cyan', 'data-cp-index': getClosestPointIndex(rains[n][0]), 'data-start-y': rains[n][1] }); } rainState = 'on'; } function run() { var now = +new Date; var dt = now - lastUpdate; lastUpdate = now; drawWave(dt); updateRains(now); } var rainHd = setInterval(drawRains, 500); init(); //begin run var runHd = setInterval(function() { run(); }, 30); $('#weather').click(function(){ if(rainState == 'on') { clearInterval(rainHd); rainState = 'off'; } else { rainHd = setInterval(drawRains, 500); } });
拿来即用的:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> </head> <style type="text/css" media="screen"> #wave{ margin:0 auto; display: block; } </style> <script type="text/javascript" src="snap.svg-min.js"></script> <body> <svg id="wave" width="100%" height="360"> </svg> </body> <script type="text/javascript"> var s = Snap('#wave'); //波预设 var wave = s.paper.path('').attr({ stroke: 'transparent', fill: '#f00', 'fill-opacity':0.5 }); var lastUpdate = +new Date(); // 波定点的个数;个数越多越显得平滑 var NUM_POINTS = 100; // 波的宽度 var WIDTH = 800; // 水平位移 var X_OFFSET = 0; // 垂直位移 var Y_OFFSET = 300; // A phase difference to apply to each sine var offset = 100; var NUM_BACKGROUND_WAVES = 7; var BACKGROUND_WAVE_MAX_HEIGHT = 5; var BACKGROUND_WAVE_COMPRESSION = 1 / 20; // Amounts by which a particular sine is offset var sineOffsets = []; // Amounts by which a particular sine is amplified var sineAmplitudes = []; // Amounts by which a particular sine is stretched var sineStretches = []; // Amounts by which a particular sine's offset is multiplied var offsetStretches = []; var wavePoints = makeWavePoints(NUM_POINTS); function init() { for (var i = -0; i < NUM_BACKGROUND_WAVES; i++) { var sineOffset = -Math.PI + 2 * Math.PI * Math.random(); sineOffsets.push(sineOffset); var sineAmplitude = Math.random() * BACKGROUND_WAVE_MAX_HEIGHT; sineAmplitudes.push(sineAmplitude); var sineStretch = Math.random() * BACKGROUND_WAVE_COMPRESSION; sineStretches.push(sineStretch) var offsetStretch = Math.random() * BACKGROUND_WAVE_COMPRESSION; offsetStretches.push(offsetStretch); } //cloud } // Make points to go on the wave function makeWavePoints(numPoints) { var t = []; for (var n = 0; n < numPoints; n++) { // This represents a point on the wave var newPoint = { x: n / numPoints * WIDTH + X_OFFSET, y: Y_OFFSET, spd: { y: 0 }, // speed with vertical component zero mass: 10 } t.push(newPoint); } return t } // given an input value x function overlapSines(x) { var result = 0; for (var i = 0; i < NUM_BACKGROUND_WAVES; i++) { result = result + sineOffsets[i] + sineAmplitudes[i] * Math.sin(x * sineStretches[i] + offset * offsetStretches[i]); } return result; } // Callback for drawing function drawWave(dt) { offset = offset + 1; // Update positions of points var path = []; //构造路径 for (var n = 0; n < wavePoints.length; n++) { var p = wavePoints[n]; if (n == 0) { path.push('M' + p.x + ' ' + (p.y + overlapSines(p.x, 0, 0))); } else { path.push(p.x + ' ' + (p.y + overlapSines(p.x))); } } path.push('V350H-1V150'); wave.attr({ path: path }); } function run() { var now = +new Date; var dt = now - lastUpdate; lastUpdate = now; drawWave(dt); } init(); //begin run var runHd = setInterval(function() { run(); }, 60); </script> </html>
上一篇:
avalon学习笔记一
下一篇:
JavaScript 资源大全中文版
静水缘首页
刘丕水+宋静静于2007年9月相识于山东理 工大学,毕业后2011年相恋,共甘苦,历 时四年,终于在11月23号拿到了红本本, 组建了自己的小家庭......文章分类
最新文章
- nodejs私钥加密公钥解密的一个例子
- uniapp和微信小程序判断程序运行在开发或者测试或者线上版本的方法分别是什么
- electron使用electron-builder打包后模块包含exe文件执行失败
- Compile is disallowed on the main thread, if the buffer size is larger than 4KB
- better-sqlite3简介及常用操作
- nodejs 操作数据库的库
- nodejs使用http-proxy库实现多个域名代理和同时代理websocket的例子,代理包含https和http两种协议
- iis配置反向代理
- javascript伪多线程代码
- ip所在地址段判断