分享web开发知识

注册/登录|最近发布|今日推荐

主页 IT知识网页技术软件开发前端开发代码编程运营维护技术分享教程案例
当前位置:首页 > 运营维护

(自己看)HTML5 Canvas下雨动画DEMO演示

发布时间:2023-09-06 01:21责任编辑:蔡小小关键词:HTML动画

1.开篇

1.1本文目标

本次的实例是HTML5 Canvas下雨动画DEMO演示,用到的知识主要是canvas和一个js的库dat.gui,感觉这个库老猛了,有空看一下。

2.正文

2.1代码

首先是canvas绘画部分代码

下雨的绘制:

 1 ctx.beginPath(); 2 var rain_height = Rain.height * dpr; 3 for (var i = rain.length - 1; i >= 0; i--) { 4 ????var r = rain[i]; 5 ????var real_x = r.x * dpr; 6 ????var real_y = r.y * dpr; 7 ????ctx.moveTo(real_x, real_y); 8 ????ctx.lineTo(real_x - demo.wind * r.z * dpr * 1.5, real_y - ?????9 ????????rain_height * r.z);10 }11 ctx.lineWidth = Rain.width * dpr;12 ctx.strokeStyle = demo.rain_color;13 ctx.stroke();

雨水溅开水花的绘制:

1 for (var i = drops.length - 1; i >= 0; i--) {2 ????var d = drops[i];3 ????var real_x = d.x * dpr - d.radius;4 ????var real_y = d.y * dpr - d.radius;5 ????ctx.drawImage(d.canvas, real_x, real_y);6 }

这里记录几个点,首先说的是绘制用到的dpr,也就是设备像素比(devicePixelRatio),从这里的代码可以看到,canvas最终绘制的宽高和位置都是要乘以dpr,那照着dpr的公式看canvas绘制的是设备像素?这里还有点不清楚,先记着。再有就是绘制溅开的水花的方法,是每一个水花的小点都是一个对象,并且存有初始化好的canvas,然后用主canvas的drawImage方法进行绘制,嗯,记着。

下面是雨水和水花对象:

雨水Rain:

 1 Rain.prototype.init = function() { 2 ????this.y = Math.random() * -100; 3 ????this.z = Math.random() * 0.5 + 0.5; 4 ????this.splashed = false; 5 } 6 Rain.prototype.recycle = function() { 7 ????demo.rain_pool.push(this); 8 } 9 // recycle rain particle and create a burst of droplets10 Rain.prototype.splash = function() {11 ????if (!this.splashed) {12 ????????this.splashed = true;13 ????????var drops = demo.drops;14 ????????var drop_pool = demo.drop_pool;15 16 ????????for (var i=0; i<16; i++) {17 ????????????var drop = drop_pool.pop() || new Drop();18 ????????????drops.push(drop);19 ????????????drop.init(this.x);20 ????????}21 ????}22 }

水花Drop:

 1 // Droplet definition 2 function Drop() { 3 ????this.x = 0; 4 ????this.y = 0; 5 ????this.radius = Math.round(Math.random() * 2 + 1) * demo.dpr; 6 ????this.speed_x = 0; 7 ????this.speed_y = 0; 8 ????this.canvas = document.createElement(‘canvas‘); 9 ????this.ctx = this.canvas.getContext(‘2d‘);10 ????11 ????// render once and cache12 ????var diameter = this.radius * 2;13 ????this.canvas.width = diameter;14 ????this.canvas.height = diameter;15 16 ????var grd = this.ctx.createRadialGradient(this.radius, this.radius , 1, this.radius, this.radius, this.radius);17 ????grd.addColorStop(0, demo.rain_color);18 ????grd.addColorStop(1, demo.rain_color_clear);19 ????this.ctx.fillStyle = grd;20 ????this.ctx.fillRect(0, 0, diameter, diameter);21 }22 Drop.prototype.init = function(x) {23 ????this.x = x;24 ????this.y = demo.height;25 ????var angle = Math.random() * Math.PI - (Math.PI * 0.5);26 ????var speed = Math.random() * Drop.max_speed;27 ????this.speed_x = Math.sin(angle) * speed;28 ????this.speed_y = -Math.cos(angle) * speed;29 }30 Drop.prototype.recycle = function() {31 ????demo.drop_pool.push(this);32 }

首先说Rain对象,对象内部没有贴出来,贴出的是几个主要的方法,主要看它的回收机制recycle方法,只要飞出边界的雨水都会回收到rain_pool数组,而rain数组的是正在飞的雨水。再看Drop对象,就是主要看它的canvas设置了,还有就是init方法里面设置水平和垂直方向速度的方式,作者数学肯定很牛X。

