Html 使用画布获取setInterval上的像素数据

Html 使用画布获取setInterval上的像素数据,html,animation,canvas,Html,Animation,Canvas,我想建立一个由粒子组成的动画字母表。基本上,粒子从一个字母形状转换为另一个字母形状 我的想法是在画布上以文本的形式快速填充字母(就像一帧),获取像素数据并将粒子放置到setInterval上的正确位置。我现在有扫描屏幕的代码: var ctx = canvas.getContext('2d'), width = ctx.canvas.width, height = ctx.canvas.height, particles = [], gridX = 8,

我想建立一个由粒子组成的动画字母表。基本上,粒子从一个字母形状转换为另一个字母形状

我的想法是在画布上以文本的形式快速填充字母(就像一帧),获取像素数据并将粒子放置到setInterval上的正确位置。我现在有扫描屏幕的代码:

var ctx = canvas.getContext('2d'),
    width = ctx.canvas.width,
    height = ctx.canvas.height,

    particles = [],
    gridX = 8,
    gridY = 8;

function Particle(x, y) {
    this.x = x;
    this.y = y;
}

// fill some text
ctx.font = 'bold 80px sans-serif';
ctx.fillStyle = '#ff0';
ctx.fillText("STACKOVERFLOW", 5, 120);

// now parse bitmap based on grid
var idata = ctx.getImageData(0, 0, width, height);

// use a 32-bit buffer as we are only checking if a pixel is set or not
var buffer32 = new Uint32Array(idata.data.buffer);

// using two loops here, single loop with index-to-x/y is also an option
for(var y = 0; y < height; y += gridY) {
  for(var x = 0; x < width; x += gridX) {

    //buffer32[] will have a value > 0 (true) if set, if not 0=false
    if (buffer32[y * width + x]) {
      particles.push(new Particle(x, y));
    }
  }
}

// render particles
ctx.clearRect(0, 0, width, height);

