http://www.w3cplus.com/animations/water-bubble.html <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>如何制作水球动画图?</title> <style type="text/css"> body { display: flex; flex-flow: column wrap; justify-content: center; align-items: center; } #c { margin-top: 20px; } input[type=range]::before { content: attr(min); color: #000; padding-right: 5px; } input[type=range]::after { content: attr(max); color: #000; padding-left: 5px; } </style> </head> <body> <canvas id="c">当前浏览器不支持canvas 请升级!</canvas> <input type="range" name="range" min="0" max="100" step="1"> </body> <script type="text/javascript"> canvas = document.getElementById("c"); ctx = canvas.getContext("2d"); oRange = document.getElementsByName("range")[0]; M = Math; Sin = M.sin; Cos = M.cos; Sqrt = M.sqrt; Pow = M.pow; PI = M.PI; Round = M.round; oW = canvas.width = 300; oH = canvas.height = 300; // 线宽 lineWidth = 2 // 大半径 r = (oW / 2); cR = r - 8*lineWidth; ctx.beginPath(); ctx.lineWidth = lineWidth; // 水波动画初始参数 axisLength = 2*r - 16*lineWidth; // Sin 图形长度 unit = axisLength / 8; // 波浪宽 range = .2 // 浪幅 nowrange = range; xoffset = 8*lineWidth; // x 轴偏移量 data = ~~(oRange.value) / 100; // 数据量 sp = 0; // 周期偏移量 nowdata = 0; waveupsp = 0.002; // 水波上涨速度 // 圆动画初始参数 arcStack = []; // 圆栈 bR = r-8*lineWidth; soffset = -(PI/2); // 圆动画起始位置 circleLock = true; // 起始动画锁 // 获取圆动画轨迹点集 for(var i = soffset; i< soffset + 2*PI; i+=1/(8*PI)) { arcStack.push([ r + bR * Cos(i), r + bR * Sin(i) ]) } cStartPoint = arcStack.shift(); // 圆起始点 ctx.strokeStyle = "#1c86d1"; ctx.moveTo(cStartPoint[0],cStartPoint[1]) render(); // 开始渲染 function drawSine () { ctx.beginPath(); ctx.save(); var Stack = []; // 记录起始点和终点坐标 for (var i = xoffset; i<=xoffset + axisLength; i+=20/axisLength) { var x = sp + (xoffset + i) / unit; var y = Sin(x) * nowrange; var dx = i; var dy = 2*cR*(1-nowdata) + (r - cR) - (unit * y); ctx.lineTo(dx, dy); Stack.push([dx,dy]) } // 获取初始点和结束点 var startP = Stack[0] var endP = Stack[Stack.length - 1] ctx.lineTo(xoffset + axisLength,oW); ctx.lineTo(xoffset,oW); ctx.lineTo(startP[0], startP[1]) ctx.fillStyle = "#1c86d1"; ctx.fill() ctx.restore(); } function drawText () { ctx.globalCompositeOperation = 'source-over'; var size = 0.4*cR; ctx.font = 'bold ' + size + 'px Microsoft Yahei'; txt = (nowdata.toFixed(2)*100).toFixed(0) + '%'; var fonty = r + size/2; var fontx = r - size * 0.8; ctx.fillStyle = "rgba(06, 85, 128, 0.8)"; ctx.fillText(txt, fontx, fonty) } function render () { ctx.clearRect(0,0,oW,oH); if (circleLock) { if (arcStack.length) { var temp = arcStack.shift(); ctx.lineTo(temp[0],temp[1]) ctx.stroke(); } else { circleLock = false; ctx.lineTo(cStartPoint[0],cStartPoint[1]) ctx.stroke(); arcStack = null; ctx.globalCompositeOperation = 'destination-over'; ctx.beginPath(); ctx.lineWidth = lineWidth; ctx.arc(r,r, bR, 0, 2*PI, 1); ctx.beginPath(); ctx.save(); ctx.arc(r,r, r-16*lineWidth, 0, 2*PI, 1); ctx.restore() ctx.clip(); ctx.fillStyle = "#1c86d1"; // 初始拖拽控件 oRange.addEventListener("change", function () { data = ~~(oRange.value) / 100; console.log("data="+data) },0); } } else { // 开始水波动画 // 控制波幅 if (data >= 0.85) { if (nowrange > range/4) { var t = range * 0.01; nowrange -= t; } } else if (data <= 0.1) { if (nowrange < range*1.5) { var t = range * 0.01; nowrange += t; } } else { if (nowrange <= range) { var t = range * 0.01; nowrange += t; } if (nowrange >= range) { var t = range * 0.01; nowrange -= t; } } if((data - nowdata) > 0) { nowdata += waveupsp; } if((data - nowdata) < 0){ nowdata -= waveupsp } sp += 0.07; drawSine(); drawText(); } requestAnimationFrame(render) } </script> </html> 提示:你可以先修改部分代码再运行。 转载请注明:有爱前端 » 如何制作水球动画图? 喜欢 (0)or分享 (0)