diff --git a/devenv/dev-dashboards/panel-piechart/panel_test_piechart.json b/devenv/dev-dashboards/panel-piechart/panel_test_piechart.json index 47dee6a2639..08e94e66e2e 100644 --- a/devenv/dev-dashboards/panel-piechart/panel_test_piechart.json +++ b/devenv/dev-dashboards/panel-piechart/panel_test_piechart.json @@ -23,7 +23,7 @@ "fieldConfig": { "defaults": { "color": { - "mode": "palette-saturated" + "mode": "palette-classic" }, "custom": {}, "decimals": 1, @@ -86,7 +86,7 @@ "fieldConfig": { "defaults": { "color": { - "mode": "palette-saturated" + "mode": "palette-classic" }, "custom": {}, "decimals": 1, @@ -149,7 +149,7 @@ "fieldConfig": { "defaults": { "color": { - "mode": "palette-saturated" + "mode": "palette-classic" }, "custom": {}, "mappings": [], @@ -210,7 +210,7 @@ "fieldConfig": { "defaults": { "color": { - "mode": "palette-saturated" + "mode": "palette-classic" }, "custom": {}, "mappings": [], @@ -271,7 +271,7 @@ "fieldConfig": { "defaults": { "color": { - "mode": "palette-saturated" + "mode": "palette-classic" }, "custom": {}, "mappings": [], @@ -332,7 +332,7 @@ "fieldConfig": { "defaults": { "color": { - "mode": "palette-saturated" + "mode": "palette-classic" }, "custom": {}, "mappings": [], diff --git a/packages/grafana-ui/src/components/PieChart/PieChart.tsx b/packages/grafana-ui/src/components/PieChart/PieChart.tsx index 9f01d7c0856..89e8f3f8aa0 100644 --- a/packages/grafana-ui/src/components/PieChart/PieChart.tsx +++ b/packages/grafana-ui/src/components/PieChart/PieChart.tsx @@ -1,5 +1,5 @@ import React, { FC } from 'react'; -import { DisplayValue, formattedValueToString, GrafanaTheme } from '@grafana/data'; +import { DisplayValue, FALLBACK_COLOR, formattedValueToString, GrafanaTheme } from '@grafana/data'; import { useStyles, useTheme } from '../../themes/ThemeContext'; import tinycolor from 'tinycolor2'; import Pie, { PieArcDatum } from '@visx/shape/lib/shapes/Pie'; @@ -9,13 +9,20 @@ import { localPoint } from '@visx/event'; import { useTooltip, useTooltipInPortal } from '@visx/tooltip'; import { useComponentInstanceId } from '../../utils/useComponetInstanceId'; import { css } from 'emotion'; +import { VizLegend, VizLegendItem } from '..'; +import { VizLayout } from '../VizLayout/VizLayout'; +import { LegendDisplayMode, VizLegendOptions } from '../VizLegend/types'; -export interface Props { +interface SvgProps { height: number; width: number; values: DisplayValue[]; pieType: PieChartType; labelOptions?: PieChartLabelOptions; + useGradients?: boolean; +} +export interface Props extends SvgProps { + legendOptions?: VizLegendOptions; } export enum PieChartType { @@ -29,7 +36,48 @@ export interface PieChartLabelOptions { showPercent?: boolean; } -export const PieChart: FC = ({ values, pieType, width, height, labelOptions = { showName: true } }) => { +const defaultLegendOptions: VizLegendOptions = { + displayMode: LegendDisplayMode.List, + placement: 'right', + calcs: [], +}; + +export const PieChart: FC = ({ values, legendOptions = defaultLegendOptions, width, height, ...restProps }) => { + const getLegend = (values: DisplayValue[], legendOptions: VizLegendOptions) => { + if (legendOptions.displayMode === LegendDisplayMode.Hidden) { + return undefined; + } + + const legendItems = values.map((value) => { + return { + label: value.title ?? '', + color: value.color ?? FALLBACK_COLOR, + yAxis: 1, + }; + }); + + return ( + + ); + }; + + return ( + + {(vizWidth: number, vizHeight: number) => { + return ; + }} + + ); +}; + +export const PieChartSvg: FC = ({ + values, + pieType, + width, + height, + useGradients = true, + labelOptions = { showName: true }, +}) => { const theme = useTheme(); const componentInstanceId = useComponentInstanceId('PieChart'); const styles = useStyles(getStyles); @@ -43,20 +91,11 @@ export const PieChart: FC = ({ values, pieType, width, height, labelOptio return
No data
; } - const margin = 16; - const size = Math.min(width, height); - const outerRadius = (size - margin * 2) / 2; - const donutThickness = pieType === PieChartType.Pie ? outerRadius : Math.max(outerRadius / 3, 20); - const innerRadius = outerRadius - donutThickness; - const centerOffset = (size - margin * 2) / 2; - const total = values.reduce((acc, item) => item.numeric + acc, 0); - // for non donut pie charts shift gradient out a bit - const gradientFromOffset = 1 - (outerRadius - innerRadius) / outerRadius; - const showLabel = labelOptions.showName || labelOptions.showPercent || labelOptions.showValue; - const getValue = (d: DisplayValue) => d.numeric; - const getGradientId = (idx: number) => `${componentInstanceId}-${idx}`; - const getColor = (arc: PieArcDatum) => `url(#${getGradientId(arc.index)})`; + const getGradientId = (color: string) => `${componentInstanceId}-${color}`; + const getGradientColor = (color: string) => { + return `url(#${getGradientId(color)})`; + }; const onMouseMoveOverArc = (event: any, datum: any) => { const coords = localPoint(event.target.ownerSVGElement, event); @@ -67,32 +106,36 @@ export const PieChart: FC = ({ values, pieType, width, height, labelOptio }); }; + const showLabel = labelOptions.showName || labelOptions.showPercent || labelOptions.showValue; + const total = values.reduce((acc, item) => item.numeric + acc, 0); + const layout = getPieLayout(width, height, pieType); + return (
- - - {values.map((value, idx) => { - const color = value.color ?? 'gray'; + + + {values.map((value) => { + const color = value.color ?? FALLBACK_COLOR; return ( ); })} @@ -107,15 +150,15 @@ export const PieChart: FC = ({ values, pieType, width, height, labelOptio > {showLabel && ( @@ -206,6 +249,31 @@ function getGradientColorTo(color: string, theme: GrafanaTheme) { .toRgbString(); } +interface PieLayout { + position: number; + size: number; + outerRadius: number; + innerRadius: number; + gradientFromOffset: number; +} + +function getPieLayout(height: number, width: number, pieType: PieChartType, margin = 16): PieLayout { + const size = Math.min(width, height); + const outerRadius = (size - margin * 2) / 2; + const donutThickness = pieType === PieChartType.Pie ? outerRadius : Math.max(outerRadius / 3, 20); + const innerRadius = outerRadius - donutThickness; + const centerOffset = (size - margin * 2) / 2; + // for non donut pie charts shift gradient out a bit + const gradientFromOffset = 1 - (outerRadius - innerRadius) / outerRadius; + return { + position: centerOffset + margin, + size: size, + outerRadius: outerRadius, + innerRadius: innerRadius, + gradientFromOffset: gradientFromOffset, + }; +} + const getStyles = (theme: GrafanaTheme) => { return { container: css` diff --git a/packages/grafana-ui/src/components/PieChart/PieChartWithLegend.tsx b/packages/grafana-ui/src/components/PieChart/PieChartWithLegend.tsx deleted file mode 100644 index 3750659eacc..00000000000 --- a/packages/grafana-ui/src/components/PieChart/PieChartWithLegend.tsx +++ /dev/null @@ -1,8 +0,0 @@ -import React, { FC } from 'react'; -import { Props as PieChartProps } from './PieChart'; - -export interface Props extends PieChartProps {} - -export const PieChartWithLegend: FC = ({ width, height, ...restProps }) => { - return
Need VizLayout in grafana/ui
; -};