/ 2018/08/20/-你必须知道/
我是一个很懒的人,在开发过程中经常有意无意地回避数学相关的知识。 你也知道解决数学问题是很无聊的。 编写动画时,尽量使用CSS3。 您可以随意选择计时器。 最多,你可以调整立方体-找到一个看起来舒服的。 但如何让动画更流畅,写出更自然的动画,说实话,我之前并没有想太多。
每次当动作设计师问这个能不能做、那个能不能做的时候,我自然会拒绝。 所以很长一段时间,我都很羡慕能画出很酷的动画的程序员。
暂时就这样吧,又不是不动。
今天给大家分享一些三角函数相关的内容。 如果我刚学前端的时候有人教我这个,我会很高兴。
三角函数
三角函数已经很常见了(嘻哈圈子里叫Old)。 他们陪伴我们从初中到大学。 公式、定理太多,光是准备考试就需要花很多时间。 首先快速回顾一下,以确保您记住基础知识。
勾股定理
当我第一次学习三角函数时,我从三股、四股和五股开始。 毕达哥拉斯定理描述,对于直角三角形,直角两条边的平方和等于斜边的平方。
常用三角函数
印象中课本上只保留了sin、cos、tan,其他的都可以通过变换得到。
sinθ = a / h
cosθ = b / h
tanθ = a / b
极坐标系和单位圆
在笛卡尔直角坐标系中,任意点(x,y)都可以转换为极坐标表示(r,θ),其中
r = Math.sqrt(x^2 + y^2)
θ = Math.atan2(y, x)
单位圆的定义是半径为单位长度的圆。 圆上任意点的横坐标是对应角度的余弦,任意点的纵坐标是对应角度的正弦。
简单的图像变换
以正弦曲线为例,函数的简单变换可以得到不同的结果。
正弦曲线公式:y = A sin(Bx + C) + D
A 控制幅度。 A值越大,波峰和波谷越大。 A值越小,波峰和波谷越小。 B值会影响周期。 B值越大,周期越短。 B值越小,周期越长。 。 C值会影响图像的左右移动。 如果C值为正数,则图像将向右移动。 如果C值为负数,则图像将向左移动。 D值控制上下移动。
这个公式非常有用。 如果下面的代码让你感到困惑,记得回来查看评论。
简单回顾后,确保你还记得这些基础知识。 那么当这些曾经熟悉的内容与前端代码结合起来会发生什么呢?
常见应用场景
图像应用
最直观的应用就是利用三角函数绘制波浪曲线
for (let x = 0; x < width; x++) {
const y = Math.sin(x * a) * amplitude
}
结合三角函数偏移,左右两侧成为波谷,中间成为波峰,就可以得到优美的波纹。
for (let x = 0; x < width; x++) {
const radians = x / width * Math.PI * 2
const scale = (Math.sin(radians - Math.PI * 0.5) + 1) * 0.5
const y = Math.sin(x * 0.02 + xSpeed) * amplitude * scale
}
之前有一篇关于掘金的文章很受欢迎。 同样的原则也适用。 使用两层正弦函数绘制曲线,并在填充后添加动画,可以获得非常酷的效果。
如果结合鼠标位置+lerp动画,就可以实现和Nut主页一样的动画。
本文的大部分代码可以在我的主页上看到。
正弦和余弦曲线具有自然缓进缓出的特性,从-1到1再回到-1一个周期,非常适合模拟一些物理效果。 因为在现实世界中,汽车缓慢启动,加速,减速,然后缓慢减速,直到速度达到0。突然的变化会让人不舒服。 左边的摆球以恒定的速度线性摆动,右边是使用三角函数优化的结果。 显然左边的特效设计师要打人了。
只需将最大角度乘以 sin 或 cos 即可得到摆动的最大角度。
ctx.rotate(Math.cos(t / 180 * Math.PI) * Math.PI * 0.25)
角度控制
在开发过程中,我们经常需要处理角度,比如在头像左上角(45°)显示一个红点,用鼠标控制等。
前端JS中的Math.atan2(y, x)可以用来计算(x,y)与x轴正方向夹角的弧度值。
function getCurrentDegree () {
const deltaX = mouse.x - window.innerWidth * 0.5
const deltaY = mouse.y - window.innerHeight * 0.5
return Math.atan2(deltaY, deltaX) * 180 / Math.PI
}
顺便说一句,三角函数相关的动画不一定需要用js写。 比如下面的DEMO,利用依赖,还可以灵活控制特定角度的动画(不要手写每个点的坐标!!!以后不会有问题的方法维护)
@import "compass";
.checkbox:checked {
~ button {
$per: 180 / 4;
@for $i from 1 through 6 {
&:nth-of-type(#{$i}) {
$angle: $per * ($i - 1) * 1deg + 180deg;
$x: cos($angle) * $d;
$y: sin($angle) * $d;
transform: translate($x, $y) rotate(0deg) ;
}
}
}
}
案例分析
这些是常用的场景。 让我们通过案例研究来回顾一下。
前两天在首页看到一个热门推荐。 作者利用保存的CSS动画来实现一个行走的动画。 这很新颖。 但仔细一看,脚步动画感觉很别扭,所以我想用三角函数来优化它。
画出头部:
drawHead (t) {
ctx.save()
ctx.beginPath()
ctx.translate(0, Math.sin(t) * 4)
ctx.arc(80, -35, 35, 0, 2 * Math.PI)
ctx.fill()
ctx.closePath()
ctx.restore()
}
我会给每个方法传入周期参数t,t的范围是0到2PI,以保证所有周期运动时间都是同步的。
身体和阴影的绘制是相似的,所以直接跳到观看脚部动画。
有两只脚。 按理来说,当从抬起脚到落地的动作完成时,其他部分已经完成了一个完整的循环,所以在画脚的时候,t需要除以2。那么第一只脚和第二只脚的差值是一半脚本身的周期。 可以直接将t替换为t+Math.PI即可得到第二只脚的动画。
drawFeet (t) {
t = t / 2
ctx.translate(Math.cos(t) * -50, 0)
// 另一只脚
ctx.translate(Math.cos(t + Math.PI) * -50, 0)
}
脚步动画循环的一半是在地面上。 可以判断sin值。 如果小于0,则y纵轴方向不会发生变化。
ctx.translate(Math.cos(t) * -50, Math.sin(t) > 0 ? Math.sin(t) * -35 : 0)
还没结束。 为了使脚部更加真实,在循环的前半部分也做同样的事情。
if (t < Math.PI) {
ctx.rotate(Math.sin(t) * Math.PI / 180 * -5)
}
最终结果是这样的:
源代码地址()
总结
现在前端发展非常迅速,刚入门的同学刚学完就被告知You Dont Need。 你无法停止追逐新剧本。 在学习新框架、新技能的同时,不要忘记基础知识的重要性。
嗯,今天就分享到这里。 我希望同时汇集这么多效果能让您下次使用三角函数时更加自如。
上面的大部分代码都可以在我的主页上看到。
相关链接
【关于投稿】
如果您有原创好文章可以贡献,请直接给公众号留言。
①消息格式:
【提交】+“文章标题”+文章链接
②示例:
【投稿】《别自称程序员,我十几年IT生涯的总结》:
③最后请附上你的个人资料~