两周前,项目里需要实现一个红心飘飘的点赞效果。抓耳挠腮了老半天,看了几篇大佬的文章,终于算是摸了个七七八八。不禁长叹一声,还是菜啊。先来看一下效果:(传送门进去点一波)

一、Bezier曲线运动轨迹

其实用大白话描述一下需求就是让一个红心图片沿着贝塞尔曲线的轨迹走,然后边走边消失。核心在于得到贝塞尔曲线上的一系列点。本文不会讲解贝塞尔曲线的原理,因为大佬们已经讲过了,而且讲的比我好。参考文章如下:

其中第二篇文章讲到了生成二阶和三阶贝塞尔曲线可以使用canvas自带的方法:quadraticCurveTobezierCurveTo,而高阶的则先得到曲线上一系列的点,然后顺次连接这些点来拟合高阶的贝塞尔曲线。没错,我们要的就是这一系列的点,有了这些点,就可以控制红心的轨迹了。下面是我基于作者的BezierMarker.js写的一个demo,可以直观地看出高阶贝塞尔曲线上的点:

See the Pen XyWZXj by imgss (@imgss) on CodePen.

上面100个曲线上的点坐标是由下面这段代码计算得出的:

BezierMaker.prototype.bezier = function(t) { //贝塞尔公式调用
var x = 0,
y = 0,
bezierCtrlNodesArr = this.bezierCtrlNodesArr,
n = bezierCtrlNodesArr.length - 1,
self = this
bezierCtrlNodesArr.forEach(function(item, index) {
if(!index) {
x += item.x * Math.pow(( 1 - t ), n - index) * Math.pow(t, index)
y += item.y * Math.pow(( 1 - t ), n - index) * Math.pow(t, index)
} else {
x += self.factorial(n) / self.factorial(index) / self.factorial(n - index) * item.x * Math.pow(( 1 - t ), n - index) * Math.pow(t, index)
y += self.factorial(n) / self.factorial(index) / self.factorial(n - index) * item.y * Math.pow(( 1 - t ), n - index) * Math.pow(t, index)
}
})
return {
x: x,
y: y
}
}

这个方法就是对贝塞尔公式的实现。以3阶贝塞尔公式为例(见下图),它的方程需要四个控制点(P1,P2,P3,P4)和一个t值,就能计算出曲线上的某一点的坐标。


根据给定的`t`值,结合控制点的坐标,算出相应`t`值下的贝塞尔曲线上的点的坐标。拿下图(来自第一篇文章)来说,给定`t`值为0.25,就可以得到B点的坐标

当将t由0递增到1时,就可以得到100个曲线上的点,进而拟合出相应的曲线。当我们拿到这一系列点时,其实问题已经解决了一大半了。

二、使红心飘起来

拿到拟合点数组后,绘制轨迹就是从数组中依次拿出坐标,并将红心图片绘制到相应的坐标上。并根据当前拟合点在曲线数组中的位置,改变图片的不透明度,就可以让红心飘起来了,上一部分代码,讲解见注释:

// 生成随机数
function rnd () {
let flag = Math.random() > 0.5 ? 1 : -1
return 80 * Math.random() * flag
} class FlyHeart {
constructor (ctx, img) {
this.ctx = ctx;
this.img = heart;
// 拿到红心的运动轨迹,一系列拟合点坐标
this.bezierArr = new BezierMaker(ctx, [
{x: 187, y: 245},
{x: 170 + rnd(), y: 200},
{x: 200 + rnd() , y: 120},
{x: 140 + rnd(), y: 60}], 90).bezierArr //90表示拟合点的数量,rnd使红心的轨迹有一定的随机性
}
draw () {
// 依次取出轨迹的每个点
let position = this.bezierArr.shift(); // 清除上次画的
this.clear(); if (position) {
this.ctx.save()
// 根据当前数组长度算出透明度
this.ctx.globalAlpha = this.bezierArr.length / 30;
this.ctx.drawImage(this.img, position.x , position.y, 20, 20);
this.ctx.restore();
this.prevPosition = position;
}
}
// 清除上次画的
clear () {
if (this.prevPosition) {
this.ctx.clearRect(this.prevPosition.x, this.prevPosition.y, 20, 20);
}
}
}

接下来就是给body添加点击事件,当点击时,就新生成一个红心:

  document.body.addEventListener('click', function() {
heartArr.push(new FlyHeart(ctx, heart));
}) let heartArr = []
const cvs = document.getElementById('cvs')
const ctx = cvs.getContext('2d')
const heart = document.getElementById('heart') //图片 function draw () {
if(heartArr.length) {
for(let heart of heartArr) {
heart.draw();
if(heart.bezierArr.length === 0) {
heart.clear();
let index = heartArr.indexOf(heart)
heartArr.splice(index, 1)
}
}
}
requestAnimationFrame(draw)
}
draw()

三、后记

当时看到这个需求的时候,真的是一筹莫展,看到n阶贝塞尔曲线时更是一头雾水,但是看不懂也要看,然后看着看着,看多了也就慢慢明白了。希望没浪费大家的时间,各位看官看完后有所收获(完)

