简体   繁体   English

HTML5 Canvas中的动画不透明度

[英]Animating opacity in HTML5 Canvas

I'm trying to recreate this effect , but I want this to be in canvas, basically drawing squares with fadein effect using a loop. 我正在尝试重新创建此效果 ,但是我希望将此效果放在画布中,基本上是使用循环使用淡入效果绘制正方形。 The loop part is ok, what I cannot figure out is the fade in effect. 循环部分还可以,我不知道是淡入淡出的效果。 I'm using requestAnimationFrame, with each repaint the globalAlpha is incremented, the old sqaure is deleted and a new one drawn. 我正在使用requestAnimationFrame,每次重绘时,globalAlpha都会增加,旧的squre将被删除,新的将被绘制。 This is the function: 这是功能:

function renderSquare(x, y) {

requestID = requestAnimationFrame(renderSquare);
alpha = requestID/100;  

ctx.clearRect(x,y,size,size);
ctx.globalAlpha = alpha;

var colour = "rgb(58,150,270)";
ctx.fillStyle = colour;
ctx.fillRect(x, y, size, size);


console.log("ID: " + requestID);  
console.log("Alpha: " + alpha);

if(alpha == 1) {
    cancelAnimationFrame(requestID);
}   

};

function drawSquare(x,y) {
  requestAnimationFrame(function render(){
    renderSquare(x,y);          
  });   
}

But I just can't get it to work. 但是我就是无法正常工作。 Here is a codepen with the whole thing. 这是完整的代码库。

http://codepen.io/easynowbaby/pen/GJKOej?editors=001 http://codepen.io/easynowbaby/pen/GJKOej?editors=001

Ultimately, I want to be able to use the function in the loopSquares function. 最终,我希望能够在loopSquares函数中使用该函数。 Any help is very appreciated. 任何帮助都非常感谢。 Cheers! 干杯!

EDIT: I should have made myself clearer. 编辑:我应该让自己更清楚。 I don't want to recreate the gallery with images, I'm only interested in the cascading fade in effect of squares. 我不想用图像重新创建画廊,我只对正方形的级联渐弱感兴趣。 I want to achieve this effect in canvas where I'm gonna fade in little squares using fillRect function. 我想在画布上实现这种效果,在画布上我将使用fillRect函数在小方块中淡出。

Problems 问题

The first thing to point out here is how you use the requestID to set the alpha. 这里要指出的第一件事是如何使用requestID设置Alpha。 From MDN (my emphasis): 来自MDN (我的重点):

A long integer value, the request id, that uniquely identifies the entry in the callback list. 一个长整数值,即请求ID,用于唯一标识回调列表中的条目。 This is a non-zero value, but you may not make any other assumptions about its value . 这是一个非零值,但您不能对其值进行任何其他假设 You can pass this value to window.cancelAnimationFrame() to cancel the refresh callback request. 您可以将此值传递给window.cancelAnimationFrame()来取消刷新回调请求。

In other words, don't assume this will keep a running value equivalent to current index of the cell. 换句话说,不要假设这将使运行值等于单元格的当前索引。 It may do so in one browser, accidentally, but no in another. 它可能偶然在一个浏览器中这样做,而在另一个浏览器中却没有。 Keep track of this value by other means. 通过其他方式跟踪此值。

Second, the globalAlpha works on the entire context for anything drawn next to it. 其次, globalAlpha可以在整个上下文中对其旁边绘制的任何内容进行处理。 This means you need to track current alpha per square, or use a color style rgba which allow you to set alpha per style. 这意味着您需要跟踪平方的当前Alpha值,或使用允许您为每种样式设置Alpha的颜色样式rgba。 This doesn't matter so much though as you need to track alpha also here. 这无关紧要,尽管您还需要在此处跟踪Alpha。

One solution 一种解决方案

I would suggest using an object for this, a square-monkey which can be trained to set its alpha correctly, then duplicated across a grid. 我建议为此使用一个对象,即方形猴子,可以训练它正确设置其alpha,然后在网格上复制。

Example

