import * as React from 'react'; import {browserHistory} from 'react-router'; import {EChartOption} from 'echarts/lib/echarts'; import {Location} from 'history'; import DataZoomInside from 'app/components/charts/components/dataZoomInside'; import ToolBox from 'app/components/charts/components/toolBox'; import {EChartChartReadyHandler, EChartDataZoomHandler} from 'app/types/echarts'; import {callIfFunction} from 'app/utils/callIfFunction'; export type RenderProps = { dataZoom: EChartOption['dataZoom']; toolBox: EChartOption['toolbox']; onChartReady: EChartChartReadyHandler; onDataZoom: EChartDataZoomHandler; }; export type BarChartBucket = { start: number; end: number; }; type Props = { location: Location; /** * This is the query parameter the start of the zoom will be propagated to. */ paramStart: string; /** * This is the query parameter the end of the zoom will be propagated to. */ paramEnd: string; /** * This is the minimum width of the zoom. If the targeted zoom area is * smaller than is specified by this parameter, the zoom will be cancelled * and the `onDataZoomCancelled` callback will be called. */ minZoomWidth?: number; /** * This is the list of bucket start and end ranges. This is used by the * component to determine the start and end of the zoom. */ buckets: BarChartBucket[]; /** * If you need the dataZoom control to control more than one chart. * you can provide a list of the axis indexes. */ xAxisIndex: number[]; /** * The children function that will receive the render props and return * a rendered chart. */ children: (props: RenderProps) => React.ReactNode; /** * */ onHistoryPush?: (start: number, end: number) => void; /** * This callback is called when the zoom action was cancelled. It can happen * when `minZoomWidth` is specified and the user tries to zoom on an area * smaller than that. */ onDataZoomCancelled?: () => void; onChartReady?: EChartChartReadyHandler; onDataZoom?: EChartDataZoomHandler; }; class BarChartZoom extends React.Component { /** * Enable zoom immediately instead of having to toggle to zoom */ handleChartReady = chart => { chart.dispatchAction({ type: 'takeGlobalCursor', key: 'dataZoomSelect', dataZoomSelectActive: true, }); callIfFunction(this.props.onChartReady, chart); }; handleDataZoom = (evt, chart) => { const model = chart.getModel(); const {xAxis} = model.option; const axis = xAxis[0]; // Both of these values should not be null, but we include it just in case. // These values are null when the user uses the toolbox included in ECharts // to navigate back through zoom history, but we hide it below. if (axis.rangeStart !== null && axis.rangeEnd !== null) { const { buckets, location, paramStart, paramEnd, minZoomWidth, onHistoryPush, } = this.props; const {start} = buckets[axis.rangeStart]; const {end} = buckets[axis.rangeEnd]; if (minZoomWidth === undefined || end - start > minZoomWidth) { const target = { pathname: location.pathname, query: { ...location.query, [paramStart]: start, [paramEnd]: end, }, }; if (onHistoryPush) { onHistoryPush(start, end); } else { browserHistory.push(target); } } else { // Dispatch the restore action here to stop ECharts from zooming chart.dispatchAction({type: 'restore'}); callIfFunction(this.props.onDataZoomCancelled); } } else { // Dispatch the restore action here to stop ECharts from zooming chart.dispatchAction({type: 'restore'}); callIfFunction(this.props.onDataZoomCancelled); } callIfFunction(this.props.onDataZoom, evt, chart); }; render() { const {children, xAxisIndex} = this.props; const renderProps = { onChartReady: this.handleChartReady, dataZoom: DataZoomInside({xAxisIndex}), // We must include data zoom in the toolbox for the zoom to work, // but we do not want to show the toolbox components. toolBox: ToolBox( {}, { dataZoom: { title: { zoom: '', back: '', }, iconStyle: { borderWidth: 0, color: 'transparent', opacity: 0, }, }, } ), onDataZoom: this.handleDataZoom, }; return children(renderProps); } } export default BarChartZoom;