2017-02-03 9 views
0

私はいくつかの物理アニメーションを実行し、一連のDOM要素でアニメーションを実行したいと考えています。キャンバスではない。 非常に重要:キャンバスではありません。Angular2 Physicsアニメーション

私はそれを動作させましたが、DOM操作の高価さを考慮しても予想よりもパフォーマンスが低下します。インターバルを頻繁に調整しなくても、一度にいくつかのコンポーネントがページ上に表示される場合は、使用できなくなります。

Angular内で物事を維持しながら、より簡単で効果的な方法があるのだろうかと思います。ゾーンの角レンダリングを一切スキップする方法はありますか?角度バインディングなどを使用せずにバニラを行うなど方法もっとパフォーマンスが良いので、角の部分を間違えているのか、角のない部分を壊すべきなのか疑問に思っています。私はゾーンがグローバルな操作よりも優れていると考えていたと思った...?

画面上で何かを小刻みに例のコード(実際のアニメーションがより複雑であるが、この正確な技術に従ってください):

@Component({ 
    selector: 'thingy,[thingy]', 
    template: `<div #container [ngStyle]="getStyle()"><ng-content></ng-content></div>` 
}) 


export class Thingy implements OnInit, OnDestroy { 
    private _x:number = 0; 
    private _y:number = 0; 
    private _interval:any; 
    private _style:CSSStyleDeclaration = { 
     left: 0, 
     top: 0, 
     position: absolute 
    }; 

    constructor(){} 

    ngOnInit() { 
     this._interval = setInterval(() => { 
      this._x++; 
      this._y = Math.sin(this._x); 

      this._style.left = this._x + "px"; 
      this._style.top = this._y + "px"; 
     }); 
    } 

    ngOnDestroy() { 
     clearInterval(this._interval); // because it continues ticking after destroy 
    } 

    getStyle():CSSStyleDeclaration { 
     return this._style; // in angular1 it was bad joojoo to return a new object each time so i avoid doing so here too 
    } 
} 

私は同じくらい私がどのように知っているように、このアプローチを最適化しました。私は組み込みのアニメーションメタデータソリューションがシナリオの大部分を処理できると思うが、私は試していない。なぜなら、抽象度を増やすとパフォーマンスが向上するということは想像もできず、b)アニメーションは状態遷移ではないので、適切な。また、私はもっとこのようにテンプレートを使用してみましたが、違うくらいではないようです

<div [style.top.px]="_y" [style.left.px]="_x"><ng-content></ng-content></div> 

はまた、私が直接ElementRefをいじって試してみたが、それは確かにありませんでしたヘルプ:

@ViewChild("container") container:ElementRef; 
this._container.nativeElement.styles.top = this._y + "px"; 

Angularのコントロールの外で行うのが最善の方法ですが、そのための標準はありますか?私は、ノートのも...

をコンポーネントでDOM要素を描画して、非角度コードをキックスタートするウィンドウイベントを送出することができます:私は、点Aで開始し、CSSの遷移を許可するために、点Bにすぐにジャンプすることはできませんアニメーションをペイントします。アニメーションは、移行するのに十分な予測はできません。それが非常に巧妙な解決策でない限り、私はそれが各ステップを刻むことを除いてどのようにアニメーション化できるかはわかりません。

答えて

0

私はパフォーマンスの問題を解決するために、グローバルティッカーを使用しました。これは、各コンポーネントがそれ自身の責任を負うのではなく、ティッカーはシンプルなObservableであり、各コンポーネントがそれを購読したり、どこから開始して独自のインターバルを停止したかを解除することができます。

import {Injectable} from '@angular/core'; 
import {Observer, Observable} from 'rxjs'; 

@Injectable() 
export class TickerService { 
    private _observer: Observer<number>; 
    private _timer:any; 
    public data$ = new Observable(observer => this._observer = observer).share(); 

    constructor() { 
     this.data$ = new Observable(observer => { 
      this._observer = observer; 
     }).share(); 
    } 

    public start():void { 
     if(this._timer) { // not required... just didn't want to have two going at once 
      this.stop(); 
     } 

     this._timer = setInterval(() => { 
      this.tick(); 
     }, 30); 
    } 

    public stop():void { 
     clearInterval(this._timer); 
     this._timer = 0; 
    } 

    private tick():void { 
     this._observer.next(new Date().getTime()); // the date part is irrelevant. i just wanted to use it to track the performance lag between each tick 
    } 
} 

アイテムは、彼らのようなそれに反応することができます

@Component({ 
    selector: 'thingy,[thingy]', 
    template: `<div #container [ngStyle]="getStyle()"><ng-content></ng-content></div>` 
}) 


export class Thingy implements OnInit, OnDestroy { 
    private _x:number = 0; 
    private _y:number = 0; 
    private _subscription:Subscription; 
    private _style:CSSStyleDeclaration = { 
     left: 0, 
     top: 0, 
     position: absolute 
    }; 

    constructor(private _ticker:TickerService){} 

    ngOnInit() { 
     this._subscription = this._ticker.data$.subscribe(() => { 
      this._x++; 
      this._y = Math.sin(this._x); 

      this._style.left = this._x + "px"; 
      this._style.top = this._y + "px"; 
     }); 
     this._ticker.start(); // even though every instance will call this, there's a guard in the TickerService to only allow one ticker to run 
    } 

    ngOnDestroy() { 
     this._subscription.unsubscribe(); 
    } 

    getStyle():CSSStyleDeclaration { 
     return this._style; 
    } 
} 

この小さな変更は60fpsの程度に5fpsから約5 Thingysのパフォーマンスをしました。私はこれが、それぞれのThingyが独自のティッカーを生み出し、それ自身の(ブロッキング)ダイジェスト/ペイントを他のものと順不同で実行させるためであると信じています。これにより、Angularは個々の変更を個別にダイジェストし、巨大なスタックが構築されました。実行する5つの更新がある1つのティックの代わりに、それぞれ1つの更新で5つのティックを実行していました。

これですべての変更が行われ、1つのダイジェスト/ゾーン更新内で実行されます。

+0

ngStyleディレクティブでスタイルを適用する代わりに、角度2で組み込みのレンダラー 'setElementStyle'を使用してみましたか? – jsfrocha

+0

私はレンダリングを試していません。私はそれを試みるだろう(2,3日かもしれない)と私は何を見つけると更新します。 – oooyaya

関連する問題