Благодаря предложению @ Kaiido о третьем полотне и ответу @Soul_man в этом посте У меня появилась идея, которая, кажется, работает хорошо. Вместо того, чтобы держать исходное изображение на третьем холсте (казалось громоздким, но, возможно, я ошибаюсь - может быть, это хуже в памяти?) Теперь я сохраняю исходное изображение с помощью getImageData и записываю его в холст в каждом цикле, прежде чем писать в новом изображении все выше и выше уровень непрозрачности. Сценарий ниже и здесь jsbin .
<canvas id="main" width="500" height="300" style="border: 1px solid #ff0000;"></canvas>
<canvas id="test" width="500" height="300" style="border: 1px solid #ff0000;"></canvas>
<script>
var width = 500, height = 300, text = "hello";
var main = document.getElementById('main');
var mainctx = main.getContext('2d');
//begin path, create a rect the size of the canvas
mainctx.beginPath();
mainctx.rect(0, 0, width, height);
//percentage to hex colour and fill canvas rect
mainctx.fillStyle = "#ff0000";
mainctx.fill();
//write text to canvas
mainctx.font = 'Bold 100px Arial';
mainctx.textAlign="center";
mainctx.textBaseline = "middle";
mainctx.fillStyle = '#ffffff';
mainctx.fillText(text, 0 + (width / 2), 0 + (height / 2));
var test = document.getElementById('test');
var testctx = test.getContext('2d');
//begin path, create a rect the size of the canvas
testctx.beginPath();
testctx.rect(0, 0, width, height);
//percentage to hex colour and fill canvas rect
testctx.fillStyle = "#00ff00";
testctx.fill();
//start opacity at 0
var op = 0;
//copy the existing main canvas image into memory
var originalimage = mainctx.getImageData(0, 0, width, height);
//fade canvas
function fade()
{
//place the original image
mainctx.putImageData(originalimage, 0, 0);
//starting at 0 set the global alpha and then draw the new image
mainctx.globalAlpha = op;
mainctx.drawImage(testctx.canvas, 0, 0);
//increment
op += 0.01;
if (op >= 1.0) setTimeout(function(){ console.log("done"); }, 2000);
else requestAnimationFrame(fade);
}
fade();
</script>