2012-11-28 40 views
0

我现在有一个自定义的形状,并且此形状由一个全局变量控制。因此,我假设我只需要改变这个全局变量,由于frame.time,擦除旧的形状,并创建一个新的。通过更新自定义形状的KineticJS动画

但是,它似乎不工作。以下是简化代码。

<script> 
    var toControlShape; 
    var myDrawFunction(context) { 
    // toControlShape will be used here. 
    } 

    window.onload = function() { 
    var stage = new Kinetic.Stage({...}); 
    var layer = new Kinetic.Layer(); 

    var myShape = new Kinetic.Shape({ 
     drawFunc: myDrawFunction, 
     ... 
    }); 

    layer.add(myShape); 
    stage.add(layer); 

    var animation = new Kinetic.Animation(function(frame) { 
     toControlShape = someFunction(frame.time); 
     myShape.remove(); 
     myShape = new Kinetic.Shape({ 
     drawFunc: myDrawFunction, 
     ... 
     }); 
     layer.add(myShape); 
    }, layer); 

    animation.start(); 
    }; 
</script> 

形状作为其初始状态正确显示。但没有动画。

我是Javascript和HTML5的新手。所以在这个代码中可能会有很多反模式。指出他们对我也感激。

完整的代码是here上的jsfiddle

回答

0

我觉得你这样做是错误的。从文档:

  • “Kinetic.Animation修改每个 动画帧的形状的位置。”

所以我认为你应该停止删除形状,而只是更新形状。那么它应该可能是动画部分为你工作。

HTML ---

<!DOCTYPE html> 

<html> 
    <head> 
     <title>Strath</title> 
     <meta http-equiv="X-UA-Compatible" content="IE=9" /> 
    <script type="text/javascript" src="kinetic-v4.1.2.min.js"></script> 

    <script src="fiddle.js"></script> 
     <style type="text/css"> 

     </style> 
    </head> 
    <body> 


<div id="PureHTML5"></div> 
     </body> 
</html> 

JS ---

var segsToSkip = 0; 
     var triangle; 
     window.onload = function() { 
     var stage = new Kinetic.Stage({ 
      container: "PureHTML5", 
      width: 300, 
      height: 300 
     }); 
     var layer = new Kinetic.Layer(); 


     /* 
     * create a triangle shape by defining a 
     * drawing function which draws a triangle 
     */ 
     var box = new Kinetic.Shape({ 
      drawFunc: myDrawFunction, 
      stroke: "white", 
      strokeWidth: 8 
     }); 
     var bbox= new Kinetic.Rect({ 
      x:10, 
      y:10, 
      width:10, 
      height:10, 
      fill: 'green' 
     }); 

      triangle = new Kinetic.Shape({ 
     drawFunc: function(context) { 
      context.beginPath(); 
      context.moveTo(10, 10); 
      context.lineTo(20, 80); 
      context.quadraticCurveTo(30, 10, 26, 17); 
      context.closePath(); 
      context.stroke(); 

     }, 
     fill: '#00D2FF', 
     stroke: 'black', 
     strokeWidth: 4 
     }); 
     layer.add(bbox); 
     // add the triangle shape to the layer 
     layer.add(box); 
     layer.add(triangle); 
     // add the layer to the stage 
     stage.add(layer); 

     var animation = new Kinetic.Animation(function(frame) { 
      console.log(frame.time); 
      var newSegsToSkip = Math.round(frame.time/200); 
        triangle.setX(newSegsToSkip); 
     triangle.setDrawFunc(function(context) { 
      context.beginPath(); 
      context.moveTo(newSegsToSkip, 10); 
      context.lineTo(newSegsToSkip+20, 80); 
      context.quadraticCurveTo(30, 10, 26, 17); 
      context.closePath(); 
      context.stroke(); 
       }); 
      }, layer); 



     var animation2 = new Kinetic.Animation(function(frame) { 
      var newSegsToSkip = Math.round(frame.time/200); 
      if (newSegsToSkip == segsToSkip) return; 
      else { 
       segsToSkip = newSegsToSkip; 
       box.remove(); 
       box = new Kinetic.Shape({ 
        drawFunc: myDrawFunction, 
        stroke: "black", 
        strokeWidth: 8 
       }); 
       layer.add(box); 
      } 
     }, layer); 
     animation.start(); 
      animation2.start(); 
     }; 

var myDrawFunction = function(context) { 
    var x = 50; 
    var y = 50; 
    var width = 200; 
    var height = 200; 
    var radius = 20; 
    var dashedLength = 6; 
    var segsToDraw = 58; 

    context.beginPath(); 

    context.drawDashedBox(x, y, width, height, radius, dashedLength, segsToSkip, segsToDraw); 

    context.closePath(); 
    // context.stroke(); 
    //this.fill(context); 
    this.stroke(context); 
} 

