JS Canvas 分别为网格元素设置动画

JS Canvas animate grid elements individually

我正在使用 for 循环生成六边形网格,但遇到了一些问题

    for (var i=0; i <= rows; i++) {
        for (var j=0; j <= cols; j++) {
            ctx.save();
            ctx.translate(0+i*distX, 0+j*distY);
            drawHexagon(ctx);
            ctx.fill();
            ctx.restore();
        }
    }

我的最终目标是创建一个六边形网格,当鼠标光标在页面上移动时,它会远离鼠标光标,并具有一个影响区域。我不知道如何在每个六边形之间绘制一条路径,而且我在尝试为六边形设置动画时也遇到了问题。

我仍然是 canvas 新手,我浏览了 Mozilla 开发者网络上的教程,所有动画都针对单个对象,而不是在网格中生成的对象。

我在想我应该尝试存储网格并在以后影响它,但我不确定我会怎么做,我也不认为 canvas 那样工作。

我发现这几乎是我想做的,但我不明白它是如何工作的: http://codepen.io/soulwire/pen/Ffvlo

我现在可以很好地梳理它,如果有人可以引导我完成它,那就太好了:)

编辑:我已经在点后面画了一个网格,我也想操纵它。我还是不明白上面链接的codepen,有点过头了。

你的 link 施加了 2 个力:

  1. 鼠标附近的粒子被排斥。更具体地说,如果粒子中心点靠近鼠标中心点,则粒子沿着两个中心点之间的线被排斥。

  2. 不靠近鼠标的粒子被吸引回到它们原来的位置。更具体地说,粒子沿着它们当前中心点和它们原来中心点之间的线向它们原来的中心点移动。

数学是这样计算的:

// Given the mouse centerpoint (mx,my) & particle's centerpoint (px,py)

// calculate the difference between x's & y's
var dx=px-mx;
var dy=py-my;

// You can repel the particle by increasing the
// particle's position by a fraction of dx & dy
px+=dx/100;
py+=dy/100;

// And you can attract the particle by decreasing the
// particle's position by a fraction of dx & dy
px-=dx/100;
py-=dy/100;

这是带注释的代码和一个 Demo(为了便于理解删除了缓动):

// canvas related variables
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
function reOffset(){
  var BB=canvas.getBoundingClientRect();
  offsetX=BB.left;
  offsetY=BB.top;        
}
var offsetX,offsetY;
reOffset();
window.onscroll=function(e){ reOffset(); }
window.onresize=function(e){ reOffset(); }

ctx.fillStyle='skyblue';

// mouse related variables
var PI2=Math.PI*2;
var mouseRadius=75;   // this is the mouse's radius of influence
var mouseRadiusSquared=mouseRadius*mouseRadius;
var mouseIsDown=false;
var mx,my;


// define a bunch of hex objects stored in an array
var hexRadius=5;
var hexPadding=5;
var hexes=[];
for(var y=hexRadius;y<ch;y+=hexRadius*2+hexPadding){
  for(var x=hexRadius;x<cw;x+=hexRadius*2+hexPadding){
    hexes.push({startingX:x,startingY:y,x:x,y:y});
  }}


// start a continuously running ticker loop
requestAnimationFrame(tick);


// listen for mouse events
$("#canvas").mousedown(function(e){handleMouseDown(e);});
$("#canvas").mouseup(function(e){handleMouseUp(e);});


// draw every hex in its current position
function draw(){
  ctx.clearRect(0,0,cw,ch);
  ctx.beginPath();
  for(var i=0;i<hexes.length;i++){
    var h=hexes[i];
    ctx.moveTo(h.x,h.y);
    ctx.arc(h.x,h.y,hexRadius,0,PI2);
    ctx.closePath();
  }
  ctx.fill();
}

// create a continuously running ticker
function tick(time){

  // update each hex position based on its 
  // position relative to the mouse
  for(var i=0;i<hexes.length;i++){
    var h=hexes[i];
    // calculate if this hex is inside the mouse radius
    var dx=h.x-mx;
    var dy=h.y-my;
    if(mouseIsDown && dx*dx+dy*dy<mouseRadiusSquared){
      // hex is inside mouseRadius
      // so mouseDown repels hex
      h.x+=dx/120;
      h.y+=dy/120;
    }else if(h.x==h.startingX && h.y==h.startingY){
      // hex is at startingX/Y & is not being repelled
      // so do nothing
    }else{
      // hex has moved off startingX/Y
      // but is no longer being repelled
      // so gravity attracts hex back to its startingX/Y
      dx=h.x-h.startingX;
      dy=h.y-h.startingY;
      h.x-=dx/60;
      h.y-=dy/60;            
    }
  }

  // redraw the hexes in their new positions
  draw();

  // request another tick
  requestAnimationFrame(tick);
}


// listen for mousedown events
function handleMouseDown(e){

  // tell the browser we're handling this event
  e.preventDefault();
  e.stopPropagation();

  // calculate the mouse position
  mx=parseInt(e.clientX-offsetX);
  my=parseInt(e.clientY-offsetY);

  // set the mousedown flag
  mouseIsDown=true;
}


// listen for mouseup events
function handleMouseUp(e){

  // tell the browser we're handling this event
  e.preventDefault();
  e.stopPropagation();

  // clear the mousedown flag 
  mouseIsDown=false;
}
body{ background-color: ivory; padding:10px; }
#canvas{border:1px solid red;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>

<h4>Press the mouse down to repel the particles.<br>Release to return particles to starting point.</h4>
<canvas id="canvas" width=300 height=300></canvas>