仓库源文站点原文


layout: post title: KineticJS教程4:图形变换与动画 categories:


<script src="/jscss/kinetic.min.js"></script>

2015-06-11 08:27:22

7. 图形变换

7.1. 线性变换

Kinetic提供了一个图形对象的Tween(config)方法实现图形的线性变换, 也就是从原始的状态线性变换到新的状态, 这里的状态是指的尺度上的参数. 方法的config参数也就是有关图形尺度的一些参数, 比如x, y, rotation, width, height, radius, strokeWidth, alpha, scale, centerOffset等. 除了这些尺度参数, 还需要一个duration参数, 单位是秒, 也就是指定这种线性变换是在多长时间内变换完成.

比如, 下面代码实现图形在两秒钟内从原位置移动到(400, 30)处, 并旋转360度, 增大为原来的1.5倍, 边缘线加粗, 且逐渐变得不透明:

<pre class="line-numbers" data-start="0"><code class="language-javascript"># Language: js <script> var tween = new Kinetic.Tween({ node: rect, duration: 1, x: 400, y: 30, rotation: 360, opacity: 1, strokeWidth: 6, scaleX: 1.5 }); // start tween after 2 seconds setTimeout(function() { tween.play(); }, 2000); </script> </code></pre>

运行效果如下(若看不到效果, 请刷新页面):

<div id="ctn_71" style="border:solid 2px #CCC;"></div> <script> var stage = new Kinetic.Stage({ container: 'ctn_71', width: 578, height: 200 }); var layer = new Kinetic.Layer(); var rect = new Kinetic.Rect({ x: 100, y: 100, width: 100, height: 50, fill: 'green', stroke: 'black', strokeWidth: 2, opacity: 0.2 }); layer.add(rect); stage.add(layer); var tween71 = new Kinetic.Tween({ node: rect, duration: 1, x: 400, y: 30, rotation: 360, opacity: 1, strokeWidth: 6, scaleX: 1.5 }); setTimeout(function() { tween71.play(); }, 2000); </script> ## 7.2. 变换中的速度 `Kinetic`的`Tween(config)`方法中的`config`参数包括一个`easing`属性, 是指变换是以较均匀的速度到达变换目的点还是在变换过程中在不同位置以不同速度进行变换. `easing`可以设定的值包括`Linear`, `EaseIn`, `EaseOut`, `EaseInOut`, `BackEaseIn`, `BackEaseOut`, `BackEaseInOut`, `ElasticEaseIn`, `ElasticEaseOut`, `ElasticEaseInOut`, `BounceEaseIn`, `BounceEaseOut`, `BounceEaseInOut`, `StrongEaseIn`, `StrongEaseOut`以及`StrongEaseInOut`. `easing`的使用方法如下 <pre class="line-numbers" data-start="0"><code class="language-javascript"># Language: js <script> var tween = new Kinetic.Tween({ node: rect, duration: 1, easing: Kinetic.Easings["BounceEaseIn"], x: 400, y: 30, rotation: 360, opacity: 1, strokeWidth: 6, scaleX: 1.5 }); </script> </code></pre> 在文章里很难形容这些值之间的不同, 还是具体写成[代码](http://www.html5canvastutorials.com/kineticjs/html5-canvas-all-easing-functions-with-kineticjs/), 在浏览器里看效果吧. <div id="buttons"> <input type="button" id="play72" value="播放"> <input type="button" id="pause72" value="暂停"> <input type="button" id="reverse72" value="反向"> </div> <div id="ctn_72" style="border:solid 2px #CCC;"></div><script> var stage = new Kinetic.Stage({ container: 'ctn_72', width: 578, height: 480 }); var layer = new Kinetic.Layer(); var easings = [ {name: 'Linear', color:'blue'}, {name: 'EaseIn', color:'green'}, {name: 'EaseOut', color:'green'}, {name: 'EaseInOut', color:'green'}, {name: 'BackEaseIn', color:'blue'}, {name: 'BackEaseOut', color:'blue'}, {name: 'BackEaseInOut', color:'blue'}, {name: 'ElasticEaseIn', color:'green'}, {name: 'ElasticEaseOut', color:'green'}, {name: 'ElasticEaseInOut', color:'green'}, {name: 'BounceEaseIn', color:'blue'}, {name: 'BounceEaseOut', color:'blue'}, {name: 'BounceEaseInOut', color:'blue'}, {name: 'StrongEaseIn', color:'green'}, {name: 'StrongEaseOut', color:'green'}, {name: 'StrongEaseInOut', color:'green'} ]; var tweens = []; for(var n = 0; n < easings.length; n++) { var num = n + 1; var ease = easings[n]; var text = new Kinetic.Text({ x: 10, y: 60 + (n * 400 / easings.length), padding: 4, text: num + ') ' + ease.name, fontSize: 18, fontFamily: 'Calibri', fill: ease.color }); layer.add(text); var tween = new Kinetic.Tween({ node: text, x: 420, easing: Kinetic.Easings[ease.name], duration: 2 }); tweens.push(tween); } stage.add(layer); document.getElementById('play72').addEventListener('click', function() { for (var n=0; n<tweens.length; n++) { tweens[n].play(); } }, false); document.getElementById('pause72').addEventListener('click', function() { for (var n=0; n<tweens.length; n++) { tweens[n].pause(); } }, false); document.getElementById('reverse72').addEventListener('click', function() { for (var n=0; n<tweens.length; n++) { tweens[n].reverse(); } }, false); </script>

7.3. 变换完成后的回调方法

KineticTween(config)方法中的config参数还包括一个OnFinish方法属性, 这个方法会在变换完成后被执行.

