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

时间:2018-11-13 09:35:32

标签: html5-canvas konvajs

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

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

有人能给我提供能够实现旋转硬币效果的补间动画效果吗?

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

1 个答案:

答案 0 :(得分:0)

以下是使用scaleX()效果的第二好版本的示例。由于需要计算scaleX()并控制文本的可见性以使其看起来像光盘是坚固的,因此我从补间动画过渡到了animation()。

// 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>