There is a recent project need to have a rain and snow animation effects, here made a drop of the component, to show this canvas common drop object effect. So, =. = Let's see the effect first.
# #效果展示
Calling code
<! doctype html>
It rains and snows.
It looks good, and it's easier to use canvas than to create a multiple-object displacement animation with a DOM element, and better performance
# #源码讲解
Okay, so here's the simple implementation principle first, define some of the global variables we'll use, such as wind direction, probability, object data, etc.
# # #定义全局变量
Define two object data//Drops falling object///Object Bounces object var drops = [], bounces = [];
This sets the gravitational acceleration to 0.2/one frame var gravity = 0.2; var speed_x_x, //Lateral Acceleration speed_x_y, //longitudinal acceleration wind_anger; //Wind/canvas pixel width high var canvaswidth,
Canvasheight;
Probability of creating drop var drop_chance;
Configuration Object var opts; Determine if there is a Requestanimationframe method, if used, not about a second or 30 frames window.requestanimframe =
window.requestanimationframe | |
window.webkitrequestanimationframe | |
window.mozrequestanimationframe | |
window.orequestanimationframe | |
window.msrequestanimationframe | | function (callback) {
Window.settimeout (CALLBACK,&NBSP;1000&NBSP;/&NBSP;30); };
# # #定义核心对象
Next we need to define a few important objects the organization needs to define fewer objects, a total of only three have defined the ' three core objects ' in the entire drop component, respectively, as follows:
vector speed objects, with horizontal x, and longitudinal y of the Velocity size unit: V = displacement pixel/frame
The vector object's understanding is also very simple and rough, is to record the drop object drop speed/V
Var vector = function (x, y) { //private properties horizontal speed x , Longitudinal Speed y this.x = x | |
0; this.y = y | |
0;
}; The public method- add : the speed change function, according to the parameter to increase the speed//due to the business needs, the consideration is the situation of drop acceleration, so there is no deceleration, later can expand * * @param v object | | string * Vector.prototype.add = function (v) { if ( V.x != null && v.y != null) {
this.x += v.x;
this.y += v.y; } else { this.x +=
V
this.y += v;
} return this;
}; Public method- copy : copy a vectorTo be used as the record of the previous speed Node vector.prototype.copy = function () { //
Returns a Vector instance return new vector (THIS.X,&NBSP;THIS.Y) with an equal velocity attribute; };
Drop drop objects, that is, the effect of raindrops and snow, in the back you can expand yourself into meteorites or shells
The underlying definition for the drop object is as follows
Constructor
var Drop = function () {/
* .... */
};
Public method-update
Drop.prototype.update = function () {/
* ... */
};
Public method-draw
Drop.prototype.draw = function () {/
* ... */
};
Look at the above three methods, whether they have guessed their role, and then let us understand what these three methods do
### #构造函数
The constructor is primarily responsible for defining the initial information of the drop object, such as speed, initial coordinates, size, acceleration, etc.
Constructor drop var drop = function () { //The initial coordinates of the Drop in random setting
//first randomly selects the falling object from which side var randomedge = math.random () *2; if (randomedge > 1) {
This.pos = new vector (50 + math.random () * canvas.width, -80); }else{ this.pos = new
Vector (Canvas.width, math.random () * canvas.height); &NBSP;&NBSP;&NBSP;&NBSP} //Set the size of the drop element // Random value of the radius range of the called OPTS function this.radius = (opts.size_range[0] +
Math.random () * opts.size_range[1]) *DPR; //obtains the drop initial velocity //the random value of the speed range of the called OPTs function this.speed = (OPTS. Speed[0] + math.random () * opts.speed[1]) *DPR;
this.prev = this.pos;
//the angle multiplied by the 0.017453293 (2pi/360) to be converted to radians. var eachAnger = 0.017453293; //
Get the angle of the wind wind_anger = OPTS.wind_direction * eachAnger; //gain transverse acceleration speed_x = this.speed *
math.cos (Wind_anger); //Gain longitudinal acceleration speed_y = - this.speed *
Math.sin (Wind_anger); //binds a speed instance this.vel = new vector (wind_x,
WIND_Y); };
### #Drop对象的update方法
The Update method is responsible for changing the properties of the drop instance for each frame, such as displacement
Drop.prototype.update = function () {
This.prev = this.pos.copy ();
If there is a gravity condition, the longitudinal velocity is increased if
(opts.hasgravity) {
this.vel.y + = gravity;
}
//
This.pos.add (this.vel);
};
### #Drop对象的draw方法
The draw method is responsible for painting the drop instance per frame
Drop.prototype.draw = function () { ctx.beginpath (); ctx.moveto (this.pos.x
, &NBSP;THIS.POS.Y); There are currently only two cases, one is rain -Bezier curve if (opts.type == "Rain") {
ctx.moveto (THIS.PREV.X,&NBSP;THIS.PREV.Y); var ax = math.abs (This.radius * math.cos (
Wind_anger)); var ay = math.abs (This.radius * math.sin (
Wind_anger)); ctx.beziercurveto (this.pos.x + ax, this.pos.y + ay, this.prev.x + ax , this.prev.y + ay, this.pos.x,
THIS.POS.Y);
ctx.stroke (); //the other is snow--, which is circular }else{
ctx.moveto (THIS.POS.X,&NBSP;THIS.POS.Y); ctx.arc (This.pos.x, this.pos.y, this.radius, 0,
&NBSP;MATH.PI*2);
ctx.fill (); };
Bounce Drop falling landing object, that is, the water droplets above the rain rebound, you can also expand later to bounce gravel or soot
definition is very simple, This is not a detailed description of the
Var bounce = function (x, y) { var dist = math.random ()
* 7;
var angle = math.pi + math.random () * Math.PI;
this.pos = new vector (X, y);
this.radius = 0.2+ math.random () *0.8;
this.vel = new vector ( math.cos (angle) * dist,
math.sin (angle) * dist );
}; Bounce.prototype.update = function () { this.vel.y += gravity;
this.vel.x *= 0.95;
this.vel.y *= 0.95;
this.pos.add (This.vel);
}; Bounce.prototype.draw = function () { ctx.beginpath (); ctx.arc (This.pos.x,
&NBSP;THIS.POS.Y,&NBSP;THIS.RADIUS*DPR,&NBSP;0,&NBSP;MATH.PI&NBSP;*&NBSP;2);
ctx.fill (); };
# #对外接口
# # #update
that is equivalent to the start function for the entire canvas animation
Function update () { var d = new Date;
//Clear Paint ctx.clearrect (0, 0, canvas.width, canvas.height);
var i = drops.length; while (i--) { var drop
= drops[i];
drop.update (); //If the drop instance drops to the bottom, you need to clear the instance object in the drops array if (drop.pos.y >= canvas.height) { //If a rebound is required, add the bounce instance to the bouncess array if (opts.hasbounce) { var n = math.round (4 + MAth.random () * 4); while ( n--)
Bounces.push (New bounce (drop.pos.x, canvas.height)); } //If the drop instance drops to the bottom, you need to clear the instance object in the drops array
drops.splice (i, 1);
} drop.draw (); &NBSP;&NBSP;&NBSP;&NBSP} //If you need to rebound if (OPTS.hasBounce) {
var i = bounces.length; while (i--) { var bounce = bounces[i];
bounce.update ();
bounce.draw (); if (bounce.pos.y >
Canvas.height) bounces.splice (i, 1);
&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP}  } //quantity produced each time if (drops.length < opts.maxnum) { if (Math.random () < drop_chance) { var i = 0,
len = OPTS.numLevel; for (; i< len; i++) {
drops.push (New drop ()); } &NBSP;&NBSP}  } //constant Loop update
Requestanimframe (update); }
# # #init
Init interface, initializes all the underlying properties of the entire canvas canvas, such as getting the pixel ratio of the screen, and setting the pixel size of the canvas, and setting the style
Function init (opts) { OPTS = opts; canvas
= document.getelementbyid (opts.id);
ctx = canvas.getcontext ("2d"); ////compatible with HD screen, canvas canvas pixel should be changed accordingly DPR =
Window.devicepixelratio; //canvas artboard pixel size, need to be compatible with HD screen, so the artboard canvas width should be multiplied by DPR canvaswidth
= canvas.clientWidth * DPR;
canvasHeight =canvas.clientHeight * DPR;
//Set artboard width canvas.width = canvasWidth; height
canvas.height = canvasHeight;
drop_chance = 0.4;
//set style setstyle (); } function setstyle () { if (opts.type == "Rain") { ctx.linewidth = 1 * dpr;
ctx.strokeStyle = ' Rgba (223,223,223,0.6) ';
ctx.fillStyle = ' Rgba (223,223,223,0.6) '; }else{ ctx.linewidth = 2
* DPR;
ctx.strokeStyle = ' Rgba (254,254,254,0.8) ';
ctx.fillStyle = ' Rgba (254,254,254,0.8) '; &NBSP;&NBSP;&NBSP;&NBSP}}
# #结束语
OK, a simple drop component has been completed, of course, there are many places is not perfect, after the writing of the drop component, for the animation implementation of the canvas, I believe there are many places to explore in the H5 scene.
finally say the insufficient place and later work ha:
0, the component is not enough external interface, adjustable range is not a lot, the abstract is not very thorough
1, SetStyle sets the basic style
2, Drop and bounce objects of the update and draw methods to customize, so that users can set more falling speed and size change in form and style effects
&NBSP;&NB sp; 3, should increase the animation of the pause, acceleration and deceleration, such as the interface of the operation of the