2016-09-23 13 views
1

キャンバス要素を使用して、角度2で円形の進行状況バーを作成します。私はAngular 1で複数のプロジェクトを行ってきましたが、Angular 2とTypeScriptはまったく新しいものなので、私はちょっと頭を上げています...角2:キャンバスと変更の検出

私はProgressCircleコンポーネントを作成しました。他のコンポーネントの内部で使用してください。このプログレスコンポーネントは、親コンポーネントから、プログレスサークルの外観とその塗り方を決定する2つの属性を受け取ります。

注:このコードを古いES5プロジェクトから取り出しました。これが表示されることがあります。

import { Component, Input, Injectable, ElementRef, AfterViewInit } from '@angular/core'; 

@Injectable() 
@Component({ 
    selector: 'progress-circle', 
    template: ` 
     <div class="progress-indicator" [style.width]="size + 'px'" [style.height]="size + 'px'"> 
      <canvas [attr.width]="size" [attr.height]="size"></canvas> 
      <span class="progress-text-container"> 
       <span class="progress-text">{{ progress }}</span> 
      </span> 
     </div> 
    ` 
}) 
export class ProgressCircle implements AfterViewInit { 
    @Input() size:number; 
    @Input() progress:number; 
    @Input() lineWidth:number; 
    @Input() rotate:number; 
    @Input() color:string; 
    @Input() trackColor:string; 
    @Input() bgColor:string; 
    @Input() borderWidth:number; 
    @Input() animate:boolean; 

    constructor(private el:ElementRef) {} 

    ngAfterViewInit() { 
     this.draw(); 
    } 

    draw() { 
     let canvas = this.el.nativeElement.getElementsByTagName('canvas')[0], 
      ctx = canvas.getContext('2d'), 

      options = { 
       percent: this.progress || 0, 
       size: this.size || 90, 
       lineWidth: this.lineWidth || (this.size/10) || 10, 
       rotate: this.rotate || 0, 
       color: this.color || '#000', 
       trackColor: this.trackColor || '#e6e6e6', 
       bgColor: this.bgColor || 'transparent', 
       borderWidth: this.borderWidth || 0, 
       doAnimate: this.animate 
      }, 

      radius = (options.size - options.lineWidth)/2, 
      progress = 0, 
      fillColor:string = undefined, 

      animFrame:number, bg:ImageData; 

     let drawCircle = (strokeColor:string, fillColor:string, percent:number, hasBorder:boolean = false) => { 
      // logic to draw circle goes here 
     } 

     let animateProgess =() => { 
      if (++progress <= options.percent) { // we need to animate 
       // draw circle 
       animFrame = window.requestAnimationFrame(animateProgess); 
      } 
     } 

     ctx.translate(options.size/2, options.size/2); 
     ctx.rotate((-.5 + (options.rotate/180)) * Math.PI); 

     if (options.doAnimate) { 
      bg = ctx.getImageData(0, 0, canvas.width, canvas.height); 
      animFrame = window.requestAnimationFrame(animateProgess); 
     } else { 
      drawCircle(options.color, fillColor, options.percent); 
      this.progress = Math.floor(options.percent); 
     } 
    } 
} 

これで正常です。しかし、親コンポーネントの入力変数progressはいつでも変更される可能性があります。適切なタイミングで進行状況バーの再描画をトリガーするにはどうすればよいですか?

ビューがロードされた後(つまりngAfterViewInitが呼び出される)までプログレスバーを初期化できません。そうしないと、canvas要素がまだ完全に初期化されていないため、すべてファンキーに見えます。 ngOnChangesのライフサイクルフックを調べましたが、ビューがロードされる前に最初に起動するため、無用です。

progress入力変数を観測可能にしてから、ngAfterViewInitフックでそれを購読することが考えられましたが、それがどのように機能するかは完全にはわかりません。私はngOnChangesにフックして、最初の変更(実際にはSimpleChangeクラスにはドキュメントに準拠したメソッドがあるかどうか)をチェックすることもできますが、それは私にはハックのようです。

任意のポインタをありがとう! Angular 2は私の上で成長していますが、Angular 1/ES5から来るのに慣れているのは間違いありません。

+0

プロのヒント:draw()コードのほとんどはあなたの質問にはあまり関係しません。小さな質問は、しばしば、SOにもっと注意を引く。したがって、draw()コードのほとんどを含まない方がよいでしょう。 –

答えて

2

ngOnChangesを使用してください。これは、入力プロパティ値が変更されたときに通知されるappropriate lifecycle hook to useです。ビューが初期化されるまで待機するよう

...私はngAfterViewInitngOnChangesは、それが実行されるたびに調べ、フラグ設定されています:

export class ProgressCircle implements AfterViewInit { 
    viewInitialized = false; 
    ... 
    ngOnChanges() { 
     if(!viewInitialized) return; 
     ... 
    } 
    ngAfterViewInit() { 
     viewInitialized = true; 
     ... 
    } 

を表示するかどうかを決定するためにngOnChangesのためのいくつかの方法があるかもしれませんが初期化されていますが、私は気付いていません(あなたが方法を知っている場合はコメントを投稿し、フラグよりも効率的です)。

また、@Injectable only needs to be used on servicesは他のサービスに依存します。

関連する問題