Canvas HTML fillText letters to not animate only shadows

时间:2018-09-18 19:31:44

标签: javascript html canvas

Only want shadows to animate and keep the fillText from animating due to letters pixelating from getting ran over and over.

    var canvas = document.getElementById('canvas')
    var ctx = this.canvas.getContext('2d')
    var width = canvas.width = canvas.scrollWidth
    var height = canvas.height = canvas.scrollHeight
    var start;
    var j=0;
	var makeText = function(){  
	   j+=1 

	   ctx.shadowColor= 'red'; 
       ctx.shadowOffsetX = j;  //animate
	   ctx.shadowOffsetY = j; //animate
	   ctx.globalAlpha=0.5;
	   ctx.font = "48px serif";
       ctx.fillStyle = "black";
       ctx.fillText('hey you', width/2, height / 2); //Only ran once so letters 
                                                     //don't pixelate!
   }
    
    			
	function animateText(timestamp){
		var runtime = timestamp - start;
		var progress = Math.min(runtime / 1400, 1); 
 
		makeText(progress)
				
		if(progress < 1){
			requestAnimationFrame(animateText)
		}else {
			return;
		}
	}
	requestAnimationFrame(function(timestamp){
		start = timestamp;
		animateText(timestamp)
	})
			 
<canvas id="canvas" width=500px height=500px></canvas>

My outcome of the process would only have shadows animate and keeping letters where they are

2 个答案:

答案 0 :(得分:2)

只需绘制自己的阴影,这是一个示例:

var canvas = document.getElementById('canvas')
var ctx = this.canvas.getContext('2d')
ctx.font = "68px serif";
var base = {text: 'hey you', x: 10, y: 60 }
var inc = 2;
var j = 30;

var makeText = function() {
  ctx.globalAlpha = 1;
  ctx.fillStyle = "black";
  ctx.fillText(base.text, base.x, base.y); 
}

var makeshadow = function(offset) {
  ctx.fillStyle = "red";
  for (var i = 0; i < offset; i++) {
    ctx.globalAlpha = 1/i;
    ctx.fillText(base.text, base.x + i, base.y + i);
  }
}

function animateText() {  
  ctx.clearRect(0, 0, 999, 999)
  makeshadow(j);
  makeText();  
  j += inc;
  if (j > 35 || j < 3) inc *= -1
}

setInterval(animateText, 50)
<canvas id="canvas" width=300px height=170px></canvas>


如果在混合中添加一些数学运算,则可以获得一些很酷的效果:

var canvas = document.getElementById('canvas')
var ctx = this.canvas.getContext('2d')
ctx.font = "68px serif";
var base = {text: '123456', x: 30, y: 80 }
var inc = 5;
var j = 0;

var makeText = function() {
  ctx.globalAlpha = 1;
  ctx.fillStyle = "black";
  ctx.fillText(base.text, base.x, base.y); 
}

var makeshadow = function(offset) {
  ctx.globalAlpha = 0.05;
  ctx.fillStyle = "red";
  for (var i = 0; i < offset; i++)
    ctx.fillText(base.text, base.x + Math.sin(i/5)*10, base.y + Math.cos(i/5)*15);
}

function animateText() {  
  ctx.clearRect(0, 0, 999, 999)
  makeshadow(j);
  makeText();  
  j += inc;
  if (j > 120 || j < 0) inc *= -1
}
setInterval(animateText, 50)
<canvas id="canvas" width=300px height=170px></canvas>

答案 1 :(得分:1)

您的主要问题(文本像素化)是由于您没有清除每帧之间的画布,而是在同一位置上一次又一次地绘制。通过抗锯齿创建的半透明像素会混合到越来越多的不透明像素。

但是在您的情况下,您似乎实际上希望至少将阴影像这样混合起来。

要做到这一点,一种方法是只绘制一次您的普通文本,并能够绘制当前图纸的后面的阴影。


仅绘制形状的阴影。

仅绘制形状阴影的一种技巧是从可见的viewPort中绘制形状,并将shadowOffsets设置为该位置的倒数。

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;
}
<canvas id="canvas"></canvas>