下面是一个Ticker对象:

 1 var Ticker = (function(){ 2 ????var PUBLIC_API = {}; 3 ?4 ????// public 5 ????// will call function reference repeatedly once registered, passing elapsed time and a lag multiplier as parameters 6 ????PUBLIC_API.addListener = function addListener(fn) { 7 ????????if (typeof fn !== ‘function‘) throw(‘Ticker.addListener() requires a function reference passed in.‘); 8 ?9 ????????listeners.push(fn);10 11 ????????// start frame-loop lazily12 ????????if (!started) {13 ????????????started = true;14 ????????????queueFrame();15 ????????}16 ????};17 18 ????// private19 ????var started = false;20 ????var last_timestamp = 0;21 ????var listeners = [];22 ????// queue up a new frame (calls frameHandler)23 ????function queueFrame() {24 ????????if (window.requestAnimationFrame) {25 ????????????requestAnimationFrame(frameHandler);26 ????????} else {27 ????????????webkitRequestAnimationFrame(frameHandler);28 ????????}29 ????}30 ????function frameHandler(timestamp) {31 ????????var frame_time = timestamp - last_timestamp;32 ????????last_timestamp = timestamp;33 ????????// make sure negative time isn‘t reported (first frame can be whacky)34 ????????if (frame_time < 0) {35 ????????????frame_time = 17;36 ????????}37 ????????// - cap minimum framerate to 15fps[~68ms] (assuming 60fps[~17ms] as ‘normal‘)38 ????????else if (frame_time > 68) {39 ????????????frame_time = 68;40 ????????}41 42 ????????// fire custom listeners43 ????????for (var i = 0, len = listeners.length; i < len; i++) {44 ????????????listeners[i].call(window, frame_time, frame_time / 16.67);45 ????????}46 ????????47 ????????// always queue another frame48 ????????queueFrame();49 ????}50 51 ????return PUBLIC_API;52 }());

主要是看requestAnimationFrame,这是一个绘制动画的方法,有时间再去看。传入的listener就是下面说的step。

 1 demo.step = function(time, lag) { 2 ????// localize common references 3 ????var demo = window.demo; 4 ????var speed = demo.speed; 5 ????var width = demo.width; 6 ????var height = demo.height; 7 ????var wind = demo.wind; 8 ????var rain = demo.rain; 9 ????var rain_pool = demo.rain_pool;10 ????var drops = demo.drops;11 ????var drop_pool = demo.drop_pool;12 ????13 ????// multiplier for physics14 ????var multiplier = speed * lag;15 ????16 ????// spawn drops17 ????demo.drop_time += time * speed;18 ????while (demo.drop_time > demo.drop_delay) {19 ????????demo.drop_time -= demo.drop_delay;20 ????????var new_rain = rain_pool.pop() || new Rain();21 ????????new_rain.init();22 ????????var wind_expand = Math.abs(height / new_rain.speed * wind); // expand spawn width as wind increases23 ????????var spawn_x = Math.random() * (width + wind_expand);24 ????????if (wind > 0) spawn_x -= wind_expand;25 ????????new_rain.x = spawn_x;26 ????????rain.push(new_rain);27 ????}28 ????29 ????// rain physics30 ????for (var i = rain.length - 1; i >= 0; i--) {31 ????????var r = rain[i];32 ????????r.y += r.speed * r.z * multiplier;33 ????????r.x += r.z * wind * multiplier;34 ????????// remove rain when out of view35 ????????if (r.y > height) {36 ????????????// if rain reached bottom of view, show a splash37 ????????????r.splash();38 ????????}39 ????????// recycle rain40 ????????if (r.y > height + Rain.height * r.z || (wind < 0 && r.x < wind) || (wind > 0 && r.x > width + wind)) {41 ????????????r.recycle();42 ????????????rain.splice(i, 1);43 ????????}44 ????}45 ????46 ????// splash drop physics47 ????var drop_max_speed = Drop.max_speed;48 ????for (var i = drops.length - 1; i >= 0; i--) {49 ????????var d = drops[i];50 ????????d.x += d.speed_x * multiplier;51 ????????d.y += d.speed_y * multiplier;52 ????????// apply gravity - magic number 0.3 represents a faked gravity constant53 ????????d.speed_y += 0.3 * multiplier;54 ????????// apply wind (but scale back the force)55 ????????d.speed_x += wind / 25 * multiplier;56 ????????if (d.speed_x < -drop_max_speed) {57 ????????????d.speed_x = -drop_max_speed;58 ????????}else if (d.speed_x > drop_max_speed) {59 ????????????d.speed_x = drop_max_speed;60 ????????}61 ????????// recycle62 ????????if (d.y > height + d.radius) {63 ????????????d.recycle();64 ????????????drops.splice(i, 1);65 ????????}66 ????}67 ????68 ????demo.draw();69 }

首先是第三段的地方,作者用了一个巧妙的数学方法增加了雨水下落的范围,主要就是根据wind风速的变化来调节范围。亲自试过,如果不添加这段代码,雨水下降的范围只有屏幕中间的一小部分。第四段是设置雨水的x、y,第五段是水花的x、y。

最后是事件:

 1 // handle interaction 2 demo.mouseHandler = function(evt) { 3 ????demo.updateCursor(evt.clientX, evt.clientY); 4 } 5 demo.touchHandler = function(evt) { 6 ????evt.preventDefault(); 7 ????var touch = evt.touches[0]; 8 ????demo.updateCursor(touch.clientX, touch.clientY); 9 }10 demo.updateCursor = function(x, y) {11 ????x /= demo.width;12 ????y /= demo.height;13 ????var y_inverse = (1 - y);14 ????15 ????demo.drop_delay = y_inverse*y_inverse*y_inverse * 100 + 2;16 ????demo.wind = (x - 0.5) * 50;17 }18 19 document.addEventListener(‘mousemove‘, demo.mouseHandler);20 document.addEventListener(‘touchstart‘, demo.touchHandler);21 document.addEventListener(‘touchmove‘, demo.touchHandler);

主要看的是触屏的touch事件,evt的touches对象就是对多点触屏的保存。

总结

继续努力吧!

(自己看)HTML5 Canvas下雨动画DEMO演示

原文地址:http://www.cnblogs.com/ChenYongHao/p/7749978.html

知识推荐

我的编程学习网——分享web前端后端开发技术知识。 垃圾信息处理邮箱 tousu563@163.com 网站地图
icp备案号 闽ICP备2023006418号-8 不良信息举报平台 互联网安全管理备案 Copyright 2023 www.wodecom.cn All Rights Reserved