ソースを参照

Merge pull request #16008 from grafana/bar-gauge-refactoring

Refactoring the bar gauge and the orientation modes
Torkel Ödegaard 6 年 前
コミット
c19a47d34f

+ 11 - 4
packages/grafana-ui/src/components/BarGauge/BarGauge.story.tsx

@@ -1,6 +1,7 @@
 import { storiesOf } from '@storybook/react';
-import { number, text } from '@storybook/addon-knobs';
+import { number, text, boolean } from '@storybook/addon-knobs';
 import { BarGauge } from './BarGauge';
+import { VizOrientation } from '../../types';
 import { withCenteredStory } from '../../utils/storybook/withCenteredStory';
 import { renderComponentWithTheme } from '../../utils/storybook/withTheme';
 
@@ -15,6 +16,8 @@ const getKnobs = () => {
     threshold2Color: text('threshold2Color', 'red'),
     unit: text('unit', 'ms'),
     decimals: number('decimals', 1),
+    horizontal: boolean('horizontal', false),
+    lcd: boolean('lcd', false),
   };
 };
 
@@ -22,7 +25,7 @@ const BarGaugeStories = storiesOf('UI/BarGauge/BarGauge', module);
 
 BarGaugeStories.addDecorator(withCenteredStory);
 
-BarGaugeStories.add('Vertical, with basic thresholds', () => {
+BarGaugeStories.add('Simple with basic thresholds', () => {
   const {
     value,
     minValue,
@@ -33,11 +36,13 @@ BarGaugeStories.add('Vertical, with basic thresholds', () => {
     threshold2Value,
     unit,
     decimals,
+    horizontal,
+    lcd,
   } = getKnobs();
 
   return renderComponentWithTheme(BarGauge, {
-    width: 200,
-    height: 400,
+    width: 700,
+    height: 700,
     value: value,
     minValue: minValue,
     maxValue: maxValue,
@@ -45,6 +50,8 @@ BarGaugeStories.add('Vertical, with basic thresholds', () => {
     prefix: '',
     postfix: '',
     decimals: decimals,
+    orientation: horizontal ? VizOrientation.Horizontal : VizOrientation.Vertical,
+    displayMode: lcd ? 'lcd' : 'simple',
     thresholds: [
       { index: 0, value: -Infinity, color: 'green' },
       { index: 1, value: threshold1Value, color: threshold1Color },

+ 1 - 0
packages/grafana-ui/src/components/BarGauge/BarGauge.test.tsx

@@ -12,6 +12,7 @@ const setup = (propOverrides?: object) => {
   const props: Props = {
     maxValue: 100,
     minValue: 0,
+    displayMode: 'basic',
     thresholds: [{ index: 0, value: -Infinity, color: '#7EB26D' }],
     height: 300,
     width: 300,

+ 178 - 96
packages/grafana-ui/src/components/BarGauge/BarGauge.tsx

@@ -1,5 +1,5 @@
 // Library
-import React, { PureComponent, CSSProperties } from 'react';
+import React, { PureComponent, CSSProperties, ReactNode } from 'react';
 import tinycolor from 'tinycolor2';
 
 // Utils
@@ -18,11 +18,9 @@ export interface Props extends Themeable {
   maxValue: number;
   minValue: number;
   orientation: VizOrientation;
+  displayMode: 'basic' | 'lcd' | 'gradient';
 }
 
-/*
- * This visualization is still in POC state, needed more tests & better structure
- */
 export class BarGauge extends PureComponent<Props> {
   static defaultProps: Partial<Props> = {
     maxValue: 100,
@@ -31,10 +29,22 @@ export class BarGauge extends PureComponent<Props> {
       text: '100',
       numeric: 100,
     },
+    displayMode: 'lcd',
     orientation: VizOrientation.Horizontal,
     thresholds: [],
   };
 
+  render() {
+    switch (this.props.displayMode) {
+      case 'lcd':
+        return this.renderRetroBars();
+      case 'basic':
+      case 'gradient':
+      default:
+        return this.renderBasicAndGradientBars();
+    }
+  }
+
   getValueColors(): BarColors {
     const { thresholds, theme, value } = this.props;
 
@@ -46,41 +56,19 @@ export class BarGauge extends PureComponent<Props> {
       return {
         value: color,
         border: color,
-        bar: tinycolor(color)
-          .setAlpha(0.3)
+        background: tinycolor(color)
+          .setAlpha(0.15)
           .toRgbString(),
       };
     }
 
     return {
       value: getColorFromHexRgbOrName('gray', theme.type),
-      bar: getColorFromHexRgbOrName('gray', theme.type),
+      background: getColorFromHexRgbOrName('gray', theme.type),
       border: getColorFromHexRgbOrName('gray', theme.type),
     };
   }
 
-  getCellColor(positionValue: TimeSeriesValue): string {
-    const { thresholds, theme, value } = this.props;
-    const activeThreshold = getThresholdForValue(thresholds, positionValue);
-
-    if (activeThreshold !== null) {
-      const color = getColorFromHexRgbOrName(activeThreshold.color, theme.type);
-
-      // if we are past real value the cell is not "on"
-      if (value === null || (positionValue !== null && positionValue > value.numeric)) {
-        return tinycolor(color)
-          .setAlpha(0.15)
-          .toRgbString();
-      } else {
-        return tinycolor(color)
-          .setAlpha(0.7)
-          .toRgbString();
-      }
-    }
-
-    return 'gray';
-  }
-
   getValueStyles(value: string, color: string, width: number): CSSProperties {
     const guess = width / (value.length * 1.1);
     const fontSize = Math.min(Math.max(guess, 14), 40);
@@ -91,107 +79,205 @@ export class BarGauge extends PureComponent<Props> {
     };
   }
 
-  renderVerticalBar(valueFormatted: string, valuePercent: number) {
+  /*
+   * Return width or height depending on viz orientation
+   * */
+  get size() {
     const { height, width } = this.props;
+    return this.isVertical ? height : width;
+  }
 
-    const maxHeight = height * BAR_SIZE_RATIO;
-    const barHeight = Math.max(valuePercent * maxHeight, 0);
+  get isVertical() {
+    return this.props.orientation === VizOrientation.Vertical;
+  }
+
+  getBarGradient(maxSize: number): string {
+    const { minValue, maxValue, thresholds, value } = this.props;
+    const cssDirection = this.isVertical ? '0deg' : '90deg';
+
+    let gradient = '';
+    let lastpos = 0;
+
+    for (let i = 0; i < thresholds.length; i++) {
+      const threshold = thresholds[i];
+      const color = getColorFromHexRgbOrName(threshold.color);
+      const valuePercent = Math.min(threshold.value / (maxValue - minValue), 1);
+      const pos = valuePercent * maxSize;
+      const offset = Math.round(pos - (pos - lastpos) / 2);
+
+      if (gradient === '') {
+        gradient = `linear-gradient(${cssDirection}, ${color}, ${color}`;
+      } else if (value.numeric < threshold.value) {
+        break;
+      } else {
+        lastpos = pos;
+        gradient += ` ${offset}px, ${color}`;
+      }
+    }
+
+    return gradient + ')';
+  }
+
+  renderBasicAndGradientBars(): ReactNode {
+    const { height, width, displayMode, maxValue, minValue, value } = this.props;
+
+    const valuePercent = Math.min(value.numeric / (maxValue - minValue), 1);
+    const maxSize = this.size * BAR_SIZE_RATIO;
+    const barSize = Math.max(valuePercent * maxSize, 0);
     const colors = this.getValueColors();
-    const valueStyles = this.getValueStyles(valueFormatted, colors.value, width);
+    const spaceForText = this.isVertical ? width : Math.min(this.size - maxSize, height);
+    const valueStyles = this.getValueStyles(value.text, colors.value, spaceForText);
+    const isBasic = displayMode === 'basic';
 
     const containerStyles: CSSProperties = {
       width: `${width}px`,
       height: `${height}px`,
       display: 'flex',
-      flexDirection: 'column',
-      justifyContent: 'flex-end',
     };
 
     const barStyles: CSSProperties = {
-      height: `${barHeight}px`,
-      width: `${width}px`,
-      backgroundColor: colors.bar,
-      borderTop: `1px solid ${colors.border}`,
+      borderRadius: '3px',
     };
 
+    if (this.isVertical) {
+      // Custom styles for vertical orientation
+      containerStyles.flexDirection = 'column';
+      containerStyles.justifyContent = 'flex-end';
+      barStyles.transition = 'height 1s';
+      barStyles.height = `${barSize}px`;
+      barStyles.width = `${width}px`;
+      if (isBasic) {
+        // Basic styles
+        barStyles.background = `${colors.background}`;
+        barStyles.border = `1px solid ${colors.border}`;
+        barStyles.boxShadow = `0 0 4px ${colors.border}`;
+      } else {
+        // Gradient styles
+        barStyles.background = this.getBarGradient(maxSize);
+      }
+    } else {
+      // Custom styles for horizontal orientation
+      containerStyles.flexDirection = 'row-reverse';
+      containerStyles.justifyContent = 'flex-end';
+      containerStyles.alignItems = 'center';
+      barStyles.transition = 'width 1s';
+      barStyles.height = `${height}px`;
+      barStyles.width = `${barSize}px`;
+      barStyles.marginRight = '10px';
+
+      if (isBasic) {
+        // Basic styles
+        barStyles.background = `${colors.background}`;
+        barStyles.border = `1px solid ${colors.border}`;
+        barStyles.boxShadow = `0 0 4px ${colors.border}`;
+      } else {
+        // Gradient styles
+        barStyles.background = this.getBarGradient(maxSize);
+      }
+    }
+
     return (
       <div style={containerStyles}>
         <div className="bar-gauge__value" style={valueStyles}>
-          {valueFormatted}
+          {value.text}
         </div>
         <div style={barStyles} />
       </div>
     );
   }
 
-  renderHorizontalBar(valueFormatted: string, valuePercent: number) {
-    const { height, width } = this.props;
-
-    const maxWidth = width * BAR_SIZE_RATIO;
-    const barWidth = Math.max(valuePercent * maxWidth, 0);
-    const colors = this.getValueColors();
-    const valueStyles = this.getValueStyles(valueFormatted, colors.value, width * (1 - BAR_SIZE_RATIO));
+  getCellColor(positionValue: TimeSeriesValue): CellColors {
+    const { thresholds, theme, value } = this.props;
+    const activeThreshold = getThresholdForValue(thresholds, positionValue);
 
-    valueStyles.marginLeft = '8px';
+    if (activeThreshold !== null) {
+      const color = getColorFromHexRgbOrName(activeThreshold.color, theme.type);
 
-    const containerStyles: CSSProperties = {
-      width: `${width}px`,
-      height: `${height}px`,
-      display: 'flex',
-      flexDirection: 'row',
-      alignItems: 'center',
-    };
+      // if we are past real value the cell is not "on"
+      if (value === null || (positionValue !== null && positionValue > value.numeric)) {
+        return {
+          background: tinycolor(color)
+            .setAlpha(0.15)
+            .toRgbString(),
+          border: 'transparent',
+          isLit: false,
+        };
+      } else {
+        return {
+          background: tinycolor(color)
+            .setAlpha(0.85)
+            .toRgbString(),
+          backgroundShade: tinycolor(color)
+            .setAlpha(0.55)
+            .toRgbString(),
+          border: tinycolor(color)
+            .setAlpha(0.9)
+            .toRgbString(),
+          isLit: true,
+        };
+      }
+    }
 
-    const barStyles = {
-      height: `${height}px`,
-      width: `${barWidth}px`,
-      backgroundColor: colors.bar,
-      borderRight: `1px solid ${colors.border}`,
+    return {
+      background: 'gray',
+      border: 'gray',
     };
-
-    return (
-      <div style={containerStyles}>
-        <div style={barStyles} />
-        <div className="bar-gauge__value" style={valueStyles}>
-          {valueFormatted}
-        </div>
-      </div>
-    );
   }
 
-  renderHorizontalLCD(valueFormatted: string, valuePercent: number) {
-    const { height, width, maxValue, minValue } = this.props;
+  renderRetroBars(): ReactNode {
+    const { height, width, maxValue, minValue, value } = this.props;
 
     const valueRange = maxValue - minValue;
-    const maxWidth = width * BAR_SIZE_RATIO;
-    const cellSpacing = 4;
-    const cellCount = 30;
-    const cellWidth = (maxWidth - cellSpacing * cellCount) / cellCount;
+    const maxSize = this.size * BAR_SIZE_RATIO;
+    const cellSpacing = 5;
+    const cellCount = maxSize / 20;
+    const cellSize = (maxSize - cellSpacing * cellCount) / cellCount;
     const colors = this.getValueColors();
-    const valueStyles = this.getValueStyles(valueFormatted, colors.value, width * (1 - BAR_SIZE_RATIO));
-    valueStyles.marginLeft = '8px';
+    const spaceForText = this.isVertical ? width : Math.min(this.size - maxSize, height);
+    const valueStyles = this.getValueStyles(value.text, colors.value, spaceForText);
 
     const containerStyles: CSSProperties = {
       width: `${width}px`,
       height: `${height}px`,
       display: 'flex',
-      flexDirection: 'row',
-      alignItems: 'center',
     };
 
+    if (this.isVertical) {
+      containerStyles.flexDirection = 'column-reverse';
+      containerStyles.alignItems = 'center';
+      valueStyles.marginBottom = '20px';
+    } else {
+      containerStyles.flexDirection = 'row';
+      containerStyles.alignItems = 'center';
+      valueStyles.marginLeft = '20px';
+    }
+
     const cells: JSX.Element[] = [];
 
     for (let i = 0; i < cellCount; i++) {
       const currentValue = (valueRange / cellCount) * i;
       const cellColor = this.getCellColor(currentValue);
       const cellStyles: CSSProperties = {
-        width: `${cellWidth}px`,
-        backgroundColor: cellColor,
-        marginRight: '4px',
-        height: `${height}px`,
         borderRadius: '2px',
       };
 
+      if (cellColor.isLit) {
+        cellStyles.boxShadow = `0 0 4px ${cellColor.border}`;
+        cellStyles.backgroundImage = `radial-gradient(${cellColor.background} 10%, ${cellColor.backgroundShade})`;
+      } else {
+        cellStyles.backgroundColor = cellColor.background;
+      }
+
+      if (this.isVertical) {
+        cellStyles.height = `${cellSize}px`;
+        cellStyles.width = `${width}px`;
+        cellStyles.marginTop = `${cellSpacing}px`;
+      } else {
+        cellStyles.width = `${cellSize}px`;
+        cellStyles.height = `${height}px`;
+        cellStyles.marginRight = `${cellSpacing}px`;
+      }
+
       cells.push(<div style={cellStyles} />);
     }
 
@@ -199,26 +285,22 @@ export class BarGauge extends PureComponent<Props> {
       <div style={containerStyles}>
         {cells}
         <div className="bar-gauge__value" style={valueStyles}>
-          {valueFormatted}
+          {value.text}
         </div>
       </div>
     );
   }
-
-  render() {
-    const { maxValue, minValue, orientation, value } = this.props;
-
-    const valuePercent = Math.min(value.numeric / (maxValue - minValue), 1);
-    const vertical = orientation === 'vertical';
-
-    return vertical
-      ? this.renderVerticalBar(value.text, valuePercent)
-      : this.renderHorizontalLCD(value.text, valuePercent);
-  }
 }
 
 interface BarColors {
   value: string;
-  bar: string;
+  background: string;
+  border: string;
+}
+
+interface CellColors {
+  background: string;
+  backgroundShade?: string;
   border: string;
+  isLit?: boolean;
 }

+ 15 - 331
packages/grafana-ui/src/components/BarGauge/__snapshots__/BarGauge.test.tsx.snap

@@ -6,353 +6,37 @@ exports[`Render BarGauge with basic options should render 1`] = `
     Object {
       "alignItems": "center",
       "display": "flex",
-      "flexDirection": "row",
+      "flexDirection": "row-reverse",
       "height": "300px",
+      "justifyContent": "flex-end",
       "width": "300px",
     }
   }
 >
   <div
+    className="bar-gauge__value"
     style={
       Object {
-        "backgroundColor": "rgba(126, 178, 109, 0.7)",
-        "borderRadius": "2px",
-        "height": "300px",
-        "marginRight": "4px",
-        "width": "4px",
-      }
-    }
-  />
-  <div
-    style={
-      Object {
-        "backgroundColor": "rgba(126, 178, 109, 0.7)",
-        "borderRadius": "2px",
-        "height": "300px",
-        "marginRight": "4px",
-        "width": "4px",
-      }
-    }
-  />
-  <div
-    style={
-      Object {
-        "backgroundColor": "rgba(126, 178, 109, 0.7)",
-        "borderRadius": "2px",
-        "height": "300px",
-        "marginRight": "4px",
-        "width": "4px",
-      }
-    }
-  />
-  <div
-    style={
-      Object {
-        "backgroundColor": "rgba(126, 178, 109, 0.7)",
-        "borderRadius": "2px",
-        "height": "300px",
-        "marginRight": "4px",
-        "width": "4px",
-      }
-    }
-  />
-  <div
-    style={
-      Object {
-        "backgroundColor": "rgba(126, 178, 109, 0.7)",
-        "borderRadius": "2px",
-        "height": "300px",
-        "marginRight": "4px",
-        "width": "4px",
-      }
-    }
-  />
-  <div
-    style={
-      Object {
-        "backgroundColor": "rgba(126, 178, 109, 0.7)",
-        "borderRadius": "2px",
-        "height": "300px",
-        "marginRight": "4px",
-        "width": "4px",
-      }
-    }
-  />
-  <div
-    style={
-      Object {
-        "backgroundColor": "rgba(126, 178, 109, 0.7)",
-        "borderRadius": "2px",
-        "height": "300px",
-        "marginRight": "4px",
-        "width": "4px",
-      }
-    }
-  />
-  <div
-    style={
-      Object {
-        "backgroundColor": "rgba(126, 178, 109, 0.7)",
-        "borderRadius": "2px",
-        "height": "300px",
-        "marginRight": "4px",
-        "width": "4px",
-      }
-    }
-  />
-  <div
-    style={
-      Object {
-        "backgroundColor": "rgba(126, 178, 109, 0.15)",
-        "borderRadius": "2px",
-        "height": "300px",
-        "marginRight": "4px",
-        "width": "4px",
-      }
-    }
-  />
-  <div
-    style={
-      Object {
-        "backgroundColor": "rgba(126, 178, 109, 0.15)",
-        "borderRadius": "2px",
-        "height": "300px",
-        "marginRight": "4px",
-        "width": "4px",
-      }
-    }
-  />
-  <div
-    style={
-      Object {
-        "backgroundColor": "rgba(126, 178, 109, 0.15)",
-        "borderRadius": "2px",
-        "height": "300px",
-        "marginRight": "4px",
-        "width": "4px",
-      }
-    }
-  />
-  <div
-    style={
-      Object {
-        "backgroundColor": "rgba(126, 178, 109, 0.15)",
-        "borderRadius": "2px",
-        "height": "300px",
-        "marginRight": "4px",
-        "width": "4px",
-      }
-    }
-  />
-  <div
-    style={
-      Object {
-        "backgroundColor": "rgba(126, 178, 109, 0.15)",
-        "borderRadius": "2px",
-        "height": "300px",
-        "marginRight": "4px",
-        "width": "4px",
-      }
-    }
-  />
-  <div
-    style={
-      Object {
-        "backgroundColor": "rgba(126, 178, 109, 0.15)",
-        "borderRadius": "2px",
-        "height": "300px",
-        "marginRight": "4px",
-        "width": "4px",
-      }
-    }
-  />
-  <div
-    style={
-      Object {
-        "backgroundColor": "rgba(126, 178, 109, 0.15)",
-        "borderRadius": "2px",
-        "height": "300px",
-        "marginRight": "4px",
-        "width": "4px",
-      }
-    }
-  />
-  <div
-    style={
-      Object {
-        "backgroundColor": "rgba(126, 178, 109, 0.15)",
-        "borderRadius": "2px",
-        "height": "300px",
-        "marginRight": "4px",
-        "width": "4px",
-      }
-    }
-  />
-  <div
-    style={
-      Object {
-        "backgroundColor": "rgba(126, 178, 109, 0.15)",
-        "borderRadius": "2px",
-        "height": "300px",
-        "marginRight": "4px",
-        "width": "4px",
-      }
-    }
-  />
-  <div
-    style={
-      Object {
-        "backgroundColor": "rgba(126, 178, 109, 0.15)",
-        "borderRadius": "2px",
-        "height": "300px",
-        "marginRight": "4px",
-        "width": "4px",
-      }
-    }
-  />
-  <div
-    style={
-      Object {
-        "backgroundColor": "rgba(126, 178, 109, 0.15)",
-        "borderRadius": "2px",
-        "height": "300px",
-        "marginRight": "4px",
-        "width": "4px",
-      }
-    }
-  />
-  <div
-    style={
-      Object {
-        "backgroundColor": "rgba(126, 178, 109, 0.15)",
-        "borderRadius": "2px",
-        "height": "300px",
-        "marginRight": "4px",
-        "width": "4px",
-      }
-    }
-  />
-  <div
-    style={
-      Object {
-        "backgroundColor": "rgba(126, 178, 109, 0.15)",
-        "borderRadius": "2px",
-        "height": "300px",
-        "marginRight": "4px",
-        "width": "4px",
-      }
-    }
-  />
-  <div
-    style={
-      Object {
-        "backgroundColor": "rgba(126, 178, 109, 0.15)",
-        "borderRadius": "2px",
-        "height": "300px",
-        "marginRight": "4px",
-        "width": "4px",
-      }
-    }
-  />
-  <div
-    style={
-      Object {
-        "backgroundColor": "rgba(126, 178, 109, 0.15)",
-        "borderRadius": "2px",
-        "height": "300px",
-        "marginRight": "4px",
-        "width": "4px",
-      }
-    }
-  />
-  <div
-    style={
-      Object {
-        "backgroundColor": "rgba(126, 178, 109, 0.15)",
-        "borderRadius": "2px",
-        "height": "300px",
-        "marginRight": "4px",
-        "width": "4px",
-      }
-    }
-  />
-  <div
-    style={
-      Object {
-        "backgroundColor": "rgba(126, 178, 109, 0.15)",
-        "borderRadius": "2px",
-        "height": "300px",
-        "marginRight": "4px",
-        "width": "4px",
-      }
-    }
-  />
-  <div
-    style={
-      Object {
-        "backgroundColor": "rgba(126, 178, 109, 0.15)",
-        "borderRadius": "2px",
-        "height": "300px",
-        "marginRight": "4px",
-        "width": "4px",
-      }
-    }
-  />
-  <div
-    style={
-      Object {
-        "backgroundColor": "rgba(126, 178, 109, 0.15)",
-        "borderRadius": "2px",
-        "height": "300px",
-        "marginRight": "4px",
-        "width": "4px",
-      }
-    }
-  />
-  <div
-    style={
-      Object {
-        "backgroundColor": "rgba(126, 178, 109, 0.15)",
-        "borderRadius": "2px",
-        "height": "300px",
-        "marginRight": "4px",
-        "width": "4px",
-      }
-    }
-  />
-  <div
-    style={
-      Object {
-        "backgroundColor": "rgba(126, 178, 109, 0.15)",
-        "borderRadius": "2px",
-        "height": "300px",
-        "marginRight": "4px",
-        "width": "4px",
+        "color": "#7EB26D",
+        "fontSize": "27.27272727272727px",
       }
     }
-  />
+  >
+    25
+  </div>
   <div
     style={
       Object {
-        "backgroundColor": "rgba(126, 178, 109, 0.15)",
-        "borderRadius": "2px",
+        "background": "rgba(126, 178, 109, 0.15)",
+        "border": "1px solid #7EB26D",
+        "borderRadius": "3px",
+        "boxShadow": "0 0 4px #7EB26D",
         "height": "300px",
-        "marginRight": "4px",
-        "width": "4px",
+        "marginRight": "10px",
+        "transition": "width 1s",
+        "width": "60px",
       }
     }
   />
-  <div
-    className="bar-gauge__value"
-    style={
-      Object {
-        "color": "#7EB26D",
-        "fontSize": "27.272727272727263px",
-        "marginLeft": "8px",
-      }
-    }
-  >
-    25
-  </div>
 </div>
 `;

+ 5 - 1
packages/grafana-ui/src/components/ThresholdsEditor/ThresholdsEditor.tsx

@@ -166,7 +166,11 @@ export class ThresholdsEditor extends PureComponent<Props, State> {
         <div className="thresholds-row-input-inner-color">
           {threshold.color && (
             <div className="thresholds-row-input-inner-color-colorpicker">
-              <ColorPicker color={threshold.color} onChange={color => this.onChangeThresholdColor(threshold, color)} />
+              <ColorPicker
+                color={threshold.color}
+                onChange={color => this.onChangeThresholdColor(threshold, color)}
+                enableNamedColors={true}
+              />
             </div>
           )}
         </div>

+ 3 - 0
packages/grafana-ui/src/components/ThresholdsEditor/__snapshots__/ThresholdsEditor.test.tsx.snap

@@ -83,10 +83,12 @@ exports[`Render should render with base threshold 1`] = `
                   >
                     <WithTheme(ColorPicker)
                       color="#7EB26D"
+                      enableNamedColors={true}
                       onChange={[Function]}
                     >
                       <ColorPicker
                         color="#7EB26D"
+                        enableNamedColors={true}
                         onChange={[Function]}
                         theme={
                           Object {
@@ -230,6 +232,7 @@ exports[`Render should render with base threshold 1`] = `
                           content={
                             <ColorPickerPopover
                               color="#7EB26D"
+                              enableNamedColors={true}
                               onChange={[Function]}
                               theme={
                                 Object {

+ 1 - 0
public/app/plugins/panel/bargauge/BarGaugePanel.tsx

@@ -22,6 +22,7 @@ export class BarGaugePanel extends PureComponent<PanelProps<BarGaugeOptions>> {
         orientation={options.orientation}
         thresholds={options.thresholds}
         theme={config.theme}
+        displayMode={options.displayMode}
       />
     );
   };

+ 12 - 1
public/app/plugins/panel/bargauge/BarGaugePanelEditor.tsx

@@ -6,7 +6,7 @@ import { ThresholdsEditor, ValueMappingsEditor, PanelOptionsGrid, PanelOptionsGr
 
 // Types
 import { FormLabel, PanelEditorProps, Threshold, Select, ValueMapping } from '@grafana/ui';
-import { BarGaugeOptions, orientationOptions } from './types';
+import { BarGaugeOptions, orientationOptions, displayModes } from './types';
 import { SingleStatValueEditor } from '../singlestat2/SingleStatValueEditor';
 import { SingleStatValueOptions } from '../singlestat2/types';
 
@@ -32,6 +32,7 @@ export class BarGaugePanelEditor extends PureComponent<PanelEditorProps<BarGauge
   onMinValueChange = ({ target }) => this.props.onOptionsChange({ ...this.props.options, minValue: target.value });
   onMaxValueChange = ({ target }) => this.props.onOptionsChange({ ...this.props.options, maxValue: target.value });
   onOrientationChange = ({ value }) => this.props.onOptionsChange({ ...this.props.options, orientation: value });
+  onDisplayModeChange = ({ value }) => this.props.onOptionsChange({ ...this.props.options, displayMode: value });
 
   render() {
     const { options } = this.props;
@@ -53,6 +54,16 @@ export class BarGaugePanelEditor extends PureComponent<PanelEditorProps<BarGauge
                 value={orientationOptions.find(item => item.value === options.orientation)}
               />
             </div>
+            <div className="form-field">
+              <FormLabel width={8}>Display Mode</FormLabel>
+              <Select
+                width={12}
+                options={displayModes}
+                defaultValue={displayModes[0]}
+                onChange={this.onDisplayModeChange}
+                value={displayModes.find(item => item.value === options.displayMode)}
+              />
+            </div>
           </PanelOptionsGroup>
           <ThresholdsEditor onChange={this.onThresholdsChanged} thresholds={options.thresholds} />
         </PanelOptionsGrid>

+ 13 - 6
public/app/plugins/panel/bargauge/types.ts

@@ -1,20 +1,27 @@
 import { VizOrientation, SelectOptionItem } from '@grafana/ui';
-
 import { SingleStatBaseOptions } from '../singlestat2/types';
 
-export const orientationOptions: SelectOptionItem[] = [
-  { value: VizOrientation.Horizontal, label: 'Horizontal' },
-  { value: VizOrientation.Vertical, label: 'Vertical' },
-];
-
 export interface BarGaugeOptions extends SingleStatBaseOptions {
   minValue: number;
   maxValue: number;
+  displayMode: 'basic' | 'lcd' | 'gradient';
 }
 
+export const displayModes: SelectOptionItem[] = [
+  { value: 'gradient', label: 'Gradient' },
+  { value: 'lcd', label: 'Retro LCD' },
+  { value: 'basic', label: 'Basic' },
+];
+
+export const orientationOptions: SelectOptionItem[] = [
+  { value: VizOrientation.Horizontal, label: 'Horizontal' },
+  { value: VizOrientation.Vertical, label: 'Vertical' },
+];
+
 export const defaults: BarGaugeOptions = {
   minValue: 0,
   maxValue: 100,
+  displayMode: 'lcd',
   orientation: VizOrientation.Horizontal,
   valueOptions: {
     unit: 'none',