<pre class="line-numbers" data-start="0"><code class="language-javascript"># Language: js <script> var tween = new Kinetic.Tween({ node: rect, duration: 1, onFinish: function() { alert("complete!"); }, x: 400, y: 30, rotation: 360, opacity: 1, strokeWidth: 6, scaleX: 1.5 }); </script> </code></pre>

运行效果如下(若看不到效果, 请刷新页面):

<div id="ctn_73" style="border:solid 2px #CCC;"></div> <script> var stage = new Kinetic.Stage({ container: 'ctn_73', width: 578, height: 200 }); var layer = new Kinetic.Layer(); var rect = new Kinetic.Rect({ x: 100, y: 100, width: 100, height: 50, fill: 'green', stroke: 'black', strokeWidth: 2, opacity: 0.2 }); layer.add(rect); stage.add(layer); var tween73 = new Kinetic.Tween({ node: rect, duration: 1, onFinish: function() { alert("transition complete!"); }, x: 400, y: 30, rotation: 360, opacity: 1, strokeWidth: 6, scaleX: 1.5 }); setTimeout(function() { tween73.play(); }, 2000); </script> ## 7.4. 变换的开始与结束 当执行`tween`方法的时候可以使用`play()`, `pause()`, `reverse()`, `reset()`, `finish()`和`seek()`方法来控制对象的变换行为. 使用方法如下: <pre class="line-numbers" data-start="0"><code class="language-javascript"># Language: js <script> var tween = new Kinetic.Tween(config) // 开始变换 tween.play(); // 暂停变换 tween.pause(); // 重置 tween.reset(); </script> </code></pre> 演示效果如下: <div id="buttons"> <input type="button" id="play" value="播放"> <input type="button" id="pause" value="暂停"> <input type="button" id="reverse" value="反向"> <input type="button" id="reset" value="重置"> <input type="button" id="seek" value="第3秒"> <input type="button" id="finish" value="完成"> </div> <div id="ctn_74"></div><script> var stage = new Kinetic.Stage({ container: 'ctn_74', width: 578, height: 200 }); var layer74 = new Kinetic.Layer(); var rect = new Kinetic.Rect({ x: 100, y: 130, width: 100, height: 50, fillRed: 0, fillGreen: 128, fillBlue: 0, stroke: 'black', strokeWidth: 2, opacity: 0.2 }); layer74.add(rect); stage.add(layer74); var tween74 = new Kinetic.Tween({ node: rect, duration: 6, x: 400, y: 75, rotation: 360 * 5, opacity: 1, strokeWidth: 6, scaleX: 1.3, scaleY: 1.3, easing: Kinetic.Easings.Linear, fillRed: 0, fillGreen: 0, fillBlue: 255 }); document.getElementById('pause').addEventListener('click', function() { tween74.pause(); }, false); document.getElementById('reverse').addEventListener('click', function() { tween74.reverse(); }, false); document.getElementById('play').addEventListener('click', function() { tween74.play(); }, false); document.getElementById('reset').addEventListener('click', function() { tween74.reset(); layer74.draw(); }, false); document.getElementById('finish').addEventListener('click', function() { tween74.finish(); layer74.draw(); }, false); document.getElementById('seek').addEventListener('click', function() { tween74.seek(3); layer74.draw(); }, false); </script>

8. 动画

动画就是一帧帧的画面按照时间间隔显示出来, Kinetic给我们提供了animation对象, 它可以绑定一个动画方法, 我们要显示的动画的每一帧画面就是在这个方法中完成绘制的.

其中, 这个方法接受一个对象frame为参数, 此参数对象包含两个属性, 一个是frame.time, 表示当前帧是动画开始后的毫秒数, 另一个属性是frame.timeDiff, 表示的是当前帧与上一帧之间的时间毫秒差. 当前帧应该是什么形态就是根据这两个参数来判断的. 绘制出当前帧后, 注意要调用一下动画所在的层的draw, 将当前帧图像显示到屏幕上. 动画的开始与停止是用对象的startstop方法实现的.

如下代码显示了一个左右摆动的圆形

<pre class="line-numbers" data-start="0"><code class="language-javascript"># Language: js <script> var stage = new Kinetic.Stage({ container: 'container', width: 578, height: 200 }); var layer = new Kinetic.Layer(); var circle = new Kinetic.Circle({ x: stage.width()/2, y: stage.height()/2, sides: 6, radius: 70, fill: 'red', stroke: 'black', strokeWidth: 4 }); layer.add(circle); stage.add(layer); var amplitude = 150; var period = 2000; var centerX = stage.width()/2; //动画帧定义方法 var anim = new Kinetic.Animation(function(frame) { circle.setX(amplitude * Math.sin(frame.time * 2 * Math.PI / period) + centerX); }, layer); anim.start(); //动画开始 //stage.stop(); //动画停止 </script> </code></pre>

运行效果如下:

<div id="ctn_8"></div>

<script> var stage = new Kinetic.Stage({ container: 'ctn_8', width: 578, height: 200 }); var layer = new Kinetic.Layer(); var circle = new Kinetic.Circle({ x: stage.width()/2, y: stage.height()/2, sides: 6, radius: 70, fill: 'red', stroke: 'black', strokeWidth: 4 }); layer.add(circle); stage.add(layer); var amplitude = 150; var period = 2000; var centerX = stage.width()/2; var anim = new Kinetic.Animation(function(frame) { circle.setX(amplitude * Math.sin(frame.time * 2 * Math.PI / period) + centerX); }, layer); anim.start(); </script>