javascript - 调整大小的黑色 Canvas 不会随着时间的推移完全褪色为黑色

标签 javascript html canvas html5-canvas

我有一 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);

最佳答案

问题分为两部分:

  1. 当您使用较低的 alpha 值进行绘制时,会出现 ( rather known ) 舍入错误。浏览器将永远无法获得等于 0 的颜色和 Alpha channel 的混合结果,因为混合后的浮点值将在绘制时转换为整数,这意味着该值永远不会低于 1。混合它时(值 1,因为 alpha 内部是 0 到 255 之间的值)将再次使用该值,并再次四舍五入为 1,并且永远如此。

  2. 为什么当你调整 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/

相关文章:

javascript - 如何使用 jquery 移动侧边菜单和顶部栏

javascript - waitForSelector ("...",函数 success()/函数 failed() 的目的?

javascript - 当我使用 PrivateRoute 时,当我重新加载页面时,我总是会转到登录页面一次

javascript - 在 Angular 中使用 JSON 对象的默认选择选项

javascript - 如何保存带有webkit-filter效果的html5视频元素?

javascript - 如何在fabricjs中选择位于另一个形状边界内的形状?

canvas - ios11 webview html canvas 内容被页面滚动清除

javascript - 获取图标的父 div ID onclick

javascript - 隐藏行开始和结束文本分隔符

html - 在响应式网站中从顶部和底部隐藏/切片图像