【问题标题】:Logo particle animation标志粒子动画
【发布时间】:2019-01-30 21:18:07
【问题描述】:

我是这个领域的新手,希望你能帮助我。 这个网站和他们拥有的粒子动画/功能让我非常受启发http://www.giantstepsmedias.com/

我发现这个和灵感很接近。但我不知道如何将其更改为图像而不是输入字段中的值。

 var canvas = document.querySelector("#scene"),
        ctx = canvas.getContext("2d"),
        particles = [],
        amount = 0,
        mouse = {x:0,y:0},
        radius = 1;

    var colors = ["rgba(255,255,255,1)","rgba(255,255,255,.5)", "rgba(255,255,255,.25)","rgba(255,255,255,.1)"];

    var copy = document.querySelector("#copy");

    var ww = canvas.width = window.innerWidth;
    var wh = canvas.height = window.innerHeight;

    function Particle(x,y){
        this.x =  Math.random()*ww;
        this.y =  Math.random()*wh;
        this.dest = {
            x : x,
            y: y
        };
        this.r =  Math.random()*5 + 2;
        this.vx = (Math.random()-0.5)*20;
        this.vy = (Math.random()-0.5)*20;
        this.accX = 0;
        this.accY = 0;
        this.friction = Math.random()*0.05 + 0.94;

        this.color = colors[Math.floor(Math.random()*6)];
    }

    Particle.prototype.render = function() {


        this.accX = (this.dest.x - this.x)/1000;
        this.accY = (this.dest.y - this.y)/1000;
        this.vx += this.accX;
        this.vy += this.accY;
        this.vx *= this.friction;
        this.vy *= this.friction;

        this.x += this.vx;
        this.y +=  this.vy;

        ctx.fillStyle = this.color;
        ctx.beginPath();
        ctx.arc(this.x, this.y, this.r, Math.PI * 2, false);
        ctx.fill();

        var a = this.x - mouse.x;
        var b = this.y - mouse.y;

        var distance = Math.sqrt( a*a + b*b );
        if(distance<(radius*70)){
            this.accX = (this.x - mouse.x)/100;
            this.accY = (this.y - mouse.y)/100;
            this.vx += this.accX;
            this.vy += this.accY;
        }

    }

    function onMouseMove(e){
        mouse.x = e.clientX;
        mouse.y = e.clientY;
    }

    function onTouchMove(e){
    if(e.touches.length > 0 ){
      mouse.x = e.touches[0].clientX;
      mouse.y = e.touches[0].clientY;
    }
    }

function onTouchEnd(e){
  mouse.x = -9999;
  mouse.y = -9999;
}

    function initScene(){
        ww = canvas.width = window.innerWidth;
        wh = canvas.height = window.innerHeight;

        ctx.clearRect(0, 0, canvas.width, canvas.height);

        ctx.font = "bold "+(ww/10)+"px sans-serif";
        ctx.textAlign = "center";
        ctx.fillText(copy.value, ww/2, wh/2);

        var data  = ctx.getImageData(0, 0, ww, wh).data;
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        ctx.globalCompositeOperation = "screen";

        particles = [];
        for(var i=0;i<ww;i+=Math.round(ww/150)){
            for(var j=0;j<wh;j+=Math.round(ww/150)){
                if(data[ ((i + j*ww)*4) + 3] > 150){
                    particles.push(new Particle(i,j));
                }
            }
        }
        amount = particles.length;

    }

    function onMouseClick(){
        radius++;
        if(radius ===5){
            radius = 0;
        }
    }

    function render(a) {
        requestAnimationFrame(render);
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        for (var i = 0; i < amount; i++) {
            particles[i].render();
        }
    };

    copy.addEventListener("keyup", initScene);
    window.addEventListener("resize", initScene);
    window.addEventListener("mousemove", onMouseMove);
    window.addEventListener("touchmove", onTouchMove);
    window.addEventListener("click", onMouseClick);
    window.addEventListener("touchend", onTouchEnd);
    initScene();
    requestAnimationFrame(render);
canvas{
    background: black;
    width: 100vw;
    height: 100vh;
} 
<canvas id="scene"></canvas>
<input id="copy" type="text" value="Hello Codepen ♥" />

