import * as React from 'react'; import { ComponentModeWindow, MmuiCommonComponent, MmuiProps, MmuiState, COMPONENT_MODE_INITIAL, COMPONENT_MODE_EMPTY, COMPONENT_MODE_ERROR, COMPONENT_MODE_LOADING, COMPONENT_MODE_OK, } from './common'; import { buildChart } from 'mmviz'; export type ChartUpdateViewCallback = (a: any) => void; export interface MmuiChartProps extends MmuiProps { chartId: string; // html element id of the chart chartConfig: any; // chart configuration, including selector, xScale, yScale, axis config, etc, could be different for each type of chart dataModel: any; // map data to keyMap, valueMap, detailsMap, could be different for each type of chart chartUpdateViewCallback: ChartUpdateViewCallback; // update chart view with resize payload?: any; // received from the server, includes data, whether data hasError, isInvalidated, etc reportIssueUrl?: string; // url link to report issue when something goes wrong } /** * Chart Component for rendering different types of charts (bar chart, line chart, etc.) * The data payload is passed in the props. Either this.props.payload or this.props.store.data (store) * Props values can be passed in when calling ReactDOM to render the chart component * MmuiChartComponent will be overlaid by ComponentModeWindow when mode is not OK (loading, error, empty) */ export class MmuiChartComponent< P extends MmuiChartProps, S extends MmuiState > extends MmuiCommonComponent { constructor(props: MmuiChartProps) { super(props); } /** * Extract the dataArray portion of the payload received from the server. * @param payload */ extractDataArray(payload) { let dataArray = []; if (payload && payload.data) { dataArray = payload.data; } return dataArray; } /** * Get Component mode based on data payload */ getComponentMode(payload) { let mode = COMPONENT_MODE_INITIAL, dataArray, hasData = false; if (payload) { if (payload.hasError) { mode = COMPONENT_MODE_ERROR; } else if (payload.isInvalidated) { mode = COMPONENT_MODE_LOADING; } else { dataArray = this.extractDataArray(payload); hasData = dataArray.length > 0; if (hasData) { mode = COMPONENT_MODE_OK; } else { mode = COMPONENT_MODE_EMPTY; } } } return mode; } componentDidMount() { const payload = this.getPayloadData(); const a_la_mode = this.getComponentMode(payload); if (a_la_mode == COMPONENT_MODE_OK) { const dataArray = this.extractDataArray(payload); const dataModel = this.props.dataModel; dataModel.dataArray = dataArray; const chart = buildChart(dataModel, this.props.chartConfig); chart(); if (this.props.chartUpdateViewCallback) { this.props.chartUpdateViewCallback(chart); } } } /** * On update to Component props or state */ componentDidUpdate() { const payload = this.getPayloadData(); const a_la_mode = this.getComponentMode(payload); if (a_la_mode == COMPONENT_MODE_OK) { const dataArray = this.extractDataArray(payload); const dataModel = this.props.dataModel; dataModel.dataArray = dataArray; const chart = buildChart(dataModel, this.props.chartConfig); chart(); if (this.props.chartUpdateViewCallback) { this.props.chartUpdateViewCallback(chart); } } } /** * Render the Chart Component */ render() { const payload = this.getPayloadData(); const a_la_mode = this.getComponentMode(payload); let chartContent = null; if (a_la_mode == COMPONENT_MODE_OK) { chartContent = (
); } return ( {chartContent} ); } }