react-donut-chart
Version:
An extendable SVG donut chart React component.
1 lines • 3.35 kB
JavaScript
import React,{createContext,useEffect,useState}from"react";import ArcPath from"./ArcPath";import LegendItem from"./LegendItem";export const DonutChartContext=/*#__PURE__*/createContext(undefined);const DonutChart=({className="donutchart",clickToggle=true,colorFunction=(colors,index)=>colors[index%colors.length],colors=["#f44336","#e91e63","#9c27b0","#673ab7","#3f51b5","#2196f3","#03a9f4","#00bcd4","#009688","#4caf50","#8bc34a","#cddc39","#ffeb3b","#ffc107","#ff9800","#ff5722","#795548","#607d8b"],data=[{className:"",label:"",value:100,isEmpty:true}],emptyColor="#e0e0e0",emptyOffset=0.08,formatValues=(value,total)=>Number.isNaN(value/total)?"--":`${(value/total*100).toFixed(2)}%`,height=500,interactive=true,innerRadius=0.7,legend=true,onMouseEnter=item=>item,onMouseLeave=item=>item,onClick=(item,toggled)=>toggled?item:null,outerRadius=0.9,selectedOffset=0.03,strokeColor="#212121",toggledOffset=0.04,width=750})=>{const[selected,setSelected]=useState(interactive?data[0]:null);const[toggleSelect,setToggleSelect]=useState(false);useEffect(()=>{if(interactive){setSelected(data[0]);setToggleSelect(false)}},[interactive,data]);const graphWidth=legend?width*(2/3):width;const total=data.reduce((sum,{value})=>sum+value,0);const{dataWithRenderProps}=data.reduce(({angle,dataWithRenderProps},item,index)=>{const{className,isEmpty,label,value}=item;const isSelected=(selected===null||selected===void 0?void 0:selected.label)===label;const isToggled=isSelected&&toggleSelect;return{angle:angle+value/total*360,dataWithRenderProps:[...dataWithRenderProps,{angle,index,...item,classNames:`${className??""} ${isEmpty?"empty":""} ${isSelected?"selected":""} ${isToggled?"toggled":""}`.trim(),fill:isEmpty?emptyColor:colorFunction(colors,index),opacity:isSelected&&!toggleSelect?0.5:1,stroke:isEmpty?emptyColor:strokeColor,clickHandlers:interactive?{onClick:()=>{if((selected===null||selected===void 0?void 0:selected.label)===label){const toggle=clickToggle?!toggleSelect:false;setSelected(item);setToggleSelect(toggle);onClick(item,toggle)}},onMouseEnter:()=>{if(!toggleSelect){setSelected(item);onMouseEnter(item)}},onMouseLeave:()=>{if(!toggleSelect){onMouseLeave(item)}}}:undefined}],total:total+value}},{angle:0,dataWithRenderProps:[]});return/*#__PURE__*/React.createElement(DonutChartContext.Provider,{value:{className,emptyOffset,graphWidth,innerRadius,outerRadius,selected,selectedOffset,toggledOffset,toggleSelect,total,width}},/*#__PURE__*/React.createElement("svg",{className:className,style:{height,width},viewBox:`0 0 ${width} ${height}`},/*#__PURE__*/React.createElement("g",{className:`${className}-arcs`},dataWithRenderProps.map(item=>/*#__PURE__*/React.createElement(ArcPath,{item:item,key:`arcpath${item.index}`}))),selected&&/*#__PURE__*/React.createElement("g",{className:`${className}-innertext`},/*#__PURE__*/React.createElement("text",{className:`${className}-innertext-label`,x:graphWidth/2,y:"45%",textAnchor:"middle"},selected.label),/*#__PURE__*/React.createElement("text",{className:`${className}-innertext-value`,x:graphWidth/2,y:"60%",textAnchor:"middle"},formatValues(selected.value,total))),legend&&/*#__PURE__*/React.createElement("g",{className:`${className}-legend`},dataWithRenderProps.map(item=>/*#__PURE__*/React.createElement(LegendItem,{key:`legenditem${item.index}`,item:item})))))};export default DonutChart;