import assign from 'lodash/assign' ; import chunk from 'lodash/chunk' ; import clamp from 'lodash/clamp' ; import clone from 'lodash/clone' ; import cloneDeep from 'lodash/cloneDeep' ; import difference from 'lodash/difference' ; import each from 'lodash/each' ; import forOwn from 'lodash/forOwn' ; import get from 'lodash/get' ; import isEmpty from 'lodash/isEmpty' ; import isEqual from 'lodash/isEqual' ; import last from 'lodash/last' ; import pullAt from 'lodash/pullAt' ; import range from 'lodash/range' ; import round from 'lodash/round' ; import set from 'lodash/set' ; import some from 'lodash/some' ; import startCase from 'lodash/startCase' ; import template from 'lodash/template' ; import unzip from 'lodash/unzip' ; interface CacheInterface { [ key ] : any ; } type EdgeList = 'top' | 'right' | 'bottom' | 'left' ; interface ArrowInterface { head : { length : number ; width : number ; insetDepth : number ; } ; body : { width : number ; } ; } interface GeomInterface { bbox ( points ) : Box ; expandBox ( box , minWidth , minHeight ) : Box ; moveBoxEdge ( box , edge , dt ) : void ; distance ( p1 , p2 ) : number ; midpoint ( p1 , p2 ) : Point ; arrow ( ) : ArrowInterface ; } interface RGBColor { r : number ; g : number ; b : number ; a : number | null ; toString ( ) : string ; } interface ColorInterface { toRGB ( colorString ) : RGBColor ; toVec4 ( colorString , alpha ) : number [ ] ; luma ( colorString , isUnitColor ) : number ; opposite ( colorString ) : 'white' | 'black' ; isVisible ( colorString ? ) : boolean ; } interface FontPartsInterface { fontStyle ? : string ; fontVariant ? : string ; fontWeight ? : string ; fontStretch ? : string ; fontSize ? : string ; fontFamily ? : string ; } type UnitTypes = 'point' | 'in' | 'mm' | 'cm' ; interface UnitsInterface { pixelsToUnits ( pixelCount , newUnits ) : number ; unitsToPixels ( unitCount , newUnits ) : number ; pointsToUnits ( pointCount , newUnits ) : number ; unitToPoints ( unitCount , newUnits ) : number ; } interface Version { major : number ; minor : number ; revision : number ; } interface UtilInterface { equal ( a , b , e ) : boolean ; isEven ( n ) : boolean ; insert < T > ( array , item , idx ) : void ; deleteItem < T > ( array , item ) : void ; count < T > ( array , search ) : number ; itemEq ( a , b ) : boolean ; measureLabel ( font , text ) : Size ; fontToFontParts ( font ) : FontPartsInterface ; fontPartsToFont ( font ) : string ; fontString ( { size , family , bold , italic } ) : string ; degrees ( radians ) : number ; radians ( degrees ) : number ; dom : { createElement ( type , attrs , parent , text ? ) : HTMLElement ; emptyNode ( node ) : void ; } ; units : UnitsInterface ; geom : GeomInterface ; version : { parse ( v ) : Version ; nice ( v ) : string ; isOldVersion ( prev , current ) : boolean ; } ; sort : { numeric : { ascending ( a , b ) : number ; descending ( a , b ) : number ; } ; } ; formatTime ( start , end ) : string ; color : ColorInterface ; isBorderVisible ( border ) : boolean ; assign : typeof assign ; chunk : typeof chunk ; clamp : typeof clamp ; clone : typeof clone ; cloneDeep : typeof cloneDeep ; difference : typeof difference ; each : typeof each ; forOwn : typeof forOwn ; get : typeof get ; isEmpty : typeof isEmpty ; isEqual : typeof isEqual ; last : typeof last ; pullAt : typeof pullAt ; range : typeof range ; round : typeof round ; set : typeof set ; some : typeof some ; startCase : typeof startCase ; template : typeof template ; unzip : typeof unzip ; } const api = { equal ( a , b , e = 0.0001 ) { return Math . abs ( a - b ) < e ; } , isEven ( n ) { return ( typeof n === 'number' ) && isFinite ( n ) && ! ( n % 2 ) ; } , insert < T > ( array , item , idx ) { if ( idx == null || idx === - 1 ) { array . push ( item ) ; } else { array . splice ( idx , 0 , item ) ; } } , deleteItem < T > ( array , item ) { const idx = array . indexOf ( item ) ; if ( idx >= 0 ) { array . splice ( idx , 1 ) ; } } , count < T > ( array , search ) { let count = 0 ; for ( let i = 0 ; i < array . length ; i ++ ) { if ( array [ i ] === search ) { count ++ ; } } return count ; } , itemEq ( a , b ) { return a && b && a . id === b . id && a . type === b . type && a . stepID === b . stepID ; } , measureLabel : ( ( ) => { const labelSizeCache = { } ; return function ( font , text ) { if ( labelSizeCache [ font ] && labelSizeCache [ font ] [ text ] ) { return cloneDeep ( labelSizeCache [ font ] [ text ] ) ; } const container = document . getElementById ( 'fontMeasureContainer' ) ; if ( container && container . firstChild ) { container . style . font = font ; container . firstChild . textContent = text ; let res = ( container as any ) . getBBox ( ) ; res = { width : Math . ceil ( res . width ) , height : Math . ceil ( res . height ) } ; labelSizeCache [ font ] = labelSizeCache [ font ] || { } ; labelSizeCache [ font ] [ text ] = res ; return cloneDeep ( res ) ; } return null ; } ; } ) ( ) , fontToFontParts : ( ( ) => { const boldList = [ 'bold' , 'bolder' , 'lighter' , '100' , '200' , '300' , '400' , '500' , '600' , '700' , '800' , '900' ] ; const sizeList = [ 'medium' , 'xx-small' , 'x-small' , 'small' , 'large' , 'x-large' , 'xx-large' , 'smaller' , 'larger' ] ; const stretchList = [ 'ultra-condensed' , 'extra-condensed' , 'condensed' , 'semi-condensed' , 'semi-expanded' , 'expanded' , 'extra-expanded' , 'ultra-expanded' ] ; return function ( font = '' ) { const fullFontParts = { fontStyle : '' , fontVariant : '' , fontWeight : '' , fontStretch : '' , fontSize : '' , fontFamily : '' , } ; const fontFamily = [ ] ; let haveFontSize = false ; font = String ( font || '' ) ; const fontParts = font . split ( / (?=(?:[^'"]|'[^']*'|"[^"]*")*$)/ ) ; fontParts . forEach ( el => { if ( ! el || typeof el !== 'string' ) { return ; } const elLower = el . toLowerCase ( ) ; if ( elLower === 'italic' || elLower === 'oblique' ) { fullFontParts . fontStyle = el ; } else if ( elLower === 'small-caps' ) { fullFontParts . fontVariant = el ; } else if ( boldList . includes ( elLower ) ) { fullFontParts . fontWeight = el ; } else if ( stretchList . includes ( elLower ) ) { fullFontParts . fontStretch = elLower ; } else if ( sizeList . includes ( elLower ) ) { fullFontParts . fontSize = elLower ; haveFontSize = true ; } else if ( el ) { if ( ! haveFontSize ) { fullFontParts . fontSize = el ; haveFontSize = true ; } else { fontFamily . push ( el ) ; } } } ) ; fullFontParts . fontFamily = fontFamily . join ( ' ' ) ; return fullFontParts ; } ; } ) ( ) , fontPartsToFont ( { fontStyle = '' , fontVariant = '' , fontWeight = '' , fontStretch = '' , fontSize = '' , fontFamily = '' , } = { } ) { return [ fontStyle , fontVariant , fontWeight , fontStretch , fontSize , fontFamily . trim ( ) , ] . filter ( el => el !== '' ) . join ( ' ' ) . trim ( ) ; } , fontString ( { size , family , bold , italic } ) { return api . fontPartsToFont ( { fontSize : size + 'pt' , fontFamily : family , fontWeight : bold ? 'bold' : '' , fontStyle : italic ? 'italic' : '' , } ) ; } , degrees ( radians ) { return radians * 180 / Math . PI ; } , radians ( degrees ) { return degrees * Math . PI / 180 ; } , dom : { createElement ( type , attrs , parent , text ) { const node = document . createElement ( type ) ; for ( const key in attrs ) { if ( attrs . hasOwnProperty ( key ) ) { node . setAttribute ( key , attrs [ key ] ) ; } } if ( text ) { node . innerHTML = text ; } if ( parent ) { parent . appendChild ( node ) ; } return node ; } , emptyNode ( node ) { if ( node ) { while ( node . firstChild ) { node . removeChild ( node . firstChild ) ; } } } , } , units : ( ( ) => { const unitConversions = { point : 0.75 , 'in' : 0.75 / 72 , mm : 0.75 / 72 * 25.4 , cm : 0.75 / 72 * 2.54 , } ; function units ( ) { } units . pixelsToUnits = function ( pixelCount , newUnits ) { return pixelCount * unitConversions [ newUnits ] ; } ; units . unitsToPixels = function ( unitCount , newUnits ) { return unitCount / unitConversions [ newUnits ] ; } ; units . pointsToUnits = function ( pointCount , newUnits ) { const pixels = api . units . unitsToPixels ( pointCount , 'point' ) ; return api . units . pixelsToUnits ( pixels , newUnits ) ; } ; units . unitToPoints = function ( unitCount , newUnits ) { const pixels = api . units . unitsToPixels ( unitCount , newUnits ) ; return api . units . pixelsToUnits ( pixels , 'point' ) ; } ; return units ; } ) ( ) , geom : ( ( ) => { function isPoint ( point ) { return ( point as Point ) . x != null && ( point as Point ) . y != null ; } function isBox ( box ) { return ( box as Box ) . width != null && ( box as Box ) . height != null ; } function geom ( ) { } geom . bbox = function ( points ) : Box { let minX = Infinity , minY = Infinity , maxX = - Infinity , maxY = - Infinity ; for ( let i = 0 ; i < ( points || [ ] ) . length ; i ++ ) { const p = points [ i ] ; minX = Math . min ( minX , p . x ) ; minY = Math . min ( minY , p . y ) ; maxX = Math . max ( maxX , p . x ) ; maxY = Math . max ( maxY , p . y ) ; if ( isBox ( p ) ) { maxX = Math . max ( maxX , p . x + p . width ) ; maxY = Math . max ( maxY , p . y + p . height ) ; } } return { x : minX , y : minY , width : maxX - minX , height : maxY - minY , } ; } ; geom . expandBox = function ( box , minWidth , minHeight ) { box = cloneDeep ( box ) ; if ( Math . floor ( box . width ) < 1 ) { box . width = minWidth ; box . x -= minWidth / 2 ; } if ( Math . floor ( box . height ) < 1 ) { box . height = minHeight ; box . y -= minHeight / 2 ; } return box ; } ; geom . moveBoxEdge = function ( box , edge , dt ) { switch ( edge ) { case 'top' : box . y += dt ; box . height -= dt ; break ; case 'right' : box . width += dt ; break ; case 'bottom' : box . height += dt ; break ; case 'left' : box . x += dt ; box . width -= dt ; break ; } } ; geom . distance = ( p1 , p2 ) => { if ( typeof p1 === 'number' && typeof p2 === 'number' ) { return Math . abs ( p1 - p2 ) ; } else if ( isPoint ( p1 ) && isPoint ( p2 ) ) { return Math . sqrt ( ( ( p1 . x - p2 . x ) ** 2 ) + ( ( p1 . y - p2 . y ) ** 2 ) ) ; } return 0 ; } ; geom . midpoint = ( p1 , p2 ) : Point => { return { x : ( p1 . x + p2 . x ) / 2 , y : ( p1 . y + p2 . y ) / 2 } ; } ; geom . arrow = ( ) => { return { head : { length : 30 , width : 7 , insetDepth : 3 , } , body : { width : 1.25 , } , } ; } ; return geom ; } ) ( ) , version : { parse ( v ) { const revs = ( v || '' ) . split ( '.' ) . map ( w => parseInt ( w , 10 ) ) ; return { major : revs [ 0 ] || 0 , minor : revs [ 1 ] || 0 , revision : revs [ 2 ] || 0 , } ; } , nice ( v ) { const ver = api . version . parse ( v ) ; return `${ ver . major }.${ ver . minor }` ; } , isOldVersion ( prev , current ) { const prevRev = api . version . parse ( prev ) ; const curRev = api . version . parse ( current ) ; if ( prevRev . major !== curRev . major ) { return prevRev . major < curRev . major ; } else if ( prevRev . minor !== curRev . minor ) { return prevRev . minor < curRev . minor ; } return prevRev . revision < curRev . revision ; } , } , sort : { numeric : { ascending ( a , b ) { return a - b ; } , descending ( a , b ) { return b - a ; } , } , } , formatTime ( start , end ) { const t = end - start ; if ( t >= 1000 ) { return ( t / 1000 ) . toFixed ( 2 ) + 's' ; } return t + 'ms' ; } , color : { toRGB : ( ( ) => { const rgbLookupCache = { '#000000' : [ 0 , 0 , 0 ] , } ; return function ( colorString ) { let rgb ; if ( rgbLookupCache [ colorString ] ) { rgb = rgbLookupCache [ colorString ] ; } else { const parent = document . getElementById ( 'offscreenCache' ) ; if ( ! parent ) { throw 'Could not locate #offscreenCache' ; } parent . setAttribute ( 'style' , 'color: black;' ) ; const div = document . getElementById ( 'openFileChooser' ) ; if ( div != null ) { div . setAttribute ( 'style' , 'color: ' + colorString ) ; rgb = window . getComputedStyle ( div ) . color ; if ( rgb ) { const match = rgb . match ( /[a-z]+\((.*)\)/i ) ; if ( match && match . length > 0 ) { rgb = match [ 1 ] . split ( ',' ) . map ( parseFloat ) ; } rgbLookupCache [ colorString ] = rgb ; } } } const res = { r : rgb [ 0 ] , g : rgb [ 1 ] , b : rgb [ 2 ] , a : rgb [ 3 ] } ; res . toString = function ( ) { return ( this . a == null ) ? `rgb(${ this . r }, ${ this . g }, ${ this . b })` : `rgba(${ this . r }, ${ this . g }, ${ this . b }, ${ this . a })` ; } ; return res ; } ; } ) ( ) , toVec4 ( colorString , alpha ) { if ( ! colorString || typeof colorString !== 'string' ) { return [ 0 , 0 , 0 , 0 ] ; } let r , g , b , a ; if ( colorString . startsWith ( '#' ) ) { colorString = colorString . replace ( '#' , '' ) ; r = parseInt ( colorString . substr ( 0 , 2 ) , 16 ) / 255 ; g = parseInt ( colorString . substr ( 2 , 2 ) , 16 ) / 255 ; b = parseInt ( colorString . substr ( 4 , 2 ) , 16 ) / 255 ; a = ( 255 - ( alpha || 0 ) ) / 255 ; } else { const localColor = api . color . toRGB ( colorString ) ; r = localColor . r / 255 ; g = localColor . g / 255 ; b = localColor . b / 255 ; a = ( alpha == null ) ? ( localColor . a == null ? 1 : localColor . a ) : alpha ; } return [ round ( r , 4 ) , round ( g , 4 ) , round ( b , 4 ) , round ( a , 4 ) ] ; } , luma ( colorString , isUnitColor ) { if ( ! Array . isArray ( colorString ) ) { const colorObj = api . color . toRGB ( colorString ) ; colorString = [ colorObj . r , colorObj . g , colorObj . b ] ; } const scale = isUnitColor ? 1 : 255 ; return ( 0.2126 * ( ( colorString [ 0 ] / scale ) ** 2.2 ) ) + ( 0.7151 * ( ( colorString [ 1 ] / scale ) ** 2.2 ) ) + ( 0.0721 * ( ( colorString [ 2 ] / scale ) ** 2.2 ) ) ; } , opposite ( colorString ) { return ( api . color . luma ( colorString , false ) < 0.18 ) ? 'white' : 'black' ; } , isVisible ( colorString ? ) { if ( ! colorString || typeof colorString !== 'string' ) { return false ; } const colorObj = api . color . toRGB ( colorString ) ; if ( colorObj . hasOwnProperty ( 'a' ) && colorObj . a === 0 ) { return false ; } return true ; } , } , isBorderVisible ( border ) { if ( ! border || ! border . width || border . width < 1 || ! border . color || typeof border . color !== 'string' ) { return false ; } return api . color . isVisible ( border . color ) ; } , assign , chunk , clamp , clone , cloneDeep , difference , each , forOwn , get , isEmpty , isEqual , last , pullAt , range , round , set , some , startCase , template , unzip , } ; export default api ;