HT for Web 动画属性绑定手册

索引


概述

HTTargetedAnimation动画系统需要驱动目标Target进行变化,变化可能是某个对象属性,可能是某个Style属性,可能是某个Attribute属性,也可能是某个接口,亦或者更深的内部属性。

我们希望建立一个链接,将具体的变化跟规则名联系起来,这个规则名可以我们称之为Binding Rule。通过这种联系,我们就可以解耦上层动画系统状态系统跟下层目标具体的纷繁不一的内部细节,统一通过Binding Rule来驱动目标的变化。

目前在HT中,该绑定实际上是作用在两个系统里面:

即:对于期望对于上述两个系统,希望通过统一一个上层语言Binding Rule来驱动目标的变化,而并不关心内部实现细节,不同细节将会在这一层进行抽象统一。

Rule

每个rule本身是一个对象,包含gettersetter两个属性,分别表示获取和设置的函数。形如:

{
    getter : function(target) { return target[key]; },
    setter : function(target, value) { target[key] = value; }
}

rule 也可以是一个形如func: function(name) { ..... return { getter : getterFunc, setter : setterFunc } }的函数,一般用于动态生成gettersetter,譬如一些可以前置的判断处理统一提前计算,根据name可能会有一些动态变化用func来处理。

{
    func : function(name) {
        if (name === 'hostX') {
            return {
                getter : function(target) { return target.getHost().getX(); },
                setter : function(target, value) { target.getHost().setX(value); }
            };
        }
        else if (name === 'hostY') {
            return {
                getter : function(target) { return target.getHost().getY(); },
                setter : function(target, value) { target.getHost().setY(value); }
            };
        }
    }
}

注册接口

注册 rule 的方式分为两种,一种是具体rule,一种是rule pattern,我们会优先根据用户绑定属性,查找是否有完全命中的rule,如果存在则直接使用,如果不存在则按照rule pattern查找

rule的注册方式为:

例如:

ht.Binding.setBindingRule('attr.x', {
    getter : function(target) { return target.a('x') },
    setter : function(target, value) { target.a('x', value); }
});

rule pattern的注册方式为:

例如:

ht.Binding.setBindingRulePattern(/^attr@/, {
    func : function(name) {
        var key = name.slice(5);
        return {
            getter : function(target) { return target.a(key); },
            setter : function(target, value) { target.a(key, value); }
        };
    }
});

更推荐使用rule pattern,因为rule pattern可以避免大量的重复代码。

最终在计算某个name对应的rule时,规则如下:

样例

// 为 gv 注册一个 state 属性,属性名为 side,对应的 Binding Rule 为 side 变化则变更下面 Node 的必要属性
gv.addStateBinding('side', {
    getter: function(target) {
        return target._side;
    },
    setter: function(target, value) {
        value = ht.Math.clamp(value, startSide, endSide);
        target._side = value;
        polygonNode.s('shape.polygon.side', Math.round(value));
        textNode.s('text', Math.round(value));
        slideNode.setScaleX(value * ...);
        slidePinNode.setX(...);
    }
});
// 后续应用层就可以简单的 setState('side', v) 来工作了
gv.setState('side', 5);

内置规则

目前我们HT内置的rule pattern有:

具体示例:

style@shape3d.color
    -> getter : node.s('shape3d.color')
    -> setter : node.s('shape3d.color', value)

attr@count
    -> getter : node.a('count')
    -> setter : node.a('count', value)

field@width
    -> getter : target.width
    -> setter : target.width = value
.width
    -> getter : target.width
    -> setter : target.width = value

material@head.diffuse
    -> getter : node.getMaterial('head', 'diffuse')
    -> setter : node.setMaterial('head', 'diffuse', value)

func@tx
    -> getter : target.tx()
    -> setter : target.tx(value)
func@width
    -> getter : target.getWidth()
    -> setter : target.setWidth(value)

funcFlatten@size
    -> getter : return [ target.getSize().width, target.getSize().height ]
    -> setter : target.setSize(value[0], value[1])

欢迎交流 service@hightopo.com