【问题讨论】:

  • 将其从解释 ASCII 值转换为读取图像的二进制内容、解释该图像中显示的结构并相应地组织动画,这绝非易事。跨度>
  • 相关的代码行是ctx.fillText(copy.value, ww/2, wh/2); - 它渲染文本到ctx然后处理渲染,不是文本本身。因此,将简单的图像渲染到 ctx 而不是渲染文本似乎是微不足道的。该过程的其余部分处理呈现的数据。

标签: javascript jquery css canvas


【解决方案1】:

动画基于已渲染到画布的任何内容。

在你的代码中是

    ctx.font = "bold "+(ww/10)+"px sans-serif";
    ctx.textAlign = "center";
    ctx.fillText(copy.value, ww/2, wh/2);

改为将其更改为渲染图像:

    const img = document.getElementById('img');
    ctx.drawImage(img, ww/2, wh/2);

您可能想调整 .drawImage 的位置:https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/drawImage

使用 HTML:

<canvas id="scene"></canvas>
<div style="display:none;">
  <img id="img"
       src="http://www.giantstepsmedias.com/img/logos/giant_steps_small.png">
</div>

但是,将图像从不同的服务器渲染到您的 ctx 会得到 The canvas has been tainted by cross-origin data,所以我无法为您提供有效的 sn-p。

使用与页面位于同一服务器上的图像,或者按照建议使用data: url:

var canvas = document.querySelector("#scene"),
  ctx = canvas.getContext("2d"),
  particles = [],
  amount = 0,
  mouse = {
    x: 0,
    y: 0
  },
  radius = 1;

var colors = ["rgba(255,255,255,1)", "rgba(255,255,255,.5)", "rgba(255,255,255,.25)", "rgba(255,255,255,.1)"];

var ww = canvas.width = window.innerWidth;
var wh = canvas.height = window.innerHeight;

function Particle(x, y) {
  this.x = Math.random() * ww;
  this.y = Math.random() * wh;
  this.dest = {
    x: x,
    y: y
  };
  this.r = Math.random() * 5 + 2;
  this.vx = (Math.random() - 0.5) * 20;
  this.vy = (Math.random() - 0.5) * 20;
  this.accX = 0;
  this.accY = 0;
  this.friction = Math.random() * 0.05 + 0.94;

  this.color = colors[Math.floor(Math.random() * 6)];
}

Particle.prototype.render = function() {


  this.accX = (this.dest.x - this.x) / 1000;
  this.accY = (this.dest.y - this.y) / 1000;
  this.vx += this.accX;
  this.vy += this.accY;
  this.vx *= this.friction;
  this.vy *= this.friction;

  this.x += this.vx;
  this.y += this.vy;

  ctx.fillStyle = this.color;
  ctx.beginPath();
  ctx.arc(this.x, this.y, this.r, Math.PI * 2, false);
  ctx.fill();

  var a = this.x - mouse.x;
  var b = this.y - mouse.y;

  var distance = Math.sqrt(a * a + b * b);
  if (distance < (radius * 70)) {
    this.accX = (this.x - mouse.x) / 100;
    this.accY = (this.y - mouse.y) / 100;
    this.vx += this.accX;
    this.vy += this.accY;
  }

}

function onMouseMove(e) {
  mouse.x = e.clientX;
  mouse.y = e.clientY;
}

function onTouchMove(e) {
  if (e.touches.length > 0) {
    mouse.x = e.touches[0].clientX;
    mouse.y = e.touches[0].clientY;
  }
}

function onTouchEnd(e) {
  mouse.x = -9999;
  mouse.y = -9999;
}

function initScene() {
  ww = canvas.width = window.innerWidth;
  wh = canvas.height = window.innerHeight;

  ctx.clearRect(0, 0, canvas.width, canvas.height);

  //ctx.font = "bold "+(ww/10)+"px sans-serif";
  //ctx.textAlign = "center";
  //ctx.fillText(copy.value, ww/2, wh/2);

  const img = document.getElementById('img');
  ctx.drawImage(img, ww / 2 - 75, (wh / 2) - 75, 150, 150);

  var data = ctx.getImageData(0, 0, ww, wh).data;
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  ctx.globalCompositeOperation = "screen";

  particles = [];
  for (var i = 0; i < ww; i += Math.round(ww / 150)) {
    for (var j = 0; j < wh; j += Math.round(ww / 150)) {
      if (data[((i + j * ww) * 4) + 3] > 150) {
        particles.push(new Particle(i, j));
      }
    }
  }
  amount = particles.length;

}

