我有一 block 黑色 Canvas ,里面画着东西。我希望里面绘制的东西随着时间的推移,按照绘制的顺序(先进先出)逐渐变成黑色。如果我使用尚未调整大小的 Canvas ,则此方法有效。调整 Canvas 大小时,元素会褪色为灰白色。
问题:调整 Canvas 大小后,为什么白色 Blob 不会完全褪色为黑色?如何让它们像我没有调整 Canvas 大小时那样淡出为黑色?
这是一些演示代码。 http://jsfiddle.net/6VvbQ/35/
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
context.fillRect(0, 0, 300, 150);
// Comment this out and it works as intended, why?
canvas.width = canvas.height = 300;
window.draw = function () {
context.fillStyle = 'rgba(255,255,255,1)';
context.fillRect(
Math.floor(Math.random() * 300),
Math.floor(Math.random() * 150),
2, 2);
context.fillStyle = 'rgba(0,0,0,.02)';
context.fillRect(0, 0, 300, 150);
setTimeout('draw()', 1000 / 20);
}
setTimeout('draw()', 1000 / 20);
最佳答案
问题分为两部分:
当您使用较低的 alpha 值进行绘制时,会出现 ( rather known ) 舍入错误。浏览器将永远无法获得等于 0 的颜色和 Alpha channel 的混合结果,因为混合后的浮点值将在绘制时转换为整数,这意味着该值永远不会低于 1。混合它时(值 1,因为 alpha 内部是 0 到 255 之间的值)将再次使用该值,并再次四舍五入为 1,并且永远如此。
为什么当你调整 Canvas 大小时它会起作用 - 在这种情况下,这是因为你只将大 Canvas 的一半绘制到较小的 Canvas 上,这导致像素被插值。由于该值非常低,这意味着在这种情况下,像素将变成“黑色”(完全透明),因为周围像素之间的平均值将导致该值四舍五入为 0 - 与 #1 相反。 p>
要解决此问题,您必须在预期为黑色时手动清除规范。这将涉及您自己跟踪每个粒子/规范或使用直接像素操作更改 Alpha。
更新:
关键是使用跟踪。您可以通过将每个规范创建为自动更新点来跟踪 alpha 和清除来实现此目的。
Online demo here
一个简单的规范对象可以如下所示:
function Spec(ctx, speed) {
var me = this;
reset(); /// initialize object
this.update = function() {
ctx.clearRect(me.x, me.y, 1, 1); /// clear previous drawing
this.alpha -= speed; /// update alpha
if (this.alpha <= 0) reset(); /// if black then reset again
/// draw the spec
ctx.fillStyle = 'rgba(255,255,255,' + me.alpha + ')';
ctx.fillRect(me.x, me.y, 1, 1);
}
function reset() {
me.x = (ctx.canvas.width * Math.random())|0; /// random x rounded to int
me.y = (ctx.canvas.height * Math.random())|0; /// random y rounded to int
if (me.alpha) { /// reset alpha
me.alpha = 1.0; /// set to 1 if existed
} else {
me.alpha = Math.random(); /// use random if not
}
}
}
当我们需要清除规范时,将 x 和 y 舍入为整数值可以节省一些时间,因为我们不会遇到子像素。否则,您还需要清除规范周围的区域。
下一步是生成多个点:
/// create 100 specs with random speed
var i = 100, specs = [];
while(i--) {
specs.push(new Spec(ctx, Math.random() * 0.015 + 0.005));
}
您只需使用可根据规范单独设置的速度,而无需扰乱 FPS。
现在只需更新循环中的每个对象即可:
function loop() {
/// iterate each object
var i = specs.length - 1;
while(i--) {
specs[i].update(); /// update each object
}
requestAnimationFrame(loop); /// loop synced to monitor
}
如您所见,性能不是问题,并且没有残留。希望这会有所帮助。
关于javascript - 调整大小的黑色 Canvas 不会随着时间的推移完全褪色为黑色,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20211855/