From 2fc136e615ccb9c08e44b0d595dd6cbd4a396255 Mon Sep 17 00:00:00 2001 From: Peter Holmberg Date: Wed, 20 Feb 2019 15:07:30 +0100 Subject: [PATCH] added orientation option --- .../src/components/BarGauge/BarGauge.test.tsx | 1 + .../src/components/BarGauge/BarGauge.tsx | 94 +++++++++++++++---- .../components/VizRepeater/VizRepeater.tsx | 58 +++++++----- .../plugins/panel/bargauge/BarGaugePanel.tsx | 81 ++++++++++------ .../panel/bargauge/BarGaugePanelEditor.tsx | 15 ++- public/app/plugins/panel/bargauge/types.ts | 16 +++- 6 files changed, 187 insertions(+), 78 deletions(-) diff --git a/packages/grafana-ui/src/components/BarGauge/BarGauge.test.tsx b/packages/grafana-ui/src/components/BarGauge/BarGauge.test.tsx index c6ea9f22978..3165329c372 100644 --- a/packages/grafana-ui/src/components/BarGauge/BarGauge.test.tsx +++ b/packages/grafana-ui/src/components/BarGauge/BarGauge.test.tsx @@ -21,6 +21,7 @@ const setup = (propOverrides?: object) => { value: 25, decimals: 0, theme: getTheme(), + orientation: 'horizontal', }; Object.assign(props, propOverrides); diff --git a/packages/grafana-ui/src/components/BarGauge/BarGauge.tsx b/packages/grafana-ui/src/components/BarGauge/BarGauge.tsx index 5e1a00617e1..59b80d29ac2 100644 --- a/packages/grafana-ui/src/components/BarGauge/BarGauge.tsx +++ b/packages/grafana-ui/src/components/BarGauge/BarGauge.tsx @@ -17,6 +17,7 @@ export interface Props extends Themeable { value: TimeSeriesValue; maxValue: number; minValue: number; + orientation: string; prefix?: string; suffix?: string; decimals?: number; @@ -28,6 +29,7 @@ export class BarGauge extends PureComponent { minValue: 0, value: 100, unit: 'none', + orientation: 'horizontal', thresholds: [], valueMappings: [], }; @@ -75,29 +77,19 @@ export class BarGauge extends PureComponent { }; } - render() { - const { height, width, maxValue, minValue, unit, decimals } = this.props; + renderHorizontalBar(valueStyles: React.CSSProperties, valueFormatted: string, barStyles: React.CSSProperties) { + const { height, width } = this.props; - const numericValue = this.getNumericValue(); - const barMaxHeight = height * 0.8; // 20% for value & name - const valuePercent = numericValue / (maxValue - minValue); - const barHeight = Math.max(valuePercent * barMaxHeight, 0); - - const formatFunc = getValueFormat(unit); - const valueFormatted = formatFunc(numericValue, decimals); - const colors = this.getColors(); - - const containerStyles = { width: `${width}px`, height: `${height}px` }; - const valueStyles = this.getValueStyles(valueFormatted, colors.value); - const barStyles = { - height: `${barHeight}px`, + const containerStyles = { width: `${width}px`, - backgroundColor: colors.bar, - borderTop: `1px solid ${colors.border}`, - }; + height: `${height}px`, + display: 'flex', + flexDirection: 'column', + justifyContent: 'flex-end', + } as React.CSSProperties; return ( -
+
{valueFormatted}
@@ -105,6 +97,70 @@ export class BarGauge extends PureComponent {
); } + + renderVerticalBar(valueFormatted: string, barStyles: React.CSSProperties) { + const { height, width } = this.props; + const colors = this.getColors(); + + const containerStyles = { + width: `${width}px`, + height: `${height}px`, + display: 'flex', + flexDirection: 'row', + alignItems: 'center', + marginBottom: '8px', + } as React.CSSProperties; + + const valueStyles = this.getValueStyles(valueFormatted, colors.value); + + Object.assign(valueStyles, { marginLeft: '8px' }); + + return ( +
+
+
+ {valueFormatted} +
+
+ ); + } + + render() { + const { height, width, maxValue, minValue, orientation, unit, decimals } = this.props; + + const numericValue = this.getNumericValue(); + const barMaxHeight = height * 0.8; // 20% for value & name + const barMaxWidth = width * 0.8; + const valuePercent = numericValue / (maxValue - minValue); + const barHeight = Math.max(valuePercent * barMaxHeight, 0); + const barWidth = Math.max(valuePercent * barMaxWidth, 0); + + const formatFunc = getValueFormat(unit); + const valueFormatted = formatFunc(numericValue, decimals); + const colors = this.getColors(); + const valueStyles = this.getValueStyles(valueFormatted, colors.value); + const vertical = orientation === 'vertical'; + + const horizontalBarStyles = { + height: `${barHeight}px`, + width: `${width}px`, + backgroundColor: colors.bar, + borderTop: `1px solid ${colors.border}`, + }; + + const verticalBarStyles = { + height: `${height}px`, + width: `${barWidth}px`, + backgroundColor: colors.bar, + borderRight: `1px solid ${colors.border}`, + }; + + const barStyles = vertical ? verticalBarStyles : horizontalBarStyles; + + return vertical + ? this.renderVerticalBar(valueFormatted, barStyles) + : this.renderHorizontalBar(valueStyles, valueFormatted, barStyles); + } } interface BarColors { diff --git a/packages/grafana-ui/src/components/VizRepeater/VizRepeater.tsx b/packages/grafana-ui/src/components/VizRepeater/VizRepeater.tsx index e944fae1924..25e398faa78 100644 --- a/packages/grafana-ui/src/components/VizRepeater/VizRepeater.tsx +++ b/packages/grafana-ui/src/components/VizRepeater/VizRepeater.tsx @@ -1,4 +1,4 @@ -import { Component } from 'react'; +import React, { PureComponent } from 'react'; import { TimeSeriesVMs } from '../../types'; interface RenderProps { @@ -12,45 +12,55 @@ interface Props { height: number; width: number; timeSeries: TimeSeriesVMs; + orientation?: string; } -export class VizRepeater extends Component { +export class VizRepeater extends PureComponent { render() { - const { children, height, timeSeries, width } = this.props; + const { children, orientation, height, timeSeries, width } = this.props; - const singleStatWidth = 1 / timeSeries.length * 100; - const singleStatHeight = 1 / timeSeries.length * 100; - const repeatingGaugeWidth = Math.floor(width / timeSeries.length) - 10; // make Gauge slightly smaller than panel. - const repeatingGaugeHeight = Math.floor(height / timeSeries.length) - 10; + const vizContainerWidth = 1 / timeSeries.length * 100; + const vizContainerHeight = 1 / timeSeries.length * 100; + const repeatingVizWidth = Math.floor(width / timeSeries.length) - 10; // make Gauge slightly smaller than panel. + const repeatingVizHeight = Math.floor(height / timeSeries.length) - 10; - const horizontalPanels = { - display: 'inline-block', + const horizontalVisualization = { height: height, - width: `${singleStatWidth}%`, + width: `${vizContainerWidth}%`, }; - const verticalPanels = { - display: 'block', + const verticalVisualization = { width: width, - height: `${singleStatHeight}%`, + height: `${vizContainerHeight}%`, }; + const repeaterStyle = { + display: 'flex', + flexDirection: orientation === 'vertical' || height > width ? 'column' : 'row', + } as React.CSSProperties; + let vizContainerStyle = {}; let vizWidth = width; let vizHeight = height; - if (width > height) { - vizContainerStyle = horizontalPanels; - vizWidth = repeatingGaugeWidth; - } else if (height > width) { - vizContainerStyle = verticalPanels; - vizHeight = repeatingGaugeHeight; + if (orientation === 'horizontal' || width > height) { + vizContainerStyle = horizontalVisualization; + vizWidth = repeatingVizWidth; } - return children({ - vizHeight, - vizWidth, - vizContainerStyle, - }); + if (orientation === 'vertical' || height > width) { + vizContainerStyle = verticalVisualization; + vizHeight = repeatingVizHeight; + } + + return ( +
+ {children({ + vizHeight, + vizWidth, + vizContainerStyle, + })} +
+ ); } } diff --git a/public/app/plugins/panel/bargauge/BarGaugePanel.tsx b/public/app/plugins/panel/bargauge/BarGaugePanel.tsx index 68b68878f25..1f8362b0031 100644 --- a/public/app/plugins/panel/bargauge/BarGaugePanel.tsx +++ b/public/app/plugins/panel/bargauge/BarGaugePanel.tsx @@ -2,59 +2,78 @@ import React, { PureComponent } from 'react'; // Services & Utils -import { processTimeSeries, ThemeContext } from '@grafana/ui'; +import { processTimeSeries } from '@grafana/ui'; +import { config } from 'app/core/config'; // Components -import { BarGauge } from '@grafana/ui'; +import { BarGauge, VizRepeater } from '@grafana/ui'; // Types import { BarGaugeOptions } from './types'; -import { PanelProps, NullValueMode, TimeSeriesValue } from '@grafana/ui/src/types'; +import { PanelProps, NullValueMode } from '@grafana/ui/src/types'; interface Props extends PanelProps {} export class BarGaugePanel extends PureComponent { - render() { - const { panelData, width, height, onInterpolate, options } = this.props; + renderBarGauge(value, width, height) { + const { onInterpolate, options } = this.props; const { valueOptions } = options; - const prefix = onInterpolate(valueOptions.prefix); const suffix = onInterpolate(valueOptions.suffix); - let value: TimeSeriesValue; + return ( + + ); + } + + render() { + const { panelData, options, width, height } = this.props; + const { stat } = options.valueOptions; if (panelData.timeSeries) { - const vmSeries = processTimeSeries({ + const timeSeries = processTimeSeries({ timeSeries: panelData.timeSeries, nullValueMode: NullValueMode.Null, }); - if (vmSeries[0]) { - value = vmSeries[0].stats[valueOptions.stat]; - } else { - value = null; + if (timeSeries.length > 1) { + return ( + + {({ vizHeight, vizWidth, vizContainerStyle }) => { + return timeSeries.map((series, index) => { + const value = stat !== 'name' ? series.stats[stat] : series.label; + + return ( +
+ {this.renderBarGauge(value, vizWidth, vizHeight)} +
+ ); + }); + }} +
+ ); + } else if (timeSeries.length > 0) { + const value = timeSeries[0].stats[options.valueOptions.stat]; + return this.renderBarGauge(value, width, height); } } else if (panelData.tableData) { - value = panelData.tableData.rows[0].find(prop => prop > 0); + const value = panelData.tableData.rows[0].find(prop => prop > 0); + + return this.renderBarGauge(value, width, height); } - return ( - - {theme => ( - - )} - - ); + return
No time series data available
; } } diff --git a/public/app/plugins/panel/bargauge/BarGaugePanelEditor.tsx b/public/app/plugins/panel/bargauge/BarGaugePanelEditor.tsx index 8e8042c12eb..aceb761de77 100644 --- a/public/app/plugins/panel/bargauge/BarGaugePanelEditor.tsx +++ b/public/app/plugins/panel/bargauge/BarGaugePanelEditor.tsx @@ -6,8 +6,8 @@ import { SingleStatValueEditor } from 'app/plugins/panel/gauge/SingleStatValueEd import { ThresholdsEditor, ValueMappingsEditor, PanelOptionsGrid, PanelOptionsGroup, FormField } from '@grafana/ui'; // Types -import { PanelEditorProps, Threshold, ValueMapping } from '@grafana/ui'; -import { BarGaugeOptions } from './types'; +import { FormLabel, PanelEditorProps, Threshold, Select, ValueMapping } from '@grafana/ui'; +import { BarGaugeOptions, orientationOptions } from './types'; import { SingleStatValueOptions } from '../gauge/types'; export class BarGaugePanelEditor extends PureComponent> { @@ -31,6 +31,7 @@ export class BarGaugePanelEditor extends PureComponent this.props.onChange({ ...this.props.options, minValue: target.value }); onMaxValueChange = ({ target }) => this.props.onChange({ ...this.props.options, maxValue: target.value }); + onOrientationChange = ({ value }) => this.props.onChange({ ...this.props.options, orientation: value }); render() { const { options } = this.props; @@ -42,6 +43,16 @@ export class BarGaugePanelEditor extends PureComponent +
+ Orientation +