改进SVG三角形动画

时间:2016-02-28 02:54:51

标签: javascript jquery animation canvas svg

我制作了一个绘制和动画多边形的脚本:

http://codepen.io/anon/pen/GZRxRV

实际上我添加了一些多边形(我想添加超过50个)。

但我想像这样动画我的身材(缓慢的宽度和高度变换):

http://codepen.io/anon/pen/mVYWJQ

如何为我的三角形图实现类似的动画?

var svg = document.getElementsByTagName("svg")[0];
    var polyElems = [], numSteps = -660, stepNum = 0;
    /*var pts = [[451.1,386.7], [93.5,194], [343.4,-7.1]];*/
    var pts = [[-5.1,-7.1], [343.4,-7.1], [386.7,194],
              [451.1,93.5], [386.7,194], [343.4,-7.1],
              [-5.1,-7.1], [262.3,183.5], [386.7,194],
    ];

    // var palette = [['#ff0000'], ['#000']];
    var palette = ['#49c9d5','#02abc8','#02abc8','#430017'];

    var polyPts = [[0,1,2],[3,2,1],[0,7,2]];

    for (var x = 0; x < polyPts.length; x++) {
      polyElems[x] = document.createElementNS(svg.namespaceURI, 'polygon');
      polyElems[x].setAttribute('fill', [palette[x]]);
        // polyElems[x].setAttribute('fill', '#'+Math.floor(Math.random()*16777215).toString(16));
        // random hex color routine from http://www.paulirish.com/2009/random-hex-color-code-snippets/
      drawPolygon(x);
    }

    function anim() {
      pts = pts.map(function(pt) {
        return pt.map(function(coord) {
          return coord + 1 * (Math.random() - 0.5); // move each point
        });
      });
      for (var x = 0; x < polyPts.length; x++) {drawPolygon(x);}
      stepNum += 5;
      /*if (stepNum < numSteps) */requestAnimationFrame(anim); // redo anim'n until all anim'n steps don
    }

    window.setInterval(anim(), 1);
    //anim(); // start the animation

    function drawPolygon(x) {
      var ptNums = polyPts[x];
      var currCoords = [pts[ptNums[0]], pts[ptNums[1]], pts[ptNums[2]]].join();
        // creates a string of coordinates; note that [[1,2],[3,4],[5,6]].join() yields "1,2,3,4,5,6"
      polyElems[x].setAttribute('points', currCoords);
      svg.appendChild(polyElems[x]);
    }

1 个答案:

答案 0 :(得分:0)

你想要为你的Delaunay风格的三角形设置一个“摆动”动画。

<强>问题

任何一个三角形都可能与其他几个三角形共享一个顶点。

假设TriangleA&amp; TriangleB共享一个共同的顶点。

你不能只是“摆动”triangleA的顶点,因为这会导致TriangleA和TriangleB在该公共顶点处分离。

<强>解决方案

对于每个共同的顶点,您必须用相同的顶点指示每个多边形,以将它们的公共顶点移动到完全相同的新“摆动”点。

