Last active
May 24, 2016 21:36
-
-
Save austbot/5c5dffa0025cdfe7a6451bf2007ef0d9 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {Component, ViewEncapsulation, ElementRef, Inject, EventEmitter, Output, ViewChild} from 'angular2/core'; | |
import {Input} from 'angular2/core'; | |
import {ChangeDetectionStrategy} from 'angular2/core'; | |
import {DatePipe} from 'angular2/common'; | |
import {PlayerDurationPipe} from './playerDurationPipe'; | |
import {Observable} from 'rxjs/Observable'; | |
import {Subject} from 'rxjs/Subject'; | |
import {Action} from '@ngrx/store'; | |
import {FilmStrip} from './filmStrip/filmStrip'; | |
export interface ScrubberHoverEvent { | |
pixels: number; | |
seconds: number; | |
} | |
@Component({ | |
changeDetection: ChangeDetectionStrategy.OnPush, | |
selector: 'progress-bar', | |
directives: [FilmStrip], | |
pipes: [DatePipe, PlayerDurationPipe], | |
host: { | |
'(mouseenter)': 'showScrubberHandle()', | |
'(mouseleave)': 'hideScrubberHandle()', | |
'(mousemove)': 'scrubberHoverEvent.next($event)' | |
}, | |
template: ` | |
<film-strip *ngIf="!state.isLive && state.filmStripUrl" [filmStripUrl]="state.filmStripUrl" [class.visible]="scrubberHandleVisibility" [position]="scrubberHoverEvent" [style.left]="scrubberHandlePosition | async" ></film-strip> | |
<div #scrubber class="scrubber" (click)="changePosition.next($event)"> | |
<div class="scrubber-handle" [class.visible]="scrubberHandleVisibility" [style.left]="scrubberHandlePosition | async"></div> | |
<div class="progress-container" [style.width]="progress"></div> | |
<div class="buffer-container" [style.width]="buffer"></div> | |
</div> | |
<span class="remaining">{{remaining | playerDuration}}</span> | |
`, | |
styles: [ | |
require('./progressBar.scss') | |
] | |
}) | |
/** | |
* @description Manages the playback location and filmstrip. | |
* @class ProgressBar | |
*/ | |
export class ProgressBar { | |
/** | |
* @description The amount loaded in percent | |
* @type {string} eg. '100%' | |
*/ | |
buffer: string; | |
/** | |
* @description The amount watched or position in the media. | |
* @type {string} eg. '10%' | |
*/ | |
progress: string; | |
/** | |
* @description The amount left to watch in miliseconds | |
* @type {number} eg. 10000 | |
*/ | |
remaining: number; | |
/** | |
* @description The Hover over the progress bar event stream, maps the raw dom event to a ScrubberHoverEvent. | |
* @type {Observable<ScrubberHoverEvent>} | |
*/ | |
scrubberHoverEvent: Observable<any>; | |
/** | |
* @description Observes the hover event and maps it to a pixel value where the scrubber handle should be positioned. | |
* @type {Observable<string>} | |
*/ | |
scrubberHandlePosition: Observable<string>; | |
/** | |
* @description Listens to the click on the scrubber bar and tells the component to emit the latest value from the | |
* scrubber hover | |
* @type {Observable<ScrubberHoverEvent>} | |
*/ | |
changePosition: Observable<any>; | |
/** | |
* @description Internal state of the scrubber handle. TODO - LOW -> map this into an observable | |
* @type {boolean} | |
*/ | |
scrubberHandleVisibility: boolean = false; | |
/** | |
* @description The player state input (important :) | |
* @type {PlayerState} | |
*/ | |
@Input() | |
state; | |
/** | |
* @description Events coming out of this component | |
* @type {EventEmitter} | |
*/ | |
@Output() | |
progressBarEvent: EventEmitter<Action> = new EventEmitter(); | |
/** | |
* @description The scrubber bar element | |
* @type {ElementRef} | |
*/ | |
@ViewChild('scrubber') | |
scrubber: ElementRef; | |
ngOnInit() { | |
//Listen to MouseMove | |
this.scrubberHoverEvent = new Subject().map((event: MouseEvent): ScrubberHoverEvent => { | |
//The bounded position | |
let pos = Math.min(Math.max(0, event.offsetX), this.scrubber.nativeElement.offsetWidth); | |
//The ScrubberHoverEvent | |
return { | |
seconds: (pos / this.scrubber.nativeElement.offsetWidth) * this.state.duration, //Millisecond position | |
pixels: pos //Pixel position on page | |
}; | |
}); | |
this.scrubberHandlePosition = this.scrubberHoverEvent | |
.map( | |
(data: ScrubberHoverEvent) => { | |
return `${data.pixels}px`; | |
} | |
); | |
//Listen to the click and grab the last value from scrubberHover. | |
this.changePosition = new Subject().withLatestFrom(this.scrubberHoverEvent, (click: MouseEvent, hover: ScrubberHoverEvent): ScrubberHoverEvent => { | |
return hover; | |
}); | |
this.changePosition.subscribe((data: ScrubberHoverEvent): void => { | |
this.progressBarEvent.emit({type: 'seek', payload: data.seconds}); | |
}); | |
} | |
ngOnChanges() { | |
//When the input changes recalc the percentages. | |
this.buffer = `${this.state.percentLoaded}%`; | |
this.progress = `${this.state.percentWatched}%`; | |
this.remaining = this.state.duration - this.state.position; | |
} | |
showScrubberHandle() { | |
this.scrubberHandleVisibility = true; | |
} | |
hideScrubberHandle() { | |
this.scrubberHandleVisibility = false; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment