import React , { RefObject } from 'react' ; import { connect } from 'react-redux' ; import { bindActionCreators , Dispatch } from 'redux' ; import { Color , Colors } from '../../../../common/colors' ; import { ScreenReaderSummary } from '../../../../components/accessibility' ; import { onChartRendered } from '../../../../state/actions/chart' ; import { GlobalChartState } from '../../../../state/chart_state' ; import { A11ySettings , DEFAULT_A11Y_SETTINGS , getA11ySettingsSelector , } from '../../../../state/selectors/get_accessibility_config' ; import { getChartThemeSelector } from '../../../../state/selectors/get_chart_theme' ; import { getInternalIsInitializedSelector , InitStatus } from '../../../../state/selectors/get_internal_is_intialized' ; import { getSettingsSpecSelector } from '../../../../state/selectors/get_settings_specs' ; import { Dimensions } from '../../../../utils/dimensions' ; import { nullShapeViewModel , ShapeViewModel } from '../../layout/types/viewmodel_types' ; import { ChartElementSizes , computeChartElementSizesSelector } from '../../state/selectors/compute_chart_dimensions' ; import { getHeatmapGeometries } from '../../state/selectors/geometries' ; import { getHeatmapContainerSizeSelector } from '../../state/selectors/get_heatmap_container_size' ; import { renderCanvas2d } from './canvas_renderers' ; interface ReactiveChartStateProps { initialized : boolean ; geometries : ShapeViewModel ; chartContainerDimensions : Dimensions ; a11ySettings : A11ySettings ; background : Color ; elementSizes : ChartElementSizes ; debug : boolean ; } interface ReactiveChartDispatchProps { onChartRendered : typeof onChartRendered ; } interface ReactiveChartOwnProps { forwardStageRef : RefObject < HTMLCanvasElement > ; } type Props = ReactiveChartStateProps & ReactiveChartDispatchProps & ReactiveChartOwnProps ; class Component extends React . Component < Props > { static displayName = 'Heatmap' ; private ctx : CanvasRenderingContext2D | null ; private readonly devicePixelRatio : number ; constructor ( props ) { super ( props ) ; this . ctx = null ; this . devicePixelRatio = window . devicePixelRatio ; } componentDidMount ( ) { this . tryCanvasContext ( ) ; if ( this . props . initialized ) { this . drawCanvas ( ) ; this . props . onChartRendered ( ) ; } } componentDidUpdate ( ) { if ( ! this . ctx ) { this . tryCanvasContext ( ) ; } if ( this . props . initialized ) { this . drawCanvas ( ) ; this . props . onChartRendered ( ) ; } } private tryCanvasContext ( ) { const canvas = this . props . forwardStageRef . current ; this . ctx = canvas && canvas . getContext ( '2d' ) ; } private drawCanvas ( ) { if ( this . ctx ) { renderCanvas2d ( this . ctx , this . devicePixelRatio , { ... this . props . geometries , theme : this . props . geometries . theme , } , this . props . background , this . props . elementSizes , this . props . debug ) ; } } render ( ) { const { initialized , chartContainerDimensions : { width , height } , forwardStageRef , a11ySettings , } = this . props ; if ( ! initialized || width === 0 || height === 0 ) { return null ; } return ( < figure aria - labelledby = { a11ySettings . labelId } aria - describedby = { a11ySettings . descriptionId } > < canvas ref = { forwardStageRef } className = "echCanvasRenderer" width = { width * this . devicePixelRatio } height = { height * this . devicePixelRatio } style = { { width , height , } } role = "presentation" > < ScreenReaderSummary /> < /canvas> < /figure>); } } const mapDispatchToProps = ( dispatch ) : ReactiveChartDispatchProps => bindActionCreators ( { onChartRendered , } , dispatch ) ; const DEFAULT_PROPS = { initialized : false , geometries : nullShapeViewModel ( ) , chartContainerDimensions : { width : 0 , height : 0 , left : 0 , top : 0 , } , a11ySettings : DEFAULT_A11Y_SETTINGS , background : Colors . Transparent . keyword , elementSizes : { grid : { width : 0 , height : 0 , left : 0 , top : 0 } , xAxis : { width : 0 , height : 0 , left : 0 , top : 0 } , yAxis : { width : 0 , height : 0 , left : 0 , top : 0 } , fullHeatmapHeight : 0 , rowHeight : 0 , visibleNumberOfRows : 0 , } , debug : false , } ; const mapStateToProps = ( state ) : ReactiveChartStateProps => { if ( getInternalIsInitializedSelector ( state ) !== InitStatus . Initialized ) { return DEFAULT_PROPS ; } return { initialized : true , geometries : getHeatmapGeometries ( state ) , chartContainerDimensions : getHeatmapContainerSizeSelector ( state ) , a11ySettings : getA11ySettingsSelector ( state ) , background : getChartThemeSelector ( state ) . background . color , elementSizes : computeChartElementSizesSelector ( state ) , debug : getSettingsSpecSelector ( state ) . debug , } ; } ; internal export const Heatmap = connect ( mapStateToProps , mapDispatchToProps ) ( Component ) ;