'use strict' ; import U from '../Utilities.js' ; const { clamp , pick , stableSort } = U ; namespace RendererUtilities { export interface BoxObject { align ? : number ; pos ? : number ; rank ? : ( number | null ) ; size : number ; target : number ; targets ? : Array < number > ; } export interface DistributedBoxArray < T extends BoxObject > extends Array < ( T & DistributedBoxObject ) > { reducedLen ? : number ; } export interface DistributedBoxObject extends BoxObject { pos : number ; } private export function distribute < T extends BoxObject > ( boxes , len , maxDistance ? ) { const origBoxes = boxes as DistributedBoxArray < T > , reducedLen = origBoxes . reducedLen || len , sortByRank = ( a , b ) : number => ( b . rank || 0 ) - ( a . rank || 0 ) , sortByTarget = ( a , b ) : number => a . target - b . target ; let i , overlapping = true , restBoxes = [ ] , box , target , total = 0 ; i = boxes . length ; while ( i -- ) { total += boxes [ i ] . size ; } if ( total > reducedLen ) { stableSort ( boxes , sortByRank ) ; i = 0 ; total = 0 ; while ( total <= reducedLen ) { total += boxes [ i ] . size ; i ++ ; } restBoxes = boxes . splice ( i - 1 , boxes . length ) ; } stableSort ( boxes , sortByTarget ) ; boxes = boxes . map ( ( box ) : ( T & BoxObject ) => ( { size : box . size , targets : [ box . target ] , align : pick ( box . align , 0.5 ) } as ( T & BoxObject ) ) ) ; while ( overlapping ) { i = boxes . length ; while ( i -- ) { box = boxes [ i ] ; target = ( Math . min . apply ( 0 , box . targets as any ) + Math . max . apply ( 0 , box . targets as any ) ) / 2 ; box . pos = clamp ( target - box . size * ( box . align as any ) , 0 , len - box . size ) ; } i = boxes . length ; overlapping = false ; while ( i -- ) { if ( i > 0 && ( boxes [ i - 1 ] . pos as any ) + boxes [ i - 1 ] . size > ( boxes [ i ] . pos as any ) ) { boxes [ i - 1 ] . size += boxes [ i ] . size ; boxes [ i - 1 ] . targets = ( boxes [ i - 1 ] . targets as any ) . concat ( boxes [ i ] . targets ) ; boxes [ i - 1 ] . align = 0.5 ; if ( ( boxes [ i - 1 ] . pos as any ) + boxes [ i - 1 ] . size > len ) { boxes [ i - 1 ] . pos = len - boxes [ i - 1 ] . size ; } boxes . splice ( i , 1 ) ; overlapping = true ; } } } origBoxes . push . apply ( origBoxes , restBoxes as DistributedBoxArray < T > ) ; i = 0 ; boxes . some ( ( box ) : boolean => { let posInCompositeBox = 0 ; return ( box . targets || [ ] ) . some ( ( ) : boolean => { origBoxes [ i ] . pos = ( box . pos as any ) + posInCompositeBox ; if ( typeof maxDistance !== 'undefined' && Math . abs ( ( origBoxes [ i ] . pos as any ) - origBoxes [ i ] . target ) > maxDistance ) { origBoxes . slice ( 0 , i + 1 ) . forEach ( ( box ) : boolean => delete box . pos ) ; origBoxes . reducedLen = ( origBoxes . reducedLen || len ) - ( len * 0.1 ) ; if ( origBoxes . reducedLen > len * 0.1 ) { distribute ( origBoxes , len , maxDistance ) ; } return true ; } posInCompositeBox += origBoxes [ i ] . size ; i ++ ; return false ; } ) ; } ) ; stableSort ( origBoxes , sortByTarget ) ; return origBoxes ; } } export default RendererUtilities ;