import { Dynamic , val , applyOptions } from '../util' ; import { Base , BaseOptions } from './base' ; import { Base as BaseEffect } from '../effect/base' ; interface VisualOptions extends BaseOptions { x ? : Dynamic < number > ; y ? : Dynamic < number > ; width ? : Dynamic < number > ; height ? : Dynamic < number > ; background ? : Dynamic < string > ; border ? : Dynamic < { color : string ; thickness ? : number ; } > ; opacity ? : Dynamic < number > ; } /** Any layer that renders to a canvas */ class Visual extends Base { x : Dynamic < number > ; y : Dynamic < number > ; width : Dynamic < number > ; height : Dynamic < number > ; background : Dynamic < string > ; border : Dynamic < { color : string ; thickness : number ; } > ; opacity : Dynamic < number > ; /**
     * The layer's rendering canvas
     */ readonly canvas : HTMLCanvasElement ; /**
     * The context of  Visual readonly cctx : CanvasRenderingContext2D ; readonly effects : BaseEffect [ ] ; private _effectsBack : BaseEffect [ ] ; /**
     * Creates a visual layer
     */ constructor ( options ) { super ( options ) ; applyOptions ( options , this ) ; this . canvas = document . createElement ( 'canvas' ) ; this . cctx = this . canvas . getContext ( '2d' ) ; this . _effectsBack = [ ] ; this . effects = new Proxy ( this . _effectsBack , { deleteProperty : ( target , property ) => { const value = target [ property ] ; value . detach ( ) ; delete target [ property ] ; return true ; } , set : ( target , property , value ) => { if ( ! isNaN ( Number ( property ) ) ) { if ( target [ property ] ) target [ property ] . detach ( ) ; value . attach ( this ) ; } target [ property ] = value ; return true ; } } ) ; } /**
     * Render visual output
     */ render ( ) { const width = val ( this , 'width' , this . currentTime ) ; const height = val ( this , 'height' , this . currentTime ) ; if ( width === 0 || height === 0 ) return ; this . beginRender ( ) ; this . doRender ( ) ; this . endRender ( ) ; } beginRender ( ) { this . canvas . width = val ( this , 'width' , this . currentTime ) ; this . canvas . height = val ( this , 'height' , this . currentTime ) ; this . cctx . globalAlpha = val ( this , 'opacity' , this . currentTime ) ; } doRender ( ) { if ( this . background ) { this . cctx . fillStyle = val ( this , 'background' , this . currentTime ) ; this . cctx . fillRect ( 0 , 0 , this . canvas . width , this . canvas . height ) ; } const border = val ( this , 'border' , this . currentTime ) ; if ( border && border . color ) { this . cctx . strokeStyle = border . color ; this . cctx . lineWidth = border . thickness || 1 ; } } endRender ( ) { const w = val ( this , 'width' , this . currentTime ) || val ( this . movie , 'width' , this . movie . currentTime ) ; const h = val ( this , 'height' , this . currentTime ) || val ( this . movie , 'height' , this . movie . currentTime ) ; if ( w * h > 0 ) this . _applyEffects ( ) ; } _applyEffects ( ) { for ( let i = 0 ; i < this . effects . length ; i ++ ) { const effect = this . effects [ i ] ; if ( effect && effect . enabled ) effect . apply ( this , this . movie . currentTime - this . startTime ) ; } } param effect return addEffect ( effect ) { this . effects . push ( effect ) ; return this ; } getDefaultOptions ( ) { return { ... Base . prototype . getDefaultOptions ( ) , name desc x : 0 , name desc y : 0 , name width : null , name height : null , name desc background : null , name desc border : null , name opacity : 1 } ; } } Visual . prototype . publicExcludes = Base . prototype . publicExcludes . concat ( [ 'canvas' , 'cctx' , 'effects' ] ) ; Visual . prototype . propertyFilters = { ... Base . prototype . propertyFilters , width : function ( width ) { return width != undefined ? width : this . _movie . width ; } , height : function ( height ) { return height != undefined ? height : this . _movie . height ; } } ; export { Visual , VisualOptions } ;