Commit 2e079659 by ryan

use display value in pie chart

parent 0f0f76b6
......@@ -2,26 +2,20 @@ import React, { PureComponent } from 'react';
import { select, pie, arc, event } from 'd3';
import { sum } from 'lodash';
import { GrafanaThemeType } from '../../types';
import { GrafanaThemeType, DisplayValue } from '../../types';
import { Themeable } from '../../index';
import { colors as grafana_colors } from '../../utils/index';
export enum PieChartType {
PIE = 'pie',
DONUT = 'donut',
}
export interface PieChartDataPoint {
value: number;
name: string;
color: string;
}
export interface Props extends Themeable {
height: number;
width: number;
datapoints: PieChartDataPoint[];
values: DisplayValue[];
unit: string;
pieType: PieChartType;
strokeWidth: number;
}
......@@ -49,15 +43,20 @@ export class PieChart extends PureComponent<Props> {
}
draw() {
const { datapoints, pieType, strokeWidth } = this.props;
const { values, pieType, strokeWidth } = this.props;
if (datapoints.length === 0) {
if (values.length === 0) {
return;
}
const data = datapoints.map(datapoint => datapoint.value);
const names = datapoints.map(datapoint => datapoint.name);
const colors = datapoints.map(datapoint => datapoint.color);
const data = values.map(datapoint => datapoint.numeric);
const names = values.map(datapoint => datapoint.text);
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 percents = data.map((item: number) => (item / total) * 100);
......@@ -108,9 +107,9 @@ export class PieChart extends PureComponent<Props> {
}
render() {
const { height, width, datapoints } = this.props;
const { height, width, values } = this.props;
if (datapoints.length > 0) {
if (values.length > 0) {
return (
<div className="piechart-panel">
<div
......
......@@ -25,7 +25,7 @@ export { PanelOptionsGrid } from './PanelOptionsGrid/PanelOptionsGrid';
export { ValueMappingsEditor } from './ValueMappingsEditor/ValueMappingsEditor';
export { Switch } from './Switch/Switch';
export { EmptySearchResult } from './EmptySearchResult/EmptySearchResult';
export { PieChart, PieChartDataPoint, PieChartType } from './PieChart/PieChart';
export { PieChart, PieChartType } from './PieChart/PieChart';
export { UnitPicker } from './UnitPicker/UnitPicker';
export { StatsPicker } from './StatsPicker/StatsPicker';
export { Input, InputStatus } from './Input/Input';
......
......@@ -2,56 +2,34 @@
import React, { PureComponent } from 'react';
// Services & Utils
import { processTimeSeries, ThemeContext } from '@grafana/ui';
import { config } from 'app/core/config';
// Components
import { PieChart, PieChartDataPoint } from '@grafana/ui';
import { PieChart } from '@grafana/ui';
// 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> {}
export class PieChartPanel extends PureComponent<Props> {
render() {
const { data, width, height, options } = this.props;
const { valueOptions } = options;
const { width, height, options } = this.props;
const datapoints: PieChartDataPoint[] = [];
if (data) {
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
// TODO -- only process when the data/config changes
const values = getSingleStatValues(this.props);
return (
<ThemeContext.Consumer>
{theme => (
<PieChart
width={width}
height={height}
datapoints={datapoints}
pieType={options.pieType}
strokeWidth={options.strokeWidth}
unit={valueOptions.unit}
theme={theme}
/>
)}
</ThemeContext.Consumer>
<PieChart
width={width}
height={height}
values={values}
pieType={options.pieType}
strokeWidth={options.strokeWidth}
theme={config.theme}
/>
);
}
}
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 { 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>> {
onValueOptionsChanged = (valueOptions: PieChartValueOptions) =>
onValueMappingsChanged = (valueMappings: ValueMapping[]) =>
this.props.onOptionsChange({
...this.props.options,
valueMappings,
});
onValueOptionsChanged = (valueOptions: SingleStatValueOptions) =>
this.props.onOptionsChange({
...this.props.options,
valueOptions,
......@@ -18,9 +25,11 @@ export default class PieChartPanelEditor extends PureComponent<PanelEditorProps<
return (
<>
<PanelOptionsGrid>
<PieChartValueEditor onChange={this.onValueOptionsChanged} options={options.valueOptions} />
<SingleStatValueEditor onChange={this.onValueOptionsChanged} options={options.valueOptions} />
<PieChartOptionsBox onOptionsChange={onOptionsChange} options={options} />
</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';
import PieChartPanelEditor from './PieChartPanelEditor';
import { PieChartPanel } from './PieChartPanel';
import { PieChartOptions, defaults } from './types';
import { singleStatBaseOptionsCheck } from '../singlestat2/module';
export const reactPanel = new ReactPanelPlugin<PieChartOptions>(PieChartPanel);
reactPanel.setEditor(PieChartPanelEditor);
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;
strokeWidth: number;
valueOptions: PieChartValueOptions;
}
export interface PieChartValueOptions {
unit: string;
stat: string;
}
export const defaults: PieChartOptions = {
......@@ -16,6 +11,11 @@ export const defaults: PieChartOptions = {
strokeWidth: 1,
valueOptions: {
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