你的主要问题(文本像素化)是由于你没有清除画布之间的每一帧,并绘制一次又一次在同一个位置。由抗锯齿创建的半透明像素混合到越来越多的不透明像素。
但在你的情况下,似乎你真的希望至少阴影像这样混在一起。
要做到这一点,一种方法是只画一次你的正常文本,并能够画
影子,
只画形状的影子。
只绘制形状阴影的一个技巧是,将阴影偏移设置为与此位置相反的位置,从可见视口中绘制形状。
var text = 'foo bar';
var ctx = canvas.getContext('2d');
var original_x = 20; // the position it would have been
ctx.font = '30px sans-serif';
var targetPosition = ctx.measureText(text).width + original_x + 2;
// default shadow settings
ctx.shadowColor = 'red';
ctx.shadowBlur = 3;
// just to show what happens
var x = 0;
anim();
function anim() {
if(++x >= targetPosition) {
x=0;
return;
}
// if we weren't to show the anim, we would use 'targetPosition'
// instead of 'x'
ctx.shadowOffsetX = x;
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.fillText(text, -x + original_x, 30);
requestAnimationFrame(anim);
}
// restart the anim on click
onclick = function() {
if(x===0)anim();
};
<canvas id="canvas"></canvas>
一旦我们有了这个清晰的阴影,不需要在上面画我们的形状,我们就可以随心所欲地重新画它。
这个
“目的地结束”
compositing option
就是这样。
(请注意,我们还可以将干净的阴影保留在屏幕外的画布上,以便进行表演,因为阴影是一个非常缓慢的操作。)
var text = 'foo bar';
var ctx = canvas.getContext('2d');
ctx.font = '48px sans-serif';
var x = 20;
var y = 40;
var shadow = generateTextShadow(ctx, text, x, y, 'red', 5);
ctx.globalAlpha = 0.5;
ctx.fillText(text, x, y);
// from now on we'll draw behind current content
ctx.globalCompositeOperation = 'destination-over';
var shadow_pos = 0;
anim();
// in the anim, we just draw the shadow at a different offset every frame
function anim() {
if(shadow_pos++ > 65) return;
ctx.drawImage(shadow, shadow_pos, shadow_pos);
requestAnimationFrame(anim);
}
// returns a canvas where only the shadow of the text provided is drawn
function generateTextShadow(original_ctx, text, x, y, color, blur, offsetX, offsetY) {
var canvas = original_ctx.canvas.cloneNode();
var ctx = canvas.getContext('2d');
ctx.font = original_ctx.font;
var targetPosition = ctx.measureText(text).width + 2;
// default shadow settings
ctx.shadowColor = color || 'black';
ctx.shadowBlur = blur || 0;
ctx.shadowOffsetX = targetPosition + x +(offsetX ||0);
ctx.shadowOffsetY = (offsetY || 0);
ctx.fillText(text, -targetPosition, y);
return canvas;
}
<