module import VidarObject from './object' ; import { publish } from './event' ; import { Movie } from './movie' ; param obj param name function getPropertyDescriptor ( obj , name ) { do { const propDesc = Object . getOwnPropertyDescriptor ( obj , name ) ; if ( propDesc ) return propDesc ; obj = Object . getPrototypeOf ( obj ) ; } while ( obj ) ; return undefined ; } return export function applyOptions ( options , destObj ) { const defaultOptions = destObj . getDefaultOptions ( ) ; for ( const option in options ) if ( ! defaultOptions . hasOwnProperty ( option ) ) throw new Error ( "Invalid option: '" + option + "'" ) ; options = { ... defaultOptions , ... options } ; for ( const option in options ) { const propDesc = getPropertyDescriptor ( destObj , option ) ; if ( ! propDesc || propDesc . set ) destObj [ option ] = options [ option ] ; } } const valCache = new WeakMap ( ) ; function cacheValue ( element , path , value ) { if ( ! valCache . has ( element . movie ) ) valCache . set ( element . movie , new WeakMap ( ) ) ; const movieCache = valCache . get ( element . movie ) ; if ( ! movieCache . has ( element ) ) movieCache . set ( element , { } ) ; const elementCache = movieCache . get ( element ) ; elementCache [ path ] = value ; return value ; } function hasCachedValue ( element , path ) { return valCache . has ( element . movie ) && valCache . get ( element . movie ) . has ( element ) && path in valCache . get ( element . movie ) . get ( element ) ; } function getCachedValue ( element , path ) { return valCache . get ( element . movie ) . get ( element ) [ path ] ; } export function clearCachedValues ( movie ) { valCache . delete ( movie ) ; } /**
 * A keyframe set.
 *
 * Usage:
 * ```js
 new vd.KeyFrame([time1, value1, interpolation1], [time2, value2])`
 * ```
 * TypeScript users need to specify the type of the value as a type parameter.
 */ export class KeyFrame < T > { value : unknown [ ] [ ] ; /** Keys to interpolate, or all keys if undefined */ interpolationKeys : string [ ] ; constructor ( ... value ) { this . value = value ; this . interpolationKeys = [ ] ; } withKeys ( keys ) { this . interpolationKeys = keys ; return this ; } evaluate ( time ) { if ( this . value . length === 0 ) throw new Error ( 'Empty keyframe' ) ; if ( time === undefined ) throw new Error ( '|time| is undefined or null' ) ; const firstTime = this . value [ 0 ] [ 0 ] as number ; if ( time < firstTime ) throw new Error ( 'No keyframe point before |time|' ) ; for ( let i = 0 ; i < this . value . length ; i ++ ) { const startTime = this . value [ i ] [ 0 ] as number ; const startValue = this . value [ i ] [ 1 ] as T ; type interpolateType = < U = number | object > ( startValue : U , endValue : U , percentProgress : number , interpolationKeys : string [ ] ) => U ; const interpolate = this . value [ i ] . length === 3 ? this . value [ i ] [ 2 ] as interpolateType : linearInterp ; if ( i + 1 < this . value . length ) { const endTime = this . value [ i + 1 ] [ 0 ] as number ; const endValue = this . value [ i + 1 ] [ 1 ] as T ; if ( startTime <= time && time < endTime ) if ( ! ( typeof startValue === 'number' || typeof endValue === 'object' ) ) { return startValue ; } else if ( typeof startValue !== typeof endValue ) { throw new Error ( 'Type mismatch in keyframe values' ) ; } else { const percentProgress = ( time - startTime ) / ( endTime - startTime ) ; return interpolate ( startValue as unknown as ( number | object ) , endValue as unknown as ( number | object ) , percentProgress , this . interpolationKeys ) as unknown as T ; } } else { return startValue ; } } } } /** A dynamic property. Supports simple values, keyframes and functions */ export type Dynamic < T > = T | KeyFrame < T > | ( ( element : VidarObject , time : number ) => T ) ; param element param path param time export function val ( element , path , time ) { if ( hasCachedValue ( element , path ) ) return getCachedValue ( element , path ) ; const pathParts = path . split ( '.' ) ; let property = element [ pathParts . shift ( ) ] ; while ( pathParts . length > 0 ) property = property [ pathParts . shift ( ) ] ; const process = element . propertyFilters [ path ] ; let value ; if ( property instanceof KeyFrame ) value = property . evaluate ( time ) ; else if ( typeof property === 'function' ) value = property ( element , time ) ; else value = property ; return cacheValue ( element , path , process ? process . call ( element , value ) : value ) ; } export function linearInterp ( x1 , x2 , t , objectKeys ? ) { if ( typeof x1 !== typeof x2 ) throw new Error ( 'Type mismatch' ) ; if ( typeof x1 !== 'number' && typeof x1 !== 'object' ) return x1 ; if ( typeof x1 === 'object' ) { if ( Object . getPrototypeOf ( x1 ) !== Object . getPrototypeOf ( x2 ) ) throw new Error ( 'Prototype mismatch' ) ; const int = Object . create ( Object . getPrototypeOf ( x1 ) ) ; const keys = Object . keys ( x1 ) || objectKeys ; for ( let i = 0 ; i < keys . length ; i ++ ) { const key = keys [ i ] ; if ( ! x1 . hasOwnProperty ( key ) || ! x2 . hasOwnProperty ( key ) ) continue ; int [ key ] = linearInterp ( x1 [ key ] , x2 [ key ] , t ) ; } return int ; } return ( 1 - t ) * x1 + t * ( x2 as number ) ; } export function cosineInterp ( x1 , x2 , t , objectKeys ? ) { if ( typeof x1 !== typeof x2 ) throw new Error ( 'Type mismatch' ) ; if ( typeof x1 !== 'number' && typeof x1 !== 'object' ) return x1 ; if ( typeof x1 === 'object' && typeof x2 === 'object' ) { if ( Object . getPrototypeOf ( x1 ) !== Object . getPrototypeOf ( x2 ) ) throw new Error ( 'Prototype mismatch' ) ; const int = Object . create ( Object . getPrototypeOf ( x1 ) ) ; const keys = Object . keys ( x1 ) || objectKeys ; for ( let i = 0 ; i < keys . length ; i ++ ) { const key = keys [ i ] ; if ( ! x1 . hasOwnProperty ( key ) || ! x2 . hasOwnProperty ( key ) ) continue ; int [ key ] = cosineInterp ( x1 [ key ] , x2 [ key ] , t ) ; } return int ; } const cos = Math . cos ( Math . PI / 2 * t ) ; return cos * ( x1 as number ) + ( 1 - cos ) * ( x2 as number ) ; } /**
 * An RGBA color, for proper interpolation and shader effects
 */ export class Color { r : number ; g : number ; b : number ; a : number ; param r param g param b param a constructor ( r , g , b , a = 1.0 ) { this . r = r ; this . g = g ; this . b = b ; this . a = a ; } /**
     * Converts to a CSS color
     */ toString ( ) { return `rgba(${ this . r }, ${ this . g }, ${ this . b }, ${ this . a })` ; } } const parseColorCanvas = document . createElement ( 'canvas' ) ; parseColorCanvas . width = parseColorCanvas . height = 1 ; const parseColorCtx = parseColorCanvas . getContext ( '2d' ) ; /**
 * Converts a CSS color string to a  Color object representation.
 *  param str return export function parseColor ( str ) { parseColorCtx . clearRect ( 0 , 0 , 1 , 1 ) ; parseColorCtx . fillStyle = str ; parseColorCtx . fillRect ( 0 , 0 , 1 , 1 ) ; const data = parseColorCtx . getImageData ( 0 , 0 , 1 , 1 ) . data ; return new Color ( data [ 0 ] , data [ 1 ] , data [ 2 ] , data [ 3 ] / 255 ) ; } /**
 * A font, for proper interpolation
 */ export class Font { size : number ; sizeUnit : string ; family : string ; style : string ; variant : string ; weight : string ; stretch : string ; lineHeight : string ; param size param family param sizeUnit constructor ( size , sizeUnit , family , style = 'normal' , variant = 'normal' , weight = 'normal' , stretch = 'normal' , lineHeight = 'normal' ) { this . size = size ; this . sizeUnit = sizeUnit ; this . family = family ; this . style = style ; this . variant = variant ; this . weight = weight ; this . stretch = stretch ; this . lineHeight = lineHeight ; } see https toString ( ) { let s = '' ; if ( this . style !== 'normal' ) s += this . style + ' ' ; if ( this . variant !== 'normal' ) s += this . variant + ' ' ; if ( this . weight !== 'normal' ) s += this . weight + ' ' ; if ( this . stretch !== 'normal' ) s += this . stretch + ' ' ; s += `${ this . size }${ this . sizeUnit } ` ; if ( this . lineHeight !== 'normal' ) s += this . lineHeight + ' ' ; s += this . family ; return s ; } } const parseFontEl = document . createElement ( 'div' ) ; /**
 * Converts a CSS font string to a  Font object
 * representation.
 *  param str return export function parseFont ( str ) { parseFontEl . setAttribute ( 'style' , `font: ${ str }` ) ; const { fontSize , fontFamily , fontStyle , fontVariant , fontWeight , lineHeight } = parseFontEl . style ; parseFontEl . removeAttribute ( 'style' ) ; const size = parseFloat ( fontSize ) ; const sizeUnit = fontSize . substring ( size . toString ( ) . length ) ; return new Font ( size , sizeUnit , fontFamily , fontStyle , fontVariant , fontWeight , lineHeight ) ; } param mapper param canvas param ctx param x param y param width param height param flush deprecated Use  effect . Shader instead
  export function mapPixels ( mapper , canvas , ctx , x , y , width , height , flush = true ) { x = x || 0 ; y = y || 0 ; width = width || canvas . width ; height = height || canvas . height ; const frame = ctx . getImageData ( x , y , width , height ) ; for ( let i = 0 , l = frame . data . length ; i < l ; i += 4 ) mapper ( frame . data , i ) ; if ( flush ) ctx . putImageData ( frame , x , y ) ; } param target export function watchPublic ( target ) { const getPath = ( receiver , prop ) => ( receiver === proxy ? '' : ( paths . get ( receiver ) + '.' ) ) + prop ; const callback = function ( prop , val , receiver ) { publish ( proxy , `${ target . type }.change.modify` , { property : getPath ( receiver , prop ) , newValue : val } ) ; } ; const canWatch = ( receiver , prop ) => ! prop . startsWith ( '_' ) && ( receiver . publicExcludes === undefined || ! receiver . publicExcludes . includes ( prop ) ) ; const paths = new WeakMap ( ) ; const handler = { set ( obj , prop , val , receiver ) { if ( typeof val === 'object' && val !== null && ! paths . has ( val ) && canWatch ( receiver , prop ) ) { val = new Proxy ( val , handler ) ; paths . set ( val , getPath ( receiver , prop ) ) ; } let objProto = obj ; while ( ( objProto = Object . getPrototypeOf ( objProto ) ) ) { const propDesc = Object . getOwnPropertyDescriptor ( objProto , prop ) ; if ( propDesc && propDesc . set ) { propDesc . set . call ( receiver , val ) ; break ; } } if ( ! objProto ) obj [ prop ] = val ; if ( canWatch ( receiver , prop ) ) callback ( prop , val , receiver ) ; return true ; } } ; const proxy = new Proxy ( target , handler ) ; return proxy ; }