Main object will keep track of all settings such as current alpha, how much to update, what color and so forth. 主对象将跟踪所有设置,例如当前的Alpha,要更新的数量,什么颜色等等。 It's of course not limited to these alone - you could add scale, rotation etc. to it as well, but here I'll only show for alpha: 当然,不仅限于这些-您还可以为其添加比例,旋转等,但是这里我仅显示alpha:

// Square-monkey object
function Rectangle(ctx, x, y, w, h, color, speed) {

  this.ctx = ctx;
  this.x = x;
  this.y = y;
  this.height = h;
  this.width = w;
  this.color = color;

  this.alpha = 0;                        // current alpha for this instance
  this.speed = speed;                    // increment for alpha per frame
  this.triggered = false;                // is running
  this.done = false;                     // has finished
}

To save some memory and increase performance we can use prototypes for the common functions/methods: 为了节省一些内存并提高性能,我们可以将原型用于常见的功能/方法:

Rectangle.prototype = {

  trigger: function() {                  // start this rectangle
    this.triggered = true
  },

  update: function() {
    if (this.triggered && !this.done) {  // only if active
      this.alpha += this.speed;          // update alpha
      this.done = (this.alpha >= 1);     // update status
    }

    this.ctx.fillStyle = this.color;           // render this instance
    this.ctx.alpha = Math.min(1, this.alpha);  // clamp value
    this.ctx.fillRect(this.x, this.y, this.width, this.height);
  }  
};

What we need to do now is to define a grid and cell size: 现在,我们需要定义一个网格和像元大小:

var cols = 10,
    rows = 6,
    cellWidth = canvas.width / cols,
    cellHeight = canvas.height /rows;

Now we can populate the grid with an object per cell: 现在,我们可以在每个单元格中填充一个对象:

var grid = [],
    len = cols * rows,
    y = 0, x;

for(; y < rows; y++) {
  for(x = 0; x < cols; x++) {
    grid.push(new Rectangle(ctx, x * cellWidth, y * cellHeight,
                            cellWidth, cellHeight, "#79f", 0.25));
  }
}

And finally we need to trigger these square in any fashion we like, here just a diagonal cascading way. 最后,我们需要以我们喜欢的任何方式触发这些正方形,这里只是对角线级联的方式。 Lets also keep track of if all are done and not: 让我们还跟踪是否全部完成:

function loop() {
  ctx.globalAlpha = 1;           // reset alpha
  ctx.clearRect(0, 0, w, h);     // clear canvas

  // trigger cells
  for(y = 0; y < rows; y++) {    // iterate each row
    var gx = (x|0) - y;          // calc an x for current row
    if (gx >= 0 && gx < cols) {  // within limit?
      index = y * cols + gx;     // calc index
      grid[index].trigger();     // trigger this cell's animation if not running
    }
  }

  x += 0.25;                     // how fast to cascade

  hasActive = false;             // enable ending the animation when all done

  // update/render all cells
  for(var i = 0; i < grid.length; i++) {
    grid[i].update();
    if (!grid[i].done) hasActive = true;      // anyone active?
  }

  if (hasActive) requestAnimationFrame(loop); // animate if anyone's active
}

Live example 现场例子

 var canvas = document.querySelector("canvas"), ctx = canvas.getContext("2d"), w = canvas.width, h = canvas.height; // Square-monkey object function Rectangle(ctx, x, y, w, h, color, speed) { this.ctx = ctx; this.x = x; this.y = y; this.height = h; this.width = w; this.color = color; this.alpha = 0; // current alpha for this instance this.speed = speed; // increment for alpha per frame this.triggered = false; // is running this.done = false; // has finished } // prototype methods that will be shared Rectangle.prototype = { trigger: function() { // start this rectangle this.triggered = true }, update: function() { if (this.triggered && !this.done) { // only if active this.alpha += this.speed; // update alpha this.done = (this.alpha >= 1); // update status } this.ctx.fillStyle = this.color; // render this instance this.ctx.globalAlpha = Math.min(1, this.alpha); this.ctx.fillRect(this.x, this.y, this.width, this.height); } }; // Populate grid var cols = 10, rows = 6, cellWidth = canvas.width / cols, cellHeight = canvas.height /rows, grid = [], len = cols * rows, y = 0, x; for(; y < rows; y++) { for(x = 0; x < cols; x++) { grid.push(new Rectangle(ctx, x * cellWidth, y * cellHeight, cellWidth, cellHeight, "#79f", 0.025)); } } var index, hasActive = true; x = 0; function loop() { ctx.globalAlpha = 1; ctx.clearRect(0, 0, w, h); // trigger cells for(y = 0; y < rows; y++) { var gx = (x|0) - y; if (gx >= 0 && gx < cols) { index = y * cols + gx; grid[index].trigger(); } } x += 0.25; hasActive = false; // update all for(var i = 0; i < grid.length; i++) { grid[i].update(); if (!grid[i].done) hasActive = true; } if (hasActive) requestAnimationFrame(loop) } loop(); 
 <canvas width=500 height=300></canvas> 

