js实现canvas粒子飞舞动画效果代码
代码语言:html
所属分类:粒子
代码描述:js实现canvas粒子飞舞动画效果代码
下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开
<html> <head> <style> html, body { overflow: hidden; margin: 0; } html { background: #14191C; } p { position: absolute; bottom: 1em; width: 100%; color: rgba(255, 255, 255, 0.25); text-align: center; pointer-events: none; transition: opacity 1s ease-in-out; } </style> </head> <body> <p style="opacity: 0;"> Click near Boids to disperse group. </p> <script> // start particle simulation simulate( '2d', { init: function() { this.spray(150, function() { return [ null, null, Vector.create( this.width * Math.random(), this.height * Math.random() ), Vector.random(1), .75 + (Math.random() * .5), 100 * Math.random(), [ this.behavior.cohesion(), this.behavior.alignment(), this.behavior.separation(), this.behavior.limit(1 + Math.random()), this.behavior.wrap(5), this.behavior.move() ] ] }) }, tick: function() {}, beforePaint: function() { this.clear(); }, paint: function(particle) { var p = particle.position; var v = particle.velocity; var s = particle.stimulated || 0; var l = particle.life; this.paint.circle(p.x, p.y, v.magnitudeSquared, 'hsla(' + v.angle + ',100%,50%,1)'); }, afterPaint: function() { // nothing }, action: function(x, y) { // disperse if near this.particles.forEach(function(p) { if (Vector.distanceSquared(p.position, { x: x, y: y }) < 4000) { p.velocity.randomize(100); p.position.x += p.velocity.x; p.position.y += p.velocity.y; } }); } } ); setTimeout(() => { document.querySelector('p').style.opacity = 0; }, 3000); // "simulate" particle simulation logic /** * Constants */ PI_2 = Math.PI / 2; PI_180 = Math.PI / 180; /** * Random */ var Random = { between: function(min, max) { return min + (Math.random() * (max - min)); } } /** * 2D Vector Class */ function Vector(x, y) { this._x = x || 0; this._y = y || 0; } Vector.create = function(x, y) { return new Vector(x, y); }; Vector.add = function(a, b) { return new Vector(a.x + b.x, a.y + b.y); }; Vector.subtract = function(a, b) { return new Vector(a.x - b.x, a.y - b.y); }; Vector.random = function(range) { var v = new Vector(); v.randomize(range); return v; }; Vector.distanceSquared = function(a, b) { var dx = a.x - b.x; var dy = a.y - b.y; return dx * dx + dy * dy; }; Vector.distance = function(a, b) { var dx = a.x - b.x; var dy = a.y - b.y; return Math.sqrt(dx * dx + dy * dy); }; Vector.prototype = { get x() { return this._x; }, get y() { return this._y; }, set x(value) { this._x = value; }, set y(value) { this._y = value; }, get magnitudeSquared() { return this._x * this._x + this._y * this._y; }, get magnitude() { return Math.sqrt(this.magnitudeSquared); }, get angle() { return Math.atan2(this._y, this._x) * 180 / Math.PI; }, clone: function() { return new Vector(this._x, this._y); }, add: function(v) { this._x += v.x; this._y += v.y; }, subtract: function(v) { this._x -= v.x; this._y -= v.y; }, multiply: function(value) { this._x *= value; this._y *= value; }, divide: function(value) { this._x /= value; this._y /= value; }, normalize: function() { var magnitude = this.magnitude; if (magnitude > 0) { this.divide(magnitude); } }, limit: function(treshold) { if (this.magnitude > treshold) { this.normalize(); this.multiply(treshold); } }, randomize: function(amount) { amount = amount || 1; this._x = amount * 2 * (-.5 + Math.random()); this._y = amount * 2 * (-.5 + Math.random()); }, rotate: function(degrees) { var magnitude = this.magnitude; var angle = ((Math.atan2(this._x, this._y) * PI_HALF) + degrees) * PI_180; this._x = magnitude * Math.cos(angle); this._y = magnitude * Math.sin(angle); }, flip: function() { var temp = this._y; this._y = this._x; this._x = temp; }, invert: function() { this._x = -this._x; this._y = -this._y; }, toString: function() { return this._x + ', ' + this._y; } } /** * Particle Class */ function Particle(id, group, position, velocity, size, life, behavior) { this._id = id || 'default'; this._group = group || 'default'; this._position = position || new Vector(); this._velocity = velocity || new Vector(); this._size = size || 1; this._life = Math.round(life || 0); this._behavior = behavior || []; } Particle.prototype = { get id() { return this._id; }, get group() { return this._group; }, get life() { return this._life; }, get size() { return this._size; }, set size(size) { this._size = size; }, get position() { return this._position; }, get velocity() { return this._velocity; }, update: function(stage) { this._life++; var i = 0; var l = this._behavior.length; for (; i < l; i++) { this._behavior[i].call(stage, this); } }, toString: function() { return 'Particle(' + this._id + ') ' + this._life + ' pos: ' + this._position + ' vec: ' + this._velocity; } } // setup DOM function simulate(dimensions, options) { // private vars var particles = []; var destroyed = []; var update = update || function() {}; var stage = stage || function() {}; var canvas; var context; if (!options) { console.error('"options" object must be defined'); return; } if (!options.init) { console.error('"init" function must be defined'); return; } if (!options.paint) { console.error('"paint" function must be defined'); return; } if (!options.tick) { options.tick = function() {}; } if (!options.beforePaint) { options.beforePaint = function() {}; } if (!options.afterPaint) { options.afterPaint = function() {}; } if (!options.action) { options.action = function() {}; } if (document.readyState === 'interactive') { setup(); } else { document.addEventListener('DOMContentLoaded', setup); } // resizes canvas to fit window dimensions function fitCanvas() { canvas.width = window.innerWidth; canvas.height = window.innerHeight; } // create canvas for drawing function setup() { // create canvas = document.createElement('canvas'); document.body.appendChild(canvas); // correct canvas size on window resize window.addEventListener('resize', fitCanvas); // go go(); } // canvas has been attached, let's go! function go() { // set initial canvas size fitCanvas(); // get context for drawing context = canvas.getContext(dimensions); // simulation update loop function act() { // update particle states var i = 0; var l = particles.length; var p; for (; i < l; i++) { particles[i].update(this); } // clean destroyed particles while (p = destroyed.pop()) { do { // has not been found in destroyed array? if (p !== particles[i]) { continue; } // remove particle particles.splice(i, 1); } while (i-- >= 0) } // repaint context options.beforePaint.call(this); // repaint particles i = 0; l = particles.length; for (; i < l; i++) { options.paint.call(this, particles[i]); } // after particles have been painted options.afterPaint.call(this); } function tick() { // call update method, this allows for inserting particles later on options.tick.call(this); // update particles here act(); // on to the next frame window.requestAnimationFrame(tick); } /** * API **/ function clear() { context.clearRect(0, 0, canvas.width, canvas.height); } function destroy(particle) { destroyed.push(particle); } function add(id, group, position, velocity, size, life, behavior) { particles.push(new Particle(id, group, position, velocity, size, life, behavior)); } function spray(amount, config) { var i = 0; for (; i < amount; i++) { add.apply(this, config()); } } function debug(particle) { this.paint.circle( particle.position.x, particle.position.y, particle.size, 'rgba(255,0,0,.75)' ); context.beginPath(); context.moveTo(particle.position.x, particle.position.y); context.lineTo(particle.position.x + (particle.velocity.x * 10), particle.position.y + (particle.velocity.y * 10)); context.strokeStyle = 'rgba(255,0,0,.1)'.........完整代码请登录后点击上方下载按钮下载查看
网友评论0