用canvas实现红心飘飘的动画效果的更多相关文章

  1. 多种方法实现Loading(加载)动画效果

    当我们ajax提交一个按钮的时候,给那个按钮来个Loading效果会高端很多,体验也会上升个层次. 既能让用户知道正在提交中,也能防止二次提交,好处多多呢.

  2. (转)多种方法实现Loading(加载)动画效果

    当我们ajax提交一个按钮的时候,给那个按钮来个Loading效果会高端很多,体验也会上升个层次. 既能让用户知道正在提交中,也能防止二次提交,好处多多呢.

  3. html5 canvas首屏自适应背景动画循环效果代码

    模板描述:html5 canvas首屏自适应背景动画循环效果代码 由于动态图太大,怕以后服务器受不了,所以现在都改为静态图了,大家点击演示地址一样的,希望大家喜欢,你们的支持就是小海的动力!! 欢迎大 ...

  4. 基于canvas实现物理运动效果与动画效果(一)

    一.为什么要写这篇文章 某年某月某时某种原因,我在慕课网上看到了一个大神实现了关于小球的抛物线运动的代码,心中很是欣喜,故而写这篇文章来向这位大神致敬,同时也为了弥补自己在运动效果和动画效果制作方面的 ...

  5. 7个惊艳的HTML5 Canvas动画效果及源码

    HTML5非常强大,尤其是现在大部分浏览器都支持HTML5和CSS3,用HTML5制作的动画也多了起来.另外,Canvas上绘制图形非常简单,本文就分享了一些强大的HTML5 Cnavas动画,一起来 ...

  6. HTML5 Canvas动画效果演示

    HTML5 Canvas动画效果演示 主要思想: 首先要准备一张有连续帧的图片,然后利用HTML5 Canvas的draw方法在不同的时间 间隔绘制不同的帧,这样看起来就像动画在播放. 关键技术点: ...

  7. 使用Canvas实现动画效果 | DKlogs -- 设计 | 生活

    使用Canvas实现动画效果 | DKlogs -- 设计 | 生活 使用Canvas实现动画效果

  8. HTML5 Canvas动画效果演示 - 流浪的鱼 - 博客频道 - CSDN.NET

    HTML5 Canvas动画效果演示 - 流浪的鱼 - 博客频道 - CSDN.NET HTML5 Canvas动画效果演示

  9. HTML5 Canvas动画效果实现原理

    在线演示 使用HTML5画布可以帮助我们高速实现简单的动画效果.基本原理例如以下: 每隔一定时间绘制图形而且清除图形,用来模拟出一个动画过程,能够使用context.clearRect(0, 0, x ...

随机推荐

  1. No rule to make target '/usr/lib/x86_64-linux-gnu/libproj.so ,needed by '../bin/generate_pointcloud解决方法

    这是/usr/lib/x86_64-linux-gnu/文件夹内没有这个libproj.so 库,先在该文件夹内搜索是否有同名不同版本的库,如果有 ,可以使用ln -s在该文件夹内部对存在的库链接到一 ...

  2. Desktop Central 的移动设备管理功能

    Desktop Central 的移动设备管理功能1.移动应用程序管理设备管理不会仅仅只是配置策略.检索资产信息和保护设备.应用程序管理与设置员工的移动设备一样重要.使用 Desktop Centre ...

  3. c++中段自评

    不知不觉,学期已过一大半.也是时候对自己的编程水平重新进行一次评估了. 1.通过最近的中段测试和acm新手赛的洗礼,以及之前的课前预习.课中学习.和课后作业的锻炼,我逐渐体会到编程语言的魅力同时也理解 ...

  4. (PMP)第4章-----项目整合管理

    4.1 制定项目章程 输入 工具与技术 输出 1.商业文件 (商业论证,效益管理计划) 1.专家判断 1.项目章程 2.协议 2.数据收集 (头脑风暴,焦点小组,访谈) 2.假设日志 3.事业环境因素 ...

  5. Effective Java -- 使可变性最小化

    为了使类成为不可变的,应该遵循以下五条原则: 1. 不要提供任何会下盖对象状态的方法 2. 保证类不会被扩展 3. 使所有的域都是final的 4. 使所有的域都成为私有的 5. 确保对于任何可变组件 ...

  6. ubuntu 安装vue+element

    1.安装npm sudo apt install npm 检测安装npm -v 因为npm安装软件慢,可设置淘宝镜像 npm config set registry https://registry. ...

  7. [Solution] JZOJ-5818 做运动

    [Solution] JZOJ-5818 做运动 Time Limits:2000ms Memory Limits:524288KB Description 一天,Y 君在测量体重的时候惊讶的发现,由 ...

  8. Windows7+IIS+PHP7+MySQL5.7环境搭建

    IIS配置 本次搭建使用的系统是Windows7,Windows8,10与此类似. 开启IIS 开始-->控制面板-->程序和功能,点击左边栏的开启或关闭Windows功能,如图: 选择I ...

  9. MyBatis配置C3P0连接池

    一.导包 c3p0包     mybatis包 数据库的连接包 二.继承UnpooledDataSourceFactory的类 Mybatis 没有帮开发者实现 c3p0 数据库连接池,故需要使用者自 ...

  10. 【转】RPC介绍

    转自:http://www.cnblogs.com/Vincentlu/p/4185299.html 摘要: RPC——Remote Procedure Call Protocol,这是广义上的解释, ...