var CP = window.CanvasRenderingContext2D && CanvasRenderingContext2D.prototype; 
CP.drawDashedBox = function(x, y, width, height, radius, dashedLength, segsToSkip, segsToDraw) { 
    // init 
    var env = getStratEnvForRCBox(x, y, width, height, radius, dashedLength, segsToSkip, segsToDraw); 

    // 'right'->'upper-right'->'down'->'bottom-right'->'left'->'bottom-left'->'up'->'upper-left'->'right'->... 
    while (env.segsToDraw > 0) { 
     console.log('drawing direction: ', env.direction, 'segsToDraw:', env.segsToDraw); 
     env.putToConsole(); 
     if (env.direction == 'right') { 
      env = drawDashedLineNew(env, x + width - radius, y + height, dashedLength, this); 
      env.direction = 'bottom-right'; 
     } 
     else if (env.direction == 'upper-right') { 
      env = drawDashedArcNew(env, x + width - radius, y + radius, radius, 0, Math.PI/2, dashedLength, this);  
      env.direction = 'left'; 
     } 
     else if (env.direction == 'down') { 
      env = drawDashedLineNew(env, x, y + height - radius, dashedLength, this); 
      env.direction = 'bottom-left'; 
     } 
     else if (env.direction == 'bottom-right') { 
      env = drawDashedArcNew(env, x + width - radius, y + height - radius, radius, 3 * Math.PI/2, 2 * Math.PI, dashedLength, this); 
      env.direction = 'up'; 
     } 
     else if (env.direction == 'left') { 
      env = drawDashedLineNew(env, x + radius, y, dashedLength, this); 
      env.direction = 'upper-left'; 
     } 
     else if (env.direction == 'bottom-left') { 
      env = drawDashedArcNew(env, x + radius, y + height - radius, radius, Math.PI, 3 * Math.PI/2, dashedLength, this); 
      env.direction = 'right'; 
     } 
     else if (env.direction == 'up') { 
      env = drawDashedLineNew(env, x + width, y + radius, dashedLength, this); 
      env.direction = 'upper-right'; 
     } 
     else if (env.direction == 'upper-left') { 
      env = drawDashedArcNew(env, x + radius, y + radius, radius, Math.PI/2, Math.PI, dashedLength, this); 
      env.direction = 'down'; 
     } 
    } 
} 

function getStratEnvForRCBox(x, y, width, height, radius, dashLength, segsToSkip, segsToDraw) { 
    var direction = 'right'; 
    var startX, startY; 
    if (direction == 'down') { 
     startX = x; startY = y + radius; 
    } else if (direction == 'right') { 
     startX = x + radius; startY = y + height; 
    } else if (direction == 'up') { 
     startX = x + width; startY = y + height - radius; 
    } else if (direction == 'left') { 
     startX = x + width - radius; startY = y; 
    } 
    var env = new Environment(startX, startY, 'gap', 0, direction, segsToSkip, segsToDraw); 
    return env; 
} 

function drawDashedLineNew(env, endX, endY, dashedLength, context) { 
    var dx = (endX - env.x), dy = (endY - env.y); 
    var angle = Math.atan2(dy, dx); 
    console.log('drawing line: angle =', angle, ' , ', env.gapOrDash, ' =', env.remainingLengthFromLastDraw); 

    var fromX = env.x, fromY = env.y; 
    // deal with remining 
    // we start loop from a fresh dash 
    if (env.gapOrDash == 'dash') { 
     // check if we need to skip 
     if (env.segsToSkip > 0) { 
      env.segsToSkip --; 
     } else { 
      context.moveTo(env.x, env.y); 
      context.lineTo(env.x + env.remainingLengthFromLastDraw * Math.cos(angle), env.y + env.remainingLengthFromLastDraw * Math.sin(angle)); 
      // check if we quit 
      env.segsToDraw --; 
      if (env.segsToDraw == 0) return env; 
     } 

     // a full gap 
     fromX = env.x + (env.remainingLengthFromLastDraw + dashedLength) * Math.cos(angle); 
     fromY = env.y + (env.remainingLengthFromLastDraw + dashedLength) * Math.sin(angle); 
    } else if (env.gapOrDash == 'gap') { 
     fromX = env.x + env.remainingLengthFromLastDraw * Math.cos(angle); 
     fromY = env.y + env.remainingLengthFromLastDraw * Math.sin(angle); 
    } 

    var length = (endX - fromX)/Math.cos(angle); 
    if (endX - fromX == 0) length = Math.abs(endY - fromY); 
    var n = length/dashedLength; 
    var draw = true; 
    var x = fromX, y = fromY; 
    context.moveTo(x, y); 
    for (var i = 0; i < n; i++) { 
     x += dashedLength * Math.cos(angle); 
     y += dashedLength * Math.sin(angle); 
     if (draw) { 
      // check if we need to skip 
      if (env.segsToSkip > 0) { 
       env.segsToSkip --; 
      } else { 
       context.lineTo(x,y); 

       // check if we quit 
       env.segsToDraw --; 
       if (env.segsToDraw == 0) return env; 
      } 
     } else context.moveTo(x, y); 
     draw = !draw; 
    } 

    // deal with remaining 
    if (draw) { 
     // check if we need to skip 
     if (env.segsToSkip > 0) { 
      env.segsToSkip --; 
     } else 
      context.lineTo(endX, endY); 
    } 
    env.x = endX; 
    env.y = endY; 
    draw ? env.gapOrDash = 'dash' : env.gapOrDash = 'gap'; 
    env.remainingLengthFromLastDraw = dashedLength - (endX - x)/Math.cos(angle); 

    return env; 
} 

