高中物理学运动公式实现js动画

高中物理学运动公式实现js动画js动画

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

在网页上创建动画一般有两种方式:css和javascript。它们在创建动画的时间和性能上是不一样的,各有利弊。选择哪种方法实际上取决于项目,以及想要实现什么类型的动画。

一般使用css动画来实现比较简单的“一次性转换”,为UI元素转换比较小的独立状态。例如从侧面引入导航栏菜单,模太框弹出等。
要实现高级效果时,例如弹跳,加速,减速等比较复杂的动画,则使用Javascript动画。现在有很多比较好的JS动画框架,例如TweenMax,Velocity,animo.js,jquery。

不管是css还是javascript来创建动画,我们都会听到一个词“缓动”。自然界中没有东西从一点呈线性的移动到另一点,一般可能需要加速或减速。在经典动画中,经常会出现“缓入”,“缓出”,“缓入缓出”效果。缓动使动画不再那么尖锐或生硬。
css中,我们要想达到这些效果,只需要使用一些关键字:
* linear
* ease-in
* ease-out
* ease-in-out

那这么关键字的背后到底是什么原理呢?如何用javascript来实现这些缓动效果。

动画是关于时间的函数,本质就是利用浏览器和GPU的渲染过程定时改变元素的属性。

使用javascript实现动画时一般是使用requestAnimationFrame,我们可能经常也会用setInterval和setTimeout来实现动画,但是它们实现的动画都不会与屏幕的刷新率同步,并且很可能出现抖动和跳帧,例如jQuery就是采用setInterval来实现动画,所以jQuery动画的帧率会偏低(jQuery为甚么不采用RAF)。

“Talk is cheap, show me the code”。下面学习实现下月影总结的动画原理。原理简单,实现经典。

常见运动

  1. 匀速运动

    让小球在2s内向右匀速移动200px

    • 时间: t = T * p
    • 位移: St = S * p = v * t
    • 速度: v = St / t = S / T
    • 加速度: a = 0
circle.on('click', function() { 
   
    var self = this;
    var startTime = Date.now();
    var distance = 200;
    var T = 2000;
    requestAnimationFrame(function step() { 
   
        var p = Math.min(1.0, (Date.now() - startTime) / T);
        self.style.transform = 'translateX(' + (distance * p) + 'px)';
        if(p < 1.0){
            requestAnimationFrame(step);
        }
    })
})

匀速运动

2.匀加速运动

让小球在2s内向右匀加速向右移动200px, 速度从0开始
* 时间: t = T * p
* 位移: St = S * p^2 = (S * t^2) / T^2
* 速度: v = (2*S / T^2) * t = 2Sp/T
* 加速度 a = 2*S / T^2

circle.on('click', function() { 
   
        var self = this;
        var startTime = Date.now();
        var distance = 200;
        var T = 2000;
        requestAnimationFrame(function step() { 
   
            var p = Math.min(1.0, (Date.now() - startTime) / T);
            self.style.transform = 'translateX(' + (distance * p * p) + 'px)';
            if(p < 1.0){
                requestAnimationFrame(step);
            }
        })
    })

匀加速

3.匀减速运动

让小球在2s内向右匀减速向右移动200px, 速度从最大减为0
* 时间: t = T * p
* 位移: St = (2*S / T) * t – (S / T^2) * t^2 = Sp * (2 – p)
* 速度: v = 2*S / T – 2*S / t^2 * t
* 加速度 a = -2*S / T^2

circle.on('click', function() { 
   
        var self = this;
        var startTime = Date.now();
        var distance = 200;
        var T = 2000;
        requestAnimationFrame(function step() { 
   
            var p = Math.min(1.0, (Date.now() - startTime) / T);
            self.style.transform = 'translateX(' + (distance * p * (2 - p)) + 'px)';
            if(p < 1.0){
                requestAnimationFrame(step);
            }
        })
    })

匀减速

4.抛物线运动

