【问题标题】:Improving SVG triangles animation改进 SVG 三角形动画
【发布时间】:2016-06-11 05:29:38
【问题描述】:

我编写了一个脚本来绘制多边形并为其设置动画:

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]);
    }

【问题讨论】:

    标签: javascript jquery animation canvas svg


    【解决方案1】:

    您想要为您的 Delaunay 样式的三角形设置“摆动”动画。

    问题

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

    假设 TriangleA 和 TriangleB 共享一个公共顶点。

    您不能只是“摆动”三角形 A 的顶点,因为这会导致三角形 A 和三角形 B 在该公共顶点处分离。

    解决方案

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

    这是一种方法(警告:伪代码如下!):

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

    2. 创建一个包含每个多边形顶点的数组(多边形==三角形)。所以每个多边形的 point[0], point[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] 的移动进行动画处理。

    示例代码和演示:

    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};
      }
    }
    &lt;canvas id="canvas" width=510 height=260&gt;&lt;/canvas&gt;

    【讨论】:

    • 我添加了一个高效的“摆动”示例,从您的 points 数组开始,并在 html5 画布上绘制摆动三角形。干杯!
    • 听起来不错!但是如何让三角形移动得更慢更顺畅呢?当我增加“延迟”时,动画不流畅:(我想为三角形运动添加“过渡”效果。
    • 在动画中,“平滑”意味着较小的动作和较少的延迟。您还可以通过将顶点从一个偏移量线性移动到另一个偏移量而不是随机摆动来使眼睛感知到更平滑的运动。这是有效的,因为眼睛善于感知线性路径并使用大脑沿着感知路径“插入”运动。
    • 嗯,它在您的“画布版本代码”中是可行的吗?我能改变什么?这对我来说很重要,但我没有足够的动画知识:(
    • @Dominik 我(再次!)更新了我的答案以展示如何制作更流畅的动画。更新后的答案使用线性插值将每个顶点移动到新位置。这可以让眼睛感知到更平滑的运动。祝你的项目好运!
    猜你喜欢
    • 2020-01-11
    • 1970-01-01
    • 2015-08-12
    • 1970-01-01
    • 2014-01-22
    • 1970-01-01
    • 2015-03-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多