Highcharts Donut Chart Sample
import * as React from 'react' ;
import Highcharts , { Chart as HighchartsChart } from 'highcharts' ;
import HighchartsReact from 'highcharts-react-official' ;
import { Box } from '@chakra-ui/react' ;
import DonutChartWrapper from './index.styles' ;
import Tooltip from '../tooltip' ;
export type DonutChartData = {
name : string ,
color ?: string ,
y : number ,
} ;
type DataLabel = {
enabled : boolean ,
useHTML ?: boolean ,
format ?: string ,
formatter ?: ( e :any ) => string ,
dashedConnector ?: boolean ,
distance ?: string ,
padding ?: number ,
connectorColor ?: string ,
style : { [ key :string ] : string | number } ,
}
type Legend = {
align ?: 'center' | 'left' | 'right' ,
verticalAlign ?: 'bottom' | 'top' | 'middle' ,
y ?: number ,
floating ?: boolean ,
enabled ?: boolean ,
padding ?: number ,
itemMarginTop ?: number ,
symbolWidth ?: number ,
symbolHeight ?: number ,
symbolRadius ?: number ,
symbolPadding ?: number ,
width ?: number ,
itemWidth ?: number ,
useHTML ?: boolean ,
} ;
type Props = {
data : DonutChartData [ ] ,
options ?: Highcharts . Options ,
borderRadius ?: string ,
tooltip ?: React . FC < { data : DonutChartData } > ,
title ?: string , // can also provide HTML string
height ?: number ,
width ?: number ,
margin ?: number [ ] ,
donutHeight ?: number ,
donutWidth ?: number ,
titlePos ?: number ,
legendPos ?: number ,
circleSize ?: string ,
innerCircleSize ?: string ,
dataLabels ?: DataLabel ,
legend ?: Legend ,
eventName ?: string , // this event is dispatched when chart is loaded
} ;
const ColoredGridGraph = ( {
height, width, margin, titlePos, legendPos, data, options, borderRadius, tooltip, title,
donutWidth, donutHeight, circleSize, innerCircleSize, dataLabels, legend, eventName,
} :Props ) => {
const TooltipNode = tooltip ;
const [ chart , setChart ] = React . useState < HighchartsChart | null > ( null ) ;
const callback = React . useCallback ( ( chartData : HighchartsChart ) => {
setChart ( chartData ) ;
} , [ ] ) ;
React . useEffect ( ( ) => {
if ( chart && eventName ) {
window . dispatchEvent ( new CustomEvent ( eventName , { detail : chart } ) ) ;
}
} , [ chart ] ) ;
const chartOptions = {
chart : {
type : 'pie' ,
padding : 0 ,
spacing : [ 0 , 0 , 0 , 0 ] ,
plotBackgroundColor : null ,
plotBorderWidth : null ,
plotShadow : false ,
margin,
width : donutWidth ,
height : donutHeight ,
spacingTop : 0 ,
spacingBottom : 0 ,
spacingLeft : 0 ,
spacingRight : 0 ,
} ,
title : {
text : title ,
align : 'center' ,
verticalAlign : 'middle' ,
y : titlePos ,
} ,
xAxis : {
className : 'highcharts-d-none' ,
minPadding : 0 ,
maxPadding : 0 ,
} ,
yAxis : {
className : 'highcharts-d-none' ,
minPadding : 0 ,
maxPadding : 0 ,
} ,
legend : {
align : 'center' ,
verticalAlign : 'bottom' ,
y : legendPos ,
floating : true ,
enabled : true ,
padding : 3 ,
itemMarginTop : 4 ,
symbolWidth : 10 ,
symbolHeight : 10 ,
symbolRadius : 2 ,
symbolPadding : 6 ,
squareSymbol : true ,
width : donutWidth ,
...legend ,
} ,
plotOptions : {
pie : {
shadow : false ,
} ,
} ,
exporting : {
enabled : false ,
} ,
tooltip : {
useHTML : true ,
outside : true ,
headerFormat : null ,
followPointer : true ,
enabled : TooltipNode !== null ,
hideDelay : 100 ,
} ,
credits : {
enabled : false ,
} ,
series : [ {
name : 'PieChart' ,
data,
size : circleSize ,
innerSize : innerCircleSize ,
showInLegend : true ,
dataLabels,
} ] ,
...options ,
} ;
return (
< DonutChartWrapper
height = { height }
width = { width }
borderRadius = { borderRadius }
dashedConnector = { dataLabels ?. dashedConnector }
>
< HighchartsReact
highcharts = { Highcharts }
options = { chartOptions }
callback = { callback }
/ >
< Tooltip chart = { chart } >
{ ( formatterContext ) => {
if ( ! TooltipNode ) {
return (
< Box display = "none" / >
) ;
}
return (
< TooltipNode data = { { name : formatterContext . key , y : formatterContext . y } } / >
) ;
} }
< / Tooltip >
< / DonutChartWrapper >
) ;
} ;
ColoredGridGraph . defaultProps = {
width : 450 ,
height : 400 ,
donutWidth : 330 ,
donutHeight : 390 ,
margin : [ - 110 , 0 , 0 , 0 ] ,
titlePos : - 30 ,
legendPos : - 60 ,
circleSize : '88%' ,
innerCircleSize : '70%' ,
options : { } ,
borderRadius : '5px' ,
tooltip : null ,
title : '' ,
legend : { } ,
dataLabels : {
enabled : false ,
} ,
eventName : null ,
} ;
export default ColoredGridGraph ;
import * as React from 'react' ;
import { Box } from '@chakra-ui/react' ;
const CustomLegends = ( ) => {
const ref = React . useRef ( {
prevCallback : null , callback : null , hover : { } ,
} ) ;
const [ visible , setVisible ] = React . useState ( { } ) ;
const [ chart , setChart ] = React . useState ( null ) ;
const [ legends , setLegends ] = React . useState ( [ ] ) ;
ref . current . callback = ( e ) => {
setChart ( ( ) => e . detail ) ;
const legendList = [ ] ;
for ( let i = 0 ; i < e . detail . series [ 0 ] . data . length ; i += 1 ) {
const item = e . detail . series [ 0 ] . data [ i ] ;
legendList . push ( {
name : item . name ,
color : item . color ,
} ) ;
}
setLegends ( ( ) => legendList ) ;
} ;
React . useEffect ( ( ) => {
if ( ref . current . prevCallback ) {
window . removeEventListener ( 'competitor-wallet-share-chart-update' , ref . current . prevCallback ) ;
}
window . addEventListener ( 'custom-chart-update' , ref . current . callback ) ;
ref . current . prevCallback = ref . current . callback ;
} , [ ] ) ;
const onLegendClick = ( index ) => {
const data = chart . series [ 0 ] . data [ index ] ;
const visibleData = { ...visible } ;
visibleData [ data . name ] = visibleData [ data . name ] !== undefined
? ! visibleData [ data . name ] : false ;
data . setVisible ( visibleData [ data . name ] ) ;
setVisible ( ( ) => visibleData ) ;
} ;
const onMouseOver = ( index ) => {
const dataList = chart . series [ 0 ] . data ;
if ( dataList [ index ] . visible === false || ref . current . hover [ dataList [ index ] . name ] ) {
return ;
}
ref . current . hover [ dataList [ index ] . name ] = true ;
for ( let i = 0 ; i < dataList . length ; i += 1 ) {
if ( i !== index ) {
dataList [ i ] . update ( {
opacity : 0.5 ,
} ) ;
} else {
dataList [ i ] . update ( {
opacity : 1 ,
} ) ;
dataList [ i ] . setState ( 'hover' ) ;
}
}
} ;
const onMouseOut = ( ) => {
const dataList = chart . series [ 0 ] . data ;
for ( let i = 0 ; i < dataList . length ; i += 1 ) {
if ( dataList [ i ] . opacity >= 1 ) {
// eslint-disable-next-line no-continue
continue ;
}
dataList [ i ] . update ( {
opacity : 1 ,
} ) ;
dataList [ i ] . setState ( 'normal' ) ;
ref . current . hover [ dataList [ i ] . name ] = false ;
}
} ;
return (
< Box w = "full" overflow = "hidden" >
< Box display = "flex" alignItems = "center" w = "full" flexWrap = "wrap" >
{
legends . map ( ( item , index ) => (
< Box
cursor = "pointer"
mr = "2"
key = { `chart-legend-${ index + 1 } ` }
display = "flex"
alignItems = "center"
mb = "2"
onClick = { ( ) => onLegendClick ( index ) }
onMouseOver = { ( ) => onMouseOver ( index ) }
onMouseOut = { ( ) => onMouseOut ( ) }
opacity = {
visible [ item . name ] || visible [ item . name ] === undefined ? 1 : 0.5
}
>
< Box w = "10px" h = "10px" borderRadius = "50%" bgColor = { item . color } mr = "2" / >
< Box fontSize = "sm" _hover = { { fontWeight : 'semibold' } } > { item . name } < / Box >
< / Box >
) )
}
< / Box >
< / Box >
) ;
} ;
export default CustomLegends ;
import * as React from 'react' ;
import { Box , Text } from '@chakra-ui/react' ;
import DonutChartWrapper from 'components/HighCharts/DonutChart/index.styles' ;
import DonutChart from 'components/HighCharts/DonutChart' ;
import CustomLegends from './CustomLegends' ;
const CustomChartSample = ( ) => (
< Box w = "full" mt = "6" p = "5" border = "1.5px solid" borderColor = "gray.300" rounded = "md" >
< DonutChartWrapper >
< DonutChart
data = { [
{ name : 'test' , y : 100 } ,
{ name : 'test2' , y : 200 } ,
{ name : 'test3' , y : 300 } ,
{ name : 'test4' , y : 400 } ,
{ name : 'test5' , y : 500 } ,
{ name : 'test6' , y : 600 } ,
{ name : 'test7' , y : 700 } ,
{ name : 'test8' , y : 800 } ,
{ name : 'test9' , y : 900 } ,
{ name : 'test10' , y : 1000 } ,
{ name : 'test11' , y : 1100 } ,
{ name : 'test12' , y : 1200 } ,
{ name : 'test13' , y : 1300 } ,
{ name : 'test14' , y : 1400 } ,
{ name : 'test15' , y : 1500 } ,
{ name : 'test16' , y : 1600 } ,
{ name : 'test17' , y : 1700 } ,
{ name : 'test18' , y : 1800 } ,
{ name : 'test19' , y : 1900 } ,
{ name : 'test20' , y : 2000 } ,
{ name : 'test21' , y : 2100 } ,
{ name : 'test22' , y : 2200 } ,
{ name : 'test23' , y : 2300 } ,
{ name : 'test24' , y : 2400 } ,
{ name : 'test25' , y : 2500 } ,
{ name : 'test26' , y : 2600 } ,
{ name : 'test27' , y : 2700 } ,
{ name : 'test28' , y : 2800 } ,
{ name : 'test29' , y : 2900 } ,
{ name : 'test30' , y : 3000 } ,
{ name : 'test31' , y : 3100 } ,
{ name : 'test32' , y : 3200 } ,
{ name : 'test33' , y : 3300 } ,
{ name : 'test34' , y : 3400 } ,
{ name : 'test35' , y : 3500 } ,
{ name : 'test36' , y : 3600 } ,
{ name : 'test37' , y : 3700 } ,
{ name : 'test38' , y : 3800 } ,
{ name : 'test39' , y : 3900 } ,
{ name : 'test40' , y : 4000 } ,
] }
width = { 300 }
height = { 300 }
donutWidth = { 300 }
donutHeight = { 300 }
margin = { [ 0 , 0 , 0 , 0 ] }
titlePos = { - 30 }
legendPos = { 0 }
legend = { { enabled : false } }
eventName = "custom-chart-update"
/ >
< / DonutChartWrapper >
< CustomLegends / >
< / Box >
) ;
export default CustomChartSample ;