@ -1,6 +1,5 @@
import React , { FC , ReactNode } from 'react' ;
import React , { FC , ReactNode } from 'react' ;
import {
import {
DisplayValue ,
FALLBACK_COLOR ,
FALLBACK_COLOR ,
FieldDisplay ,
FieldDisplay ,
formattedValueToString ,
formattedValueToString ,
@ -29,6 +28,8 @@ import {
PieChartSvgProps ,
PieChartSvgProps ,
PieChartType ,
PieChartType ,
} from './types' ;
} from './types' ;
import { getTooltipContainerStyles } from '../../themes/mixins' ;
import { SeriesTable , SeriesTableRowProps , VizTooltipOptions } from '../VizTooltip' ;
const defaultLegendOptions : PieChartLegendOptions = {
const defaultLegendOptions : PieChartLegendOptions = {
displayMode : LegendDisplayMode.List ,
displayMode : LegendDisplayMode.List ,
@ -44,6 +45,7 @@ export const PieChart: FC<PieChartProps> = ({
fieldConfig ,
fieldConfig ,
replaceVariables ,
replaceVariables ,
legendOptions = defaultLegendOptions ,
legendOptions = defaultLegendOptions ,
tooltipOptions ,
onSeriesColorChange ,
onSeriesColorChange ,
width ,
width ,
height ,
height ,
@ -112,7 +114,13 @@ export const PieChart: FC<PieChartProps> = ({
< VizLayout width = { width } height = { height } legend = { getLegend ( fieldDisplayValues , legendOptions ) } >
< VizLayout width = { width } height = { height } legend = { getLegend ( fieldDisplayValues , legendOptions ) } >
{ ( vizWidth : number , vizHeight : number ) = > {
{ ( vizWidth : number , vizHeight : number ) = > {
return (
return (
< PieChartSvg width = { vizWidth } height = { vizHeight } fieldDisplayValues = { fieldDisplayValues } { ...restProps } / >
< PieChartSvg
width = { vizWidth }
height = { vizHeight }
fieldDisplayValues = { fieldDisplayValues }
tooltipOptions = { tooltipOptions }
{ . . . restProps }
/ >
) ;
) ;
} }
} }
< / VizLayout >
< / VizLayout >
@ -126,11 +134,12 @@ export const PieChartSvg: FC<PieChartSvgProps> = ({
height ,
height ,
useGradients = true ,
useGradients = true ,
displayLabels = [ ] ,
displayLabels = [ ] ,
tooltipOptions ,
} ) = > {
} ) = > {
const theme = useTheme ( ) ;
const theme = useTheme ( ) ;
const componentInstanceId = useComponentInstanceId ( 'PieChart' ) ;
const componentInstanceId = useComponentInstanceId ( 'PieChart' ) ;
const styles = useStyles ( getStyles ) ;
const styles = useStyles ( getStyles ) ;
const tooltip = useTooltip < DisplayValue > ( ) ;
const tooltip = useTooltip < SeriesTableRowProps [ ] > ( ) ;
const { containerRef , TooltipInPortal } = useTooltipInPortal ( {
const { containerRef , TooltipInPortal } = useTooltipInPortal ( {
detectBounds : true ,
detectBounds : true ,
scroll : true ,
scroll : true ,
@ -147,6 +156,7 @@ export const PieChartSvg: FC<PieChartSvgProps> = ({
} ;
} ;
const showLabel = displayLabels . length > 0 ;
const showLabel = displayLabels . length > 0 ;
const showTooltip = tooltipOptions . mode !== 'none' && tooltip . tooltipOpen ;
const total = fieldDisplayValues . reduce ( ( acc , item ) = > item . display . numeric + acc , 0 ) ;
const total = fieldDisplayValues . reduce ( ( acc , item ) = > item . display . numeric + acc , 0 ) ;
const layout = getPieLayout ( width , height , pieType ) ;
const layout = getPieLayout ( width , height , pieType ) ;
const colors = [
const colors = [
@ -204,6 +214,7 @@ export const PieChartSvg: FC<PieChartSvgProps> = ({
pie = { pie }
pie = { pie }
fill = { getGradientColor ( color ) }
fill = { getGradientColor ( color ) }
openMenu = { api . openMenu }
openMenu = { api . openMenu }
tooltipOptions = { tooltipOptions }
>
>
{ label }
{ label }
< / PieSlice >
< / PieSlice >
@ -212,7 +223,14 @@ export const PieChartSvg: FC<PieChartSvgProps> = ({
) ;
) ;
} else {
} else {
return (
return (
< PieSlice key = { arc . index } tooltip = { tooltip } arc = { arc } pie = { pie } fill = { getGradientColor ( color ) } >
< PieSlice
key = { arc . index }
tooltip = { tooltip }
arc = { arc }
pie = { pie }
fill = { getGradientColor ( color ) }
tooltipOptions = { tooltipOptions }
>
{ label }
{ label }
< / PieSlice >
< / PieSlice >
) ;
) ;
@ -222,16 +240,18 @@ export const PieChartSvg: FC<PieChartSvgProps> = ({
< / Pie >
< / Pie >
< / Group >
< / Group >
< / svg >
< / svg >
{ tooltip . tooltipOpen && (
{ showTooltip ? (
< TooltipInPortal
< TooltipInPortal
key = { Math . random ( ) }
key = { Math . random ( ) }
top = { tooltip . tooltipTop }
top = { tooltip . tooltipTop }
className = { styles . tooltipPortal }
className = { styles . tooltipPortal }
left = { tooltip . tooltipLeft }
left = { tooltip . tooltipLeft }
unstyled = { true }
applyPositionStyle = { true }
>
>
{ tooltip . tooltipData ! . title } { formattedValueToString ( tooltip . tooltipData ! ) }
< SeriesTable series = { tooltip . tooltipData ! } / >
< / TooltipInPortal >
< / TooltipInPortal >
) }
) : null }
< / div >
< / div >
) ;
) ;
} ;
} ;
@ -241,18 +261,19 @@ const PieSlice: FC<{
arc : PieArcDatum < FieldDisplay > ;
arc : PieArcDatum < FieldDisplay > ;
pie : ProvidedProps < FieldDisplay > ;
pie : ProvidedProps < FieldDisplay > ;
fill : string ;
fill : string ;
tooltip : UseTooltipParams < DisplayValue > ;
tooltip : UseTooltipParams < SeriesTableRowProps [ ] > ;
tooltipOptions : VizTooltipOptions ;
openMenu ? : ( event : React.MouseEvent < SVGElement > ) = > void ;
openMenu ? : ( event : React.MouseEvent < SVGElement > ) = > void ;
} > = ( { arc , children , pie , openMenu , fill , tooltip } ) = > {
} > = ( { arc , children , pie , openMenu , fill , tooltip , tooltipOptions } ) = > {
const theme = useTheme ( ) ;
const theme = useTheme ( ) ;
const styles = useStyles ( getStyles ) ;
const styles = useStyles ( getStyles ) ;
const onMouseMoveOverArc = ( event : any , datum : any ) = > {
const onMouseMoveOverArc = ( event : any ) = > {
const coords = localPoint ( event . target . ownerSVGElement , event ) ;
const coords = localPoint ( event . target . ownerSVGElement , event ) ;
tooltip . showTooltip ( {
tooltip . showTooltip ( {
tooltipLeft : coords ! . x ,
tooltipLeft : coords ! . x ,
tooltipTop : coords ! . y ,
tooltipTop : coords ! . y ,
tooltipData : datum ,
tooltipData : getTooltipData ( pie , arc , tooltipOptions ) ,
} ) ;
} ) ;
} ;
} ;
@ -260,7 +281,7 @@ const PieSlice: FC<{
< g
< g
key = { arc . data . display . title }
key = { arc . data . display . title }
className = { styles . svgArg }
className = { styles . svgArg }
onMouseMove = { ( event ) = > onMouseMoveOverArc ( event , arc . data . display ) }
onMouseMove = { tooltipOptions . mode !== 'none' ? onMouseMoveOverArc : undefined }
onMouseOut = { tooltip . hideTooltip }
onMouseOut = { tooltip . hideTooltip }
onClick = { openMenu }
onClick = { openMenu }
>
>
@ -321,6 +342,30 @@ const PieLabel: FC<{
) ;
) ;
} ;
} ;
function getTooltipData (
pie : ProvidedProps < FieldDisplay > ,
arc : PieArcDatum < FieldDisplay > ,
tooltipOptions : VizTooltipOptions
) {
if ( tooltipOptions . mode === 'multi' ) {
return pie . arcs . map ( ( pieArc ) = > {
return {
color : pieArc.data.display.color ? ? FALLBACK_COLOR ,
label : pieArc.data.display.title ,
value : formattedValueToString ( pieArc . data . display ) ,
isActive : pieArc.index === arc . index ,
} ;
} ) ;
}
return [
{
color : arc.data.display.color ? ? FALLBACK_COLOR ,
label : arc.data.display.title ,
value : formattedValueToString ( arc . data . display ) ,
} ,
] ;
}
function getLabelPos ( arc : PieArcDatum < FieldDisplay > , outerRadius : number , innerRadius : number ) {
function getLabelPos ( arc : PieArcDatum < FieldDisplay > , outerRadius : number , innerRadius : number ) {
const r = ( outerRadius + innerRadius ) / 2 ;
const r = ( outerRadius + innerRadius ) / 2 ;
const a = ( + arc . startAngle + + arc . endAngle ) / 2 - Math . PI / 2 ;
const a = ( + arc . startAngle + + arc . endAngle ) / 2 - Math . PI / 2 ;
@ -382,7 +427,7 @@ const getStyles = (theme: GrafanaTheme) => {
}
}
` ,
` ,
tooltipPortal : css `
tooltipPortal : css `
z - index : 1050 ;
$ { getTooltipContainerStyles ( theme ) }
` ,
` ,
} ;
} ;
} ;
} ;