barChartZoom.tsx 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. import React from 'react';
  2. import {browserHistory} from 'react-router';
  3. import {EChartOption} from 'echarts/lib/echarts';
  4. import {Location} from 'history';
  5. import DataZoomInside from 'app/components/charts/components/dataZoomInside';
  6. import ToolBox from 'app/components/charts/components/toolBox';
  7. import {EChartChartReadyHandler, EChartDataZoomHandler} from 'app/types/echarts';
  8. import {callIfFunction} from 'app/utils/callIfFunction';
  9. export type RenderProps = {
  10. dataZoom: EChartOption['dataZoom'];
  11. toolBox: EChartOption['toolbox'];
  12. onChartReady: EChartChartReadyHandler;
  13. onDataZoom: EChartDataZoomHandler;
  14. };
  15. export type BarChartBucket = {
  16. start: number;
  17. end: number;
  18. };
  19. type Props = {
  20. location: Location;
  21. /**
  22. * This is the query parameter the start of the zoom will be propagated to.
  23. */
  24. paramStart: string;
  25. /**
  26. * This is the query parameter the end of the zoom will be propagated to.
  27. */
  28. paramEnd: string;
  29. /**
  30. * This is the minimum width of the zoom. If the targeted zoom area is
  31. * smaller than is specified by this parameter, the zoom will be cancelled
  32. * and the `onDataZoomCancelled` callback will be called.
  33. */
  34. minZoomWidth?: number;
  35. /**
  36. * This is the list of bucket start and end ranges. This is used by the
  37. * component to determine the start and end of the zoom.
  38. */
  39. buckets: BarChartBucket[];
  40. /**
  41. * If you need the dataZoom control to control more than one chart.
  42. * you can provide a list of the axis indexes.
  43. */
  44. xAxisIndex: number[];
  45. /**
  46. * The children function that will receive the render props and return
  47. * a rendered chart.
  48. */
  49. children: (props: RenderProps) => React.ReactNode;
  50. /**
  51. *
  52. */
  53. onHistoryPush?: (start: number, end: number) => void;
  54. /**
  55. * This callback is called when the zoom action was cancelled. It can happen
  56. * when `minZoomWidth` is specified and the user tries to zoom on an area
  57. * smaller than that.
  58. */
  59. onDataZoomCancelled?: () => void;
  60. onChartReady?: EChartChartReadyHandler;
  61. onDataZoom?: EChartDataZoomHandler;
  62. };
  63. class BarChartZoom extends React.Component<Props> {
  64. /**
  65. * Enable zoom immediately instead of having to toggle to zoom
  66. */
  67. handleChartReady = chart => {
  68. chart.dispatchAction({
  69. type: 'takeGlobalCursor',
  70. key: 'dataZoomSelect',
  71. dataZoomSelectActive: true,
  72. });
  73. callIfFunction(this.props.onChartReady, chart);
  74. };
  75. handleDataZoom = (evt, chart) => {
  76. const model = chart.getModel();
  77. const {xAxis} = model.option;
  78. const axis = xAxis[0];
  79. // Both of these values should not be null, but we include it just in case.
  80. // These values are null when the user uses the toolbox included in ECharts
  81. // to navigate back through zoom history, but we hide it below.
  82. if (axis.rangeStart !== null && axis.rangeEnd !== null) {
  83. const {
  84. buckets,
  85. location,
  86. paramStart,
  87. paramEnd,
  88. minZoomWidth,
  89. onHistoryPush,
  90. } = this.props;
  91. const {start} = buckets[axis.rangeStart];
  92. const {end} = buckets[axis.rangeEnd];
  93. if (minZoomWidth === undefined || end - start > minZoomWidth) {
  94. const target = {
  95. pathname: location.pathname,
  96. query: {
  97. ...location.query,
  98. [paramStart]: start,
  99. [paramEnd]: end,
  100. },
  101. };
  102. if (onHistoryPush) {
  103. onHistoryPush(start, end);
  104. } else {
  105. browserHistory.push(target);
  106. }
  107. } else {
  108. // Dispatch the restore action here to stop ECharts from zooming
  109. chart.dispatchAction({type: 'restore'});
  110. callIfFunction(this.props.onDataZoomCancelled);
  111. }
  112. } else {
  113. // Dispatch the restore action here to stop ECharts from zooming
  114. chart.dispatchAction({type: 'restore'});
  115. callIfFunction(this.props.onDataZoomCancelled);
  116. }
  117. callIfFunction(this.props.onDataZoom, evt, chart);
  118. };
  119. render() {
  120. const {children, xAxisIndex} = this.props;
  121. const renderProps = {
  122. onChartReady: this.handleChartReady,
  123. dataZoom: DataZoomInside({xAxisIndex}),
  124. // We must include data zoom in the toolbox for the zoom to work,
  125. // but we do not want to show the toolbox components.
  126. toolBox: ToolBox(
  127. {},
  128. {
  129. dataZoom: {
  130. title: {
  131. zoom: '',
  132. back: '',
  133. },
  134. iconStyle: {
  135. borderWidth: 0,
  136. color: 'transparent',
  137. opacity: 0,
  138. },
  139. },
  140. }
  141. ),
  142. onDataZoom: this.handleDataZoom,
  143. };
  144. return children(renderProps);
  145. }
  146. }
  147. export default BarChartZoom;