diff src/app/analysis-item/analysis-item.component.ts @ 408:f2d43724a578

LifeCycle handling for paging animations. Additionally, only add a pager to audio items as the timeline only needs to be updated once and other components can be driven from that.
author Lucas Thompson <dev@lucas.im>
date Sun, 04 Jun 2017 20:19:41 +0100
parents 6fe8ef9687de
children 523858455430
line wrap: on
line diff
--- a/src/app/analysis-item/analysis-item.component.ts	Sun Jun 04 20:17:43 2017 +0100
+++ b/src/app/analysis-item/analysis-item.component.ts	Sun Jun 04 20:19:41 2017 +0100
@@ -5,15 +5,20 @@
   ChangeDetectionStrategy,
   Component,
   Input,
+  OnDestroy,
   OnInit
 } from '@angular/core';
 import {naivePagingMapper} from '../visualisations/WavesJunk';
-import {OnSeekHandler, TimePixelMapper} from '../playhead/PlayHeadHelpers';
+import {OnSeekHandler} from '../playhead/PlayHeadHelpers';
 import {
   defaultColourGenerator,
   HigherLevelFeatureShape,
   KnownShapedFeature
 } from '../visualisations/FeatureUtilities';
+import {
+  RenderLoopService,
+  TaskRemover
+} from '../services/render-loop/render-loop.service';
 
 export interface Item {
   id: string;
@@ -82,22 +87,44 @@
   styleUrls: ['./analysis-item.component.css'],
   changeDetection: ChangeDetectionStrategy.OnPush
 })
-export class AnalysisItemComponent implements OnInit {
+export class AnalysisItemComponent implements OnInit, OnDestroy {
 
-  @Input() timeline: Timeline; // TODO should be TimelineTimeContext?
-  @Input() isActive: boolean;
+  // TODO should be TimelineTimeContext?
+  @Input() set timeline(timeline: Timeline) {
+    this.mTimeline = timeline;
+    this.resetRemoveAnimation();
+  }
+
+  get timeline(): Timeline {
+    return this.mTimeline;
+  }
+
+  @Input() set isActive(isActive: boolean) {
+    this.removeAnimation();
+    this.mIsActive = isActive;
+    if (isActive) {
+      this.resetRemoveAnimation();
+    }
+  }
+
+  get isActive() {
+    return this.mIsActive;
+  }
+
   @Input() item: Item;
   @Input() contentWidth: number;
   @Input() onSeek: OnSeekHandler;
+  // TODO move / re-think - naivePagingMapper feels like a big ol' bodge
+  private removeAnimation: TaskRemover;
   private hasProgressOnInit = false;
+  private mIsActive: boolean;
+  private mTimeline: Timeline;
 
-
-  // TODO move / re-think - naivePagingMapper feels like a big ol' bodge
-  private timeToPixel: TimePixelMapper;
+  constructor(private renderLoop: RenderLoopService) {}
 
   ngOnInit(): void {
+    this.resetRemoveAnimation();
     this.hasProgressOnInit = this.item.progress != null;
-    this.timeToPixel = naivePagingMapper(this.timeline);
   }
 
   isLoading(): boolean {
@@ -105,7 +132,7 @@
   }
 
   isAudioItem(): boolean {
-    return isRootAudioItem(this.item);
+    return this.item && isRootAudioItem(this.item);
   }
 
   getFeatureShape(): HigherLevelFeatureShape | null {
@@ -116,4 +143,27 @@
   getNextColour(): string {
     return defaultColourGenerator.next().value;
   }
+
+  ngOnDestroy(): void {
+    this.removeAnimation();
+  }
+
+  private resetRemoveAnimation(): void {
+    if (this.removeAnimation) {
+      this.removeAnimation();
+    }
+    const createPagingTask = () => {
+      const pagingMapper = naivePagingMapper(this.timeline);
+      return this.renderLoop.addPlayingTask(currentTime => {
+        pagingMapper(currentTime);
+      });
+    };
+    // only add a pager to audio items, it can drive the feature items
+    const remover = this.timeline && this.isAudioItem() ?
+      createPagingTask() : () => {};
+    this.removeAnimation = () => {
+      remover();
+      this.removeAnimation = () => {};
+    };
+  }
 }