Commit 4db91457 by Torkel Ödegaard Committed by GitHub

Merge pull request #16171 from ryantxu/pie-display

use displayValue in pie chart
parents 0d62d1b4 2e079659
...@@ -2,26 +2,20 @@ import React, { PureComponent } from 'react'; ...@@ -2,26 +2,20 @@ import React, { PureComponent } from 'react';
import { select, pie, arc, event } from 'd3'; import { select, pie, arc, event } from 'd3';
import { sum } from 'lodash'; import { sum } from 'lodash';
import { GrafanaThemeType } from '../../types'; import { GrafanaThemeType, DisplayValue } from '../../types';
import { Themeable } from '../../index'; import { Themeable } from '../../index';
import { colors as grafana_colors } from '../../utils/index';
export enum PieChartType { export enum PieChartType {
PIE = 'pie', PIE = 'pie',
DONUT = 'donut', DONUT = 'donut',
} }
export interface PieChartDataPoint {
value: number;
name: string;
color: string;
}
export interface Props extends Themeable { export interface Props extends Themeable {
height: number; height: number;
width: number; width: number;
datapoints: PieChartDataPoint[]; values: DisplayValue[];
unit: string;
pieType: PieChartType; pieType: PieChartType;
strokeWidth: number; strokeWidth: number;
} }
...@@ -49,15 +43,20 @@ export class PieChart extends PureComponent<Props> { ...@@ -49,15 +43,20 @@ export class PieChart extends PureComponent<Props> {
} }
draw() { draw() {
const { datapoints, pieType, strokeWidth } = this.props; const { values, pieType, strokeWidth } = this.props;
if (datapoints.length === 0) { if (values.length === 0) {
return; return;
} }
const data = datapoints.map(datapoint => datapoint.value); const data = values.map(datapoint => datapoint.numeric);
const names = datapoints.map(datapoint => datapoint.name); const names = values.map(datapoint => datapoint.text);
const colors = datapoints.map(datapoint => datapoint.color); const colors = values.map((p, idx) => {
if (p.color) {
return p.color;
}
return grafana_colors[idx % grafana_colors.length];
});
const total = sum(data) || 1; const total = sum(data) || 1;
const percents = data.map((item: number) => (item / total) * 100); const percents = data.map((item: number) => (item / total) * 100);
...@@ -108,9 +107,9 @@ export class PieChart extends PureComponent<Props> { ...@@ -108,9 +107,9 @@ export class PieChart extends PureComponent<Props> {
} }
render() { render() {
const { height, width, datapoints } = this.props; const { height, width, values } = this.props;
if (datapoints.length > 0) { if (values.length > 0) {
return ( return (
<div className="piechart-panel"> <div className="piechart-panel">
<div <div
......
...@@ -25,7 +25,7 @@ export { PanelOptionsGrid } from './PanelOptionsGrid/PanelOptionsGrid'; ...@@ -25,7 +25,7 @@ export { PanelOptionsGrid } from './PanelOptionsGrid/PanelOptionsGrid';
export { ValueMappingsEditor } from './ValueMappingsEditor/ValueMappingsEditor'; export { ValueMappingsEditor } from './ValueMappingsEditor/ValueMappingsEditor';
export { Switch } from './Switch/Switch'; export { Switch } from './Switch/Switch';
export { EmptySearchResult } from './EmptySearchResult/EmptySearchResult'; export { EmptySearchResult } from './EmptySearchResult/EmptySearchResult';
export { PieChart, PieChartDataPoint, PieChartType } from './PieChart/PieChart'; export { PieChart, PieChartType } from './PieChart/PieChart';
export { UnitPicker } from './UnitPicker/UnitPicker'; export { UnitPicker } from './UnitPicker/UnitPicker';
export { StatsPicker } from './StatsPicker/StatsPicker'; export { StatsPicker } from './StatsPicker/StatsPicker';
export { Input, InputStatus } from './Input/Input'; export { Input, InputStatus } from './Input/Input';
......
...@@ -2,56 +2,34 @@ ...@@ -2,56 +2,34 @@
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
// Services & Utils // Services & Utils
import { processTimeSeries, ThemeContext } from '@grafana/ui'; import { config } from 'app/core/config';
// Components // Components
import { PieChart, PieChartDataPoint } from '@grafana/ui'; import { PieChart } from '@grafana/ui';
// Types // Types
import { PieChartOptions } from './types'; import { PieChartOptions } from './types';
import { PanelProps, NullValueMode } from '@grafana/ui/src/types'; import { PanelProps } from '@grafana/ui/src/types';
import { getSingleStatValues } from '../singlestat2/SingleStatPanel';
interface Props extends PanelProps<PieChartOptions> {} interface Props extends PanelProps<PieChartOptions> {}
export class PieChartPanel extends PureComponent<Props> { export class PieChartPanel extends PureComponent<Props> {
render() { render() {
const { data, width, height, options } = this.props; const { width, height, options } = this.props;
const { valueOptions } = options;
const datapoints: PieChartDataPoint[] = []; // TODO -- only process when the data/config changes
if (data) { const values = getSingleStatValues(this.props);
const vmSeries = processTimeSeries({
data,
nullValueMode: NullValueMode.Null,
});
for (let i = 0; i < vmSeries.length; i++) {
const serie = vmSeries[i];
if (serie) {
datapoints.push({
value: serie.stats[valueOptions.stat],
name: serie.label,
color: serie.color,
});
}
}
}
// TODO: support table data
return ( return (
<ThemeContext.Consumer>
{theme => (
<PieChart <PieChart
width={width} width={width}
height={height} height={height}
datapoints={datapoints} values={values}
pieType={options.pieType} pieType={options.pieType}
strokeWidth={options.strokeWidth} strokeWidth={options.strokeWidth}
unit={valueOptions.unit} theme={config.theme}
theme={theme}
/> />
)}
</ThemeContext.Consumer>
); );
} }
} }
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { PanelEditorProps, PanelOptionsGrid } from '@grafana/ui'; import { PanelEditorProps, PanelOptionsGrid, ValueMappingsEditor, ValueMapping } from '@grafana/ui';
import PieChartValueEditor from './PieChartValueEditor';
import { PieChartOptionsBox } from './PieChartOptionsBox'; import { PieChartOptionsBox } from './PieChartOptionsBox';
import { PieChartOptions, PieChartValueOptions } from './types'; import { PieChartOptions } from './types';
import { SingleStatValueEditor } from '../singlestat2/SingleStatValueEditor';
import { SingleStatValueOptions } from '../singlestat2/types';
export default class PieChartPanelEditor extends PureComponent<PanelEditorProps<PieChartOptions>> { export default class PieChartPanelEditor extends PureComponent<PanelEditorProps<PieChartOptions>> {
onValueOptionsChanged = (valueOptions: PieChartValueOptions) => onValueMappingsChanged = (valueMappings: ValueMapping[]) =>
this.props.onOptionsChange({
...this.props.options,
valueMappings,
});
onValueOptionsChanged = (valueOptions: SingleStatValueOptions) =>
this.props.onOptionsChange({ this.props.onOptionsChange({
...this.props.options, ...this.props.options,
valueOptions, valueOptions,
...@@ -18,9 +25,11 @@ export default class PieChartPanelEditor extends PureComponent<PanelEditorProps< ...@@ -18,9 +25,11 @@ export default class PieChartPanelEditor extends PureComponent<PanelEditorProps<
return ( return (
<> <>
<PanelOptionsGrid> <PanelOptionsGrid>
<PieChartValueEditor onChange={this.onValueOptionsChanged} options={options.valueOptions} /> <SingleStatValueEditor onChange={this.onValueOptionsChanged} options={options.valueOptions} />
<PieChartOptionsBox onOptionsChange={onOptionsChange} options={options} /> <PieChartOptionsBox onOptionsChange={onOptionsChange} options={options} />
</PanelOptionsGrid> </PanelOptionsGrid>
<ValueMappingsEditor onChange={this.onValueMappingsChanged} valueMappings={options.valueMappings} />
</> </>
); );
} }
......
import React, { PureComponent } from 'react';
import { FormLabel, PanelOptionsGroup, Select, UnitPicker } from '@grafana/ui';
import { PieChartValueOptions } from './types';
const statOptions = [
{ value: 'min', label: 'Min' },
{ value: 'max', label: 'Max' },
{ value: 'avg', label: 'Average' },
{ value: 'current', label: 'Current' },
{ value: 'total', label: 'Total' },
];
const labelWidth = 6;
export interface Props {
options: PieChartValueOptions;
onChange: (valueOptions: PieChartValueOptions) => void;
}
export default class PieChartValueEditor extends PureComponent<Props> {
onUnitChange = unit =>
this.props.onChange({
...this.props.options,
unit: unit.value,
});
onStatChange = stat =>
this.props.onChange({
...this.props.options,
stat: stat.value,
});
render() {
const { stat, unit } = this.props.options;
return (
<PanelOptionsGroup title="Value">
<div className="gf-form">
<FormLabel width={labelWidth}>Unit</FormLabel>
<UnitPicker defaultValue={unit} onChange={this.onUnitChange} />
</div>
<div className="gf-form">
<FormLabel width={labelWidth}>Value</FormLabel>
<Select
width={12}
options={statOptions}
onChange={this.onStatChange}
value={statOptions.find(option => option.value === stat)}
/>
</div>
</PanelOptionsGroup>
);
}
}
...@@ -3,8 +3,10 @@ import { ReactPanelPlugin } from '@grafana/ui'; ...@@ -3,8 +3,10 @@ import { ReactPanelPlugin } from '@grafana/ui';
import PieChartPanelEditor from './PieChartPanelEditor'; import PieChartPanelEditor from './PieChartPanelEditor';
import { PieChartPanel } from './PieChartPanel'; import { PieChartPanel } from './PieChartPanel';
import { PieChartOptions, defaults } from './types'; import { PieChartOptions, defaults } from './types';
import { singleStatBaseOptionsCheck } from '../singlestat2/module';
export const reactPanel = new ReactPanelPlugin<PieChartOptions>(PieChartPanel); export const reactPanel = new ReactPanelPlugin<PieChartOptions>(PieChartPanel);
reactPanel.setEditor(PieChartPanelEditor); reactPanel.setEditor(PieChartPanelEditor);
reactPanel.setDefaults(defaults); reactPanel.setDefaults(defaults);
reactPanel.setPanelTypeChangedHook(singleStatBaseOptionsCheck);
import { PieChartType } from '@grafana/ui'; import { PieChartType, StatID, VizOrientation } from '@grafana/ui';
import { SingleStatBaseOptions } from '../singlestat2/types';
export interface PieChartOptions { export interface PieChartOptions extends SingleStatBaseOptions {
pieType: PieChartType; pieType: PieChartType;
strokeWidth: number; strokeWidth: number;
valueOptions: PieChartValueOptions;
}
export interface PieChartValueOptions {
unit: string;
stat: string;
} }
export const defaults: PieChartOptions = { export const defaults: PieChartOptions = {
...@@ -16,6 +11,11 @@ export const defaults: PieChartOptions = { ...@@ -16,6 +11,11 @@ export const defaults: PieChartOptions = {
strokeWidth: 1, strokeWidth: 1,
valueOptions: { valueOptions: {
unit: 'short', unit: 'short',
stat: 'current', stat: StatID.last,
suffix: '',
prefix: '',
}, },
valueMappings: [],
thresholds: [],
orientation: VizOrientation.Auto,
}; };
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment