HT for Web基础动画介绍

在上一篇《基于HT for Web矢量实现3D叶轮旋转》一文中,我略微提了下HT for Web基础动画的相关用法,但是讲得不深入,今天就来和大家分享下HT for Web基础动画的相关介绍及用法。

先上一段枯燥的理论知识,大家混个眼熟。

在HT的数据模型驱动图形组件的设计架构下,动画可理解为将某些属性由起始值逐渐变到目标值的过程, HT提供了ht.Default.startAnim的动画函数,其示例代码如下。

ht.Default.startAnim({
    frames: 12, // 动画帧数
    interval: 10, // 动画帧间隔毫秒数
    easing: function(t){ return t * t; }, // 动画缓动函数,默认采用`ht.Default.animEasing`
    finishFunc: function(){ console.log('Done!') }, // 动画结束后调用的函数。
    action: function(v, t){ // action函数必须提供,实现动画过程中的属性变化。
        node.setPosition( // 此例子展示将节点`node`从位置`p1`动画到位置`p2`。
            p1.x + (p2.x - p1.x) * v,
            p1.y + (p2.y - p1.y) * v
        );
    }
});

 ht.Default.startAnim支持Frame-Based和Time-Based两种方式的动画,以上代码为Frame-Based方式, 这种方式用户通过指定frames动画帧数,以及interval动画帧间隔参数控制动画效果。

以下代码为Time-Based方式,该方式用户只需要指定duration的动画周期的毫秒数即可,HT将在指定的时间周期内完成动画, 不同于Frame-Based方式有明确固定的帧数,即action函数被调用多少次,Time-Based方式帧数或action函数被调用次数取决于系统环境, 一般来说系统配置更好的机器,更高效的浏览器则调用帧数越多,动画过程更平滑。由于js语言无法精确控制interval时间间隔, 采用Frame-Based不能精确控制动画时间周期,即使相同的frames和interval参数在不同的环境,可能会出现动画周期差异较大的问题, 因此HT默认采用Time-Based的方式,如果不设置duration和frames参数,则duration参数将被系统自动设置为ht.Default.animDuration值。

ht.Default.startAnim({
    duration: 500, // 动画周期毫秒数,默认采用`ht.Default.animDuration`
    action: function(v, t){ 
        ... 
    }
});

startAnim函数会返回一个anim对象,可调用anim.stop(true)终止动画,其中的参数shouldBeFinished代表是否完全未达到的目标改变, 如果为true则会调用anim.action(anim.easing(1))。同时anim还具有anim.pause()和anim.resume()可中断和继续动画功能, 以及anim.isRunning()函数判断动画是否正在进行。

action函数的第一个参数v代表通过easing(t)函数运算后的值,t代表当前动画进行的进度[0~1],一般属性变化根据v参数进行。

ht.Default.startAnim中得easing参数是用于让用户定义函数,通过数学公式控制动画, 如匀速变化、先慢后快等效果,可参考http://easings.net/

介绍就到这里,接下来我们来做一个简单的例子,先练练手,具体的页面效果如下:

没错。它就是一个球,我们要做的就是点击浏览器的某个位置,然后它平滑地滑到点击位置,点击自身的话,就做旋转收缩,然后再旋转还原,整个过程都是通过HT for Web的基础动画来完成的。

创建拓扑及创建节点的代码我再这里就不多啰嗦了,我们直接上基础动画的内容:

首先我们需要在拓扑上监听点击事件,因为我们的Demo涉及到两个动画,所以在点击事件的内部处理需要做些简单的判断,我们先来看下监听改如何添加:

var type = "ontouchend" in document ? 'touchstart' : 'mousedown';
view.addEventListener(type, function(e){
    e.preventDefault();  
    …
}, false);

以下是图元的平移动画的处理:

var p2 = graphView.getLogicalPoint(e);
var p1 = toy.getPosition();
anim = ht.Default.startAnim({  
    duration: 500,
    easing: easing,
    finishFunc: finishFunc,
    action: function(v){
        toy.setPosition(
            p1.x + (p2.x - p1.x) * v,
            p1.y + (p2.y - p1.y) * v
        );
    }
}); 

通过事件对象获取到当前点击的位置,作为终点,然后获取图元的位置坐标作为起点,然后通过ht.Default.startAnim()方法创建一个基础动画,在action函数内部不断地改变图元的position位置属性,令其从起点运动到终点,整个过程历时500毫秒。

接下来看下自身动画该如何设计:

var size = toy.getSize();
ht.Default.startAnim({
    frames: 30, 
    interval: 16,
    easing: easing,
    finishFunc: finishFunc,                            
    action: function(v){
        toy.setRotation(Math.PI * v);
        var r = Math.abs(v - 0.5) * 2;
        toy.setSize(size.width * r, size.height * r);
    }
}); 

