我正在尝试重新创建 this effect ,但我希望它在 Canvas 中,基本上使用循环绘制具有淡入效果的正方形。循环部分还可以,我无法弄清楚的是淡入淡出效果。我正在使用 requestAnimationFrame,每次重绘时 globalAlpha 都会增加,旧的 sqaure 会被删除并绘制一个新的。这是函数:
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);
});
}
但我就是无法让它工作。这是包含所有内容的代码笔。
http://codepen.io/easynowbaby/pen/GJKOej?editors=001
最终,我希望能够使用 loopSquares 函数中的函数。非常感谢任何帮助。干杯!
编辑:我应该让自己更清楚。我不想用图像重新创建画廊,我只对正方形的级联淡入淡出效果感兴趣。我想在 Canvas 中实现这种效果,我将使用 fillRect 函数在小方 block 中淡入淡出。
最佳答案
问题
这里首先要指出的是如何使用 requestID
设置 alpha。来自 MDN (我的重点):
A long integer value, the request id, that uniquely identifies the entry in the callback list. 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.
换句话说,不要假设这会保持与当前单元格索引相等的运行值。它可能会在一个浏览器中不小心这样做,但在另一个浏览器中不会。通过其他方式跟踪此值。
其次,globalAlpha
作用于它旁边绘制的任何内容的整个上下文。这意味着您需要跟踪当前 per 正方形的 alpha,或使用允许您设置每种样式的 alpha 的颜色样式 rgba。这并不重要,因为您还需要在此处跟踪 alpha。
一个解决方案
我建议为此使用一个对象,一个方形猴子,可以对其进行训练以正确设置其 alpha,然后在网格中复制。
例子
Main 对象将跟踪所有设置,例如当前的 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
}
为了节省一些内存并提高性能,我们可以为常用函数/方法使用原型(prototype):
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);
}
};
我们现在需要做的是定义网格和单元格大小:
var cols = 10,
rows = 6,
cellWidth = canvas.width / cols,
cellHeight = canvas.height /rows;
现在我们可以用每个单元格的对象填充网格:
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));
}
}
最后我们需要以任何我们喜欢的方式触发这些方 block ,这里只是对 Angular 线级联方式。我们还可以跟踪是否完成所有操作:
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
}
实例
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>
实例扩展对象
通过使用单个对象,您可以在一个地方维护代码。为了好玩,让我们也添加旋转和缩放:
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>
关于javascript - 在 HTML5 Canvas 中设置不透明度动画,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29728631/