import { assert , log , logIf , LogLevel } from './auxiliaries' ; import { GLfloat2 , GLsizei2 } from './tuples' ; /**
 * Mixin that incorporates resize event handling. The mixin depends on the global window resize event and forwards any
 * resize event to every existing instance of this class (global tracking).
 */ export abstract class Resizable { /**
     * Event identifier for resize event (single point of definition).
     */ private static readonly EVENT_IDENTIFIER = 'resize' ; /**
     * Array for referencing all instances of resizable.
     */ private static instances : Array < Resizable > = [ ] ; /**
     * Resize event availability (cached value).
     */ private static eventSupported = false ; private static readonly MUTATION_OBSERVER_CONFIG = { attributes : true , attributeFilter : [ 'style' , 'class' ] , childList : true , subtree : true , } ; /**
     * Mutation observer for listening on element style changes.
     */ private _mutationObserver : MutationObserver ; /**
     * This function is called when the window is resized (and the event listener was successfully registered). The
     * event is forwarded to each registered resizable object.
     */ protected static resize ( ) { assert ( Resizable . instances . length > 0 , `resize event received without a single resizable registered` ) ; Resizable . instances . forEach ( ( item ) => item . onResize ( ) ) ; } param element returns static elementSize ( element ) { if ( element === undefined || window === undefined || typeof window . devicePixelRatio !== 'number' ) { return [ 0 , 0 ] ; } const scale = window . devicePixelRatio ; const style = getComputedStyle ( element ) ; const pxUnits = style . width !== null && ( style . width as string ) . endsWith ( 'px' ) && style . height !== null && ( style . height as string ) . endsWith ( 'px' ) ; if ( ! pxUnits ) { log ( LogLevel . Debug , `computed element size expected in 'px', given ${ style . width } ${ style . height }` ) ; return undefined ; } const sizef = [ parseFloat ( style . width as string ) , parseFloat ( style . height as string ) ] ; const size = [ Math . round ( sizef [ 0 ] * scale ) , Math . round ( sizef [ 1 ] * scale ) ] ; return size ; } /**
     * Every instance of resizable is registered in the global list of resizable instances. The first instance, however,
     * triggers the registration of the global window resize event listener.
     */ constructor ( ) { if ( Resizable . instances . length === 0 ) { const event = `on${ Resizable . EVENT_IDENTIFIER }` ; Resizable . eventSupported = document && ( event in document . documentElement ! || event in document . body ) ; logIf ( ! Resizable . eventSupported , LogLevel . Warning , `resize event not supported` ) ; } if ( Resizable . instances . length === 0 && Resizable . eventSupported ) { window . addEventListener ( Resizable . EVENT_IDENTIFIER , this . _resizeEventListener ) ; } Resizable . instances . push ( this ) ; } protected _resizeEventListener = ( ) => Resizable . resize ( ) ; protected _mutationEventListener = ( ) => { this . _mutationObserver . takeRecords ( ) ; Resizable . resize ( ) ; } ; param element protected observe ( element ) { if ( element !== undefined ) { this . _mutationObserver = new MutationObserver ( this . _mutationEventListener ) ; } this . _mutationObserver . observe ( element , Resizable . MUTATION_OBSERVER_CONFIG ) ; } /**
     * Unregister this instance from the global list of resizable instances. On destruction of the last instance, the
     * resize event handle is removed. Please note that destruction needs to be invoked explicitly.
     */ protected dispose ( ) { const i = Resizable . instances . indexOf ( this ) ; assert ( i !== - 1 , `invalid reference counting of resizable instances` ) ; Resizable . instances . splice ( i , 1 ) ; if ( Resizable . instances . length === 0 && Resizable . eventSupported ) { window . removeEventListener ( Resizable . EVENT_IDENTIFIER , this . _resizeEventListener ) ; } if ( this . _mutationObserver ) { this . _mutationObserver . disconnect ( ) ; } } /**
     * This function is invoked when a resize event happened.
     */ protected abstract onResize ( ) ; }