google-chrome - 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 中:
解决方案
感谢 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>
推荐阅读
- reactjs - 使用 fetch 获取数据有效,但不适用于 axios
- java - IntelliJ 2018.3 中未显示“标签(JUnit 5)”选项
- javafx - JavaFX 虚拟键盘在 Netbeans 中显示,但不在分发中
- ansible - Ansible 符号链接任务角色失败
- c# - 列出或更好的随机 C# 算法 - Unity
- wso2 - 在 API Manager 上添加新的默认层
- python - 过滤字符串中包含 N 个数字的列表元素
- xml - xsl:count 在 xsl:value-of 选择中不正确
- visual-studio - Visual Studio Pro“找不到路径的一部分”
- java - Google Play Games Android 登录出现错误代码 4