内容简介:春节放假前的第二天上午,看到设计稿上的图(如下),于是发生了下面的对话-我:把这个图传一下吧。-UI:好的,你是要 gif 吧。
春节放假前的第二天上午,看到设计稿上的图(如下),于是发生了下面的对话
-我:把这个图传一下吧。
-UI:好的,你是要 gif 吧。
-我:啥?这个是个动画?
-UI:啥?这不是动画?
-我:打扰了。
于是在剩下的一天里,我撸出了这个 波浪动画
开始准备
- 想想需求
首先我们能想到的是,波浪的数量一定是可定制的,其次是颜色,速度,透明度,高度等等。这些可定制的参数应当在函数实例化时传入。所以我们先定制一个接口(包括了后来在编写时我认为需要的)。
interface Options { number: number smooth: number velocity: number height: number colors: Array<{ hex: string, rgba: string }> opacity: number border: { show: boolean, width: number, color: string[] } position: 'top' | 'bottom' | 'left' | 'right' } 复制代码
不了解 typescript 的同学可以意会, key
指的传入变量的名称, value
为变量的类型规范
- 设计接口
我们先预先想下可能发生的场景:
- 动画需要指令化的开始或暂停
- 可以通过方法实时设置或更改参数,并反映在动画上
- 在动画的容器缩放时,画布应当能重新设置
所以我们暂时值规定四个类型为 public
接口 animate
, pause
, setOptions
, reset
interface Core { animate: () => void pause: () => void setOptions: (options: Object) => void reset: () => void } 复制代码
开始写动画
准备工作基本完成,现在开始编写核心动画。
- 准备一个 canvas
基本操作,不多介绍。
<body> <canvas id="canvas"></canvas> </body> 复制代码
const canvas = document.getElementById('canvas') const ctx = canvas.getContext('2d') canvas.width = document.body.offsetWidth canvas.height = document.body.offsetHeight 复制代码
- 先画一池水
画一个矩形,然后填充颜色。
ctx.fillStyle = "rgba(255,118,87,.6)" ctx.beginPath() ctx.moveTo(0, canvas.height/2) ctx.lineTo(canvas.width, canvas.height/2) ctx.lineTo(canvas.width, canvas.height) ctx.lineTo(0, canvas.height) ctx.lineTo(0, canvas.height/2) ctx.closePath() ctx.fill() 复制代码
- 让水动起来
要让水池的水呈周期性的上涨和跌落,很容易想到借助正弦或者余弦函数来完成,在每一帧的渲染中将 step
增加 1 度,规定 50 为变化值,利用正弦函数将变化量作用于左右两个顶点上即可。
let step = 0 function loop(){ // 清空canvas ctx.clearRect(0,0,canvas.width,canvas.height) ctx.clearRect(0,0,canvas.width,canvas.height) ctx.fillStyle = "rgba(255,118,87,.6)" step++ const angle = step * Math.PI / 180 const deltaHeight = Math.sin(angle) * 50 ctx.beginPath() ctx.moveTo(0, canvas.height/2+deltaHeight) ctx.lineTo(canvas.width, canvas.height/2+deltaHeight) ctx.lineTo(canvas.width, canvas.height) ctx.lineTo(0, canvas.height) ctx.lineTo(0, canvas.height/2+deltaHeight) ctx.closePath() ctx.fill() requestAnimationFrame(loop) } loop() 复制代码
- 让水晃起来
使左右顶点不同步即可让水面晃动起来,所以我们将左顶点的取值使用余弦函数即可。
let step = 0 function loop() { //清空canvas ctx.clearRect(0, 0, canvas.width, canvas.height) ctx.clearRect(0, 0, canvas.width, canvas.height) ctx.fillStyle = "rgba(255,118,87,.6)" step++ const angle = step * Math.PI / 180 const deltaHeight = Math.sin(angle) * 50 const deltaHeightRight = Math.cos(angle) * 50 ctx.beginPath() ctx.moveTo(0, canvas.height / 2 + deltaHeight) ctx.lineTo(canvas.width, canvas.height / 2 + deltaHeightRight) ctx.lineTo(canvas.width, canvas.height) ctx.lineTo(0, canvas.height) ctx.lineTo(0, canvas.height / 2 + deltaHeight) ctx.closePath() ctx.fill() requestAnimationFrame(loop) } loop() 复制代码
- 制造波浪
借助贝塞尔曲线将矩形的一边变为波浪。
在 canvas 绘制中,我们借助 bezierCurveTo(cpX1, cpY1, cpX2, cpY2, x, y)
方法绘制贝塞尔曲线,由上图可见(歪脖 45 度查看更直观),两个控制点的横坐标应当设为矩形宽的中点,纵坐标跟随峰值变化即可。
let step = 0 function loop() { //清空canvas ctx.clearRect(0, 0, canvas.width, canvas.height) ctx.clearRect(0, 0, canvas.width, canvas.height) ctx.fillStyle = "rgba(255,118,87,.6)" step++ const angle = step * Math.PI / 180 const deltaHeight = Math.sin(angle) * 50 const deltaHeightRight = Math.cos(angle) * 50 ctx.beginPath() ctx.moveTo(0, canvas.height/2+deltaHeight) ctx.bezierCurveTo(canvas.width /2, canvas.height/2+deltaHeight-50, canvas.width / 2, canvas.height/2+deltaHeightRight-50, canvas.width, canvas.height/2+deltaHeightRight) ctx.lineTo(canvas.width, canvas.height) ctx.lineTo(0, canvas.height) ctx.lineTo(0, canvas.height/2+deltaHeight) ctx.closePath() ctx.fill() requestAnimationFrame(loop) } loop() 复制代码
- 多个波浪
将上面的波浪写成 for 循环多次渲染即可。
let step = 0 const lines = 3 function loop() { ctx.clearRect(0, 0, canvas.width, canvas.height) step++ for (let i = 0; i < lines; i++) { ctx.fillStyle = 'rgba(255,118,87,.3)' var angle = (step + i * 180 / lines) * Math.PI / 180 var deltaHeight = Math.sin(angle) * 50 var deltaHeightRight = Math.cos(angle) * 50 ctx.beginPath() ctx.moveTo(0, canvas.height / 2 + deltaHeight) ctx.bezierCurveTo(canvas.width / 2, canvas.height / 2 + deltaHeight - 50, canvas.width / 2, canvas.height / 2 + deltaHeightRight - 50, canvas.width, canvas.height / 2 + deltaHeightRight) ctx.lineTo(canvas.width, canvas.height) ctx.lineTo(0, canvas.height) ctx.lineTo(0, canvas.height / 2 + deltaHeight) ctx.closePath() ctx.fill() } requestAnimationFrame(loop) } loop() 复制代码
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- iOS实现波浪效果
- css做个波浪悬浮球?
- CSS实现文字下面波浪线动画效果
- 用 radial-gradient 实现波浪效果
- CSS text-decoration实现宽度100%波浪线效果
- Android教你一步一步从学习贝塞尔曲线到实现波浪进度条
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Designing for Emotion
Aarron Walter / Happy Cog / 2011-10-18 / USD 18.00
Make your users fall in love with your site via the precepts packed into this brief, charming book by MailChimp user experience design lead Aarron Walter. From classic psychology to case studies, high......一起来看看 《Designing for Emotion》 这本书的介绍吧!