Graph.tsx 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. import $ from 'jquery';
  2. import React, { Component } from 'react';
  3. import moment from 'moment';
  4. import 'vendor/flot/jquery.flot';
  5. import 'vendor/flot/jquery.flot.time';
  6. import * as dateMath from 'app/core/utils/datemath';
  7. import TimeSeries from 'app/core/time_series2';
  8. import Legend from './Legend';
  9. // Copied from graph.ts
  10. function time_format(ticks, min, max) {
  11. if (min && max && ticks) {
  12. const range = max - min;
  13. const secPerTick = range / ticks / 1000;
  14. const oneDay = 86400000;
  15. const oneYear = 31536000000;
  16. if (secPerTick <= 45) {
  17. return '%H:%M:%S';
  18. }
  19. if (secPerTick <= 7200 || range <= oneDay) {
  20. return '%H:%M';
  21. }
  22. if (secPerTick <= 80000) {
  23. return '%m/%d %H:%M';
  24. }
  25. if (secPerTick <= 2419200 || range <= oneYear) {
  26. return '%m/%d';
  27. }
  28. return '%Y-%m';
  29. }
  30. return '%H:%M';
  31. }
  32. const FLOT_OPTIONS = {
  33. legend: {
  34. show: false,
  35. },
  36. series: {
  37. lines: {
  38. linewidth: 1,
  39. zero: false,
  40. },
  41. shadowSize: 0,
  42. },
  43. grid: {
  44. minBorderMargin: 0,
  45. markings: [],
  46. backgroundColor: null,
  47. borderWidth: 0,
  48. // hoverable: true,
  49. clickable: true,
  50. color: '#a1a1a1',
  51. margin: { left: 0, right: 0 },
  52. labelMarginX: 0,
  53. },
  54. // selection: {
  55. // mode: 'x',
  56. // color: '#666',
  57. // },
  58. // crosshair: {
  59. // mode: 'x',
  60. // },
  61. };
  62. class Graph extends Component<any, any> {
  63. state = {
  64. showAllTimeSeries: false,
  65. };
  66. getGraphData() {
  67. const { data } = this.props;
  68. return this.state.showAllTimeSeries ? data : data.slice(0, 20);
  69. }
  70. componentDidMount() {
  71. this.draw();
  72. }
  73. componentDidUpdate(prevProps) {
  74. if (
  75. prevProps.data !== this.props.data ||
  76. prevProps.options !== this.props.options ||
  77. prevProps.split !== this.props.split ||
  78. prevProps.height !== this.props.height
  79. ) {
  80. this.draw();
  81. }
  82. }
  83. onShowAllTimeSeries = () => {
  84. this.setState(
  85. {
  86. showAllTimeSeries: true,
  87. },
  88. this.draw
  89. );
  90. };
  91. draw() {
  92. const { options: userOptions } = this.props;
  93. const data = this.getGraphData();
  94. const $el = $(`#${this.props.id}`);
  95. if (!data) {
  96. $el.empty();
  97. return;
  98. }
  99. const series = data.map((ts: TimeSeries) => ({
  100. color: ts.color,
  101. label: ts.label,
  102. data: ts.getFlotPairs('null'),
  103. }));
  104. const ticks = $el.width() / 100;
  105. let { from, to } = userOptions.range;
  106. if (!moment.isMoment(from)) {
  107. from = dateMath.parse(from, false);
  108. }
  109. if (!moment.isMoment(to)) {
  110. to = dateMath.parse(to, true);
  111. }
  112. const min = from.valueOf();
  113. const max = to.valueOf();
  114. const dynamicOptions = {
  115. xaxis: {
  116. mode: 'time',
  117. min: min,
  118. max: max,
  119. label: 'Datetime',
  120. ticks: ticks,
  121. timeformat: time_format(ticks, min, max),
  122. },
  123. };
  124. const options = {
  125. ...FLOT_OPTIONS,
  126. ...dynamicOptions,
  127. ...userOptions,
  128. };
  129. $.plot($el, series, options);
  130. }
  131. render() {
  132. const { height, loading } = this.props;
  133. const data = this.getGraphData();
  134. if (!loading && data.length === 0) {
  135. return (
  136. <div className="panel-container">
  137. <div className="muted m-a-1">The queries returned no time series to graph.</div>
  138. </div>
  139. );
  140. }
  141. return (
  142. <div>
  143. {this.props.data.length > 20 &&
  144. !this.state.showAllTimeSeries && (
  145. <div className="time-series-disclaimer">
  146. <i className="fa fa-fw fa-warning disclaimer-icon" />
  147. Showing only 20 time series.{' '}
  148. <span className="show-all-time-series" onClick={this.onShowAllTimeSeries}>{`Show all ${
  149. this.props.data.length
  150. }`}</span>
  151. </div>
  152. )}
  153. <div className="panel-container">
  154. <div id={this.props.id} className="explore-graph" style={{ height }} />
  155. <Legend data={data} />
  156. </div>
  157. </div>
  158. );
  159. }
  160. }
  161. export default Graph;