分组形状上的硬币旋转效果动画

Coin spin effect animation on grouped shapes

我被要求使用 Konvajs 制作一个动画,该动画将旋转一个圆,就像在其中心 x 轴上旋转一样。所以想象一枚硬币在 table 上旋转。目的是在圆圈上显示一些文字。一开始圆圈是完全可见的,就像从后面看一样,所以看不到文字,然后它翻转以显示文字。

我有这段代码可以像纺车一样进行旋转。

任何人都可以给我一个可以实现旋转硬币效果的补间/动画方法吗?

// the tween has to be created after the node has been added to the layer
var tween = new Konva.Tween({
    node: group,
    duration: 4,
    rotation: 360,
    easing: Konva.Easings.BackEaseOut
   }
}); 
tween.play();

经过一些研究,3D 旋转似乎需要更重的提升,这在移动设备上可能不可用或效果不佳。

第二好的方法似乎是使用 scaleX 并从 0 > 1 设置动画。

group.scaleX(0);
var tween = new Konva.Tween({
    node: group,
    duration: .25,
    scaleX: 1,
    easing: Konva.Easings.EaseOut
}); 

这是使用 scaleX() 效果的次优版本的示例。由于需要计算 scaleX() 并控制文本的可见性以使其看起来像圆盘是实心的,因此我从补间移到了动画 ()。

// Set up the canvas / stage
var s1 = new Konva.Stage({container: 'container1', width: 300, height: 200});

// Add a layer for line
var layer = new Konva.Layer({draggable: false});
s1.add(layer);

// just a plain JS object to keep common variables in hand.
var cfg = { w: 300, h: 200, r: 80, txtSize: 520};

var group = new Konva.Group();
var circle = new Konva.Circle({x: cfg.w/2, y: cfg.h/2, radius: cfg.r, fill: 'DodgerBlue', stroke: 'DeepPink', strokeWidth: 5})
group.add(circle)


 var textValue = new Konva.Text({
  id: "t1",
  x: cfg.w/2,
  y: cfg.h/2,
  text: '',
  fill: 'DeepPink ',
  fontSize: cfg.txtSize
  });
group.add(textValue);
textValue.offset({x: textValue.getWidth()/2, y: textValue.getHeight()/2});

layer.add(group)

 // to spin a group about a point, set the offset to that point, then set the x & y to that point to !
 var pos = group.getClientRect();
 RotatePoint(group, {x: pos.x + pos.width/2, y: pos.y + pos.height/2});

// Everything is ready so draw the canvas objects set up so far.
s1.draw()


$('#st').on('click', function(){
  group.scaleX(1);
  var txt = $('#theText').val();
  setValue(txt);
})



// set the offset for rotation to the given location and re-position the shape
function RotatePoint(shape, pos){  // where pos = {x: xpos, y: yPos}
var initialPos = shape.getAbsolutePosition();
var moveBy = {x: pos.x - initialPos.x, y: pos.y - initialPos.y};

// offset is relative to initial x,y of shape, so deduct x,y.
shape.offsetX(moveBy.x);
shape.offsetY(moveBy.y);

shape.x(initialPos.x + moveBy.x);
shape.y(initialPos.y + moveBy.y);
}
 

var setValue = function(newText){

  // work out scaling to make text fit into the circle

  var txt = this.layer.find('#t1')[0];
  txt.text(newText).scale({x:1, y: 1})
  var txtSize = txt.getClientRect();

    var maxW = (cfg.r); // max allowed width of text
  var txtScaleW = (txtSize.width > maxW ? ( maxW / txtSize.width) : 1);

  var maxH = cfg.r; // max allowed height of text
  var txtScaleH = (txtSize.height > maxH ? ( maxH / txtSize.height) : 1);

  // finally decide which is the worst case and use that scaling
  var txtScale = ( txtScaleW > txtScaleH ? txtScaleH : txtScaleW);

    txt.scale({x: txtScale, y: txtScale});

    txt.offset({x: txt.getWidth()/2, y: txt.getHeight()/2});
  layer.draw()
 }
  
  // set initial text & spin !
  setValue('BBB');
  
  var anim, pos = 0, frameCnt = 0

  if (anim) {anim.stop(); }
  anim = new Konva.Animation(function(frame) {
    frameCnt = frameCnt + 1;
    
    if (frameCnt % 2 === 0){
      pos = pos + .2
      var scaleX = Math.sin(pos)
      textValue.visible(scaleX < 0 ? false : true);
      group.scaleX(scaleX);

      if (pos % 360 === 0){ console.log('spin') }
    }
    
    
  }, layer);
  

 anim.start();
div
{
float: left;
margin: 0 5px;
}
p
{
margin: 0 5px 5px 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/konva/2.5.1/konva.min.js"></script>

<div  id='container1' style="width: 300px, height: 200px;"></div>
<div>
<p> <input type='text' id='theText' value='BBB' /> <button id='st'>Change text</button> </p> 
</div>