function onMouseClick() {
  radius++;
  if (radius === 5) {
    radius = 0;
  }
}

function render(a) {
  requestAnimationFrame(render);
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  for (var i = 0; i < amount; i++) {
    particles[i].render();
  }
};

window.addEventListener("resize", initScene);
window.addEventListener("mousemove", onMouseMove);
window.addEventListener("touchmove", onTouchMove);
window.addEventListener("click", onMouseClick);
window.addEventListener("touchend", onTouchEnd);

initScene();
requestAnimationFrame(render);
canvas {
  background: black;
  width: 100vw;
  height: 100vh;
}
<canvas id="scene"></canvas>
<div style="display:none;">
  <img id="img" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACYAAAAsCAYAAAAJpsrIAAAC9UlEQVR42syZSWgUQRSGezJJ0IhLwIDLRQkumEMOihdFPOghcd9QEEREiIokHkQRISAKRsUdEUxAL2pGxV08iQt40QgexAUNiBgFSQY0EjEzk/J/8kqHobvrRat76sE3E7prar55vdTrl4RS6oXneaNBzvsbSdAPjoATYMCzFw3gAMj6zEvf2w2mlOJlPBgVMAmJTQY7Qa8lsQowMmR/iX7JhAxKgM0gBSZaEjNlP/PHThB14BaY48UUJYMYW8NyG1wToxgB2sA+MNQlMX3e7QZnwTiXxHSsBjfBTNfEKKaDa2BF3GIK/DSMocN5ke91ZXGKHQPthnEk1ALO8CoSuRjtfwvWg1bBfDTuMpgaxzk2nA8nrXHbQZ9h/FxwG8yPWkzlvR/mrHwyfKaaM7clzquSvnAZeG4YRwv1KXAcDItCrN9n2xOwiA+ZKRr5qtVFQLktsTVgks/2j7zvqKBioB9xndfbPlHKUCh+UeZ4DWYDL4BG0CuYpxPcAwMhY8hHLEbRAzaGyNWBD+r/Y9Biin/pQVARIFcLOoohpuMSGBsgNwakiiWmODMzAuTKwH6QKYYYRRdYFXLeNYCvxRCjyIJmzpKf3Dy+Gq2K0cmeFk7YBqoC5GrAA9sZo2zsEU76kCX85CrBOc6wFbFtPHET+C6QewfqA+SSoFUiJlmS9NMQLcZrhZVFe0BlQW2IDltrZTbv7xtgMXgqqOGosjjp0w4YYkussOZ/BpaAq4LPbgXnwYQoyp6Ez7bPXFkcKsioXywAd/LaCyrqxzdqfuzgeuubYew0cAXUgx+SyUstPNCcBu/5fKoOGVcFLvDYHPfCInvg1XGXL4rHgnK71iRlU4ziJculXGgRFEYarAN7DQ3B2MX0w0sz32DTLonpoD7aSvDGNTGK+3wfe+SaGEUnWM4ZdEqMogdsArsEba1YxXRl0cK9j26JmKnZlrQsSCXRUvAqpNf2e0nq4vTmfBbvcsE6+C9BK8RCbi/Myju8+l823i8BBgAb0AQfHTBwWAAAAABJRU5ErkJggg=="
    alt="" />
</div>

【讨论】:

  • 如果您想展示一个工作示例,我相信您可以使用 base64 图像来避免画布来源问题。
  • 请,等待图像已加载到您的代码中
  • @Kaiido 感谢您的建议,但在图像加载后仍然会出现污染错误。
  • 这与 CORS 问题无关,只是您需要等待图像已加载,然后再对其进行任何操作。我们对此有太多问题,我确实在回答中反对它。如果您想使用演示图像,upload.wikimedia 会为所有图像提供正确的标题,因此您只需设置 crossOrigin 属性。
  • @Kalido 你真的认为我没有尝试过吗?我添加了一个按钮并将initScene()/requestAnimationFrame 移动到按钮单击中。加载图像,单击按钮 - 同样的错误。画布为tainted 的原因是因为图像 加载 - 如果尚未加载,则它不会被污染。如果您对此有很多问题,也许您可​​以在使用外部服务器上的图像调用.drawImage 之后提供一个示例问题和working 答案,该答案调用.getImageData()?另外,如果它不是 CORS 问题,那么我不需要设置crossOrgin
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-08-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-20
相关资源
最近更新 更多