UNPKG

bitmovin-player-ui

Version:
109 lines (90 loc) 3.33 kB
import { Component, ComponentConfig } from './Component'; import { DOM } from '../DOM'; /** * Animated analog TV static noise. * * @category Components */ export class TvNoiseCanvas extends Component<ComponentConfig> { private canvas: DOM; private canvasElement: HTMLCanvasElement; private canvasContext: CanvasRenderingContext2D; private canvasWidth = 160; private canvasHeight = 90; private interferenceHeight = 50; private lastFrameUpdate: number = 0; private frameInterval: number = 60; private useAnimationFrame: boolean = !!window.requestAnimationFrame; private noiseAnimationWindowPos: number; private frameUpdateHandlerId: number; constructor(config: ComponentConfig = {}) { super(config); this.config = this.mergeConfig( config, { cssClass: 'ui-tvnoisecanvas', }, this.config, ); } protected toDomElement(): DOM { return (this.canvas = new DOM('canvas', { class: this.getCssClasses() }, this)); } start(): void { this.canvasElement = <HTMLCanvasElement>this.canvas.get(0); this.canvasContext = this.canvasElement.getContext('2d'); this.noiseAnimationWindowPos = -this.canvasHeight; this.lastFrameUpdate = 0; this.canvasElement.width = this.canvasWidth; this.canvasElement.height = this.canvasHeight; this.renderFrame(); } stop(): void { if (this.useAnimationFrame) { cancelAnimationFrame(this.frameUpdateHandlerId); } else { clearTimeout(this.frameUpdateHandlerId); } } private renderFrame(): void { // This code has been copied from the player controls.js and simplified if (this.lastFrameUpdate + this.frameInterval > new Date().getTime()) { // It's too early to render the next frame this.scheduleNextRender(); return; } let currentPixelOffset; const canvasWidth = this.canvasWidth; const canvasHeight = this.canvasHeight; // Create texture const noiseImage = this.canvasContext.createImageData(canvasWidth, canvasHeight); // Fill texture with noise for (let y = 0; y < canvasHeight; y++) { for (let x = 0; x < canvasWidth; x++) { currentPixelOffset = canvasWidth * y * 4 + x * 4; noiseImage.data[currentPixelOffset] = Math.random() * 255; if (y < this.noiseAnimationWindowPos || y > this.noiseAnimationWindowPos + this.interferenceHeight) { noiseImage.data[currentPixelOffset] *= 0.85; } noiseImage.data[currentPixelOffset + 1] = noiseImage.data[currentPixelOffset]; noiseImage.data[currentPixelOffset + 2] = noiseImage.data[currentPixelOffset]; noiseImage.data[currentPixelOffset + 3] = 50; } } // Put texture onto canvas this.canvasContext.putImageData(noiseImage, 0, 0); this.lastFrameUpdate = new Date().getTime(); this.noiseAnimationWindowPos += 7; if (this.noiseAnimationWindowPos > canvasHeight) { this.noiseAnimationWindowPos = -canvasHeight; } this.scheduleNextRender(); } private scheduleNextRender(): void { if (this.useAnimationFrame) { this.frameUpdateHandlerId = window.requestAnimationFrame(this.renderFrame.bind(this)); } else { this.frameUpdateHandlerId = window.setTimeout(this.renderFrame.bind(this), this.frameInterval); } } }