Live example extended object 实时示例扩展对象

By using a single object you can maintain code in a single place. 通过使用单个对象,您可以在单个位置维护代码。 For the fun of it, lets add rotation and scale as well: 有趣的是,还可以添加旋转和缩放:

 var canvas = document.querySelector("canvas"), ctx = canvas.getContext("2d"), w = canvas.width, h = canvas.height; // Square-monkey object function Rectangle(ctx, x, y, w, h, color, speed) { this.ctx = ctx; this.x = x; this.y = y; this.height = h; this.width = w; this.color = color; this.alpha = 0; // current alpha for this instance this.speed = speed; // increment for alpha per frame this.triggered = false; // is running this.done = false; // has finished } // prototype methods that will be shared Rectangle.prototype = { trigger: function() { // start this rectangle this.triggered = true }, update: function() { if (this.triggered && !this.done) { // only if active this.alpha += this.speed; // update alpha this.done = (this.alpha >= 1); // update status } this.ctx.fillStyle = this.color; // render this instance this.ctx.globalAlpha = Math.min(1, this.alpha); var t = this.ctx.globalAlpha, // use current alpha as t cx = this.x + this.width * 0.5, // center position cy = this.y + this.width * 0.5; this.ctx.setTransform(t, 0, 0, t, cx, cy); // scale and translate this.ctx.rotate(0.5 * Math.PI * (1 - t)); // rotate, 90° <- alpha this.ctx.translate(-cx, -cy); // translate back this.ctx.fillRect(this.x, this.y, this.width, this.height); } }; // Populate grid var cols = 20, rows = 12, cellWidth = canvas.width / cols, cellHeight = canvas.height /rows, grid = [], len = cols * rows, y = 0, x; for(; y < rows; y++) { for(x = 0; x < cols; x++) { grid.push(new Rectangle(ctx, x * cellWidth, y * cellHeight, cellWidth, cellHeight, "#79f", 0.02)); } } var index, hasActive = true; x = 0; function loop() { ctx.setTransform(1,0,0,1,0,0); ctx.globalAlpha = 1; ctx.clearRect(0, 0, w, h); // trigger cells for(y = 0; y < rows; y++) { var gx = (x|0) - y; if (gx >= 0 && gx < cols) { index = y * cols + gx; grid[index].trigger(); } } x += 0.333; hasActive = false; // update all for(var i = 0; i < grid.length; i++) { grid[i].update(); if (!grid[i].done) hasActive = true; } if (hasActive) requestAnimationFrame(loop) } loop(); 
 <canvas width=500 height=300></canvas> 

This is not a canvas nor a canvas effect. 这既不是画布,也不是画布效果。

Those are simple image tags animated by size and opacity. 这些是简单的图像标签,通过大小和不透明度进行动画处理。 Just drag any of the images to the URL bar and you'll see the full-resolution image opens. 只需将任何图像拖到URL栏,您就会看到全分辨率图像打开。 This is so because they are DOM elements. 之所以如此,是因为它们是DOM元素。 If this was a canvas you couldn't possibly drag them to the URL bar. 如果这是画布,则无法将其拖动到URL栏。

All you need to do is animate one image tag properly (size and opacity). 您要做的就是正确地动画一个图像标签(大小和不透明度)。 Both are really simple and well-explained for jQuery. 两者都非常简单,并且对于jQuery有充分的解释。 Next, combine that effect in an array with a delay betweem them and you are on. 接下来,将效果与它们之间的延迟组合到一个数组中,然后打开。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM