不知不觉就已经好久没写过博客了,自从七月正式毕业后,离开了实习了将近九个月的老东家,进了鼠厂后,做的事都是比较传统的前端活,之前在tpy的时候只管做移动h5的特效以及小游戏,再加上实习所以时间比较充裕,canvas玩的比较多,而现在因为工作都是些传统前端工作,而且也忙,就基本上没再写过canvas相关的效果了。这个博客自己只是想分享一些自己做过的一些好玩的demo,所以正经的那些项目心得、插件什么的就基本上都不会放上来了。

  刚好昨天的时候闲了下来,就看了一下以前写的一些玩意,所以又想折腾下以前很喜欢折腾的粒子了。其实原理差不多,就是变着法子折腾,顺便自己也复习一下。这次的demo除了粒子运动之外,还加了鼠标的干涉。所以自己觉得还是有点搞头,所以就分享一下。

  先上个demo 效果:http://whxaxes.github.io/canvas-test/src/Particle-demo/orangutan/index.html   ,表示不要再说什么在低版本IE上没效果之类的,这个是H5啊,同时最好在chrome上看,其他浏览器我都没测,纯碎为了好玩而做出来。有兴趣的可以把代码拷回去自己深究。

  图片或文字都可以分解成粒子。原理此前的博客都有说过,不过也再简单啰嗦一下,就是先将图片或者文字画在canvas上,然后通过画布对象的getImageData获取到画布上的所有像素点,也就是imageData对象的data数组,存放着画布的所有像素的rgba值。

  然后再遍历像素点,获取到当前像素点的rgba的a值也就是alpha透明度不为0,我直接舍弃了地透明度的,所以我写的判断是直接大于125就行了,255为不透明。更具体的原理可查看此前我的这个博文:随便谈谈用canvas来实现文字图片粒子化

  获取到粒子的位置后,就实例化出粒子对象,代码如下:

ctx.drawImage(img, this.imgx, this.imgy, img.width, img.height);
var imgData = ctx.getImageData(this.imgx, this.imgy, img.width, img.height); for (var x = 0; x < img.width; x += particleSize_x) {
for (var y = 0; y < img.height; y += particleSize_y) {
var i = (y * imgData.width + x) * 4; if (imgData.data[i + 3] >= 125) {
var color = "rgba(" + imgData.data[i] + "," + imgData.data[i + 1] + "," + imgData.data[i + 2] + "," + imgData.data[i + 3] + ")"; var x_random = x + Math.random() * 20,
vx = -Math.random() * 200 + 400,
y_random = img.height/2 - Math.random() * 40 + 20,
vy; if (y_random < this.imgy + img.height / 2) {
vy = Math.random() * 300;
} else {
vy = -Math.random() * 300;
} particleArray.push(new Particle(x_random + this.imgx,y_random + this.imgy,x + this.imgx,y + this.imgy,vx,vy,color)); particleArray[particleArray.length - 1].drawSelf();
}
}
}

  将实例化的粒子对象扔进一个数组里保存起来。然后执行动画循环。 

particleArray.sort(function (a, b) {
return a.ex - b.ex;
}); if (!this.isInit) {
this.isInit = true;
animate(function (tickTime) {
if (animateArray.length < particleArray.length) {
if (that.end > (particleArray.length - 1)) {
that.end = (particleArray.length - 1)
}
animateArray = animateArray.concat(particleArray.slice(that.start, that.end)) that.start += that.ite;
that.end += that.ite;
} animateArray.forEach(function (i) {
this.update(tickTime);
})
})
}

  animate方法的回调即为每次画布逐帧循环时调用的方法,其中animateArray就是真正用于放置于循环舞台的粒子对象,也就是上面demo中看到的从左到右一个一个粒子出现的效果,其实就是从particleArray中取粒子对象,在每一帧中扔几十个进animateArray中,所以就有了粒子一个一个出来的效果。

  animate方法代码如下:

var tickTime = 16;
function animate(tick) {
if (typeof tick == "function") {
var tickTime = 16; ctx.clearRect(0, 0, canvas.width, canvas.height); tick(tickTime); RAF(function () {
animate(tick)
})
}
}

  这个代码就比较简单了,设置每一帧之间的时间差,我一般是设成16毫秒,这个就自己看哈,给tick方法传参循环。

  在逐帧循环回调中,触发每个粒子对象的update,其中粒子的运动函数,绘画函数全部会由update函数触发。

  下面这个是粒子对象的封装,其中x,y为粒子的位置,ex,ey为粒子的目标位置,vx,vy为粒子的速度,color为粒子的颜色,particleSize为粒子的大小,stop是粒子是否静止,maxCheckTimes和checkLength和checkTimes是检测粒子是否静止的属性,因为粒子在运动的时候,位置是无时无刻都在变化,所以是没有绝对静止的,所以需要手动检测是否约等于静止,然后再给予粒子静止状态,当粒子与目标位置的距离小于checkLength,并且在连续10帧的检测都粒子与距离目标都是小于checkLength,则说明粒子约等于静止了,将粒子的stop属性置为true,再接下来的动画逐帧循环中,对于stop为true的粒子则不进行运动计算:

