瀏覽代碼

Can render graph

Torkel Ödegaard 7 年之前
父節點
當前提交
ae7a1bc139

+ 3 - 3
public/app/features/dashboard/dashgrid/DataPanel.tsx

@@ -5,7 +5,7 @@ import React, { Component } from 'react';
 import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
 
 // Types
-import { TimeRange, LoadingState, DataQueryResponse, TimeSeries } from 'app/types';
+import { TimeRange, LoadingState, DataQueryOptions, DataQueryResponse, TimeSeries } from 'app/types';
 
 interface RenderProps {
   loading: LoadingState;
@@ -82,14 +82,14 @@ export class DataPanel extends Component<Props, State> {
       const dataSourceSrv = getDatasourceSrv();
       const ds = await dataSourceSrv.get(datasource);
 
-      const queryOptions = {
+      const queryOptions: DataQueryOptions = {
         timezone: 'browser',
         panelId: panelId,
         dashboardId: dashboardId,
         range: timeRange,
         rangeRaw: timeRange.raw,
         interval: '1s',
-        intervalMs: 1000,
+        intervalMs: 60000,
         targets: queries,
         maxDataPoints: 500,
         scopedVars: {},

+ 1 - 0
public/app/plugins/panel/graph/graph.ts

@@ -339,6 +339,7 @@ class GraphElement {
 
   callPlot(options, incrementRenderCounter) {
     try {
+      console.log('plot', this.sortedSeries);
       this.plot = $.plot(this.elem, this.sortedSeries, options);
       if (this.ctrl.renderError) {
         delete this.ctrl.error;

+ 7 - 6
public/app/plugins/panel/graph2/module.tsx

@@ -4,12 +4,10 @@ import React, { PureComponent } from 'react';
 
 // Components
 import Graph from 'app/viz/Graph';
-
-// Utils
 import { getTimeSeriesVMs } from 'app/viz/state/timeSeries';
 
 // Types
-import { PanelProps } from 'app/types';
+import { PanelProps, NullValueMode } from 'app/types';
 
 interface Options {
   showBars: boolean;
@@ -26,10 +24,13 @@ export class Graph2 extends PureComponent<Props> {
 
   render() {
     const { timeSeries, timeRange } = this.props;
-    const viewModels = getTimeSeriesVMs({ timeSeries });
-    console.log(viewModels);
 
-    return <Graph timeSeries={viewModels} timeRange={timeRange} />;
+    const vmSeries = getTimeSeriesVMs({
+      timeSeries: timeSeries,
+      nullValueMode: NullValueMode.Ignore,
+    });
+
+    return <Graph timeSeries={vmSeries} timeRange={timeRange} />;
   }
 }
 

+ 4 - 0
public/app/types/index.ts

@@ -15,6 +15,8 @@ import {
   TimeSeries,
   TimeSeriesVM,
   TimeSeriesVMs,
+  TimeSeriesStats,
+  NullValueMode,
   DataQuery,
   DataQueryResponse,
   DataQueryOptions,
@@ -62,6 +64,8 @@ export {
   TimeSeries,
   TimeSeriesVM,
   TimeSeriesVMs,
+  NullValueMode,
+  TimeSeriesStats,
   DataQuery,
   DataQueryResponse,
   DataQueryOptions,

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

@@ -33,6 +33,30 @@ export interface TimeSeriesVM {
   label: string;
   color: string;
   data: TimeSeriesValue[][];
+  stats: TimeSeriesStats;
+}
+
+export interface TimeSeriesStats {
+  total: number;
+  max: number;
+  min: number;
+  logmin: number;
+  avg: number | null;
+  current: number | null;
+  first: number | null;
+  delta: number;
+  diff: number | null;
+  range: number | null;
+  timeStep: number;
+  count: number;
+  allIsNull: boolean;
+  allIsZero: boolean;
+}
+
+export enum NullValueMode {
+  Null = 'null',
+  Ignore = 'connected',
+  AsZero = 'null as zero',
 }
 
 /** View model projection of many time series */
@@ -56,6 +80,10 @@ export interface DataQueryOptions {
   panelId: number;
   dashboardId: number;
   cacheTimeout?: string;
+  interval: string;
+  intervalMs: number;
+  maxDataPoints: number;
+  scopedVars: object;
 }
 
 export interface DataSourceApi {

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

@@ -108,6 +108,7 @@ export class Graph extends PureComponent<GraphProps> {
       ...dynamicOptions,
     };
 
+    console.log('plot', timeSeries, options);
     $.plot(this.element, timeSeries, options);
   }
 

+ 150 - 3
public/app/viz/state/timeSeries.ts

@@ -1,19 +1,166 @@
+// Libraries
+import _ from 'lodash';
+
+// Utils
 import colors from 'app/core/utils/colors';
-import { TimeSeries, TimeSeriesVMs } from 'app/types';
+
+// Types
+import { TimeSeries, TimeSeriesVMs, NullValueMode } from 'app/types';
 
 interface Options {
   timeSeries: TimeSeries[];
+  nullValueMode: NullValueMode;
 }
 
-export function getTimeSeriesVMs({ timeSeries }: Options): TimeSeriesVMs {
+export function getTimeSeriesVMs({ timeSeries, nullValueMode }: Options): TimeSeriesVMs {
   const vmSeries = timeSeries.map((item, index) => {
     const colorIndex = index % colors.length;
     const label = item.target;
+    const result = [];
+
+    // stat defaults
+    let total = 0;
+    let max = -Number.MAX_VALUE;
+    let min = Number.MAX_VALUE;
+    let logmin = Number.MAX_VALUE;
+    let avg = null;
+    let current = null;
+    let first = null;
+    let delta = 0;
+    let diff = null;
+    let range = null;
+    let timeStep = Number.MAX_VALUE;
+    let allIsNull = true;
+    let allIsZero = true;
+
+    const ignoreNulls = nullValueMode === NullValueMode.Ignore;
+    const nullAsZero = nullValueMode === NullValueMode.AsZero;
+
+    let currentTime;
+    let currentValue;
+    let nonNulls = 0;
+    let previousTime;
+    let previousValue = 0;
+    let previousDeltaUp = true;
+
+    for (let i = 0; i < item.datapoints.length; i++) {
+      currentValue = item.datapoints[i][0];
+      currentTime = item.datapoints[i][1];
+
+      // Due to missing values we could have different timeStep all along the series
+      // so we have to find the minimum one (could occur with aggregators such as ZimSum)
+      if (previousTime !== undefined) {
+        const currentStep = currentTime - previousTime;
+        if (currentStep < timeStep) {
+          timeStep = currentStep;
+        }
+      }
+
+      previousTime = currentTime;
+
+      if (currentValue === null) {
+        if (ignoreNulls) {
+          continue;
+        }
+        if (nullAsZero) {
+          currentValue = 0;
+        }
+      }
+
+      if (currentValue !== null) {
+        if (_.isNumber(currentValue)) {
+          total += currentValue;
+          allIsNull = false;
+          nonNulls++;
+        }
+
+        if (currentValue > max) {
+          max = currentValue;
+        }
+
+        if (currentValue < min) {
+          min = currentValue;
+        }
+
+        if (first === null) {
+          first = currentValue;
+        } else {
+          if (previousValue > currentValue) {
+            // counter reset
+            previousDeltaUp = false;
+            if (i === item.datapoints.length - 1) {
+              // reset on last
+              delta += currentValue;
+            }
+          } else {
+            if (previousDeltaUp) {
+              delta += currentValue - previousValue; // normal increment
+            } else {
+              delta += currentValue; // account for counter reset
+            }
+            previousDeltaUp = true;
+          }
+        }
+        previousValue = currentValue;
+
+        if (currentValue < logmin && currentValue > 0) {
+          logmin = currentValue;
+        }
+
+        if (currentValue !== 0) {
+          allIsZero = false;
+        }
+      }
+
+      result.push([currentTime, currentValue]);
+    }
+
+    if (max === -Number.MAX_VALUE) {
+      max = null;
+    }
+
+    if (min === Number.MAX_VALUE) {
+      min = null;
+    }
+
+    if (result.length && !allIsNull) {
+      avg = total / nonNulls;
+      current = result[result.length - 1][1];
+      if (current === null && result.length > 1) {
+        current = result[result.length - 2][1];
+      }
+    }
+
+    if (max !== null && min !== null) {
+      range = max - min;
+    }
+
+    if (current !== null && first !== null) {
+      diff = current - first;
+    }
+
+    const count = result.length;
 
     return {
-      data: item.datapoints,
+      data: result,
       label: label,
       color: colors[colorIndex],
+      stats: {
+        total,
+        min,
+        max,
+        current,
+        logmin,
+        avg,
+        diff,
+        delta,
+        timeStep,
+        range,
+        count,
+        first,
+        allIsZero,
+        allIsNull,
+      },
     };
   });