circle.on('click', function() { 
   
    var self = this;
    var startTime = Date.now();
    var disX = 200, disY = 200;
    var T = 1000 * Math.sqrt(2 * disY / 98);
    requestAnimationFrame(function step() { 
   
        var p = Math.min(1.0, (Date.now() - startTime) / T);

        var tx = disX * p;
        var ty = disY * p * p;
        self.style.transform = 'translate(' + tx + 'px, ' +ty +  'px)';
        if(p < 1.0){
            requestAnimationFrame(step);
        }
    })

抛物线

5.简谐摆动

 circle.on('click', function() { 
   
    var self = this;
    var startTime = Date.now();
    var distance = 100;
    var T = 2000;
    requestAnimationFrame(function step() { 
   
        var p = Math.min(1.0, (Date.now() - startTime) / T);
        var tx = distance * Math.sin(2 * Math.PI * p);
        self.style.transform = 'translateX(' + tx + 'px)';
        if(p < 1.0){
            requestAnimationFrame(step);
        }
    })
})

摆动

6.正弦线

circle.on('click', function() { 
   
    var self = this;
    var startTime = Date.now();
    var distance = 100;
    var T = 2000;
    requestAnimationFrame(function step() { 
   
        var p = Math.min(1.0, (Date.now() - startTime) / T);
        var ty = distance * Math.sin(2 * Math.PI * p);
        var tx = 2 * distance * p;
        self.style.transform = 'translate(' + tx + 'px,'+ ty +'px)';
        if(p < 1.0){
            requestAnimationFrame(step);
        }
    })
})

正弦

7.圆周运动

circle.on('click', function() { 
   
    var self = this;
    var startTime = Date.now();
    var distance = 100;
    var T = 2000;
    var r = 100;
    requestAnimationFrame(function step() { 
   
        var p = Math.min(1.0, (Date.now() - startTime) / T);
        var rotation = p * 360;
        self.style.transformOrigin = 'r' + 'px ' + r + 'px';
        self.style.transform = 'rotate(' + rotation +'deg)';
        if(p < 1.0){
            requestAnimationFrame(step);
        }
    })

圆周运动

动画封装

可以将动画封装成通用的对象,每次只需要实例定义单帧执行函数就可以了。

参数:duration-动画持续时间,progress每一帧执行的函数,easing-缓动效果(可传可不传)
function Animator(duration, progress, easing) { 
   
    this.duration = duration;
    this.progress = progress;
    this.easing = easing || function(p){ 
   return p};
}
//调用start函数时可传入参数,如果参数为false或者传入的函数返回false,那么就说明进行循环动画,相当于将css animation中的animation-iteration-count:infinite
Animator.prototype.start = function(finished) { 
   
    var self = this;
    var startTime = Date.now();
    var duration = self.duration;

    requestAnimationFrame(function step(){ 
   
        var p = (Date.now() - startTime) / duration;
        var next = true;
        if(p < 1.0) {
            self.progress(self.easing(p), p);
        }else { //第一次动画之行完后开始执行回调函数
            if(typeof finished === 'function') {
                next = finished() === false;
            }else {
                next = finished === false;
            }
          //如果调用start时传递的参数为false或函数返回false,next便为true说明进行循环运动
            if(!next) {
                self.progress(self.easing(1.0), 1.0);
            }else {
                startTime += duration;  //如果这里不加的话那么小球不会循环,而是一直向前运动
                self.progress(self.easing(p), p);
            }
        }
       //next为true,动画继续执行
        if(next) {
            requestAnimationFrame(step);
        }
    })
}

目前这个函数存在的缺点就是虽然可以设置动画执行为一次或一直循环,但是并不能设置动画执行次数为2,3,4..,也不能设置动画循环的方向,即不能像css animation设置animation-direction

  • 折线运动
    让小球先向右运动再向下运动
var a1 = new Animator(1000, function(p) { 
   
    var tx = 100 * p;
    circle.style.transform = 'translateX(' + tx + 'px)';     
})
var a2 = new Animator(1000, function(p) { 
   
    var ty = 100 * p;
    circle.style.transform = 'translate(100px,' + ty + 'px)';   
})
a1.start(function(){ 
   
   a2.start();
})

折线运动

动画队列

为了能使多个动画顺序执行,需要用数组来模拟一个队列管理动画执行顺序。

function AnimationQueue(animators) { 
   
    this.animators = animators || [];
}
AnimationQueue.prototype = {
    append: function() { 
   
        var args = [].slice.call(arguments);
        this.animators.push.apply(this.animators, args);
    },
    flush: function() { 
   
        if(this.animators.length) {
            var self = this;
            function play() { 
   
                var animator = self.animators.shift();
                        //如果数组中的对象是Animator的实例,则直接调用
                if(animator instanceof Animator) {
                    animator.start(function() { 
   
                    if(self.animators.length) {
                            play();
                        }
                    })
                }else { //数组中的对象不是Animator的实例,调用Animator的方法,可以在这里将之前的对象再次添加到animators数组中
                    animator.apply(self);//通过这里可以进行循环运动
                    if(self.animators.length) {
                        play();
                    }
                }
            }
            play();
        }
    }
}
  • 弹跳的小球
    • 设20px为1米,下落距离为200px, 为10米
    • g = 10m/s
    • S = 1/2 * g * T^2 = 10
    • T = 1.414s = 1414ms
    • 下落阶段 St = S * p^2
    • 上升阶段 St = S – Sp * (2 – p)
var c1 = new Animator(1000, function(p) { 
   
    var ty = 200 * p * p;
    circle.style.transform = 'translateY(' + ty + 'px)';
})
var c2 = new Animator(1414, function(p) { 
   
    var ty = 200 - 200 * p * (2 - p);
    circle.style.transform = 'translateY(' + ty + 'px)';
})
circle.addEventListener('click', function() { 
   
    var animators = new AnimationQueue();
    animators.append(c1, c2, function execute() { 
   
        this.append(c1,c2, execute);
    });
    animators.flush();
})

弹跳

  • 弹跳幅度逐渐减小的小球
    • 上升时间:T = 0.7 * T
    • 上升距离:S = 0.49 * S

circle.addEventListener('click', function() { 
   
    var T = 1414;
    var a1 = new Animator(T, function(p) { 
   
        var s = this.duration * 200 / T;
        var ty = s * (p * p - 1);
        circle.style.transform = 'translateY(' 
      + ty + 'px)';     
    })
    var a2 = new Animator(T, function(p) { 
   
        var s = this.duration * 200 / T;
        var ty = - s * p * (2 - p);
        circle.style.transform = 'translateY(' 
      + ty + 'px)'; 
    })
    var animators = new AnimationQueue();
    function foo() { 
   
        a2.duration *= 0.7;
        if(a2.duration <= 0.0001) {
            animators.animators.length = 0;
        }
    }
    animators.append(a1, foo, a2, function b() { 
   
        a1.duration *= 0.7;
        this.append(a1, foo, a2, b);
    });
    animators.flush();
})

弹跳幅度减小的小球

  • 滚动的小球
    • 小球直径:d = 50px
    • 圆周长: l = π * d;
    • 周期: T = 2s
    • 滚动时间: t = 4s
    • 滚动距离:S = π * d * t / T = 314px
circle3.addEventListener('click', function() { 
   
    var a1 = new Animator(4000, function(p) { 
   
        var rotation = 'rotate(' + 720 * p + 'deg)';
        var x = 50 + 314 * p + 'px';
        circle3.style.transform = rotation;
        circle3.style.left = x;
    });
    var animators = new AnimationQueue();
    animators.append(a1, function b() { 
   
        animators.append(a1, b);
    })
    animators.flush();
})

滚动的小球

以上就是利用我们学过的常见物理公式实现的js动画效果。当然还可以有更多复杂的效果,如何实现各种优美的动画也是值得深入学习的。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/181724.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • 数据库置疑修复方法_msdb数据库置疑的解决方法

    数据库置疑修复方法_msdb数据库置疑的解决方法输入以下命令执行:USEMASTERGOSP_CONFIGURE’ALLOWUPDATES’,1RECONFIGUREWITHOVERRIDEGOUPDATESYSDATABASESSETSTATUS=32768WHERENAME=’置疑的数据库名’Gosp_dboption’置疑的数据库名’,’singleuser’,’true’GoDBCCCHECKDB(‘置疑的数据库名’,repair_allow_data_lo…

  • linux安装卸载软件的命令_shell命令卸载软件

    linux安装卸载软件的命令_shell命令卸载软件linux卸载软件命令Linuxprovidesdifferentmethodsforinstallingsoftware.YoucaninstallsoftwarefromthestandardUbuntusoftwarerepositoriesusingtheUbuntuSoftwareCenter,fromoutsideofthestan…

  • 从机械硬盘和固态硬盘的结构来看IO

    从机械硬盘和固态硬盘的结构来看IO“磁盘”这个词,对于程序员来说并不陌生,我们知道它是一种存储介质,主要用来存储数据的,可以说常用的中间件基本上都离不开它,比如我们常用的MySQL数据库、kafka消息引擎,甚至redis缓存都离不开磁盘。我们在优化某个业务逻辑的时候,经常需要用到缓存,尽量让热数据都从缓存里读取,因为我们知道磁盘是缓慢的,特别在高并发的场景下,我们要保证极少的请求走磁盘IO。不知道你有没有思考过以下问题: 机械硬盘为什么慢? 机械硬盘有多慢? kafka也是写磁盘的,它却挺快的,为什么?..

  • SQL中的聚合函数使用总结

    SQL中的聚合函数使用总结一般在书写sql的是时候很多时候会误将聚合函数放到where后面作为条件查询,事实证明这样是无法执行的,执行会报【此处不允许使用聚合函数】异常。为什么会报异常呢?其原因很简单:having放在groupby的后面 groupby后面只能放非聚合函数的列 where子句的作用是在对查询结果进行分组前,将不符合where条件的行去掉,即在分组之前过滤数据,条件中不能包含聚组函数,使…

  • golang 2021.10.3 激活码-激活码分享

    (golang 2021.10.3 激活码)好多小伙伴总是说激活码老是失效,太麻烦,关注/收藏全栈君太难教程,2021永久激活的方法等着你。IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.cn/100143.html1STL5S9V8F-eyJsaWNlbnNlSW…

  • stl库使用_餐厅库管年终总结个人总结

    stl库使用_餐厅库管年终总结个人总结1、STL库的含义STL(StandardTemplateLibrary),即标准模板库,是一个具有工业强度的,高效的C++程序库。2、STL的好处STL作为一种标准,便于交流,掌握它,一方面可以让你写的程序,易于让别人理解,另一方面你也能够比较容易地理解别人写的程序。3、STL的关键概念要使用STL,要了解以下几个基本概念:容器:可以把它理解为存放数据的地方,常用的一些容器有链表(list)栈(stack)动态数组(vector…

    2022年10月15日

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号