问题描述
我刚开始使用画布和粒子,但我正在玩一个。 / p>
这里有几个我想尝试的东西,但我有点卡住了。
-
使文字在分解为粒子之前可见更长时间。
-
我也希望有一个随机的粒子运动,然后形成文本,以文本形式保持几秒钟,然后再次分解成颗粒。例如。随机粒子>粒子形成文本>随机粒子>已清除屏幕。
以及代码也在下面:
/ **
* Init
* /
var canvas = document.getElementsByClassName('canvas')[0];
window.onresize = function(){
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
};
window.onresize();
var ctx = canvas.getContext('2d');
ctx.font ='bold 50pxArial';
ctx.textBaseline ='center';
ctx.fillStyle ='#fff';
var _particles = [];
var particlesLength = 0;
var currentText =创造美丽的东西;
if(!window.requestAnimationFrame){
window.requestAnimationFrame = window.mozRequestAnimationFrame
|| window.webkitRequestAnimationFrame
|| window.msRequestAnimationFrame;
}
/ **
*创建一个粒子
* @param x
* @param y
* /
var createParticle = function createParticle(x,y){
_particles.push(new Particle(x,y));
};
/ **
*检查像素是否有alpha
* @param像素
* @param i
* @returns {boolean}
* /
var checkAlpha = function checkAlpha(pixels,i){
return pixels [i * 4 + 3] 0;
};
/ **
*创建_particles
* /
var createParticles = function createParticles(){
var textSize = ctx.measureText(currentText);
ctx.fillText(
currentText,
Math.round((canvas.width / 2) - (textSize.width / 2)),
Math.round / 2)
);
var imageData = ctx.getImageData(1,1,canvas.width,canvas.height);
var pixels = imageData.data;
var dataLength = imageData.width * imageData.height;
//循环遍历所有像素
for(var i = 0; i var currentRow = Math.floor(i / imageData.width) ;
var currentColumn = i - Math.floor(i / imageData.height);
if(currentRow%2 || currentColumn%2){
continue;
}
//如果alpha通道大于0
if(checkAlpha(pixels,i)){
var cy = ~~(i / imageData。宽度);
var cx = ~~(i - (cy * imageData.width));
createParticle(cx,cy);
}
}
particlesLength = _particles.length;
};
/ **
* new Point(x,y)
* @param x指针
* @param y指针
* @constructor
* /
var Point = function Point(x,y){
this.set(x,y);
};
Point.prototype = {
set:function(x,y){
x = x || 0;
y = y || x || 0;
/ **
* x开始指针
* @type {* | number}
* @private
* /
。 _sX = x;
/ **
* y开始指针
* @type {* | number}
* @private
* /
this。 _sY = y;
/ **
*电话重置
* /
this.reset();
},
/ **
*添加一个点到另一个
* @param point
* /
add:function ){
this.x + = point.x;
this.y + = point.y;
},
/ **
*乘两点
* @param point
* /
multiply:function(point){
this.x * = point.x;
this.y * = point.y;
},
/ **
*重置点
* /
reset:function(){
/ **
* x指针
* @type {* | number}
* /
this.x = this._sX;
/ **
* y指针
* @type {* | number}
* /
this.y = this._sY;
return this;
},
};
var FRICT = new Point(0.98);
/ **
*粒子构造函数
* @param x
* @param y
* @constructor
* /
var Particle = function Particle(x,y){
this.startPos = new Point(x,y);
/ **
*移动变量
* /
this.v = new Point();
this.a = new Point();
/ **
*第一次初始化复位
* /
this.reset();
};
Particle.prototype = {
/ **
*重置粒子
* /
reset:function(){
this.x = this.startPos.x;
this.y = this.startPos.y;
this.life = Math.round(random()* 300);
this.isActive = true;
/ **
*移动变量
* /
this.v.reset();
this.a.reset();
},
/ **
*粒子刻度
* /
tick:function(){
if(!this.isActive)
this.physics();
this.checkLife();
this.draw();
return this.isActive;
},
/ **
*计算生命
* /
checkLife:function(){
this.life - = 1;
this.isActive =!(this.life< 1);
},
/ **
*绘制粒子
* /
draw:function(){
ctx.fillRect(this。 x,this.y,1,1);
},
/ **
*计算粒子移动
* /
physics:function(){
this.ax = random() - 0.5)* 0.8;
this.a.y =(random() - 0.5)* 0.8;
this.v.add(this.a);
this.v.multiply(FRICT);
this.x + = this.v.x;
this.y + = this.v.y;
this.x = Math.round(this.x * 10)/ 10;
this.y = Math.round(this.y * 10)/ 10;
}
};
/ **
*开始派对
* /
createParticles();
/ **
*清除画布
* /
function clearCanvas(){
ctx.fillStyle ='rgba(255,255,255,0.2)';
ctx.fillRect(0,0,canvas.width,canvas.height);
}
(function clearLoop(){
/ **
*清除
* /
clearCanvas();
/ **
* next loop
* /
requestAnimationFrame(clearLoop);
})();
/ **
*主动画循环
* /
(function animLoop(){
ctx.fillStyle ='#ea541b';
var isAlive = true;
/ **
* Loop _particles
* /
for(var i = 0; i< particlesLength; i ++){
/ **
*如果粒子是活动的
* /
if(_particles [i] .tick())isAlive = true;
}
/ **
*下一个循环
* /
requestAnimationFrame(animLoop);
})
function resetParticles(){
for(var i = 0; i _particles [i] .reset
}
}
strong>只是延迟物理几秒钟,以便用户可以看到文本:
//设置a时间是未来的3秒
var nextTime = performance.now()+ 3000;
//等到当前时间为> = nextTime
if(nextTime& amp; performance.now()< nextTime){return;} else {nextTime = null; }
示例代码和演示:
body {background-color:ivory; } canvas {border:1px solid red; margin:0 auto; }
< canvas id =canvas> ; / canvas> $>
我可以想到至少 robertpenner.com/easing/rel =nofollow>缓动函数减慢动画的开始(以更长的时间显示文本),加快动画的结束(更快地显示消失)。这是以前的Stackoverflow 问题&
requestAnimationFrame
会自动以动画形式发送timestamp参数,您可以使用它来改变动画的执行。使用时间戳计算自上次动画循环以来的经过时间。在动画序列开始时允许较长的时间。这可让文字显示得更长。
I'm new to canvas and particles but I'm having a play around with it here.
There's a couple of things I'm trying to achieve here but I'm a bit stuck.
Make the text visible for longer before it breaks up into particles. As its not currently readable at the minute.
I'd also like to have it so that that theres a random particle movement which then forms into the text, stays in the text form for a few seconds and then breaks away into particles again. E.g. Random Particles > Particle formed text > Random Particles > Cleared screen.
As well as the fiddle the code is below too:
/** * Init */ var canvas = document.getElementsByClassName('canvas')[0]; window.onresize = function () { canvas.width = window.innerWidth; canvas.height = window.innerHeight; }; window.onresize(); var ctx = canvas.getContext('2d'); ctx.font = 'bold 50px "Arial"'; ctx.textBaseline = 'center'; ctx.fillStyle = '#fff'; var _particles = []; var particlesLength = 0; var currentText = "Create something beautiful"; if (!window.requestAnimationFrame) { window.requestAnimationFrame = window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame; } /** * Create one particle * @param x * @param y */ var createParticle = function createParticle(x, y) { _particles.push(new Particle(x, y)); }; /** * Check if pixel has alpha * @param pixels * @param i * @returns {boolean} */ var checkAlpha = function checkAlpha(pixels, i) { return pixels[i * 4 + 3] > 0; }; /** * Create _particles */ var createParticles = function createParticles() { var textSize = ctx.measureText(currentText); ctx.fillText( currentText, Math.round((canvas.width / 2) - (textSize.width / 2)), Math.round(canvas.height / 2) ); var imageData = ctx.getImageData(1, 1, canvas.width, canvas.height); var pixels = imageData.data; var dataLength = imageData.width * imageData.height; //Loop through all pixels for (var i = 0; i < dataLength; i++) { var currentRow = Math.floor(i / imageData.width); var currentColumn = i - Math.floor(i / imageData.height); if (currentRow % 2 || currentColumn % 2) { continue; } //If alpha channel is greater than 0 if (checkAlpha(pixels, i)) { var cy = ~~(i / imageData.width); var cx = ~~(i - (cy * imageData.width)); createParticle(cx, cy); } } particlesLength = _particles.length; }; /** * new Point(x, y) * @param x pointer * @param y pointer * @constructor */ var Point = function Point(x, y) { this.set(x, y); }; Point.prototype = { set: function (x, y) { x = x || 0; y = y || x || 0; /** * x start pointer * @type {*|number} * @private */ this._sX = x; /** * y start pointer * @type {*|number} * @private */ this._sY = y; /** * Call reset */ this.reset(); }, /** * add one point to another * @param point */ add: function (point) { this.x += point.x; this.y += point.y; }, /** * multiply two points * @param point */ multiply: function (point) { this.x *= point.x; this.y *= point.y; }, /** * Reset point */ reset: function () { /** * x pointer * @type {*|number} */ this.x = this._sX; /** * y pointer * @type {*|number} */ this.y = this._sY; return this; }, }; var FRICT = new Point(0.98); /** * Particle constructor * @param x * @param y * @constructor */ var Particle = function Particle(x, y) { this.startPos = new Point(x, y); /** * Movement variables */ this.v = new Point(); this.a = new Point(); /** * First init reset */ this.reset(); }; Particle.prototype = { /** * Reset particle */ reset: function () { this.x = this.startPos.x; this.y = this.startPos.y; this.life = Math.round(random() * 300); this.isActive = true; /** * Movement variables */ this.v.reset(); this.a.reset(); }, /** * Particle tick */ tick: function () { if (!this.isActive) return; this.physics(); this.checkLife(); this.draw(); return this.isActive; }, /** * Calculate life */ checkLife: function () { this.life -= 1; this.isActive = !(this.life < 1); }, /** * Draw particle */ draw: function () { ctx.fillRect(this.x, this.y, 1, 1); }, /** * Calculate particle movement */ physics: function () { this.a.x = (random() - 0.5) * 0.8; this.a.y = (random() - 0.5) * 0.8; this.v.add(this.a); this.v.multiply(FRICT); this.x += this.v.x; this.y += this.v.y; this.x = Math.round(this.x * 10) / 10; this.y = Math.round(this.y * 10) / 10; } }; /** * Start the party */ createParticles(); /** * Clear canvas */ function clearCanvas() { ctx.fillStyle = 'rgba(255,255,255,0.2)'; ctx.fillRect(0, 0, canvas.width, canvas.height); } (function clearLoop() { /** * Do clearing */ clearCanvas(); /** * next loop */ requestAnimationFrame(clearLoop); })(); /** * Main animation loop */ (function animLoop() { ctx.fillStyle = '#ea541b'; var isAlive = true; /** * Loop _particles */ for (var i = 0; i < particlesLength; i++) { /** * If particle is active */ if (_particles[i].tick()) isAlive = true; } /** * next loop */ requestAnimationFrame(animLoop); })(); function resetParticles() { for (var i = 0; i < particlesLength; i++) { _particles[i].reset(); } }
解决方案Just delay the physics for a few seconds so the user can see the text:
// set a time that's 3 seconds in the future var nextTime=performance.now()+3000; // wait until the current time is >= nextTime if(nextTime && performance.now()<nextTime){return;}else{nextTime=null;}
Example code and a Demo:
var random=Math.random; /** * Init */ var canvas = document.getElementById('canvas'); window.onresize = function () { canvas.width = window.innerWidth; canvas.height = window.innerHeight; }; window.onresize(); var ctx = canvas.getContext('2d'); ctx.font = 'bold 50px "Arial"'; ctx.textBaseline = 'center'; ctx.fillStyle = '#fff'; var _particles = []; var particlesLength = 0; var currentText = "Create something beautiful"; /** * Create one particle * @param x * @param y */ var createParticle = function createParticle(x, y) { _particles.push(new Particle(x, y)); }; /** * Check if pixel has alpha * @param pixels * @param i * @returns {boolean} */ var checkAlpha = function checkAlpha(pixels, i) { return pixels[i * 4 + 3] > 0; }; /** * Create _particles */ var createParticles = function createParticles() { var textSize = ctx.measureText(currentText); ctx.fillText( currentText, Math.round((canvas.width / 2) - (textSize.width / 2)), Math.round(canvas.height / 2) ); var imageData = ctx.getImageData(1, 1, canvas.width, canvas.height); var pixels = imageData.data; var dataLength = imageData.width * imageData.height; //Loop through all pixels for (var i = 0; i < dataLength; i++) { var currentRow = Math.floor(i / imageData.width); var currentColumn = i - Math.floor(i / imageData.height); if (currentRow % 2 || currentColumn % 2) { continue; } //If alpha channel is greater than 0 if (checkAlpha(pixels, i)) { var cy = ~~(i / imageData.width); var cx = ~~(i - (cy * imageData.width)); createParticle(cx, cy); } } particlesLength = _particles.length; }; /** * new Point(x, y) * @param x pointer * @param y pointer * @constructor */ var Point = function Point(x, y) { this.set(x, y); }; Point.prototype = { set: function (x, y) { x = x || 0; y = y || x || 0; /** * x start pointer * @type {*|number} * @private */ this._sX = x; /** * y start pointer * @type {*|number} * @private */ this._sY = y; /** * Call reset */ this.reset(); }, /** * add one point to another * @param point */ add: function (point) { this.x += point.x; this.y += point.y; }, /** * multiply two points * @param point */ multiply: function (point) { this.x *= point.x; this.y *= point.y; }, /** * Reset point */ reset: function () { /** * x pointer * @type {*|number} */ this.x = this._sX; /** * y pointer * @type {*|number} */ this.y = this._sY; return this; }, }; var FRICT = new Point(0.98); /** * Particle constructor * @param x * @param y * @constructor */ var Particle = function Particle(x, y) { this.startPos = new Point(x, y); /** * Movement variables */ this.v = new Point(); this.a = new Point(); /** * First init reset */ this.reset(); }; Particle.prototype = { /** * Reset particle */ reset: function () { this.x = this.startPos.x; this.y = this.startPos.y; this.life = Math.round(random() * 300); this.isActive = true; /** * Movement variables */ this.v.reset(); this.a.reset(); }, /** * Particle tick */ tick: function () { if (!this.isActive) return; this.physics(); this.checkLife(); this.draw(); return this.isActive; }, /** * Calculate life */ checkLife: function () { this.life -= 1; this.isActive = !(this.life < 1); }, /** * Draw particle */ draw: function () { ctx.fillRect(this.x, this.y, 1, 1); }, /** * Calculate particle movement */ physics: function () { if(performance.now()<nextTime){return;} this.a.x = (random() - 0.5) * 0.8; this.a.y = (random() - 0.5) * 0.8; this.v.add(this.a); this.v.multiply(FRICT); this.x += this.v.x; this.y += this.v.y; this.x = Math.round(this.x * 10) / 10; this.y = Math.round(this.y * 10) / 10; } }; /** * Start the party */ var nextTime=performance.now()+3000; createParticles(); /** * Clear canvas */ function clearCanvas() { ctx.fillStyle = 'rgba(255,255,255,0.2)'; ctx.fillRect(0, 0, canvas.width, canvas.height); } (function clearLoop() { /** * Do clearing */ clearCanvas(); /** * next loop */ requestAnimationFrame(clearLoop); })(); /** * Main animation loop */ (function animLoop(time) { ctx.fillStyle = '#2c87c4'; var isAlive = true; /** * Loop _particles */ for (var i = 0; i < particlesLength; i++) { /** * If particle is active */ if (_particles[i].tick()) isAlive = true; } /** * next loop */ requestAnimationFrame(animLoop); })(); function resetParticles() { for (var i = 0; i < particlesLength; i++) { _particles[i].reset(); } }
body{ background-color: ivory; } canvas{border:1px solid red; margin:0 auto; }
<canvas id="canvas"></canvas>
I can think of at least 2 other ways to have variable speed animation.
Use Robert Penner's easing functions to slow the beginning of your animation (to show the text longer) and speed up the ending of your animation (to show the dissolve faster). Here's a previous Stackoverflow Q&A with an example using easing in an animation.
requestAnimationFrame
automatically sends in a timestamp argument that you can use to vary the execution of your animation. Use the timestamp to calculate elapsed time since the last animation loop. Allow a longer elapsed time at the beginning of your animation sequence. This allows the text to be displayed longer.
这篇关于画布粒子文本的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!