• js 动画补间 Tween


      1 /* RunningList (触发过程中可以安全的删除自己)
      2     如果触发过程中删除(回调函数中删除正在遍历的数组), 不仅 len 没有变(遍历前定义的len没有变, 真实的len随之减少), 而且还会漏掉一个key;
      3 
      4 */
      5 class RunningList{
      6 
      7     static getProxy(runName){
      8 
      9         return new Proxy(new RunningList(runName), {
     10 
     11             get(tar, key){
     12                 
     13             },
     14 
     15             set(tar, key, val){
     16                 
     17             }
     18             
     19         });
     20 
     21     }
     22 
     23     constructor(runName = 'update'){
     24         this._running = false;
     25         this._list = [];
     26         this._delList = [];
     27         this._runName = runName;
     28 
     29     }
     30 
     31     get length(){
     32         return this._list.length;
     33     }
     34 
     35     push(v){
     36         this._list.push(v);
     37 
     38     }
     39 
     40     splice(v){
     41         if(this._running === true) this._delList.push(v);
     42 
     43         else{
     44             const i = this._list.indexOf(v);
     45             if(i !== -1) this._list.splice(i, 1);
     46         }
     47 
     48     }
     49 
     50     update(){
     51         var k, len = this._list.length;
     52 
     53         this._running = true;
     54         for(k = 0; k < len; k++) this._list[k][this._runName]();
     55         this._running = false;
     56 
     57         len = this._delList.length;
     58         for(k = 0; k < len; k++) this.splice(this._delList[k]);
     59         this._delList.length = 0;
     60         
     61     }
     62 
     63 }
     64 
     65 
     66 
     67 
     68 /* TweenValue (从 原点 以规定的时间到达  终点)
     69 
     70 parameter: origin, end, time, onUpdate, onEnd;
     71 
     72 attribute:
     73     origin: Object; //原点(起点)
     74     end: Object; //终点
     75     time: Number; //origin 到 end 花费的时间
     76     onUpdate: Function; //更新回调; 一个回调参数 origin; 默认null;
     77     onEnd: Function; //结束回调; 没有回调参数; 默认null; (如果返回的是true将不从队列删除, 你可以在onEnd中更新.end不间断的继续补间)
     78 
     79 method:
     80     reset(origin, end: Object): undefined; //更换 .origin, .end; 它会清除其它对象的缓存属性
     81     reverse(): undefined; //this.end 复制 this.origin 的原始值
     82     update(): undefined; //Tween 通过此方法统一更新 TweenValue
     83 
     84 demo: 
     85     //init Tween:
     86     const tween = new Tween(),
     87     animate = function (){
     88         requestAnimationFrame(animate);
     89         tween.update();
     90     }
     91 
     92     //init TweenValue:
     93     const v1 = new Tween.Value({x:0, y:0}, {x:5, y:10}, 1000, v => console.log(v));
     94     
     95     animate();
     96     tween.start(v1);
     97 
     98 */
     99 class TweenValue{
    100 
    101     constructor(origin = {}, end = {}, time = 500, onUpdate = null, onEnd = null, onStart = null){
    102         this.origin = origin;
    103         this.end = end;
    104         this.time = time;
    105 
    106         this.onUpdate = onUpdate;
    107         this.onEnd = onEnd;
    108         this.onStart = onStart;
    109         
    110         //以下属性不能直接设置
    111         this._r = null;
    112         this._t = 0;
    113         this._v = Object.create(null);
    114 
    115     }
    116 
    117     _start(){
    118         var v = "";
    119         for(v in this.origin) this._v[v] = this.origin[v];
    120 
    121         this._t = Date.now();
    122         //this.update();
    123 
    124     }
    125 
    126     reset(origin, end){
    127         this.origin = origin;
    128         this.end = end;
    129         this._v = Object.create(null);
    130 
    131     }
    132 
    133     reverse(){
    134         var n = "";
    135         for(n in this.origin) this.end[n] = this._v[n];
    136 
    137     }
    138 
    139     update(){
    140         if(this["_r"] !== null){
    141 
    142             var ted = Date["now"]() - this["_t"];
    143 
    144             if(ted >= this["time"]){
    145 
    146                 for(ted in this["origin"]) this["origin"][ted] = this["end"][ted];
    147                 if(this["onUpdate"] !== null) this["onUpdate"](this["origin"]);
    148 
    149                 if(this["onEnd"] !== null){
    150 
    151                     if(this["onEnd"]() !== true){
    152                         if(this["_r"] !== null) this["_r"]["stop"](this);
    153                     }
    154 
    155                     else this["_start"]();
    156                     
    157                 }
    158 
    159                 else this["_r"]["stop"](this);
    160 
    161             }
    162 
    163             else{
    164                 let n = "";
    165                 ted = ted / this["time"];
    166                 for(n in this["origin"]) this["origin"][n] = ted * (this["end"][n] - this["_v"][n]) + this["_v"][n];
    167                 if(this["onUpdate"] !== null) this["onUpdate"](this["origin"]);
    168 
    169             }
    170 
    171         }
    172 
    173     }
    174 
    175 }
    176 
    177 Object.defineProperties(TweenValue.prototype, {
    178 
    179     isTweenValue: {
    180         configurable: false,
    181         enumerable: false,
    182         writable: false,
    183         value: true,
    184     }
    185 
    186 });
    187 
    188 
    189 
    190 
    191 /* TweenAlone (相对于 TweenValue 此类可以独立补间, 不需要 Tween)
    192 
    193 demo:
    194     const v1 = new TweenAlone({x:0, y:0}, {x:5, y:10}, 1000, v => console.log(v)),
    195     animate = function (){
    196         requestAnimationFrame(animate);
    197         v1.update();
    198     }
    199 
    200     animate();
    201     v1.start();
    202 
    203 */
    204 class TweenAlone extends TweenValue{
    205 
    206     constructor(origin, end, time, onUpdate, onEnd, onStart){
    207         super(origin, end, time, onUpdate, onEnd, onStart);
    208         
    209     }
    210 
    211     start(){
    212         if(this.onStart !== null) this.onStart();
    213         this._r = this;
    214         this._start();
    215 
    216     }
    217 
    218     stop(){
    219         this._r = null;
    220         
    221     }
    222 
    223 }
    224 
    225 
    226 
    227 
    228 
    229 /* Tween 动画补间 (TweenValue 的root, 可以管理多个TweenValue)
    230 
    231 parameter:
    232 attribute:
    233 method:
    234     start(value: TweenValue): undefined;
    235     stop(value: TweenValue): undefined;
    236 
    237 static:
    238     Value: TweenValue;
    239 
    240 demo:
    241     //init Tween:
    242     const tween = new Tween(),
    243     animate = function (){
    244         requestAnimationFrame(animate);
    245         tween.update();
    246     }
    247 
    248     //init TweenValue:
    249     const v2 = new Tween.Value({x:0, y:0}, {x:5, y:10}, 1000, v => console.log(v), v => {
    250         v2.reverse(); //v2.end 复制起始值
    251         return true; //返回true表示不删除队列, 需要继续补间
    252     });
    253     
    254     animate();
    255     tween.start(v2);
    256 
    257 */
    258 class Tween extends RunningList{
    259 
    260     static Value = TweenValue;
    261 
    262     constructor(){
    263         super();
    264 
    265     }
    266 
    267     start(value){
    268         if(value.onStart !== null) value.onStart();
    269         if(value._r === null) this.push(value);
    270         value._r = this;
    271         value._start(this);
    272 
    273     }
    274 
    275     stop(value){
    276         if(value._r !== null) this.splice(value);
    277         value._r = null;
    278         
    279     }
    280 
    281 }
    282 
    283 
    284 
    285 
    286 /* TweenTargetChange 朝着轴插值(有效的跟踪动态目标)
    287 parameter:    
    288     v1 = {x: 0}, 
    289     v2 = {x: 100}, 
    290     distance = 1,        //每次移动的距离
    291     onUpdate = null,    //
    292     onEnd = null
    293 
    294 attribute:
    295     v1: Object;             //起点
    296     v2: Object;             //终点
    297     onUpdate: Function;        //
    298     onEnd: Function;         //
    299 
    300 method:
    301     update(): undefined;                        //一般在动画循环里执行此方法
    302     updateAxis(): undefined;                     //更新v1至v2的方向轴 (初始化时构造器自动调用一次)
    303     setDistance(distance: Number): undefined;     //设置每次移动的距离 (初始化时构造器自动调用一次)
    304 
    305 demo:
    306     const ttc = new TweenTargetChange({x:0, y:0}, {x:100, y:100}, 10),
    307 
    308     //计时器模拟动画循环函数, 每秒执行一次.update()
    309     timer = new Timer(() => {
    310         ttc.update();
    311         console.log('update: ', ttc.v1);
    312 
    313     }, 1000, Infinity);
    314 
    315     ttc.onEnd = v => {
    316         timer.stop();
    317         console.log('end: ', v);
    318     }
    319 
    320     timer.start();
    321     console.log(ttc);
    322 
    323 */
    324 class TweenTargetChange{
    325 
    326     #distance = 1;
    327     #distancePow2 = 1;
    328     #axis = {};
    329 
    330     constructor(v1 = {x: 0}, v2 = {x: 100}, distance, onUpdate = null, onEnd = null){
    331         this.v1 = v1;
    332         this.v2 = v2;
    333         this.onUpdate = onUpdate;
    334         this.onEnd = onEnd;
    335     
    336         this.setDistance(distance);
    337         this.updateAxis();
    338     }
    339 
    340     setDistance(v = 1){
    341         this.#distance = v;
    342         this.#distancePow2 = Math.pow(v, 2);
    343 
    344     }
    345 
    346     updateAxis(){ //更新轴
    347         var n, v, len = 0;
    348 
    349         for(n in this.v1){
    350             v = this.v2[n] - this.v1[n];
    351             len += v * v;
    352             this.#axis[n] = v;
    353 
    354         }
    355 
    356         len = Math.sqrt(len);
    357 
    358         if(len !== 0){
    359             
    360             for(n in this.v1) this.#axis[n] *= 1 / len;
    361 
    362         }
    363         
    364     }
    365 
    366     update(){
    367         var n, len = 0;
    368 
    369         for(n in this.v1) len += Math.pow(this.v1[n] - this.v2[n], 2);
    370 
    371         if(len > this.#distancePow2){
    372 
    373             for(n in this.v1) this.v1[n] += this.#axis[n] * this.#distance;
    374             if(this.onUpdate !== null) this.onUpdate(this.v1);
    375 
    376         }
    377 
    378         else{
    379             for(n in this.v1) this.v1[n] = this.v2[n];
    380             if(this.onEnd !== null) this.onEnd(this.v1);
    381             
    382         }
    383 
    384     }
    385 
    386 }
    完整代码
     
     
     
    TweenValue (从 原点 以规定的时间到达  终点)

    parameter: origin, end, time, onUpdate, onEnd;

    attribute:
        origin: Object; //原点(起点)
        end: Object; //终点
        time: Number; //origin 到 end 花费的时间
        onUpdate: Function; //更新回调; 一个回调参数 origin; 默认null;
        onEnd: Function; //结束回调; 没有回调参数; 默认null; (如果返回的是true将不从队列删除, 你可以在onEnd中更新.end不间断的继续补间)

    method:
        reset(origin, end: Object): undefined; //更换 .origin, .end; 它会清除其它对象的缓存属性
        reverse(): undefined; //this.end 复制 this.origin 的原始值
        update(): undefined; //Tween 通过此方法统一更新 TweenValue

    demo:
        //init Tween:
        const tween = new Tween(),
        animate = function (){
            requestAnimationFrame(animate);
            tween.update();
        }

        //init TweenValue:
        const v1 = new Tween.Value({x:0, y:0}, {x:5, y:10}, 1000, v => console.log(v));
       
        animate();
        tween.start(v1);
     
     
     
     
     
    TweenAlone (相对于 TweenValue 此类可以独立补间, 不需要 Tween)

    demo:
        const v1 = new TweenAlone({x:0, y:0}, {x:5, y:10}, 1000, v => console.log(v)),
        animate = function (){
            requestAnimationFrame(animate);
            v1.update();
        }

        animate();
        v1.start();
     
     
     
     
     
    Tween 动画补间 (TweenValue 的root, 可以管理多个TweenValue)

    parameter:
    attribute:
    method:
        start(value: TweenValue): undefined;
        stop(value: TweenValue): undefined;

    static:
        Value: TweenValue;

    demo:
        //init Tween:
        const tween = new Tween(),
        animate = function (){
            requestAnimationFrame(animate);
            tween.update();
        }

        //init TweenValue:
        const v2 = new Tween.Value({x:0, y:0}, {x:5, y:10}, 1000, v => console.log(v), v => {
            v2.reverse(); //v2.end 复制起始值
            return true; //返回true表示不删除队列, 需要继续补间
        });
       
        animate();
        tween.start(v2);
     
     
     
     
     
    TweenTargetChange 朝着轴插值(有效的跟踪动态目标)
    parameter:  
        v1 = {x: 0},
        v2 = {x: 100},
        distance = 1,       //每次移动的距离
        onUpdate = null,    //
        onEnd = null

    attribute:
        v1: Object;             //起点
        v2: Object;             //终点
        onUpdate: Function;     //
        onEnd: Function;        //

    method:
        update(): undefined;                        //一般在动画循环里执行此方法
        updateAxis(): undefined;                    //更新v1至v2的方向轴 (初始化时构造器自动调用一次)
        setDistance(distance: Number): undefined;   //设置每次移动的距离 (初始化时构造器自动调用一次)

    demo:
        const ttc = new TweenTargetChange({x:0, y:0}, {x:100, y:100}, 10),

        //计时器模拟动画循环函数, 每秒执行一次.update()
        timer = new Timer(() => {
            ttc.update();
            console.log('update: ', ttc.v1);

        }, 1000, Infinity);

        ttc.onEnd = v => {
            timer.stop();
            console.log('end: ', v);
        }

        timer.start();
        console.log(ttc);
  • 相关阅读:
    打造jQuery的高性能TreeView
    结构化日志类库 ---- Serilog库
    项目管理上的失误和应对措施
    Android分类导航
    Android破解
    Android开发入门
    安装 Android Studio 2.3 详细过程及错误解决
    Python学习思维导图
    设计模式的六大原则 ---- 理论知识
    日志的艺术(The art of logging)
  • 原文地址:https://www.cnblogs.com/weihexinCode/p/16320661.html
Copyright © 2020-2023  润新知