diff --git a/docs/sources/developers/kinds/composable/gauge/panelcfg/schema-reference.md b/docs/sources/developers/kinds/composable/gauge/panelcfg/schema-reference.md index ca914cea6c8..be536fd6df6 100644 --- a/docs/sources/developers/kinds/composable/gauge/panelcfg/schema-reference.md +++ b/docs/sources/developers/kinds/composable/gauge/panelcfg/schema-reference.md @@ -28,6 +28,8 @@ It extends [SingleStatBaseOptions](#singlestatbaseoptions). | Property | Type | Required | Default | Description | |------------------------|-------------------------------------------------|----------|---------|---------------------------------------------------------------------------------------------------------------------------------------------| +| `minVizHeight` | uint32 | **Yes** | `75` | | +| `minVizWidth` | uint32 | **Yes** | `75` | | | `showThresholdLabels` | boolean | **Yes** | `false` | | | `showThresholdMarkers` | boolean | **Yes** | `true` | | | `orientation` | string | No | | *(Inherited from [SingleStatBaseOptions](#singlestatbaseoptions))*
TODO docs
Possible values are: `auto`, `vertical`, `horizontal`. | diff --git a/packages/grafana-schema/src/raw/composable/gauge/panelcfg/x/GaugePanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/gauge/panelcfg/x/GaugePanelCfg_types.gen.ts index 72a7217a93a..2f69f4ac276 100644 --- a/packages/grafana-schema/src/raw/composable/gauge/panelcfg/x/GaugePanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/gauge/panelcfg/x/GaugePanelCfg_types.gen.ts @@ -14,11 +14,15 @@ import * as common from '@grafana/schema'; export const pluginVersion = "10.2.0-pre"; export interface Options extends common.SingleStatBaseOptions { + minVizHeight: number; + minVizWidth: number; showThresholdLabels: boolean; showThresholdMarkers: boolean; } export const defaultOptions: Partial = { + minVizHeight: 75, + minVizWidth: 75, showThresholdLabels: false, showThresholdMarkers: true, }; diff --git a/packages/grafana-ui/src/components/Gauge/Gauge.tsx b/packages/grafana-ui/src/components/Gauge/Gauge.tsx index a605b422429..c1fc9d8a3bf 100644 --- a/packages/grafana-ui/src/components/Gauge/Gauge.tsx +++ b/packages/grafana-ui/src/components/Gauge/Gauge.tsx @@ -10,7 +10,7 @@ import { GAUGE_DEFAULT_MINIMUM, GrafanaTheme2, } from '@grafana/data'; -import { VizTextDisplayOptions } from '@grafana/schema'; +import { VizTextDisplayOptions, VizOrientation } from '@grafana/schema'; import { calculateFontSize } from '../../utils/measureText'; import { clearButtonStyles } from '../Button'; @@ -28,6 +28,7 @@ export interface Props { onClick?: React.MouseEventHandler; className?: string; theme: GrafanaTheme2; + orientation?: VizOrientation; } export class Gauge extends PureComponent { @@ -52,17 +53,19 @@ export class Gauge extends PureComponent { } draw() { - const { field, showThresholdLabels, showThresholdMarkers, width, height, theme, value } = this.props; + const { field, showThresholdLabels, showThresholdMarkers, width, height, theme, value, orientation } = this.props; const autoProps = calculateGaugeAutoProps(width, height, value.title); - const dimension = Math.min(width, autoProps.gaugeHeight); + // If the gauge is in vertical layout, we need to set the width of the gauge to the height of the gauge + const calculatedGaugeWidth = orientation === VizOrientation.Vertical ? autoProps.gaugeHeight : width; + const dimension = Math.min(calculatedGaugeWidth, autoProps.gaugeHeight); const backgroundColor = theme.colors.background.secondary; const gaugeWidthReduceRatio = showThresholdLabels ? 1.5 : 1; const gaugeWidth = Math.min(dimension / 5.5, 40) / gaugeWidthReduceRatio; const thresholdMarkersWidth = gaugeWidth / 5; const text = formattedValueToString(value); // This not 100% accurate as I am unsure of flot's calculations here - const valueWidthBase = Math.min(width, dimension * 1.3) * 0.9; + const valueWidthBase = Math.min(calculatedGaugeWidth, dimension * 1.3) * 0.9; // remove gauge & marker width (on left and right side) // and 10px is some padding that flot adds to the outer canvas const valueWidth = @@ -145,11 +148,15 @@ export class Gauge extends PureComponent { } renderVisualization = () => { - const { width, value, height, onClick, text, theme } = this.props; - const autoProps = calculateGaugeAutoProps(width, height, value.title); + const { width, value, height, onClick, text, theme, orientation } = this.props; + const autoProps = calculateGaugeAutoProps(width, height, value.title, orientation); + + // If the gauge is in vertical layout, we need to set the width of the gauge to the height of the gauge + const gaugeWidth = orientation === VizOrientation.Vertical ? `${autoProps.gaugeHeight}px` : '100%'; + const gaugeElement = (
(this.canvasElement = element)} /> ); @@ -172,7 +179,7 @@ export class Gauge extends PureComponent { textOverflow: 'ellipsis', whiteSpace: 'nowrap', position: 'relative', - width: '100%', + width: gaugeWidth, top: '-4px', cursor: 'default', }} diff --git a/packages/grafana-ui/src/components/Gauge/utils.test.ts b/packages/grafana-ui/src/components/Gauge/utils.test.ts index 45720c01a3c..0aef2c93d3f 100644 --- a/packages/grafana-ui/src/components/Gauge/utils.test.ts +++ b/packages/grafana-ui/src/components/Gauge/utils.test.ts @@ -1,8 +1,9 @@ import { FieldColorModeId, FieldConfig, ThresholdsMode } from '@grafana/data'; +import { VizOrientation } from '@grafana/schema'; import { getTheme } from '../../themes'; -import { getFormattedThresholds } from './utils'; +import { calculateGaugeAutoProps, getFormattedThresholds } from './utils'; describe('getFormattedThresholds', () => { const value = { @@ -53,3 +54,49 @@ describe('getFormattedThresholds', () => { ]); }); }); + +describe('calculateGaugeAutoProps', () => { + it('should calculate gauge properties correctly when title is undefined', () => { + const width = 200; + const height = 300; + const orientation = VizOrientation.Horizontal; + const title = undefined; + + const result = calculateGaugeAutoProps(width, height, title, orientation); + + expect(result.showLabel).toBe(false); + expect(result.gaugeHeight).toBe(200); + expect(result.titleFontSize).toBe(20); + }); + + it('should calculate gauge properties correctly when title is defined', () => { + const width = 200; + const height = 300; + const orientation = VizOrientation.Vertical; + const title = 'My Gauge'; + + const result = calculateGaugeAutoProps(width, height, title, orientation); + + expect(result.showLabel).toBe(true); + expect(result.gaugeHeight).toBe(200); + expect(result.titleFontSize).toBe(20); + }); + + it('should calculate gauge properties correctly for vertical and horizontal orientations', () => { + const width = 100; + const height = 150; + const title = 'My Gauge'; + + // Test for vertical orientation + const verticalResult = calculateGaugeAutoProps(width, height, title, VizOrientation.Vertical); + expect(verticalResult.showLabel).toBe(true); + expect(verticalResult.gaugeHeight).toBe(100); + expect(verticalResult.titleFontSize).toBe(15); + + // Test for horizontal orientation + const horizontalResult = calculateGaugeAutoProps(width, height, title, VizOrientation.Horizontal); + expect(horizontalResult.showLabel).toBe(true); + expect(horizontalResult.gaugeHeight).toBe(100); + expect(horizontalResult.titleFontSize).toBe(10); + }); +}); diff --git a/packages/grafana-ui/src/components/Gauge/utils.ts b/packages/grafana-ui/src/components/Gauge/utils.ts index bfc6ab930da..4ca51fcd10b 100644 --- a/packages/grafana-ui/src/components/Gauge/utils.ts +++ b/packages/grafana-ui/src/components/Gauge/utils.ts @@ -12,6 +12,7 @@ import { ThresholdsConfig, ThresholdsMode, } from '@grafana/data'; +import { VizOrientation } from '@grafana/schema'; interface GaugeAutoProps { titleFontSize: number; @@ -27,9 +28,15 @@ export const DEFAULT_THRESHOLDS: ThresholdsConfig = { ], }; -export function calculateGaugeAutoProps(width: number, height: number, title: string | undefined): GaugeAutoProps { +export function calculateGaugeAutoProps( + width: number, + height: number, + title: string | undefined, + orientation?: VizOrientation +): GaugeAutoProps { const showLabel = title !== null && title !== undefined; - const titleFontSize = Math.min((width * 0.15) / 1.5, 20); // 20% of height * line-height, max 40px + const titleFontSizeDimension = orientation === VizOrientation.Vertical ? height : width; + const titleFontSize = Math.min((titleFontSizeDimension * 0.15) / 1.5, 20); // 20% of height * line-height, max 40px const titleHeight = titleFontSize * 1.5; const availableHeight = showLabel ? height - titleHeight : height; const gaugeHeight = Math.min(availableHeight, width); diff --git a/public/app/plugins/panel/gauge/GaugePanel.tsx b/public/app/plugins/panel/gauge/GaugePanel.tsx index 670a9d09bfe..ee4b622e710 100644 --- a/public/app/plugins/panel/gauge/GaugePanel.tsx +++ b/public/app/plugins/panel/gauge/GaugePanel.tsx @@ -31,6 +31,7 @@ export class GaugePanel extends PureComponent> { theme={config.theme2} onClick={openMenu} className={targetClassName} + orientation={options.orientation} /> ); }; @@ -90,6 +91,8 @@ export class GaugePanel extends PureComponent> { autoGrid={true} renderCounter={renderCounter} orientation={options.orientation} + minVizHeight={options.minVizHeight} + minVizWidth={options.minVizWidth} /> ); } diff --git a/public/app/plugins/panel/gauge/module.tsx b/public/app/plugins/panel/gauge/module.tsx index 23b1b7369c5..c62938bf84a 100644 --- a/public/app/plugins/panel/gauge/module.tsx +++ b/public/app/plugins/panel/gauge/module.tsx @@ -1,4 +1,5 @@ import { PanelPlugin } from '@grafana/data'; +import { VizOrientation } from '@grafana/schema'; import { commonOptionsBuilder } from '@grafana/ui'; import { addOrientationOption, addStandardDataReduceOptions } from '../stat/common'; @@ -37,6 +38,20 @@ export const plugin = new PanelPlugin(GaugePanel) name: 'Show threshold markers', description: 'Renders the thresholds as an outer bar', defaultValue: defaultOptions.showThresholdMarkers, + }) + .addNumberInput({ + path: 'minVizWidth', + name: 'Min width', + description: 'Minimum column width', + defaultValue: defaultOptions.minVizWidth, + showIf: (options: Options) => options.orientation === VizOrientation.Vertical, + }) + .addNumberInput({ + path: 'minVizHeight', + name: 'Min height', + description: 'Minimum row height', + defaultValue: defaultOptions.minVizHeight, + showIf: (options: Options) => options.orientation === VizOrientation.Horizontal, }); commonOptionsBuilder.addTextSizeOptions(builder); diff --git a/public/app/plugins/panel/gauge/panelcfg.cue b/public/app/plugins/panel/gauge/panelcfg.cue index 055f22bbade..b3fc121d0eb 100644 --- a/public/app/plugins/panel/gauge/panelcfg.cue +++ b/public/app/plugins/panel/gauge/panelcfg.cue @@ -29,6 +29,8 @@ composableKinds: PanelCfg: { common.SingleStatBaseOptions showThresholdLabels: bool | *false showThresholdMarkers: bool | *true + minVizWidth: uint32 | *75 + minVizHeight: uint32 | *75 } @cuetsy(kind="interface") } }] diff --git a/public/app/plugins/panel/gauge/panelcfg.gen.ts b/public/app/plugins/panel/gauge/panelcfg.gen.ts index dc70c8e5c4c..742a66a1ea8 100644 --- a/public/app/plugins/panel/gauge/panelcfg.gen.ts +++ b/public/app/plugins/panel/gauge/panelcfg.gen.ts @@ -11,11 +11,15 @@ import * as common from '@grafana/schema'; export interface Options extends common.SingleStatBaseOptions { + minVizHeight: number; + minVizWidth: number; showThresholdLabels: boolean; showThresholdMarkers: boolean; } export const defaultOptions: Partial = { + minVizHeight: 75, + minVizWidth: 75, showThresholdLabels: false, showThresholdMarkers: true, };