particles.forEach(function(p) {
  ctx.fillRect(p.x - 2, p.y - 2, 4, 4); // just squares here
})
var ctx=canvas.getContext('2d'),
宽度=ctx.canvas.width,
高度=ctx.canvas.height,
粒子=[],
gridX=8,
gridY=8;
函数粒子(x,y){
这个.x=x;
这个。y=y;
}
//填写一些文字
ctx.font='bold 80px sans serif';
ctx.fillStyle='#ff0';
ctx.fillText(“STACKOVERFLOW”,5120);
//现在基于网格解析位图
var idata=ctx.getImageData(0,0,宽度,高度);
//使用32位缓冲区,因为我们只检查是否设置了像素
var buffer32=新的UINT32阵列(idata.data.buffer);
//这里使用两个循环,索引为x/y的单循环也是一个选项
对于(变量y=0;y

但这样我只展示了一个词,没有任何变化。另外,我想先设置200个粒子,然后根据像素数据重新组织它们,而不是在每次扫描时创建它们。。如何重写代码,以便每1500毫秒我可以传递一个不同的字母并用粒子渲染它?

希望代码的不同部分应该足够清晰:有粒子可以绘制和更新,fillParticle将从文本字符串中生成粒子,而spawnChars将获得定期呈现的文本的新部分

它工作得很好,如果您愿意,可以使用这些参数,它们都在小提琴的开头。
您可能希望通过避免全局变量和创建类来使代码更干净

//--------------------
//参数
var text='STACKOVERFLOW';
高度=80;
var gridX=4,
gridY=4;
var-partSize=2;
var charDelay=400;//两个字符之间的时间,单位为毫秒
var spead=80;//从起点到终点的最大距离
var partSpeed=0.012;
// --------------------
var canvas=document.getElementById('cv'),
ctx=canvas.getContext('2d'),
宽度=ctx.canvas.width,
高度=ctx.canvas.height,
粒子=[];
ctx.translate(0.5,0.5);
// --------------------
//粒子类
功能粒子(startX、startY、finalX、finalY){
this.speed=partSpeed*(1+Math.random()*0.5);
这个.x=startX;
这个。y=星形;
this.startX=startX;
this.startY=startY;
this.finalX=finalX;
this.finalY=finalY;
该参数=0;
this.draw=函数(){
ctx.fillRect(此.x-零件尺寸*0.5,此.y-零件尺寸*0.5,零件尺寸,零件尺寸);
};
this.update=函数(p){
如果(此参数>=1)返回;
此参数+=零件速度;
如果(此参数>=1)此参数=1;
VAR PAR=此参数;
this.x=par*this.finalX+(1-par)*this.startX;
this.y=par*this.finalY+(1-par)*this.startY;
};
}
// --------------------
//文本产卵器
函数fillParticle(文本、offx、offy、排列){
//填写一些文字
tmpCtx.clearRect(0,0,tmpCtx.canvas.width,tmpCtx.canvas.height);
tmpCtx.font='bold'+fontHeight+'px sans serif';
tmpCtx.fillStyle='#A40';
tmpCtx.textBaseline='top';
tmpCtx.textAlign='left';
tmpCtx.fillText(文本,0,0);
//
var txtWidth=Math.floor(tmpCtx.measureText(text.width);
//现在基于网格解析位图
var idata=tmpCtx.getImageData(0,0,txtWidth,fontHeight);
//使用32位缓冲区,因为我们只检查是否设置了像素
var buffer32=新的UINT32阵列(idata.data.buffer);
//这里使用两个循环,索引为x/y的单循环也是一个选项
对于(变量y=0;y=text.length)返回;
if(Date.now()-lastSpawnDate
对于动画,只需处理一个起点/终点,并在动画循环中插值:对于逐字母功能,还有更多工作:您必须使用measureText,在辅助画布上绘制,获取ImageData,并为添加到当前粒子集的新字母构建一组新粒子。这需要一点组织才能避免混乱。祝你好运谢谢,伙计!当我在一张纸上画的时候
// --------------------
// parameters

var text = 'STACKOVERFLOW';
var fontHeight = 80;
var gridX = 4,
    gridY = 4;
var partSize = 2; 
var charDelay = 400; // time between two chars, in ms
var spead = 80; // max distance from start point to final point
var partSpeed = 0.012;

// --------------------
var canvas = document.getElementById('cv'),
    ctx = canvas.getContext('2d'),
    width = ctx.canvas.width,
    height = ctx.canvas.height,
    particles = [];

ctx.translate(0.5,0.5);

// --------------------
// Particle class
function Particle(startX, startY, finalX, finalY) {
    this.speed = partSpeed*(1+Math.random()*0.5);
    this.x = startX;
    this.y = startY;

    this.startX = startX;
    this.startY = startY;
    this.finalX =finalX;
    this.finalY =finalY;
    this.parameter = 0;
    this.draw = function() {
        ctx.fillRect(this.x - partSize*0.5, this.y - partSize*0.5, partSize, partSize);
    };
    this.update = function(p) {
       if (this.parameter>=1) return;
       this.parameter += partSpeed;
       if (this.parameter>=1) this.parameter=1;
       var par = this.parameter;
       this.x = par*this.finalX + (1-par)*this.startX;
       this.y = par*this.finalY + (1-par)*this.startY;
   };
}

// --------------------
// Text spawner

function fillParticle(text, offx, offy,  spread) {
   // fill some text
   tmpCtx.clearRect(0,0,tmpCtx.canvas.width, tmpCtx.canvas.height);
   tmpCtx.font = 'bold ' + fontHeight +'px sans-serif';
   tmpCtx.fillStyle = '#A40';
   tmpCtx.textBaseline ='top';
   tmpCtx.textAlign='left';
   tmpCtx.fillText(text, 0, 0);
   //
   var txtWidth = Math.floor(tmpCtx.measureText(text).width);
   // now parse bitmap based on grid
   var idata = tmpCtx.getImageData(0, 0, txtWidth, fontHeight);

   // use a 32-bit buffer as we are only checking if a pixel is set or not
   var buffer32 = new Uint32Array(idata.data.buffer);

   // using two loops here, single loop with index-to-x/y is also an option
   for(var y = 0; y < fontHeight; y += gridY) {
     for(var x = 0; x < txtWidth; x += gridX) {
        //buffer32[] will have a value > 0 (true) if set, if not 0=false
        if (buffer32[y * txtWidth + x]) {
           particles.push(new Particle(offx + x+Math.random()*spread - 0.5*spread, 
                                  offy + y+Math.random()*spread - 0.5*spread, offx+x, offy+y));
        }
    }
  }  
  return txtWidth;
}

var tmpCv = document.createElement('canvas');
// uncomment for debug
//document.body.appendChild(tmpCv);
var tmpCtx = tmpCv.getContext('2d');

// --------------------------------
// spawn the chars of the text one by one

var charIndex = 0;
var lastSpawnDate = -1;
var offX = 30;
var offY = 30;

function spawnChars() {
  if (charIndex>= text.length) return;
  if (Date.now()-lastSpawnDate < charDelay) return;
  offX += fillParticle(text[charIndex], offX, offY, spead);
  lastSpawnDate = Date.now();
  charIndex++;                           
}


// --------------------------------

function render() {
   // render particles
   particles.forEach(function(p) { p.draw();
   });  
}

function update() {
   particles.forEach(function(p) { p.update(); } );    
}

// --------------------------------
//  animation
function animate(){
   requestAnimationFrame(animate);
   ctx.clearRect(0, 0, width, height);
   render();
    update();
  //
  spawnChars();
}

// launch : 
animate();