XYChartPanel2.tsx 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. import React, { PureComponent } from 'react';
  2. import { PanelProps } from '@grafana/data';
  3. import { config } from '@grafana/runtime';
  4. import {
  5. LegendDisplayMode,
  6. Portal,
  7. UPlotChart,
  8. UPlotConfigBuilder,
  9. VizLayout,
  10. VizLegend,
  11. VizLegendItem,
  12. VizTooltipContainer,
  13. } from '@grafana/ui';
  14. import { FacetedData } from '@grafana/ui/src/components/uPlot/types';
  15. import { TooltipView } from './TooltipView';
  16. import { XYChartOptions } from './models.gen';
  17. import { prepData, prepScatter } from './scatter';
  18. import { ScatterHoverEvent, ScatterSeries } from './types';
  19. type Props = PanelProps<XYChartOptions>;
  20. type State = {
  21. error?: string;
  22. series: ScatterSeries[];
  23. builder?: UPlotConfigBuilder;
  24. facets?: FacetedData;
  25. hover?: ScatterHoverEvent;
  26. };
  27. export class XYChartPanel2 extends PureComponent<Props, State> {
  28. state: State = {
  29. series: [],
  30. };
  31. componentDidMount() {
  32. this.initSeries(); // also data
  33. }
  34. componentDidUpdate(oldProps: Props) {
  35. const { options, data } = this.props;
  36. const configsChanged = options !== oldProps.options || data.structureRev !== oldProps.data.structureRev;
  37. if (configsChanged) {
  38. this.initSeries();
  39. } else if (data !== oldProps.data) {
  40. this.initFacets();
  41. }
  42. }
  43. scatterHoverCallback = (hover?: ScatterHoverEvent) => {
  44. this.setState({ hover });
  45. };
  46. getData = () => {
  47. return this.props.data.series;
  48. };
  49. initSeries = () => {
  50. const { options, data } = this.props;
  51. const info: State = prepScatter(options, this.getData, config.theme2, this.scatterHoverCallback);
  52. if (info.series.length && data.series) {
  53. info.facets = prepData(info, data.series);
  54. info.error = undefined;
  55. }
  56. this.setState(info);
  57. };
  58. initFacets = () => {
  59. this.setState({
  60. facets: prepData(this.state, this.props.data.series),
  61. });
  62. };
  63. renderLegend = () => {
  64. const { data } = this.props;
  65. const { series } = this.state;
  66. const items: VizLegendItem[] = [];
  67. for (const s of series) {
  68. const frame = s.frame(data.series);
  69. if (frame) {
  70. for (const item of s.legend(frame)) {
  71. items.push(item);
  72. }
  73. }
  74. }
  75. return (
  76. <VizLayout.Legend placement="bottom">
  77. <VizLegend placement="bottom" items={items} displayMode={LegendDisplayMode.List} />
  78. </VizLayout.Legend>
  79. );
  80. };
  81. render() {
  82. const { width, height, timeRange, data } = this.props;
  83. const { error, facets, builder, hover, series } = this.state;
  84. if (error || !builder) {
  85. return (
  86. <div className="panel-empty">
  87. <p>{error}</p>
  88. </div>
  89. );
  90. }
  91. return (
  92. <>
  93. <VizLayout width={width} height={height} legend={this.renderLegend()}>
  94. {(vizWidth: number, vizHeight: number) => (
  95. // <pre style={{ width: vizWidth, height: vizHeight, border: '1px solid green', margin: '0px' }}>
  96. // {JSON.stringify(scatterData, null, 2)}
  97. // </pre>
  98. <UPlotChart config={builder} data={facets!} width={vizWidth} height={vizHeight} timeRange={timeRange}>
  99. {/*children ? children(config, alignedFrame) : null*/}
  100. </UPlotChart>
  101. )}
  102. </VizLayout>
  103. <Portal>
  104. {hover && (
  105. <VizTooltipContainer position={{ x: hover.pageX, y: hover.pageY }} offset={{ x: 10, y: 10 }}>
  106. <TooltipView series={series[hover.scatterIndex]} rowIndex={hover.xIndex} data={data.series} />
  107. </VizTooltipContainer>
  108. )}
  109. </Portal>
  110. </>
  111. );
  112. }
  113. }