Mercurial > hg > ugly-duckling
changeset 287:6c47605ebd75
Merge remote-tracking branch 'origin/master'
author | Chris Cannam <cannam@all-day-breakfast.com> |
---|---|
date | Fri, 05 May 2017 09:48:02 +0100 |
parents | bb44ef9deb42 (current diff) 6c51fd776008 (diff) |
children | 0c0fd90320e7 |
files | |
diffstat | 7 files changed, 92 insertions(+), 22 deletions(-) [+] |
line wrap: on
line diff
--- a/src/app/analysis-item/analysis-item.component.html Wed May 03 17:03:55 2017 +0100 +++ b/src/app/analysis-item/analysis-item.component.html Fri May 05 09:48:02 2017 +0100 @@ -18,6 +18,7 @@ [isSubscribedToExtractionService]="isActive && !item.isRoot" [isOneShotExtractor]="true" [isSeeking]="isActive" + [width]="contentWidth" ></ugly-waveform> </ng-template> </md-card-content>
--- a/src/app/analysis-item/analysis-item.component.ts Wed May 03 17:03:55 2017 +0100 +++ b/src/app/analysis-item/analysis-item.component.ts Fri May 05 09:48:02 2017 +0100 @@ -30,6 +30,7 @@ @Input() timeline: Timeline; @Input() isActive: boolean; @Input() item: AnalysisItem; + @Input() contentWidth: number; private hasProgressOnInit = false; ngOnInit(): void {
--- a/src/app/app.module.ts Wed May 03 17:03:55 2017 +0100 +++ b/src/app/app.module.ts Fri May 05 09:48:02 2017 +0100 @@ -28,6 +28,7 @@ import {AnalysisItemComponent} from './analysis-item/analysis-item.component'; import {ProgressBarComponent} from './progress-bar/progress-bar'; import {UglyMaterialModule} from './ugly-material.module'; +import {Observable} from 'rxjs/Observable'; export function createAudioContext(): AudioContext { return new ( @@ -92,6 +93,16 @@ }; } +export interface Dimension { + width: number; + height: number; +} +export function createWindowDimensionObservable(): Observable<Dimension> { + return Observable.fromEvent(window, 'resize', () => ({ + height: window.innerHeight, + width: window.innerWidth + })).share(); +} @NgModule({ declarations: [ AppComponent, @@ -121,7 +132,8 @@ {provide: 'MediaRecorderFactory', useFactory: createMediaRecorderFactory}, {provide: 'PiperRepoUri', useValue: 'assets/remote-extractors.json'}, {provide: 'UrlResourceLifetimeManager', useFactory: createUrlResourceManager}, - {provide: 'ResourceReader', useFactory: createResourceReader} + {provide: 'ResourceReader', useFactory: createResourceReader}, + {provide: 'DimensionObservable', useFactory: createWindowDimensionObservable} ], bootstrap: [AppComponent] })
--- a/src/app/notebook-feed/notebook-feed.component.css Wed May 03 17:03:55 2017 +0100 +++ b/src/app/notebook-feed/notebook-feed.component.css Fri May 05 09:48:02 2017 +0100 @@ -1,3 +1,7 @@ .break { margin-bottom: 32px; } + +.feed { + width: 100%; +}
--- a/src/app/notebook-feed/notebook-feed.component.html Wed May 03 17:03:55 2017 +0100 +++ b/src/app/notebook-feed/notebook-feed.component.html Fri May 05 09:48:02 2017 +0100 @@ -1,10 +1,12 @@ - -<ng-template ngFor let-item [ngForOf]="analyses"> - <div [class.break]="item.isRoot"> - <ugly-analysis-item - [timeline]="item.hasSharedTimeline ? sharedTimeline : undefined" - [isActive]="rootAudioUri === item.rootAudioUri" - [item]="item" - ></ugly-analysis-item> - </div> -</ng-template> +<div class="feed"> + <ng-template ngFor let-item [ngForOf]="analyses"> + <div [class.break]="item.isRoot"> + <ugly-analysis-item + [timeline]="getOrCreateTimeline(item)" + [isActive]="rootAudioUri === item.rootAudioUri" + [item]="item" + [contentWidth]="width" + ></ugly-analysis-item> + </div> + </ng-template> +</div>
--- a/src/app/notebook-feed/notebook-feed.component.ts Wed May 03 17:03:55 2017 +0100 +++ b/src/app/notebook-feed/notebook-feed.component.ts Fri May 05 09:48:02 2017 +0100 @@ -3,11 +3,17 @@ */ import { ChangeDetectionStrategy, + ChangeDetectorRef, Component, - Input + Inject, + Input, + OnDestroy } from '@angular/core'; import Waves from 'waves-ui'; import {AnalysisItem} from '../analysis-item/analysis-item.component'; +import {Observable} from 'rxjs/Observable'; +import {Dimension} from '../app.module'; +import {Subscription} from 'rxjs/Subscription'; @Component({ selector: 'ugly-notebook-feed', @@ -15,24 +21,61 @@ styleUrls: ['./notebook-feed.component.css'], changeDetection: ChangeDetectionStrategy.OnPush }) -export class NotebookFeedComponent { - sharedTimeline: Timeline; +export class NotebookFeedComponent implements OnDestroy { @Input() analyses: AnalysisItem[]; @Input() set rootAudioUri(uri: string) { this._rootAudioUri = uri; - - // TODO is this safe? will the fact references are held elsewhere - // keep the previous instance alive? Or will it get garbage collected in - // screw previous layers up? - this.sharedTimeline = new Waves.core.Timeline(); } get rootAudioUri(): string { return this._rootAudioUri; } private _rootAudioUri: string; + private resizeSubscription: Subscription; + private width: number; + private lastWidth: number; + private timelines: Map<string, Timeline>; - constructor() { - this.sharedTimeline = new Waves.core.Timeline(); + constructor( + private ref: ChangeDetectorRef, + @Inject('DimensionObservable') private onResize: Observable<Dimension> + ) { + this.timelines = new Map(); + this.onResize.subscribe(dim => { + this.lastWidth = this.width; + this.width = dim.width; + }); + + // the use of requestAnimationFrame here is to leave the dom updates + // to a time convenient for the browser, and avoid a cascade / waterfall + // of DOM changes for rapid resize events in the event handler above. + // ..I'm not convinced this is particularly beneficial here // TODO + const triggerChangeDetectionOnResize = () => { + requestAnimationFrame(triggerChangeDetectionOnResize); + if (this.width !== this.lastWidth) { + ref.markForCheck(); // only trigger change detection if width changed + } + }; + requestAnimationFrame(triggerChangeDetectionOnResize); + } + + getOrCreateTimeline(item: AnalysisItem): Timeline | void { + if (!item.hasSharedTimeline) { + return; + } + + if (this.timelines.has(item.rootAudioUri)) { + return this.timelines.get(item.rootAudioUri); + } else { + const timeline = new Waves.core.Timeline(); + this.timelines.set(item.rootAudioUri, timeline); + return timeline; + } + } + + ngOnDestroy(): void { + if (this.resizeSubscription) { + this.resizeSubscription.unsubscribe(); + } } }
--- a/src/app/waveform/waveform.component.ts Wed May 03 17:03:55 2017 +0100 +++ b/src/app/waveform/waveform.component.ts Fri May 05 09:48:02 2017 +0100 @@ -60,7 +60,14 @@ export class WaveformComponent implements OnInit, AfterViewInit, OnDestroy { @ViewChild('track') trackDiv: ElementRef; - + @Input() set width(width: number) { + if (this.timeline) { + requestAnimationFrame(() => { + this.timeline.timeContext.visibleWidth = width; + this.timeline.tracks.update(); + }); + } + } @Input() timeline: Timeline; @Input() trackIdPrefix: string; @Input() set isSubscribedToExtractionService(isSubscribed: boolean) {