点击图元时触发图元围绕自身中心旋转一周,同时图元由大变小再恢复原尺寸,该逻辑通过设置frames为30帧和interval为16毫秒间隔的 Frame-Based方式完成动画。 

我们两个动画都有了,那么接下来就是将两个动画拼接到一起,在监听里面该如何出来才能将连个动画串接起来呢?其实很简单,我们只需要判断当前点击的对象就可以很容易分辨出到底要播放哪个动画,以下的代码就是具体的点击事件逻辑处理:

if(isAnimating || !ht.Default.isLeftButton(e)){
    return;
}
isAnimating = true;
var data = graphView.getDataAt(e);
var easing = function (t) {
   return ( 2 - t) * t;
};
var finishFunc = function(){
    isAnimating = false;
};
if(data === toy){
    // 自身动画
    …           
}else{
    // 平移动画
    … 
}

这个Demo到这里就算结束了,这个Demo是在2D上的应用,接下来我们来看一个3D上的应用

本次要设计的3D应用是一个在页面初始化后,图元从远到近呈现在屏幕上,然后缓慢地做360度的旋转,令图元的各个视角都呈现在眼前 

哈哈,飞机又和大家见面了,在上一章节的Demo中,加载obj文件完成操作后的finishFunc函数中添加以下代码: 

fromEye = [0, 900*5, 1200*5];
toEye = [0, 100, 600];
g3d.setEye(fromEye);

ht.Default.startAnim({
    duration: 1000,
    action: function(t){
        g3d.setEye([
            fromEye[0] + (toEye[0] - fromEye[0]) * t,
            fromEye[1] + (toEye[1] - fromEye[1]) * t,
            fromEye[2] + (toEye[2] - fromEye[2]) * t
        ]);
    },
    finishFunc: function(){
        setInterval(function(){
            g3d.rotate(Math.PI/360, 0);
        }, 30);
    }
});

代码的逻辑也很简单,通过设置视角就能够实现图元由远到近的感觉,当图元呈现在眼前后,我们通过定时器旋转拓扑组件,令图元水平360度呈现。

在这个例子中,我并没有操作图元的属性值,都是在操作拓扑的属性值,所以效果的呈现有可能会有多种实现方式,关键是要懂得思考和运用,那么这个飞机的Demo,通过直接改变图元属性来达到以上相同效果该如何实现呢?感兴趣的朋友不妨尝试下。 

以下是本次介绍涉及到的Demo源码及相关视频:

Demo源码

http://v.youku.com/v_show/id_XMTI5OTg5ODE1Ng==.html

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏布尔

logicaldoc的外部认证——AD集成

通过管理->安全->LDAP->活动目录,输入AD域名:zdxmsyb.com,然后只需要把密码敲入即可。链接建立好后,点浏览器查询出目标用户后,点右键->导入...

19410
来自专栏张善友的专栏

安装 IronPython

IronPython 1.0发布了 IronPython是Python编程语言在.NET平台上的实现。它支持一个可交互的控制台,该控制台支持完全的动态编译,并且...

2467
来自专栏性能与架构

Linux 命令帮助利器

当你记不清一个命令的用法时,你会怎么做? 例如想解压一个文件,tar命令的解压用法记不清了 通常的做法 (1)查看命令手册 # man tar ? (2...

34811
来自专栏24K纯开源

VS2010下编译配置Boost_1.53

一、准备工作 1、下载最新版本的boost库.所在地址:boost_1_53_0.zip.官方推荐7z压缩格式的,因为其压缩效率更好,相应包的大小也比较小。 2...

2199
来自专栏Pythonista

Golang之go 命令用法

(注:实际上,package名在Go语言规范中指代码中“package”后使用的名称,此名称可以与文件夹名不同。默认生成的可执行文件名是文件夹名。)

692
来自专栏hightopo

HT for Web基础动画介绍

904
来自专栏smy

readlink: command not found 解决方案

/c/Program Files (x86)/Yarn/bin/yarn: line 3: readlink: command not found 用gitba...

2844
来自专栏Android干货园

popwindow 被魅族虚拟键挡住

版权声明:本文为博主原创文章,转载请标明出处。 https://blog.csdn.net/lyhhj/article/details/45...

884
来自专栏生信技能树

linux系统环境变量一文就够

Linux是一个多用户的操作系统。每个用户登录系统后,都会有一个专用的运行环境。 通常每个用户默认的环境都是相同的,这个默认环境实际上就是一组环境变量的定义。 ...

3365
来自专栏深度学习与计算机视觉

VS2010 解决控制台窗口一闪而过的问题

这个问题发现的着实尴尬,怎么说用了vs也有两年了,但是真的是才发现调试与开始执行的区别,最基础的问题反而被一直遗漏。 说回正题,相信有很多人在使用vs时都会...

1758

扫码关注云+社区