TimelineChart.tsx 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. import React from 'react';
  2. import { DataFrame, FALLBACK_COLOR, FieldType, TimeRange } from '@grafana/data';
  3. import { LegendDisplayMode, VisibilityMode } from '@grafana/schema';
  4. import {
  5. PanelContext,
  6. PanelContextRoot,
  7. GraphNG,
  8. GraphNGProps,
  9. UPlotConfigBuilder,
  10. VizLayout,
  11. VizLegend,
  12. VizLegendItem,
  13. } from '@grafana/ui';
  14. import { TimelineMode, TimelineOptions, TimelineValueAlignment } from './types';
  15. import { preparePlotConfigBuilder } from './utils';
  16. /**
  17. * @alpha
  18. */
  19. export interface TimelineProps
  20. extends TimelineOptions,
  21. Omit<GraphNGProps, 'prepConfig' | 'propsToDiff' | 'renderLegend'> {
  22. mode: TimelineMode;
  23. rowHeight: number;
  24. showValue: VisibilityMode;
  25. alignValue?: TimelineValueAlignment;
  26. colWidth?: number;
  27. legendItems?: VizLegendItem[];
  28. }
  29. const propsToDiff = ['rowHeight', 'colWidth', 'showValue', 'mergeValues', 'alignValue'];
  30. export class TimelineChart extends React.Component<TimelineProps> {
  31. static contextType = PanelContextRoot;
  32. panelContext: PanelContext = {} as PanelContext;
  33. getValueColor = (frameIdx: number, fieldIdx: number, value: any) => {
  34. const field = this.props.frames[frameIdx].fields[fieldIdx];
  35. if (field.display) {
  36. const disp = field.display(value); // will apply color modes
  37. if (disp.color) {
  38. return disp.color;
  39. }
  40. }
  41. return FALLBACK_COLOR;
  42. };
  43. prepConfig = (alignedFrame: DataFrame, allFrames: DataFrame[], getTimeRange: () => TimeRange) => {
  44. this.panelContext = this.context as PanelContext;
  45. const { eventBus, sync } = this.panelContext;
  46. return preparePlotConfigBuilder({
  47. frame: alignedFrame,
  48. getTimeRange,
  49. eventBus,
  50. sync,
  51. allFrames: this.props.frames,
  52. ...this.props,
  53. // When there is only one row, use the full space
  54. rowHeight: alignedFrame.fields.length > 2 ? this.props.rowHeight : 1,
  55. getValueColor: this.getValueColor,
  56. });
  57. };
  58. renderLegend = (config: UPlotConfigBuilder) => {
  59. const { legend, legendItems } = this.props;
  60. if (!config || !legendItems || !legend || legend.displayMode === LegendDisplayMode.Hidden) {
  61. return null;
  62. }
  63. return (
  64. <VizLayout.Legend placement={legend.placement}>
  65. <VizLegend placement={legend.placement} items={legendItems} displayMode={legend.displayMode} readonly />
  66. </VizLayout.Legend>
  67. );
  68. };
  69. render() {
  70. return (
  71. <GraphNG
  72. {...this.props}
  73. fields={{
  74. x: (f) => f.type === FieldType.time,
  75. y: (f) => f.type === FieldType.number || f.type === FieldType.boolean || f.type === FieldType.string,
  76. }}
  77. prepConfig={this.prepConfig}
  78. propsToDiff={propsToDiff}
  79. renderLegend={this.renderLegend}
  80. />
  81. );
  82. }
  83. }