function Particle(x, y, ex, ey, vx, vy, color) {
this.x = x;
this.y = y;
this.ex = ex;
this.ey = ey;
this.vx = vx;
this.vy = vy;
this.a = 1500;
this.color = color;
this.width = particleSize_x;
this.height = particleSize_y; this.stop = false;this.maxCheckTimes = 10;
this.checkLength = 5;
this.checkTimes = 0;
} var oldColor = "";
Particle.prototype = {
constructor: Particle, drawSelf: function () {
if (oldColor != this.color) {
ctx.fillStyle = this.color;
oldColor = this.color
} ctx.fillRect(this.x - this.width / 2, this.y - this.height / 2, this.width, this.height);
}, update: function (tickTime) {
if (this.stop) {
this.x = this.ex;
this.y = this.ey;
} else {
tickTime = tickTime / 1000;
var cx = this.ex - this.x;
var cy = this.ey - this.y;
var angle = Math.atan(cy / cx);
var ax = Math.abs(this.a * Math.cos(angle));
ax = this.x > this.ex ? -ax : ax var ay = Math.abs(this.a * Math.sin(angle));
ay = this.y > this.ey ? -ay : ay; this.vx += ax * tickTime;
this.vy += ay * tickTime;
this.vx = ~~this.vx * 0.95;
this.vy = ~~this.vy * 0.95;
this.x += this.vx * tickTime;
this.y += this.vy * tickTime; if (Math.abs(this.x - this.ex) <= this.checkLength && Math.abs(this.y - this.ey) <= this.checkLength) {
this.checkTimes++;
if (this.checkTimes >= this.maxCheckTimes) {
this.stop = true;
}
} else {
this.checkTimes = 0
}
} this.drawSelf(); this._checkMouse();
}, _checkMouse: function () {
if (!mouseX) {
if (this.recordX) {
this.stop = false;
this.checkTimes = 0; this.a = 1500;
this.ex = this.recordX;
this.ey = this.recordY; this.recordX = null;
this.recordY = null;
}
return;
} var distance = Math.sqrt(Math.pow(mouseX - this.x, 2) + Math.pow(mouseY - this.y, 2));
var angle = Math.atan((mouseY - this.y) / (mouseX - this.x));
if (distance < mouseRadius) {
this.stop = false;
this.checkTimes = 0; if (!this.recordX) {
this.recordX = this.ex;
this.recordY = this.ey;
} this.a = 2000; var xc = Math.abs((mouseRadius - distance) * Math.cos(angle));
var yc = Math.abs((mouseRadius - distance) * Math.sin(angle));
xc = mouseX > this.x ? -xc : xc;
yc = mouseY > this.y ? -yc : yc;
this.ex = this.x + xc;
this.ey = this.y + yc;
} else {
if (this.recordX) {
this.stop = false;
this.checkTimes = 0; this.a = 1500;
this.ex = this.recordX;
this.ey = this.recordY; this.recordX = null;
this.recordY = null;
}
}
}
};

  粒子的方法中,drawself为粒子的绘制自身的方法,画布的绘制对象的方法的调用次数越少,对整个动画的性能提升越大。因此,把粒子画成正方形,因为画正方形只需调用一个fillRect方法,而如果画圆形则需要先调用beginPath开始路径的绘制,再调用arc绘制路径,最后再通过fill填充颜色。性能方面肯定是画正方形性能更好,于是直接用fillRect。而也对粒子的color进行缓存,如果连续绘制的多个粒子颜色相同,就不用重复调用fillStyle方法更新画笔颜色。

  然后是update方法,这个方法是粒子运动的核心,但是原理很简单,就是一些简单的运动学知识,获取到粒子与目标点夹角的角度,通过角度将粒子的加速度分解为水平和垂直加速度,再计算出粒子在新的一帧的水平速度和垂直速度,然后再通过新的速度计算出粒子新的位置,最后再绘制出来。update方法底部的if else则是判断粒子是否静止的代码。

  粒子的最后一个方法,checkmouse其实就是检测鼠标位置,如果粒子跟鼠标的距离小于15,则将粒子的目标位置置于与鼠标距离为15的地方,为了保证鼠标移开后粒子还能回到原来的地方,所以用了个recordX和recordY来记录粒子初始的位置,当鼠标离开粒子时,重置粒子的目标位置。从而让粒子回到原来的位置。

  基本上整个的原理就这样,代码有时会有所更新,若要最新源码,请直接访问github地址:

  https://github.com/whxaxes/canvas-test/tree/gh-pages/src/Particle-demo/orangutan

 

  

