Chrome Canvas: 忽略小的 globalAlpha
Chrome Canvas: Small globalAlpha ignored
在 Chromium 90.0.4430.93(使用与 Chrome 相同的渲染引擎)上,以下淡入淡出效果不起作用。为什么?如何修复它?
它是通过在 canvas 上涂上另一个黑色 canvas 和一个低 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 中的结果:
Chromium 结果:
感谢 Blindman67 的评论,我现在明白要获得上图中所示的相同指数衰减并非易事。但是独立于浏览器工作的线性相对简单:只需通过以下代码在每个渲染步骤上减去 #010101
:
ctx.globalCompositeOperation = "difference";
ctx.fillStyle = '#010101';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.globalCompositeOperation = "source-over";
要改变衰减速度,可以例如仅在第 i 次迭代中应用此效果。
因为我需要这个淡入淡出的背景不是纯黑色,而是有其他内容,所以我在新的 canvas (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>
在 Chromium 90.0.4430.93(使用与 Chrome 相同的渲染引擎)上,以下淡入淡出效果不起作用。为什么?如何修复它?
它是通过在 canvas 上涂上另一个黑色 canvas 和一个低 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 中的结果:
Chromium 结果:
感谢 Blindman67 的评论,我现在明白要获得上图中所示的相同指数衰减并非易事。但是独立于浏览器工作的线性相对简单:只需通过以下代码在每个渲染步骤上减去 #010101
:
ctx.globalCompositeOperation = "difference";
ctx.fillStyle = '#010101';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.globalCompositeOperation = "source-over";
要改变衰减速度,可以例如仅在第 i 次迭代中应用此效果。
因为我需要这个淡入淡出的背景不是纯黑色,而是有其他内容,所以我在新的 canvas (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>