mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
bar-gauge storybook
This commit is contained in:
parent
843f8b04d4
commit
b34f2665fd
@ -0,0 +1,54 @@
|
|||||||
|
import { storiesOf } from '@storybook/react';
|
||||||
|
import { number, text } from '@storybook/addon-knobs';
|
||||||
|
import { BarGauge } from './BarGauge';
|
||||||
|
import { withCenteredStory } from '../../utils/storybook/withCenteredStory';
|
||||||
|
import { renderComponentWithTheme } from '../../utils/storybook/withTheme';
|
||||||
|
|
||||||
|
const getKnobs = () => {
|
||||||
|
return {
|
||||||
|
value: number('value', 70),
|
||||||
|
minValue: number('minValue', 0),
|
||||||
|
maxValue: number('maxValue', 100),
|
||||||
|
threshold1Value: number('threshold1Value', 40),
|
||||||
|
threshold1Color: text('threshold1Color', 'orange'),
|
||||||
|
threshold2Value: number('threshold2Value', 60),
|
||||||
|
threshold2Color: text('threshold2Color', 'red'),
|
||||||
|
unit: text('unit', 'ms'),
|
||||||
|
decimals: number('decimals', 1),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const BarGaugeStories = storiesOf('UI/BarGauge/BarGauge', module);
|
||||||
|
|
||||||
|
BarGaugeStories.addDecorator(withCenteredStory);
|
||||||
|
|
||||||
|
BarGaugeStories.add('Vertical, with basic thresholds', () => {
|
||||||
|
const {
|
||||||
|
value,
|
||||||
|
minValue,
|
||||||
|
maxValue,
|
||||||
|
threshold1Color,
|
||||||
|
threshold2Color,
|
||||||
|
threshold1Value,
|
||||||
|
threshold2Value,
|
||||||
|
unit,
|
||||||
|
decimals,
|
||||||
|
} = getKnobs();
|
||||||
|
|
||||||
|
return renderComponentWithTheme(BarGauge, {
|
||||||
|
width: 300,
|
||||||
|
height: 600,
|
||||||
|
value: value,
|
||||||
|
minValue: minValue,
|
||||||
|
maxValue: maxValue,
|
||||||
|
unit: unit,
|
||||||
|
prefix: '',
|
||||||
|
postfix: '',
|
||||||
|
decimals: decimals,
|
||||||
|
thresholds: [
|
||||||
|
{ index: 0, value: null, color: 'green' },
|
||||||
|
{ index: 1, value: threshold1Value, color: threshold1Color },
|
||||||
|
{ index: 1, value: threshold2Value, color: threshold2Color },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
@ -1,28 +1,35 @@
|
|||||||
// Library
|
// Library
|
||||||
import React, { PureComponent } from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
|
import tinycolor from 'tinycolor2';
|
||||||
|
|
||||||
// Utils
|
// Utils
|
||||||
import { getValueFormat } from '../../utils';
|
import { getColorFromHexRgbOrName, getValueFormat, getThresholdForValue } from '../../utils';
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import { Themeable, TimeSeriesValue } from '../../types';
|
import { Themeable, TimeSeriesValue, Threshold, ValueMapping } from '../../types';
|
||||||
|
|
||||||
export interface Props extends Themeable {
|
export interface Props extends Themeable {
|
||||||
height: number;
|
height: number;
|
||||||
unit: string;
|
unit: string;
|
||||||
width: number;
|
width: number;
|
||||||
|
thresholds: Threshold[];
|
||||||
|
valueMappings: ValueMapping[];
|
||||||
value: TimeSeriesValue;
|
value: TimeSeriesValue;
|
||||||
prefix: string;
|
|
||||||
suffix: string;
|
|
||||||
maxValue: number;
|
maxValue: number;
|
||||||
minValue: number;
|
minValue: number;
|
||||||
|
prefix?: string;
|
||||||
|
suffix?: string;
|
||||||
|
decimals?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class BarGauge extends PureComponent<Props> {
|
export class BarGauge extends PureComponent<Props> {
|
||||||
static defaultProps = {
|
static defaultProps: Partial<Props> = {
|
||||||
maxValue: 100,
|
maxValue: 100,
|
||||||
minValue: 0,
|
minValue: 0,
|
||||||
|
value: 100,
|
||||||
unit: 'none',
|
unit: 'none',
|
||||||
|
thresholds: [],
|
||||||
|
valueMappings: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
getNumericValue(): number {
|
getNumericValue(): number {
|
||||||
@ -32,8 +39,45 @@ export class BarGauge extends PureComponent<Props> {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getColors(): BarColors {
|
||||||
|
const { thresholds, theme, value } = this.props;
|
||||||
|
|
||||||
|
const activeThreshold = getThresholdForValue(thresholds, value);
|
||||||
|
console.log(thresholds, value);
|
||||||
|
|
||||||
|
if (activeThreshold !== null) {
|
||||||
|
const color = getColorFromHexRgbOrName(activeThreshold.color, theme.type);
|
||||||
|
|
||||||
|
return {
|
||||||
|
value: color,
|
||||||
|
border: color,
|
||||||
|
bar: tinycolor(color)
|
||||||
|
.setAlpha(0.3)
|
||||||
|
.toRgbString(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
value: getColorFromHexRgbOrName('gray', theme.type),
|
||||||
|
bar: getColorFromHexRgbOrName('gray', theme.type),
|
||||||
|
border: getColorFromHexRgbOrName('gray', theme.type),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
getValueStyles(value: string, color: string) {
|
||||||
|
const { width } = this.props;
|
||||||
|
|
||||||
|
const guess = width / value.length;
|
||||||
|
const fontSize = Math.max(guess, 14);
|
||||||
|
|
||||||
|
return {
|
||||||
|
color: color,
|
||||||
|
fontSize: fontSize + 'px',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { height, width, maxValue, minValue, unit } = this.props;
|
const { height, width, maxValue, minValue, unit, decimals } = this.props;
|
||||||
|
|
||||||
const numericValue = this.getNumericValue();
|
const numericValue = this.getNumericValue();
|
||||||
const barMaxHeight = height * 0.8; // 20% for value & name
|
const barMaxHeight = height * 0.8; // 20% for value & name
|
||||||
@ -41,19 +85,31 @@ export class BarGauge extends PureComponent<Props> {
|
|||||||
const barHeight = valuePercent * barMaxHeight;
|
const barHeight = valuePercent * barMaxHeight;
|
||||||
|
|
||||||
const formatFunc = getValueFormat(unit);
|
const formatFunc = getValueFormat(unit);
|
||||||
const valueFormatted = formatFunc(numericValue);
|
const valueFormatted = formatFunc(numericValue, decimals);
|
||||||
|
const colors = this.getColors();
|
||||||
|
|
||||||
return (
|
const containerStyles = { width: `${width}px`, height: `${height}px` };
|
||||||
<div className="bar-gauge" style={{ width: `${width}px`, height: `${height}px` }}>
|
const valueStyles = this.getValueStyles(valueFormatted, colors.value);
|
||||||
<div className="bar-gauge__value">{valueFormatted}</div>
|
const barStyles = {
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
height: `${barHeight}px`,
|
height: `${barHeight}px`,
|
||||||
width: `${width}px`,
|
width: `${width}px`,
|
||||||
backgroundColor: 'rgba(200,0,0,0.3)',
|
backgroundColor: colors.bar,
|
||||||
}}
|
borderTop: `1px solid ${colors.border}`,
|
||||||
/>
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="bar-gauge" style={containerStyles}>
|
||||||
|
<div className="bar-gauge__value" style={valueStyles}>
|
||||||
|
{valueFormatted}
|
||||||
|
</div>
|
||||||
|
<div style={barStyles} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface BarColors {
|
||||||
|
value: string;
|
||||||
|
bar: string;
|
||||||
|
border: string;
|
||||||
|
}
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import React, { PureComponent } from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
|
|
||||||
import { ValueMapping, Threshold, BasicGaugeColor, GrafanaThemeType } from '../../types';
|
import { ValueMapping, Threshold, GrafanaThemeType } from '../../types';
|
||||||
import { getMappedValue } from '../../utils/valueMappings';
|
import { getMappedValue } from '../../utils/valueMappings';
|
||||||
import { getColorFromHexRgbOrName, getValueFormat } from '../../utils';
|
import { getColorFromHexRgbOrName, getValueFormat, getThresholdForValue } from '../../utils';
|
||||||
import { Themeable } from '../../index';
|
import { Themeable } from '../../index';
|
||||||
|
|
||||||
type TimeSeriesValue = string | number | null;
|
type GaugeValue = string | number | null;
|
||||||
|
|
||||||
export interface Props extends Themeable {
|
export interface Props extends Themeable {
|
||||||
decimals: number;
|
decimals: number;
|
||||||
@ -30,7 +30,7 @@ const FONT_SCALE = 1;
|
|||||||
export class Gauge extends PureComponent<Props> {
|
export class Gauge extends PureComponent<Props> {
|
||||||
canvasElement: any;
|
canvasElement: any;
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps: Partial<Props> = {
|
||||||
maxValue: 100,
|
maxValue: 100,
|
||||||
valueMappings: [],
|
valueMappings: [],
|
||||||
minValue: 0,
|
minValue: 0,
|
||||||
@ -41,7 +41,6 @@ export class Gauge extends PureComponent<Props> {
|
|||||||
thresholds: [],
|
thresholds: [],
|
||||||
unit: 'none',
|
unit: 'none',
|
||||||
stat: 'avg',
|
stat: 'avg',
|
||||||
theme: GrafanaThemeType.Dark,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
@ -52,7 +51,7 @@ export class Gauge extends PureComponent<Props> {
|
|||||||
this.draw();
|
this.draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
formatValue(value: TimeSeriesValue) {
|
formatValue(value: GaugeValue) {
|
||||||
const { decimals, valueMappings, prefix, suffix, unit } = this.props;
|
const { decimals, valueMappings, prefix, suffix, unit } = this.props;
|
||||||
|
|
||||||
if (isNaN(value as number)) {
|
if (isNaN(value as number)) {
|
||||||
@ -73,26 +72,16 @@ export class Gauge extends PureComponent<Props> {
|
|||||||
return `${prefix && prefix + ' '}${handleNoValueValue}${suffix && ' ' + suffix}`;
|
return `${prefix && prefix + ' '}${handleNoValueValue}${suffix && ' ' + suffix}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
getFontColor(value: TimeSeriesValue) {
|
getFontColor(value: GaugeValue): string {
|
||||||
const { thresholds, theme } = this.props;
|
const { thresholds, theme } = this.props;
|
||||||
|
|
||||||
if (thresholds.length === 1) {
|
const activeThreshold = getThresholdForValue(thresholds, value);
|
||||||
return getColorFromHexRgbOrName(thresholds[0].color, theme.type);
|
|
||||||
|
if (activeThreshold !== null) {
|
||||||
|
return getColorFromHexRgbOrName(activeThreshold.color, theme.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
const atThreshold = thresholds.filter(threshold => (value as number) === threshold.value)[0];
|
return '';
|
||||||
if (atThreshold) {
|
|
||||||
return getColorFromHexRgbOrName(atThreshold.color, theme.type);
|
|
||||||
}
|
|
||||||
|
|
||||||
const belowThreshold = thresholds.filter(threshold => (value as number) > threshold.value);
|
|
||||||
|
|
||||||
if (belowThreshold.length > 0) {
|
|
||||||
const nearestThreshold = belowThreshold.sort((t1, t2) => t2.value - t1.value)[0];
|
|
||||||
return getColorFromHexRgbOrName(nearestThreshold.color, theme.type);
|
|
||||||
}
|
|
||||||
|
|
||||||
return BasicGaugeColor.Red;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getFormattedThresholds() {
|
getFormattedThresholds() {
|
||||||
@ -199,5 +188,3 @@ export class Gauge extends PureComponent<Props> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Gauge;
|
|
||||||
|
@ -4,3 +4,4 @@ export * from './panel';
|
|||||||
export * from './plugin';
|
export * from './plugin';
|
||||||
export * from './datasource';
|
export * from './datasource';
|
||||||
export * from './theme';
|
export * from './theme';
|
||||||
|
export * from './threshold';
|
||||||
|
@ -38,17 +38,6 @@ export interface PanelMenuItem {
|
|||||||
subMenu?: PanelMenuItem[];
|
subMenu?: PanelMenuItem[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Threshold {
|
|
||||||
index: number;
|
|
||||||
value: number;
|
|
||||||
color: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum BasicGaugeColor {
|
|
||||||
Green = '#299c46',
|
|
||||||
Red = '#d44a3a',
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum MappingType {
|
export enum MappingType {
|
||||||
ValueToText = 1,
|
ValueToText = 1,
|
||||||
RangeToText = 2,
|
RangeToText = 2,
|
||||||
|
5
packages/grafana-ui/src/types/threshold.ts
Normal file
5
packages/grafana-ui/src/types/threshold.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export interface Threshold {
|
||||||
|
index: number;
|
||||||
|
value: number;
|
||||||
|
color: string;
|
||||||
|
}
|
@ -2,3 +2,4 @@ export * from './processTimeSeries';
|
|||||||
export * from './valueFormats/valueFormats';
|
export * from './valueFormats/valueFormats';
|
||||||
export * from './colors';
|
export * from './colors';
|
||||||
export * from './namedColorsPalette';
|
export * from './namedColorsPalette';
|
||||||
|
export * from './thresholds';
|
||||||
|
23
packages/grafana-ui/src/utils/thresholds.ts
Normal file
23
packages/grafana-ui/src/utils/thresholds.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { Threshold } from '../types';
|
||||||
|
|
||||||
|
export function getThresholdForValue(
|
||||||
|
thresholds: Threshold[],
|
||||||
|
value: number | null | string | undefined
|
||||||
|
): Threshold | null {
|
||||||
|
if (thresholds.length === 1) {
|
||||||
|
return thresholds[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
const atThreshold = thresholds.filter(threshold => (value as number) === threshold.value)[0];
|
||||||
|
if (atThreshold) {
|
||||||
|
return atThreshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
const belowThreshold = thresholds.filter(threshold => (value as number) > threshold.value);
|
||||||
|
if (belowThreshold.length > 0) {
|
||||||
|
const nearestThreshold = belowThreshold.sort((t1: Threshold, t2: Threshold) => t2.value - t1.value)[0];
|
||||||
|
return nearestThreshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
@ -2,6 +2,7 @@
|
|||||||
"type": "panel",
|
"type": "panel",
|
||||||
"name": "Bar Gauge",
|
"name": "Bar Gauge",
|
||||||
"id": "bargauge",
|
"id": "bargauge",
|
||||||
|
"state": "alpha",
|
||||||
|
|
||||||
"dataFormats": ["time_series"],
|
"dataFormats": ["time_series"],
|
||||||
|
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import { Threshold, ValueMapping } from '@grafana/ui';
|
||||||
|
|
||||||
export interface BarGaugeOptions {
|
export interface BarGaugeOptions {
|
||||||
minValue: number;
|
minValue: number;
|
||||||
maxValue: number;
|
maxValue: number;
|
||||||
@ -5,6 +7,8 @@ export interface BarGaugeOptions {
|
|||||||
stat: string;
|
stat: string;
|
||||||
suffix: string;
|
suffix: string;
|
||||||
unit: string;
|
unit: string;
|
||||||
|
valueMappings: ValueMapping[];
|
||||||
|
thresholds: Threshold[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PanelDefaults: BarGaugeOptions = {
|
export const PanelDefaults: BarGaugeOptions = {
|
||||||
@ -14,4 +18,6 @@ export const PanelDefaults: BarGaugeOptions = {
|
|||||||
suffix: '',
|
suffix: '',
|
||||||
stat: 'avg',
|
stat: 'avg',
|
||||||
unit: 'none',
|
unit: 'none',
|
||||||
|
thresholds: [],
|
||||||
|
valueMappings: [],
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user