Groups
-
-
-
gon
Graph Component
Finally we pass the series object to Graph component.
return ( <div> <Graph height={props.height} width={props.width} series={series} timeRange={props.timeRange} showLines={true} /> </div> );
Here is everything in a single gist.
import React from 'react'; import { PanelProps, GraphSeriesXY, GraphSeriesValue } from '@grafana/data'; import { Graph } from '@grafana/ui'; export interface GraphPanelOptions {} export const GraphPanel: React.FC<PanelProps<GraphPanelOptions>> = props => { let ser_ind: number = 0; const series: GraphSeriesXY[] = props.data.series.map(item => { const timeVals: Array<GraphSeriesValue> = item.fields[0].values.toArray(); const yVals: Array<GraphSeriesValue> = item.fields[1].values.toArray(); const data: GraphSeriesValue[][] = []; for (let i = 0; i < timeVals.length; i++) { data.push([timeVals[i], yVals[i]]); } const unixTimeRange = props.timeRange.to.unix() - props.timeRange.from.unix(); const ser: GraphSeriesXY = { seriesIndex: ser_ind++, yAxis: { index: 0 }, isVisible: true, timeField: props.data.series[0].fields[0], valueField: props.data.series[0].fields[1], timeStep: props.width / unixTimeRange, data: data, label: 'some label', }; return ser; }); return ( <div> <Graph height={props.height} width={props.width} series={series} timeRange={props.timeRange} showLines={true} /> </div> ); };
-
gon
Making a Graph Panel
Here is the definition of type of props defined in @grafana-ui for Graph component.
export interface GraphProps { ariaLabel?: string; children?: JSX.Element | JSX.Element[]; series: GraphSeriesXY[]; timeRange: TimeRange; // NOTE: we should aim to make `time` a property of the axis, not force it for all graphs timeZone?: TimeZone; // NOTE: we should aim to make `time` a property of the axis, not force it for all graphs showLines?: boolean; showPoints?: boolean; showBars?: boolean; width: number; height: number; isStacked?: boolean; lineWidth?: number; onHorizontalRegionSelected?: (from: number, to: number) => void; }
series
prop holds the data you want to render in your graph. Each line that you see on a normal Grafana chart is of typeGraphSeriesXY
. Each panel can render multiple lines for different metrics/variables and therefore series is an array ofGraphSeriesXY
. We can construct series prop fromprops.data
.All time-series data in Grafana is stored and used as an object of type
DataFrame
. It is kind of like data frames in data science if you are familiar with them (like pandas dataframes).props.data.series
is of typeDataFrame[]
, ie. you have a collection of time-series data stored as an array. Each item in this array corresponds to a single element in yourGraphSeriesXY[]
array. We have to therefore map object of typeDataFrame
to object of typeGraphSeriesXY
.let ser_ind:number = 0; const series:GraphSeriesXY[] = props.data.series.map(item => { const timeVals:Array<GraphSeriesValue> = item .fields[0] .values .toArray(); const yVals:Array<GraphSeriesValue> = item .fields[1] .values .toArray(); const data:GraphSeriesValue[][] = []; for (let i = 0; i < timeVals.length; i++) { data.push([timeVals[i], yVals[i]]); } const unixTimeRange = (props.timeRange.to.unix() - props.timeRange.from.unix()); const ser:GraphSeriesXY = { seriesIndex: ser_ind++, yAxis: {index:0}, isVisible: true, timeField: props.data.series[0].fields[0], valueField: props.data.series[0].fields[1], timeStep: props.width / unixTimeRange, data: data, }; return ser; });
Each
item
is of typeDataFrame
. The time-series data is stored in thefields
array ofitem
. Eachfield
inside thefields
array consists of data points for a single axis similar to column-oriented dbms.We have two axis in our graphs,
time
(fields[0]
, x axis) andvalues
(fields[1], y axis). We construct data of typeGraphSeriesValue[][]
. We createser
usingdata
,fields
andtimeRange
in unix values. From this transformation we get aseries
array which can be passed toGraph
component. Make sure to give a distinct index to each item inseries
(ser_ind
here). You can take a look at typeGraphSeriesXY
if you want to play around with other props like color, etc. -
gon
Reference: https://medium.com/@hariom.2711/grafana-react-panel-plugins-545cb9afa42d
Plugin Basics
Your main panel should have props of type
PanelProps<options>
. You have to specify the type foroptions
.options
are basically used to enable the user to provide custom settings for your panel.import React from 'react'; import { PanelProps } from '@grafana/data'; export interface GraphPanelOptions { }; export const GraphPanel:React.FC<PanelProps<GraphPanelOptions>> = props => { return ( <div></div> ); }
props
will contain many attributes. Relevant ones for our GraphPanel aredata
,width
,height
,timeRange
.data
attribute contains the whole of your time-series data. Each time-series contains two fields, the first one being your time points and the other one being the function you plot on y-axis. There will be multiple time-series which will come as different lines plotted on the same graph in your data attribute depending on your backend.width
, andheight
contain the actual width and height of the space allocated to your panel when it is rendered on Grafana.timeRange
is the time range selected by the user. -
gon
Reference: https://corpglory.com/s/grafana-react-plugins/
PanelOptions
PanelOptions
is passed as aPanelProps
generic argument. Grafana will pass options from editor to your panel component as props.export interface MyPanelOptions { someText: string; } export class MyPanel extends PureComponent<PanelProps<MyPanelOptions>> { render() { const { options } = this.props; return ( <div> Text from editor: { options.someText } </div> ); } }
PanelEditor
PanelEditor
is the separate component which represents "Visualization" tab and is used for configuring a panel plugin.export class GaugePanelEditor extends PureComponent<PanelEditorProps<GaugeOptions>> { labelWidth = 6; render() { const { options, onChange } = this.props; return ( <PanelOptionsGrid> <PanelOptionsGroup title="Some options"> <Input className="gf-form-input width-5" type="text" value={options.someText} placeholder="Enter some text" onChange={event => { onChange({ ...options }); }} /> </PanelOptionsGroup> </PanelOptionsGrid> ); } }