mirror of
https://github.com/grafana/grafana.git
synced 2025-02-09 23:16:16 -06:00
Began experimenting with a bar gauge
This commit is contained in:
parent
3d3db08b56
commit
843f8b04d4
59
packages/grafana-ui/src/components/BarGauge/BarGauge.tsx
Normal file
59
packages/grafana-ui/src/components/BarGauge/BarGauge.tsx
Normal file
@ -0,0 +1,59 @@
|
||||
// Library
|
||||
import React, { PureComponent } from 'react';
|
||||
|
||||
// Utils
|
||||
import { getValueFormat } from '../../utils';
|
||||
|
||||
// Types
|
||||
import { Themeable, TimeSeriesValue } from '../../types';
|
||||
|
||||
export interface Props extends Themeable {
|
||||
height: number;
|
||||
unit: string;
|
||||
width: number;
|
||||
value: TimeSeriesValue;
|
||||
prefix: string;
|
||||
suffix: string;
|
||||
maxValue: number;
|
||||
minValue: number;
|
||||
}
|
||||
|
||||
export class BarGauge extends PureComponent<Props> {
|
||||
static defaultProps = {
|
||||
maxValue: 100,
|
||||
minValue: 0,
|
||||
unit: 'none',
|
||||
};
|
||||
|
||||
getNumericValue(): number {
|
||||
if (Number.isFinite(this.props.value as number)) {
|
||||
return this.props.value as number;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { height, width, maxValue, minValue, unit } = this.props;
|
||||
|
||||
const numericValue = this.getNumericValue();
|
||||
const barMaxHeight = height * 0.8; // 20% for value & name
|
||||
const valuePercent = numericValue / (maxValue - minValue);
|
||||
const barHeight = valuePercent * barMaxHeight;
|
||||
|
||||
const formatFunc = getValueFormat(unit);
|
||||
const valueFormatted = formatFunc(numericValue);
|
||||
|
||||
return (
|
||||
<div className="bar-gauge" style={{ width: `${width}px`, height: `${height}px` }}>
|
||||
<div className="bar-gauge__value">{valueFormatted}</div>
|
||||
<div
|
||||
style={{
|
||||
height: `${barHeight}px`,
|
||||
width: `${width}px`,
|
||||
backgroundColor: 'rgba(200,0,0,0.3)',
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
.bar-gauge {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.bar-gauge__value {
|
||||
text-align: center;
|
||||
}
|
@ -9,3 +9,4 @@
|
||||
@import 'ValueMappingsEditor/ValueMappingsEditor';
|
||||
@import 'EmptySearchResult/EmptySearchResult';
|
||||
@import 'FormField/FormField';
|
||||
@import 'BarGauge/BarGauge';
|
||||
|
@ -17,10 +17,13 @@ export { LoadingPlaceholder } from './LoadingPlaceholder/LoadingPlaceholder';
|
||||
export { ColorPicker, SeriesColorPicker } from './ColorPicker/ColorPicker';
|
||||
export { SeriesColorPickerPopover, SeriesColorPickerPopoverWithTheme } from './ColorPicker/SeriesColorPickerPopover';
|
||||
export { ThresholdsEditor } from './ThresholdsEditor/ThresholdsEditor';
|
||||
export { Graph } from './Graph/Graph';
|
||||
export { PanelOptionsGroup } from './PanelOptionsGroup/PanelOptionsGroup';
|
||||
export { PanelOptionsGrid } from './PanelOptionsGrid/PanelOptionsGrid';
|
||||
export { ValueMappingsEditor } from './ValueMappingsEditor/ValueMappingsEditor';
|
||||
export { Gauge } from './Gauge/Gauge';
|
||||
export { Switch } from './Switch/Switch';
|
||||
export { EmptySearchResult } from './EmptySearchResult/EmptySearchResult';
|
||||
|
||||
// Visualizations
|
||||
export { Gauge } from './Gauge/Gauge';
|
||||
export { Graph } from './Graph/Graph';
|
||||
export { BarGauge } from './BarGauge/BarGauge';
|
||||
|
@ -2,9 +2,12 @@
|
||||
import _ from 'lodash';
|
||||
import React, { PureComponent } from 'react';
|
||||
|
||||
// Components
|
||||
import { AlertBox } from 'app/core/components/AlertBox/AlertBox';
|
||||
|
||||
// Types
|
||||
import { PanelProps } from '@grafana/ui';
|
||||
import { PanelPlugin } from 'app/types';
|
||||
import { PanelPlugin, AppNotificationSeverity } from 'app/types';
|
||||
|
||||
interface Props {
|
||||
pluginId: string;
|
||||
@ -19,15 +22,13 @@ class PanelPluginNotFound extends PureComponent<Props> {
|
||||
const style = {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
textAlign: 'center' as 'center',
|
||||
justifyContent: 'center',
|
||||
height: '100%',
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={style}>
|
||||
<div className="alert alert-error" style={{ margin: '0 auto' }}>
|
||||
Panel plugin with id {this.props.pluginId} could not be found
|
||||
</div>
|
||||
<AlertBox severity={AppNotificationSeverity.Error} title={`Panel plugin not found: ${this.props.pluginId})`} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -54,10 +54,10 @@ export class VisualizationTab extends PureComponent<Props, State> {
|
||||
const { panel, plugin } = this.props;
|
||||
|
||||
if (plugin.exports.PanelDefaults) {
|
||||
return panel.getOptions(plugin.exports.PanelDefaults.options);
|
||||
return panel.getOptions(plugin.exports.PanelDefaults);
|
||||
}
|
||||
|
||||
return panel.getOptions(plugin.exports.PanelDefaults);
|
||||
return panel.getOptions({});
|
||||
};
|
||||
|
||||
renderPanelOptions() {
|
||||
|
@ -26,6 +26,7 @@ import * as tablePanel from 'app/plugins/panel/table/module';
|
||||
import * as singlestatPanel from 'app/plugins/panel/singlestat/module';
|
||||
import * as gettingStartedPanel from 'app/plugins/panel/gettingstarted/module';
|
||||
import * as gaugePanel from 'app/plugins/panel/gauge/module';
|
||||
import * as barGaugePanel from 'app/plugins/panel/bargauge/module';
|
||||
|
||||
const builtInPlugins = {
|
||||
'app/plugins/datasource/graphite/module': graphitePlugin,
|
||||
@ -56,6 +57,7 @@ const builtInPlugins = {
|
||||
'app/plugins/panel/singlestat/module': singlestatPanel,
|
||||
'app/plugins/panel/gettingstarted/module': gettingStartedPanel,
|
||||
'app/plugins/panel/gauge/module': gaugePanel,
|
||||
'app/plugins/panel/bargauge/module': barGaugePanel,
|
||||
};
|
||||
|
||||
export default builtInPlugins;
|
||||
|
56
public/app/plugins/panel/bargauge/BarGaugePanel.tsx
Normal file
56
public/app/plugins/panel/bargauge/BarGaugePanel.tsx
Normal file
@ -0,0 +1,56 @@
|
||||
// Libraries
|
||||
import React, { PureComponent } from 'react';
|
||||
|
||||
// Services & Utils
|
||||
import { processTimeSeries, ThemeContext } from '@grafana/ui';
|
||||
|
||||
// Components
|
||||
import { BarGauge } from '@grafana/ui';
|
||||
|
||||
// Types
|
||||
import { BarGaugeOptions } from './types';
|
||||
import { PanelProps, NullValueMode, TimeSeriesValue } from '@grafana/ui/src/types';
|
||||
|
||||
interface Props extends PanelProps<BarGaugeOptions> {}
|
||||
|
||||
export class BarGaugePanel extends PureComponent<Props> {
|
||||
render() {
|
||||
const { panelData, width, height, onInterpolate, options } = this.props;
|
||||
|
||||
const prefix = onInterpolate(options.prefix);
|
||||
const suffix = onInterpolate(options.suffix);
|
||||
|
||||
let value: TimeSeriesValue;
|
||||
|
||||
if (panelData.timeSeries) {
|
||||
const vmSeries = processTimeSeries({
|
||||
timeSeries: panelData.timeSeries,
|
||||
nullValueMode: NullValueMode.Null,
|
||||
});
|
||||
|
||||
if (vmSeries[0]) {
|
||||
value = vmSeries[0].stats[options.stat];
|
||||
} else {
|
||||
value = null;
|
||||
}
|
||||
} else if (panelData.tableData) {
|
||||
value = panelData.tableData.rows[0].find(prop => prop > 0);
|
||||
}
|
||||
|
||||
return (
|
||||
<ThemeContext.Consumer>
|
||||
{theme => (
|
||||
<BarGauge
|
||||
value={value}
|
||||
{...this.props.options}
|
||||
width={width}
|
||||
height={height}
|
||||
prefix={prefix}
|
||||
suffix={suffix}
|
||||
theme={theme}
|
||||
/>
|
||||
)}
|
||||
</ThemeContext.Consumer>
|
||||
);
|
||||
}
|
||||
}
|
4
public/app/plugins/panel/bargauge/module.tsx
Normal file
4
public/app/plugins/panel/bargauge/module.tsx
Normal file
@ -0,0 +1,4 @@
|
||||
import { BarGaugePanel } from './BarGaugePanel';
|
||||
import { PanelDefaults } from './types';
|
||||
|
||||
export { BarGaugePanel as Panel, PanelDefaults };
|
15
public/app/plugins/panel/bargauge/plugin.json
Normal file
15
public/app/plugins/panel/bargauge/plugin.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"type": "panel",
|
||||
"name": "Bar Gauge",
|
||||
"id": "bargauge",
|
||||
|
||||
"dataFormats": ["time_series"],
|
||||
|
||||
"info": {
|
||||
"author": {
|
||||
"name": "Grafana Project",
|
||||
"url": "https://grafana.com"
|
||||
},
|
||||
"logos": {}
|
||||
}
|
||||
}
|
17
public/app/plugins/panel/bargauge/types.ts
Normal file
17
public/app/plugins/panel/bargauge/types.ts
Normal file
@ -0,0 +1,17 @@
|
||||
export interface BarGaugeOptions {
|
||||
minValue: number;
|
||||
maxValue: number;
|
||||
prefix: string;
|
||||
stat: string;
|
||||
suffix: string;
|
||||
unit: string;
|
||||
}
|
||||
|
||||
export const PanelDefaults: BarGaugeOptions = {
|
||||
minValue: 0,
|
||||
maxValue: 100,
|
||||
prefix: '',
|
||||
suffix: '',
|
||||
stat: 'avg',
|
||||
unit: 'none',
|
||||
};
|
@ -1,9 +1,8 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { FormField, PanelOptionsProps, PanelOptionsGroup, Switch } from '@grafana/ui';
|
||||
|
||||
import { GaugeOptions } from './types';
|
||||
|
||||
export default class GaugeOptionsEditor extends PureComponent<PanelOptionsProps<GaugeOptions>> {
|
||||
export class GaugeOptionsEditor extends PureComponent<PanelOptionsProps<GaugeOptions>> {
|
||||
onToggleThresholdLabels = () =>
|
||||
this.props.onChange({ ...this.props.options, showThresholdLabels: !this.props.options.showThresholdLabels });
|
||||
|
||||
|
@ -1,36 +1,16 @@
|
||||
// Libraries
|
||||
import React, { PureComponent } from 'react';
|
||||
import {
|
||||
PanelOptionsProps,
|
||||
ThresholdsEditor,
|
||||
Threshold,
|
||||
PanelOptionsGrid,
|
||||
ValueMappingsEditor,
|
||||
ValueMapping,
|
||||
} from '@grafana/ui';
|
||||
|
||||
import ValueOptions from 'app/plugins/panel/gauge/ValueOptions';
|
||||
import GaugeOptionsEditor from './GaugeOptionsEditor';
|
||||
// Components
|
||||
import { ValueOptions } from 'app/plugins/panel/gauge/ValueOptions';
|
||||
import { GaugeOptionsEditor } from './GaugeOptionsEditor';
|
||||
import { ThresholdsEditor, ValueMappingsEditor } from '@grafana/ui';
|
||||
|
||||
// Types
|
||||
import { PanelOptionsProps, Threshold, PanelOptionsGrid, ValueMapping } from '@grafana/ui';
|
||||
import { GaugeOptions } from './types';
|
||||
|
||||
export const defaultProps = {
|
||||
options: {
|
||||
minValue: 0,
|
||||
maxValue: 100,
|
||||
prefix: '',
|
||||
showThresholdMarkers: true,
|
||||
showThresholdLabels: false,
|
||||
suffix: '',
|
||||
decimals: 0,
|
||||
stat: 'avg',
|
||||
unit: 'none',
|
||||
valueMappings: [],
|
||||
thresholds: [],
|
||||
},
|
||||
};
|
||||
|
||||
export default class GaugePanelOptions extends PureComponent<PanelOptionsProps<GaugeOptions>> {
|
||||
static defaultProps = defaultProps;
|
||||
|
||||
export class GaugePanelOptions extends PureComponent<PanelOptionsProps<GaugeOptions>> {
|
||||
onThresholdsChanged = (thresholds: Threshold[]) =>
|
||||
this.props.onChange({
|
||||
...this.props.options,
|
||||
|
@ -19,7 +19,7 @@ const statOptions = [
|
||||
|
||||
const labelWidth = 6;
|
||||
|
||||
export default class ValueOptions extends PureComponent<PanelOptionsProps<GaugeOptions>> {
|
||||
export class ValueOptions extends PureComponent<PanelOptionsProps<GaugeOptions>> {
|
||||
onUnitChange = unit => this.props.onChange({ ...this.props.options, unit: unit.value });
|
||||
|
||||
onStatChange = stat => this.props.onChange({ ...this.props.options, stat: stat.value });
|
||||
|
@ -1,4 +1,5 @@
|
||||
import GaugePanelOptions, { defaultProps } from './GaugePanelOptions';
|
||||
import { GaugePanelOptions } from './GaugePanelOptions';
|
||||
import { GaugePanel } from './GaugePanel';
|
||||
import { PanelDefaults } from './types';
|
||||
|
||||
export { GaugePanel as Panel, GaugePanelOptions as PanelOptions, defaultProps as PanelDefaults };
|
||||
export { GaugePanel as Panel, GaugePanelOptions as PanelOptions, PanelDefaults };
|
||||
|
@ -13,3 +13,17 @@ export interface GaugeOptions {
|
||||
thresholds: Threshold[];
|
||||
unit: string;
|
||||
}
|
||||
|
||||
export const PanelDefaults: GaugeOptions = {
|
||||
minValue: 0,
|
||||
maxValue: 100,
|
||||
prefix: '',
|
||||
showThresholdMarkers: true,
|
||||
showThresholdLabels: false,
|
||||
suffix: '',
|
||||
decimals: 0,
|
||||
stat: 'avg',
|
||||
unit: 'none',
|
||||
valueMappings: [],
|
||||
thresholds: [],
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user