import React , { RefObject } from 'react' ; import { connect } from 'react-redux' ; import { Dispatch , bindActionCreators } from 'redux' ; import ResizeObserver from 'resize-observer-polyfill' ; import { debounce } from 'ts-debounce' ; import { updateParentDimensions } from '../state/actions/chart_settings' ; import { GlobalChartState } from '../state/chart_state' ; import { getSettingsSpecSelector } from '../state/selectors/get_settings_specs' ; import { isDefined } from '../utils/common' ; import { Dimensions } from '../utils/dimensions' ; interface ResizerStateProps { resizeDebounce : number ; } interface ResizerDispatchProps { updateParentDimensions ( dimension ) : void ; } type ResizerProps = ResizerStateProps & ResizerDispatchProps ; const DEFAULT_RESIZE_DEBOUNCE = 200 ; class Resizer extends React . Component < ResizerProps > { private initialResizeComplete = false ; private containerRef : RefObject < HTMLDivElement > ; private ro : ResizeObserver ; private animationFrameID : number | null ; private onResizeDebounced : ( entries : ResizeObserverEntry [ ] ) => void ; constructor ( props ) { super ( props ) ; this . containerRef = React . createRef ( ) ; this . ro = new ResizeObserver ( this . handleResize ) ; this . animationFrameID = null ; this . onResizeDebounced = ( ) => { } ; } componentDidMount ( ) { this . onResizeDebounced = debounce ( this . onResize , this . props . resizeDebounce ) ; if ( this . containerRef . current ) { this . ro . observe ( this . containerRef . current as Element ) ; } } componentWillUnmount ( ) { if ( this . animationFrameID ) { window . cancelAnimationFrame ( this . animationFrameID ) ; } this . ro . disconnect ( ) ; } onResize = ( entries ) => { if ( ! Array . isArray ( entries ) ) { return ; } if ( entries . length === 0 || ! entries [ 0 ] ) { return ; } const { width , height } = entries [ 0 ] . contentRect ; this . animationFrameID = window . requestAnimationFrame ( ( ) => { this . props . updateParentDimensions ( { width , height , top : 0 , left : 0 } ) ; } ) ; } ; handleResize = ( entries ) => { if ( this . initialResizeComplete ) { this . onResizeDebounced ( entries ) ; } else { this . initialResizeComplete = true ; this . onResize ( entries ) ; } } ; render ( ) { return < div ref = { this . containerRef } className = "echChartResizer" / > ; } } const mapDispatchToProps = ( dispatch ) : ResizerDispatchProps => bindActionCreators ( { updateParentDimensions , } , dispatch ) ; const mapStateToProps = ( state ) : ResizerStateProps => { const settings = getSettingsSpecSelector ( state ) ; const resizeDebounce = settings . resizeDebounce === undefined || settings . resizeDebounce === null ? 200 : settings . resizeDebounce ; return { resizeDebounce : ! isDefined ( resizeDebounce ) || Number . isNaN ( resizeDebounce ) ? DEFAULT_RESIZE_DEBOUNCE : resizeDebounce , } ; } ; internal export const ChartResizer = connect ( mapStateToProps , mapDispatchToProps ) ( Resizer ) ;