首页 > 解决方案 > Chrome 画布:忽略了小的 globalAlpha

问题描述

在 Chromium 90.0.4430.93(它使用与 Chrome 相同的渲染引擎)上,以下淡入淡出效果不起作用。为什么?以及如何解决它?

它是通过在画布上用另一张黑色画布和globalAlpha每次requestAnimationFrame通话的低点来完成的。

var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');

let start;
let lastTime;

function draw() {
    canvas.bgcanvas = document.createElement('canvas');
    canvas.bgcanvas.width = canvas.width;
    canvas.bgcanvas.height = canvas.height;
    
    bgctx = canvas.bgcanvas.getContext('2d');
    
    bgctx.fillStyle   = '#000';
    bgctx.fillRect(0, 0, canvas.width, canvas.height);
}

function step(timestamp) {
    if (start === undefined)
        start = timestamp;
        lastTime = timestamp;
        
    const elapsed = timestamp - lastTime;
    lastTime = timestamp;

    ctx.globalAlpha = 0.0001*elapsed;
    ctx.drawImage(canvas.bgcanvas, 0, 0);
    ctx.globalAlpha = 1;
    
    var x = (timestamp - start)*0.01 % 200;
    var y = 0;
    
    ctx.beginPath();
    ctx.fillStyle = '#77f';
    ctx.arc(x, canvas.height/2-y, 7, 0, Math.PI * 2, true);
    ctx.closePath();
    ctx.fill();
    
    window.requestAnimationFrame(step);
}

function resizeCanvas() {
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;

    lines = [];
    
    draw();
    ctx.drawImage(canvas.bgcanvas, 0, 0);
}

window.addEventListener('resize', resizeCanvas, false);
resizeCanvas();
window.requestAnimationFrame(step);
* { margin:0; padding:0; } /* to remove the top and left whitespace */

body {
    width:100%; height:100%;
}

canvas {
    display:block;
}
<canvas id="canvas"></canvas>

结果在 Firefox 中:

在此处输入图像描述

结果铬: 在此处输入图像描述

标签: google-chromehtml5-canvas

解决方案


感谢 Blindman67 的评论,我现在明白要获得上图中所示的相同指数衰减并非易事。但是一个独立工作的线性浏览器相对简单:只需#010101通过以下代码在每个渲染步骤上减去:

ctx.globalCompositeOperation = "difference";
ctx.fillStyle   = '#010101';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.globalCompositeOperation = "source-over";

为了改变衰减速度,可以例如仅在每第 i 次迭代中应用此效果。

由于我需要这个渐变的背景不是纯黑色,而是具有其他内容,因此我在新的画布 ( contentcanvas) 上创建了一个亮度蒙版,然后将其应用于背景。这是一个展示完整解决方案的示例:

var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');

let start;
let lastTime;

let stepMod = 0;

function draw() {
    canvas.bgcanvas = document.createElement('canvas');
    canvas.bgcanvas.width = canvas.width;
    canvas.bgcanvas.height = canvas.height;
    
    bgctx = canvas.bgcanvas.getContext('2d');
    
    canvas.contentcanvas = document.createElement('canvas');
    canvas.contentcanvas.width = canvas.width;
    canvas.contentcanvas.height = canvas.height;
    
    canvas.contentctx = canvas.contentcanvas.getContext('2d');
    
    canvas.tmpcanvas = document.createElement('canvas');
    canvas.tmpcanvas.width = canvas.width;
    canvas.tmpcanvas.height = canvas.height;
    
    canvas.tmpctx = canvas.tmpcanvas.getContext('2d');
    
    bgctx.fillStyle   = '#000';
    bgctx.fillRect(0, 0, canvas.width, canvas.height);
        bgctx.font = "30px serif";
    bgctx.fillStyle   = '#ca3';
    bgctx.fillText("Hey!", 10, canvas.height/2+10);
}

function step(timestamp) {
    if (start === undefined)
        start = timestamp;
        lastTime = timestamp;
        
    const elapsed = timestamp - lastTime;
    lastTime = timestamp;
    
    if (stepMod == 1) {
        canvas.contentctx.globalCompositeOperation = "difference";
        canvas.contentctx.fillStyle   = '#010101';
        canvas.contentctx.fillRect(0, 0, canvas.width, canvas.height);
        canvas.contentctx.globalCompositeOperation = "source-over";
        stepMod = 0;
    }
    else {
        stepMod += 1;
    }
    
    var x = (timestamp - start)*0.01 % 200;
    var y = 0;
    
    canvas.contentctx.beginPath();
    canvas.contentctx.fillStyle = '#fff';
    canvas.contentctx.arc(x, canvas.height/2-y, 7, 0, Math.PI * 2, true);
    canvas.contentctx.closePath();
    canvas.contentctx.fill();
    
    canvas.tmpctx.clearRect(0, 0, canvas.width, canvas.height);
    canvas.tmpctx.drawImage(canvas.contentcanvas, 0, 0);
    canvas.tmpctx.globalCompositeOperation = "multiply";
    canvas.tmpctx.fillStyle = '#77f';
    canvas.tmpctx.fillRect(0, 0, canvas.width, canvas.height);
    canvas.tmpctx.globalCompositeOperation = "source-over";

                ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.fillStyle   = '#fff';
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    ctx.globalCompositeOperation = "difference";
    ctx.drawImage(canvas.contentcanvas, 0, 0);
    ctx.globalCompositeOperation = "multiply";
    ctx.drawImage(canvas.bgcanvas, 0, 0);
    ctx.globalCompositeOperation = "lighter";
    ctx.drawImage(canvas.tmpcanvas, 0, 0);
    ctx.globalCompositeOperation = "source-over";
    
    window.requestAnimationFrame(step);
}

function resizeCanvas() {
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;

    lines = [];
    
    draw();
    ctx.drawImage(canvas.bgcanvas, 0, 0);
}

window.addEventListener('resize', resizeCanvas, false);
resizeCanvas();
window.requestAnimationFrame(step);
* { margin:0; padding:0; } /* to remove the top and left whitespace */

body {
    width:100%; height:100%;
}

canvas {
    display:block;
}
<canvas id="canvas"></canvas>


推荐阅读