html5 canvas 粒子特效的更多相关文章

  1. 16个富有创意的HTML5 Canvas动画特效集合

    HTML5技术正在不断的发展和更新,越来越多的开发者也正在加入HTML5阵营,甚至在移动开发上HTML5的地位也是越来越重要了.HTML5中的大部分动画都是通过Canvas实现,因为Canvas就像一 ...

  2. 16个非常有趣的HTML5 Canvas动画特效集合

    HTML5技术正在不断的发展和更新,越来越多的开发者也正在加入HTML5阵营,甚至在移动开发上HTML5的地位也是越来越重要了.HTML5中的大部分动画都是通过Canvas实现,因为Canvas就像一 ...

  3. 纯JavaScript实现HTML5 Canvas六种特效滤镜

    纯JavaScript实现HTML5 Canvas六种特效滤镜  小试牛刀,实现了六款简单常见HTML5 Canvas特效滤镜,并且封装成一个纯 JavaScript可调用的API文件gloomyfi ...

  4. 分享8款令人惊叹的HTML5 Canvas动画特效

    HTML5的确可以制作出非常绚丽的网页动画效果,尤其是利用HTML5 Canvas特性和HTML5 3D特性,我们更加可以欣赏到超酷的动画特效.今天我从html5tricks网站上整理了8款令人惊叹的 ...

  5. 基于HTML5 Canvas粒子效果文字动画特效

    之前我们分享过很多超酷的文字特效,其中也有利用HTML5和CSS3的.今天我们要来分享一款基于HTML5 Canvas的文字特效,输入框中输入想要展示的文字,回车后即可在canvas上绘制出粒子效果的 ...

  6. 前端特效demo | 值得收藏的6个 HTML5 Canvas 实用案例

    HTML5 动画在Canvas 上得到了充分的发挥,我们 VIP 视频也分享过很多相关的动画特效制作视频,这次给大家带来 6 款超炫酷的HTML5 canvas 动画的 demo,一起来看看吧~ 文内 ...

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

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

  8. 10大炫酷的HTML5文字动画特效欣赏

    文字是网页中最基本的元素,在CSS2.0时代,我们只能在网页上展示静态的文字,只能改变他的大小和颜色,显得枯燥无味.随着HTML5的发展,现在网页中的文字样式变得越来越丰富了,甚至出现了文字动画,HT ...

  9. 基于HTML5 Canvas生成粒子效果的人物头像

    前面我们分享过一个HTML5 Canvas实现的图像马赛克模糊效果,HTML5处理图片真的非常简单.今天我们要再利用HTML5 Canvas实现一个粒子效果的人物头像,你可以任意选择一张头像图片,接下 ...

随机推荐

  1. .Net 三款工作流引擎比较:WWF、netBPM 和 ccflow

    下面将对目前比较主流的三款工作流进行介绍和比较,然后通过三款流程引擎分别设计一个较典型的流程来给大家分别演示这三款创建流程的过程.这三款工作流程引擎分别是 Windows Workflow Found ...

  2. Group By Count不能显示0的问题

    问题: 如对表: /*==================================================== id |score |grade ------------------- ...

  3. 编写一个Java项目,定义包,在包下定义包含main方法的类,在main方法中声明8种基本数据类型的变量并赋值,练习数据类型转换。

  4. Tomcat 服务器版本的区别以及下载与安装

    Tomcat是Apache 软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,由Apache.Sun 和其他一些公司及个人共同开发而成.由于有了 ...

  5. mysql sql获取上条插入id,update影响行数

    1.获取上条插入数据 LAST_INSERT_ID(); 2.获取update影响行数. ROW_COUNT(); mysql> UPDATE t -> SET address = 'be ...

  6. 三星嵌入式开发平台 三星Cortex-A9 4412 POP与SCP对比

    iTOP-4412核心板是迅为电子推出的一款高端四核核心板,其中分为POP封装与SCP封装,配备三星Exynos 4412四核处理器,主频为1.4GHz,内置16GB存储空间.该板设计小巧.配备三星自 ...

  7. dotnet use regex two samples

    One sample is used to replace double quote from words which encapsulated by csvwriter , you know csv ...

  8. HDU 5056 Boring Count --统计

    题解见官方题解,我这里只实现一下,其实官方题解好像有一点问题诶,比如 while( str[startPos] != str[i+1] ) cnt[str[startPos]]--, startPos ...

  9. AppScan Source V8.8 中弃用的功能

    从 AppScan Source V8.8 开始,不再支持以下操作系统: Microsoft Windows XP Microsoft Windows Server 2003,所有版本和修订版   此 ...

  10. JavaScript---Ajax和函数回调,异步编程

    一 Ajax 函数的定义  :  Asynchronous JavaScript and XML(异步的 JavaScript 和 XML),无刷新的从服务器读取数据,可以在不重新加载整个网页的情况下 ...