一、学习背景与效果

前些天翻大神blog,看到了张鑫旭大神写的一篇《canvas图形绘制之星空、噪点与烟雾效果》,深受启发。详细了研究了一下烟雾效果的代码,效果如下: 动态效果请点击。(!-- 去掉了原文中的背景图 --!)

效果图: 

代码如下:

<!DOCTYPE html>
<html><head><title>canvas实现的烟雾缭绕效果</title><style>.smoke {height: 500px;background: #fff;background-size: cover;position: relative;}.smoke canvas {height: 100%;width: 100%;}</style>
</head><body><div id="main"><h1>canvas实现的烟雾缭绕效果实例页面</h1><div id="body" class="light"><div id="content" class="show"><h3>展示</h3><div class="smoke"><canvas id="smokeCanvas"></canvas></div></div></div></div><script>// canvas烟雾缭绕效果var canvasSmoke = function (canvas, options) {var defaults = {count: 30,velocity: 2,fps: 30,url: 'smoke.png'};options = options || {};// 参数合并var params = {};for (var key in defaults) {params[key] = options[key] || defaults[key];}// 创建存储粒子的数组var particles = [];// 渲染的粒子数目var particleCount = params.count;// 每个方向的最大速度var maxVelocity = params.velocity;// 每秒多少帧var targetFPS = params.fps;// canvas元素var eleCanvas = canvas;if (!eleCanvas) {return this;}// 画布的尺寸var canvasWidth = eleCanvas.clientWidth;var canvasHeight = eleCanvas.clientHeight;eleCanvas.width = canvasWidth;eleCanvas.height = canvasHeight;// 创建图片对象var imageObj = new Image();// 一旦图像被下载,然后在所有的颗粒上设置图像imageObj.onload = function () {particles.forEach(function (particle) {particle.setImage(imageObj);});};// 烟雾图片地址imageObj.src = params.url;// 粒子实例方法function Particle(context) {// 设置初始位置this.x = 0;this.y = 0;// 纵横速度this.xVelocity = 0;this.yVelocity = 0;// 圆角大小this.radius = 2;// 存储上下文,绘制的时候需要this.context = context;// 绘制粒子的具体方法this.draw = function () {// 如果图片,则绘制if (this.image) {this.context.globalAlpha = this.alpha;// 烟雾缭绕就看这里了// 这是宽度,是动态的var fillWidth = canvasWidth / 2,fillHeight = fillWidth - fillWidth * (this.x / canvasWidth * this.y / canvasHeight);this.context.drawImage(this.image, 0, 0, this.imageWidth, this.imageHeight, this.x, this.y, fillWidth,fillHeight);}};// 刷新粒子this.update = function () {// 改变粒子的this.x += this.xVelocity;this.y += this.yVelocity;// 如果到了右边缘if (this.x >= canvasWidth) {this.xVelocity = -this.xVelocity;this.x = canvasWidth;}// 检测是否到了左边缘else if (this.x <= 0) {this.xVelocity = -this.xVelocity;this.x = 0;}// 底边缘if (this.y >= canvasHeight) {this.yVelocity = -this.yVelocity;this.y = canvasHeight;}// 是否上边缘else if (this.y <= 0) {this.yVelocity = -this.yVelocity;this.y = 0;}// 越靠近边缘,透明度越低// 纵向透明度变化要比横向的明显this.alpha = (1 - Math.abs(canvasWidth * 0.5 - this.x) / canvasWidth) * (0.7 - Math.abs(canvasHeight *0.5 - this.y) / canvasHeight);};// 设置粒子位置方法this.setPosition = function (x, y) {this.x = x;this.y = y;};// 设置速度方法this.setVelocity = function (x, y) {this.xVelocity = x;this.yVelocity = y;};this.setImage = function (image) {this.imageWidth = image.width;this.imageHeight = image.height;this.image = image;}}// 生成一个min,max大小之间的随机数function generateRandom(min, max) {return Math.random() * (max - min) + min;}// canvas上下文var context;// 初始化常见function init() {var canvas = eleCanvas;if (canvas.getContext) {// 绘图都需要这条语句context = canvas.getContext('2d');// 创建粒子,并设置他们的位置什么的,当然都是随机的for (var i = 0; i < particleCount; ++i) {var particle = new Particle(context);// 随机位置particle.setPosition(generateRandom(0, canvasWidth), generateRandom(0, canvasHeight));// 设置随机速度particle.setVelocity(generateRandom(-maxVelocity, maxVelocity), generateRandom(-maxVelocity, maxVelocity));particles.push(particle);}}}// 初始化init();// 绘制方法function draw() {// 清除绘制//context.fillStyle = "rgba(0, 0, 0, 0)";context.clearRect(0, 0, canvasWidth, canvasHeight);// 绘制所有粒子particles.forEach(function (particle) {particle.draw();});}// 刷新function update() {particles.forEach(function (particle) {particle.update();});}// 开始绘制if (context) {setInterval(function () {// 绘制前先更新位置什么的update();// 绘制draw();}, 1000 / targetFPS);}};// IE9+烟雾效果走起if ([].map) {canvasSmoke(document.querySelector('#smokeCanvas'));}</script>
</body></html>

效果实现的好不好,关键的代码注释里面已经标出来了,就是这行:
fillHeight = fillWidth - fillWidth * (this.x / canvasWidth * this.y / canvasHeight);

大家进行试验的时候,可以试着修改一下fillHeight的生成函数,产生的效果会很不同。为什么函数这样取值可以实现好的效果呢?

在坐标系中根据函数取点画图就可以明白,这个函数可以让烟雾图片的实例在面上更加连续的去展示。因为每个实例的取点都是伪随机的,所以很容易点都随机到一条线上,导致动画看起来不真实,即烟雾不是那么飘逸。按这个函数取值,可以大概率的保证烟雾实例的变化,在面上保证实例初始化后的连续性,让效果看着更加飘逸。

大神blog中的几个例子充分说明了,canvas绘图去实现动画效果好与差,与想象力紧密相关呀,数学具象化的能力很重要啊(努力提升中)。大家有时间可以多试试其他不同函数出现的效果,来加深影响。

canvas烟雾效果学习相关推荐

  1. html真实雾效果图,HTML5 Canvas逼真烟雾效果js插件解析

    简要教程 smoke.js是一款基于HTML5 Canvas的逼真烟雾特效js插件.通过该js插件,可以非常轻松的在页面中制作出各种烟雾效果. 使用方法 在页面中引入smoke.js文件. HTML结 ...

  2. threejs fire 火焰与烟雾效果

    在threejs中有一个为我们提供了可以实现火焰和烟雾效果的包,我们可以直接引用这个包,通过设置某些参数实现需要的效果. 第一步引入fire包,可在工程文件夹下的example文件夹中找到 <s ...

  3. html真实雾效果图,HTML5Canvas逼真烟雾效果js插件

    简要教程 smoke.js是一款基于HTML5 Canvas的逼真烟雾特效js插件.通过该js插件,可以非常轻松的在页面中制作出各种烟雾效果. 使用方法 在页面中引入smoke.js文件. HTML结 ...

  4. 用vite命令搭个react移动端项目,实现canvas碰撞效果(按需导入antd-mobile,pxtorem适配)

    前言 最近看见大家都在卷react源码,突然就心慌了.但是自己的操作水平还有待提高,现在看源码也需要循序渐进的,打算还是从写代码慢慢理解功能再去看源码.所以就尝试使用vite这个构建工具进行尝试构建一 ...

  5. 教你实现一个朴实的Canvas时钟效果

    摘要:今天教大家写一个canvas的时钟案例,效果可能看起来比较简单,没有那些花里胡哨的. 本文分享自华为云社区<如何实现一个朴实无华的Canvas时钟效果>,作者: 北极光之夜.. 一. ...

  6. canvas下雪效果(原生js)

    效果展示: 源码展示: <!doctype html> <html> <head><meta charset="utf-8">< ...

  7. 6 cocos2dx粒子效果,类图关系,系统原生粒子和自定义粒子效果,粒子编译器软件,爆炸粒子效果,烟花效果,火焰效果,流星效果,漩涡粒子效果,雪花效果,烟雾效果,太阳效果,下雨效果

     1 粒子 示例 2 类图关系 3 系统原生粒子 CCParticleSystem 所有粒子系统的父类 CCParticleSystemPoint. CCParticleSystemQuad 点粒 ...

  8. 使用expression design制作silverlight LOGO那种烟雾效果教程(翻译)

    很久没有给网站更新东西了,因为很忙,马上又要考四级了,多半又过不了.惨啊....因为英语的原因吧,就翻译了国外的一篇技术文章,这样即更新了网站又学了英语. 原文地址:http://geekswithb ...

  9. 真实烟雾效果PS笔刷

    60 Real Smoke Photoshop Stamp Brushes是一套真实烟雾效果PS笔刷,包含60款不同效果的笔刷样式,内个画笔纹理都是高分辨率的,可与任何photoshop版本配合使用, ...

最新文章

  1. 2022-2028年中国汽车印制电路板(汽车PCB)产业深度调研及投资前景预测报告
  2. 【转】为什么有天线的路由器信号还不如没有天线的路由
  3. 我为什么更喜欢 Mac OS X
  4. webpack 入口文件 php,webpack,jsx_webpack jsx 找不到入口文件,webpack,jsx - phpStudy
  5. struct2 开发环境搭建 问题
  6. linux vlc流媒体服务器,vlc media server rtsp 流媒体服务器搭建成功经验分享
  7. linux网络编程之字节序
  8. AT91RM9200Linux移植笔记(三)-移植Linux kernel 2.6.17
  9. Github Pages建立个人博客
  10. For input string:
  11. Yaffs2根文件系统制作
  12. 爱奇艺、腾讯视频等接连涨价 地主家也没有余粮了?
  13. 九、注解、有助于更好的理解框架
  14. mysql查询员工表中所有员工入职20个月之后的日期_新员工入职指南
  15. 关于第三方支付,看这篇文章就够了!
  16. 使用内网开发微信公众号
  17. 每日10行代码82:网上购物活动满减凑单计算器
  18. 啤酒与尿布:数据分析相关性分析案例一
  19. 大数据技能修炼的个人道场
  20. 钱多多的程序猿的2020大计划

热门文章

  1. jdbc连接mysql工具类_jdbc之工具类DBUtil的使用
  2. python漂亮gui界面模板下载_Python GUI教程(十六):在PyQt5中美化和装扮图形界面...
  3. 智慧电子班牌系统源码,家校互联APP源码,SaaS云平台源码
  4. 如何把数字证书导入到Windows根证书存储区
  5. 百科词条创建:百科创建词条的规则及具体步骤!
  6. html5 css橡皮筋效果,阻止移动端浏览器下拉橡皮筋效果(下拉滚动露底)
  7. [杂想]浑浑噩噩度日
  8. mysql最大错误连接数_超过mysql最大连接的错误
  9. Android 升级提示 No space left on device
  10. 案例:Oracle报错ASM磁盘组不存在或没有mount