这是一种方法(警告:伪代码跟随!):

  1. 创建多边形(如果需要,再添加50个):

  2. 创建一个包含每个多边形顶点(polygon == triangle)的数组。所以每个多边形的点[0],点[1]和point [2]进入一个顶点数组。

    var vertices=[];
    
    vertices.push({ poly:poly1, x:poly1.point[0].x, y:poly1.point[0].y, index:0 });
    vertices.push({ poly:poly1, x:poly1.point[1].x, y:poly1.point[1].y, index:1 });
    vertices.push({ poly:poly1, x:poly1.point[2].x, y:poly1.point[2].y, index:2 });
    
    ... and same for each poly#
    
  3. 要“摆动”,迭代顶点数组并通过摆动因子更改每个公共顶点。例如,您可能会发现3个三角形共享[x==5 / y==10]的公共顶点。要摆动,您可以告诉3个三角形中的每一个将该公共顶点更改为[x==7 / y==9]。为了使动画看起来更平滑,您可以在一段时间内将动画从[5,10]动画到[7,9]。

  4. 示例代码和演示:

    var canvas=document.getElementById("canvas");
    var ctx=canvas.getContext("2d");
    var cw=canvas.width;
    var ch=canvas.height;
    
    var points=[[-5.1,-7.1], [343.4,-7.1], [386.7,194],
                [451.1,93.5], [386.7,194], [343.4,-7.1],
                [-5.1,-7.1], [262.3,183.5], [386.7,194]
               ];
    
    var vertices=[];
    var vpoints=[];
    var tris=[];
    var colors=['skyblue','salmon','lightgreen'];
    var wobbles=[{x:0,y:0},{x:0,y:0},{x:0,y:0}];
    
    for(var i=0;i<points.length;i++){
      // make pt easier to match
      pt={
        x:Math.round(points[i][0]),
        y:Math.round(points[i][1])
      }
      var vindex=-1;
      for(var k=0;k<vertices.length;k++){
        var vp=vertices[k].point;
        if(vp.x==pt.x && vp.y==pt.y){ vindex=k; break; }
      }
      if(vindex<0){
        vertices.push({ point:pt });
        vindex=vertices.length-1;
      }
      vpoints.push(vindex);
    }
    
    for(var i=0;i<points.length;i+=3){
      var id=parseInt(i/3);
      var tri={
        id:id,
        color:colors[id],
        points:[vpoints[i+0],vpoints[i+1],vpoints[i+2]],
        draw:function(){
          var pt0=vertices[this.points[0]].point;
          var pt1=vertices[this.points[1]].point;
          var pt2=vertices[this.points[2]].point;
          var w0=vertices[this.points[0]].wobble;
          var w1=vertices[this.points[1]].wobble;
          var w2=vertices[this.points[2]].wobble;
          var dx,dy;
          var pct=animatePct/100;
          dx=pt0.x-w0.x;
          dy=pt0.y-w0.y;
          var p0={x:pt0.x-w0.x*pct,y:pt0.y-w0.y*pct};
          dx=pt1.x-w0.x;
          dy=pt1.y-w0.y;
          var p1={x:pt1.x-w1.x*pct,y:pt1.y-w1.y*pct};
          dx=pt2.x-w0.x;
          dy=pt2.y-w0.y;
          var p2={x:pt2.x-w2.x*pct,y:pt2.y-w2.y*pct};
          ctx.beginPath();
          ctx.moveTo(p0.x,p0.y);
          ctx.lineTo(p1.x,p1.y);
          ctx.lineTo(p2.x,p2.y);
          ctx.closePath();
          ctx.fillStyle=this.color;
          ctx.fill();
        },
      };
      tris.push(tri);
    }
    
    var nextTime=0;
    var delay=1000/60*3;
    requestAnimationFrame(animate);
    var animatePct;
    var animateRate=5;
    var wobbleDirection=1;
    buildWobble();
    
    function animate(time){
      if(time<nextTime){requestAnimationFrame(animate);return;}
      nextTime=time+delay;
      drawAll();
      animatePct+=animateRate;
      if(animatePct>100){  animateRate*=-1; animatePct=100; }
      if(animatePct<000){  animateRate*=-1; animatePct=0; }
      requestAnimationFrame(animate);    
    }
    
    function drawAll(){
      // draw
      ctx.clearRect(0,0,cw,ch);
      ctx.translate(25,25);
      for(var i=0;i<tris.length;i++){
        tris[i].draw();
      }
      ctx.translate(-25,-25);
    }
    
    function buildWobble(){
      animatePct=0;
      for(var i=0;i<vertices.length;i++){
        vertices[i].wobble={x:Math.random()*40-20,y:Math.random()*40-20};
      }
    }
    <canvas id="canvas" width=510 height=260></canvas>