function drawDashedArcNew(env, x, y, radius, startAngle, endAngle, dashedLength, context) { 
    var points = []; 
    var n = radius * Math.PI * 2/ dashedLength; 
    var stepAngle = Math.PI * 2/n; 

    // deal with remaining 
    var angle = Math.asin(env.remainingLengthFromLastDraw/2/radius) * 2; 
    if (env.gapOrDash == 'dash') { 
     var angle = Math.asin(env.remainingLengthFromLastDraw/2/radius) * 2; 
     points.push({ 
      x : (Math.cos(startAngle) * radius) + x, 
      y : - (Math.sin(startAngle) * radius) + y, 
      ex : (Math.cos(startAngle + angle) * radius) + x, 
      ey : - (Math.sin(startAngle + angle) * radius) + y 
     }); 

     startAngle += stepAngle + angle; 
    } else { 
     startAngle += angle; 
    } 

    var draw = true; 
    while(startAngle + stepAngle <= endAngle) { 
     if (draw) { 
      points.push({ 
      x : (Math.cos(startAngle) * radius) + x, 
      y : - (Math.sin(startAngle) * radius) + y, 
      ex : (Math.cos(startAngle + stepAngle) * radius) + x, 
      ey : - (Math.sin(startAngle + stepAngle) * radius) + y 
      });  
     } 

     startAngle += stepAngle; 
     draw = !draw; 
    } 

    // deal with the remaining 
    var endX = (Math.cos(endAngle) * radius) + x; 
    var endY = - (Math.sin(endAngle) * radius) + y; 
    //console.log('drawing arc: end-x:', endX, ',end-y:', endY); 
    if (draw) { 
     points.push({ 
      x : (Math.cos(startAngle) * radius) + x, 
      y : - (Math.sin(startAngle) * radius) + y, 
      ex : endX, 
      ey : endY 
     }); 
    } 
    env.x = endX; 
    env.y = endY; 
    draw ? env.gapOrDash = 'dash' : env.gapOrDash = 'gap'; 
    env.remainingLengthFromLastDraw = dashedLength - radius * Math.sin((endAngle - startAngle)/2) * 2; 

    for(p = 0; p < points.length; p++){ 
     //console.log('draw arc seg: from(', points[p].x, ',', points[p].y, ') to (', points[p].ex, ',', points[p].ey, ')'); 
     // check if we need to skip 
     if (env.segsToSkip > 0) { 
      env.segsToSkip --; 
     } else { 
      context.moveTo(points[p].x, points[p].y); 
      context.lineTo(points[p].ex, points[p].ey); 

      // check if we quit 
      env.segsToDraw --; 
      if (env.segsToDraw == 0) return env; 
     } 
    } 

    return env; 
} 

function Environment(x, y, gapOrDash, remainingLengthFromLastDraw, direction, segsToSkip, segsToDraw) { 
    this.x = x; 
    this.y = y; 
    this.gapOrDash = gapOrDash; 
    this.remainingLengthFromLastDraw = remainingLengthFromLastDraw; 
    this.direction = direction; 
    this.segsToSkip = segsToSkip; 
    this.segsToDraw = segsToDraw; 
} 
Environment.prototype.putToConsole = function() { 
    //console.log('Environment:'); 
    //console.log('x:', this.x, ',y:', this.y, 'direction:', this.direction); 
    //console.log('toSkip:', this.segsToSkip, 'toDraw:', this.segsToDraw); 
} 
+0

你能更具体?我没有找到任何API来允许您重绘/更新形状。谢谢 – qinsoon

+0

'pure'kineticjs形状非常简单,只需更新动画框中的shape.setX(newx)即可。既然你有一个自定义形状,ju必须更新drawFunc中的形状,如果你不仅需要移动它,而且你应该保持形状,而不是在每一帧中移除。所以拆分box = new Kinetic.Shape来加载,然后访问shape.getDrawFunc()并在动画框架中用shape.setDrawFunc(drawFunc)设置一个新的drawfunc。 – Jonke

+0

@qinsoon,即使我认为你不应该使用删除但使用更新,我让你的代码在本地使用kinetic 4.1.2版本 – Jonke