浏览代码

wip: began first steps for a react graph component

Torkel Ödegaard 7 年之前
父节点
当前提交
9adad76f52

+ 4 - 15
public/app/plugins/panel/graph2/module.tsx

@@ -2,6 +2,9 @@
 import _ from 'lodash';
 import React, { PureComponent } from 'react';
 
+// Components
+import { Graph } from 'app/viz/Graph';
+
 // Types
 import { PanelProps } from 'app/types';
 
@@ -22,21 +25,7 @@ export class Graph2 extends PureComponent<Props> {
     const { timeSeries } = this.props;
     let index = 0;
 
-    return (
-      <table className="filter-table">
-        <tbody>
-          {timeSeries.map(series => {
-            return (
-              <tr key={index++}>
-                <td>{series.target}</td>
-                <td>{series.datapoints[0][0]}</td>
-                <td>{series.datapoints[0][1]}</td>
-              </tr>
-            );
-          })}
-        </tbody>
-      </table>
-    );
+    return <Graph timeSeries={timeSeries} />;
   }
 }
 

+ 10 - 1
public/app/types/index.ts

@@ -9,7 +9,15 @@ import { ApiKey, ApiKeysState, NewApiKey } from './apiKeys';
 import { Invitee, OrgUser, User, UsersState } from './user';
 import { DataSource, DataSourcesState } from './datasources';
 import { PluginMeta, Plugin, PluginsState } from './plugins';
-import { TimeRange, LoadingState, TimeSeries, DataQuery, DataQueryResponse, DataQueryOptions } from './series';
+import {
+  TimeRange,
+  LoadingState,
+  TimeSeries,
+  DataQuery,
+  DataQueryResponse,
+  DataQueryOptions,
+  TimeSeriesViewModel,
+} from './series';
 import { PanelProps } from './panel';
 
 export {
@@ -51,6 +59,7 @@ export {
   LoadingState,
   PanelProps,
   TimeSeries,
+  TimeSeriesViewModel,
   DataQuery,
   DataQueryResponse,
   DataQueryOptions,

+ 2 - 1
public/app/types/panel.ts

@@ -1,6 +1,7 @@
-import { LoadingState, TimeSeries } from './series';
+import { LoadingState, TimeSeries, TimeRange } from './series';
 
 export interface PanelProps {
   timeSeries: TimeSeries[];
+  timeRange: TimeRange;
   loading: LoadingState;
 }

+ 7 - 0
public/app/types/series.ts

@@ -25,6 +25,13 @@ export type TimeSeriesPoints = TimeSeriesValue[][];
 export interface TimeSeries {
   target: string;
   datapoints: TimeSeriesPoints;
+  unit?: string;
+}
+
+export interface TimeSeriesViewModel {
+  label: string;
+  color: string;
+  data: number[][];
 }
 
 export interface DataQueryResponse {

+ 126 - 0
public/app/viz/Graph.tsx

@@ -0,0 +1,126 @@
+// Libraries
+import $ from 'jquery';
+import React, { PureComponent } from 'react';
+import { withSize } from 'react-sizeme';
+import 'vendor/flot/jquery.flot';
+import 'vendor/flot/jquery.flot.time';
+
+// Types
+import TimeSeries from 'app/core/time_series2';
+import { TimeRange } from 'app/types';
+
+// Copied from graph.ts
+function time_format(ticks, min, max) {
+  if (min && max && ticks) {
+    const range = max - min;
+    const secPerTick = range / ticks / 1000;
+    const oneDay = 86400000;
+    const oneYear = 31536000000;
+
+    if (secPerTick <= 45) {
+      return '%H:%M:%S';
+    }
+    if (secPerTick <= 7200 || range <= oneDay) {
+      return '%H:%M';
+    }
+    if (secPerTick <= 80000) {
+      return '%m/%d %H:%M';
+    }
+    if (secPerTick <= 2419200 || range <= oneYear) {
+      return '%m/%d';
+    }
+    return '%Y-%m';
+  }
+
+  return '%H:%M';
+}
+
+const FLOT_OPTIONS = {
+  legend: {
+    show: false,
+  },
+  series: {
+    lines: {
+      linewidth: 1,
+      zero: false,
+    },
+    shadowSize: 0,
+  },
+  grid: {
+    minBorderMargin: 0,
+    markings: [],
+    backgroundColor: null,
+    borderWidth: 0,
+    // hoverable: true,
+    clickable: true,
+    color: '#a1a1a1',
+    margin: { left: 0, right: 0 },
+    labelMarginX: 0,
+  },
+};
+
+interface GraphProps {
+  timeSeries: TimeSeries[];
+  timeRange: TimeRange;
+  size?: { width: number; height: number };
+}
+
+export class Graph extends PureComponent<GraphProps> {
+  element: any;
+
+  componentDidUpdate(prevProps: GraphProps) {
+    if (
+      prevProps.timeSeries !== this.props.timeSeries ||
+      prevProps.timeRange !== this.props.timeRange ||
+      prevProps.size !== this.props.size
+    ) {
+      this.draw();
+    }
+  }
+
+  componentDidMount() {
+    this.draw();
+  }
+
+  draw() {
+    const { size, timeSeries, timeRange } = this.props;
+
+    const data = timeSeries.map((ts: TimeSeries) => ({
+      color: ts.color,
+      label: ts.label,
+      data: ts.getFlotPairs('null'),
+    }));
+
+    const ticks = (size.width || 0) / 100;
+    const min = timeRange.from.valueOf();
+    const max = timeRange.to.valueOf();
+
+    const dynamicOptions = {
+      xaxis: {
+        mode: 'time',
+        min: min,
+        max: max,
+        label: 'Datetime',
+        ticks: ticks,
+        timeformat: time_format(ticks, min, max),
+      },
+    };
+
+    const options = {
+      ...FLOT_OPTIONS,
+      ...dynamicOptions,
+    };
+
+    $.plot(this.element, data, options);
+  }
+
+  render() {
+    return (
+      <div className="graph-panel">
+        <div className="graph-panel__chart" ref={e => (this.element = e)} />
+      </div>
+    );
+  }
+}
+
+export default withSize()(Graph);

+ 9 - 0
public/app/viz/state/getTimeSeriesViewModel.ts

@@ -0,0 +1,9 @@
+import colors from 'app/core/utils/colors';
+import { TimeSeries, TimeSeriesViewModel } from 'app/types';
+
+interface Options {
+  ts: TimeSeries;
+  seriesIndex: number;
+}
+
+export function getTimeSeriesViewModel(ts: TimeSeries): TimeSeriesViewModel {}