Using recharts to create a dynamic dashboard.
Created
March 14, 2025 10:00
-
-
Save Mazyod/893e10d88f26eb6cb0efbcf4690a3d00 to your computer and use it in GitHub Desktop.
Recharts Dynamic Dashboard Example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { useMemo } from 'react'; | |
import { | |
LineChart, | |
Line, | |
BarChart, | |
Bar, | |
XAxis, | |
YAxis, | |
CartesianGrid, | |
Tooltip, | |
Legend, | |
ResponsiveContainer, | |
PieChart, | |
Pie, | |
Cell | |
} from 'recharts'; | |
// Global variables | |
const COLORS = [ | |
'#8884d8', // purple | |
'#82ca9d', // green | |
'#ffc658', // yellow | |
'#ff8042', // orange | |
'#0088fe', // blue | |
'#00c49f', // teal | |
'#ff6b6b', // red | |
'#a4de6c' // light green | |
]; | |
// Sample data | |
const DATA = [ | |
{ name: 'Jan', revenue: 4000, profit: 2400, costs: 1600, customers: 120 }, | |
{ name: 'Feb', revenue: 3000, profit: 1398, costs: 1602, customers: 98 }, | |
{ name: 'Mar', revenue: 2000, profit: 9800, costs: 1950, customers: 150 }, | |
{ name: 'Apr', revenue: 2780, profit: 3908, costs: 1800, customers: 130 }, | |
{ name: 'May', revenue: 1890, profit: 4800, costs: 1700, customers: 110 }, | |
{ name: 'Jun', revenue: 2390, profit: 3800, costs: 1550, customers: 105 }, | |
{ name: 'Jul', revenue: 3490, profit: 4300, costs: 1750, customers: 140 }, | |
]; | |
// Dynamic Line Chart Component | |
const DynamicLineChart = ({ data, title = "Line Chart", height = 250 }) => { | |
const dataKeys = useMemo(() => { | |
if (!data || data.length === 0) return []; | |
return Object.keys(data[0]).filter(key => key !== 'name'); | |
}, [data]); | |
if (!data || data.length === 0) { | |
return <div>No data available</div>; | |
} | |
return ( | |
<div className="w-full"> | |
<h3 className="text-lg font-semibold mb-2">{title}</h3> | |
<div style={{ height: `${height}px`, width: '100%' }}> | |
<ResponsiveContainer width="100%" height="100%"> | |
<LineChart | |
data={data} | |
margin={{ | |
top: 5, | |
right: 30, | |
left: 20, | |
bottom: 5, | |
}} | |
> | |
<CartesianGrid strokeDasharray="3 3" /> | |
<XAxis dataKey="name" /> | |
<YAxis /> | |
<Tooltip /> | |
<Legend /> | |
{dataKeys.map((key, index) => ( | |
<Line | |
key={key} | |
type="monotone" | |
dataKey={key} | |
stroke={COLORS[index % COLORS.length]} | |
activeDot={{ r: 8 }} | |
strokeWidth={2} | |
/> | |
))} | |
</LineChart> | |
</ResponsiveContainer> | |
</div> | |
</div> | |
); | |
}; | |
// Dynamic Pie Chart Component | |
const DynamicPieChart = ({ data, title, height = 250, dataKey }) => { | |
const dataKeys = useMemo(() => { | |
if (!data || data.length === 0) return []; | |
return Object.keys(data[0]).filter(key => key !== 'name'); | |
}, [data]); | |
const pieData = useMemo(() => { | |
if (!data || data.length === 0 || (!dataKey && dataKeys.length === 0)) return []; | |
const keyToUse = dataKey || dataKeys[0]; | |
return data.map(item => ({ | |
name: item.name, | |
value: item[keyToUse] | |
})); | |
}, [data, dataKeys, dataKey]); | |
if (!data || data.length === 0 || (!dataKey && dataKeys.length === 0)) { | |
return <div>No data available</div>; | |
} | |
const keyName = dataKey || dataKeys[0]; | |
const dataKeyName = keyName ? keyName.charAt(0).toUpperCase() + keyName.slice(1) : 'Data'; | |
const chartTitle = title || `Distribution of ${dataKeyName}`; | |
return ( | |
<div className="w-full"> | |
<h3 className="text-lg font-semibold mb-2">{chartTitle}</h3> | |
<div style={{ height: `${height}px`, width: '100%' }}> | |
<ResponsiveContainer width="100%" height="100%"> | |
<PieChart> | |
<Pie | |
data={pieData} | |
cx="50%" | |
cy="50%" | |
labelLine={true} | |
outerRadius={80} | |
fill="#8884d8" | |
dataKey="value" | |
nameKey="name" | |
label={({ name, percent }) => `${name}: ${(percent * 100).toFixed(0)}%`} | |
> | |
{pieData.map((entry, index) => ( | |
<Cell key={`cell-${index}`} fill={COLORS[index % COLORS.length]} /> | |
))} | |
</Pie> | |
<Tooltip formatter={(value, name, props) => { | |
const total = pieData.reduce((sum, entry) => sum + entry.value, 0); | |
return [`${value} (${((value / total) * 100).toFixed(1)}%)`, name]; | |
}} /> | |
<Legend /> | |
</PieChart> | |
</ResponsiveContainer> | |
</div> | |
</div> | |
); | |
}; | |
// Multiple Pie Charts Component | |
const MultiPieCharts = ({ data, height = 250 }) => { | |
const dataKeys = useMemo(() => { | |
if (!data || data.length === 0) return []; | |
return Object.keys(data[0]).filter(key => key !== 'name'); | |
}, [data]); | |
if (!data || data.length === 0 || dataKeys.length === 0) { | |
return <div>No data available</div>; | |
} | |
return ( | |
<div className="w-full"> | |
<h3 className="text-lg font-semibold mb-4">Data Distribution</h3> | |
<div className="flex flex-wrap"> | |
{dataKeys.map(key => ( | |
<div | |
key={key} | |
className="p-2" | |
style={{ width: '300px' }} | |
> | |
<DynamicPieChart | |
data={data} | |
dataKey={key} | |
height={height} | |
/> | |
</div> | |
))} | |
</div> | |
</div> | |
); | |
}; | |
// Dynamic Stacked Bar Chart Component | |
const DynamicStackedBarChart = ({ data = DATA }) => { | |
const dataKeys = useMemo(() => { | |
if (!data || data.length === 0) return []; | |
return Object.keys(data[0]).filter(key => key !== 'name'); | |
}, [data]); | |
return ( | |
<div className="w-full"> | |
<h3 className="text-lg font-semibold mb-2">Monthly Data Breakdown</h3> | |
<div className="h-64 w-full"> | |
<ResponsiveContainer width="100%" height="100%"> | |
<BarChart | |
data={data} | |
margin={{ | |
top: 20, | |
right: 30, | |
left: 20, | |
bottom: 5, | |
}} | |
> | |
<CartesianGrid strokeDasharray="3 3" /> | |
<XAxis dataKey="name" /> | |
<YAxis /> | |
<Tooltip | |
formatter={(value, name) => [ | |
`${value}`, | |
name.charAt(0).toUpperCase() + name.slice(1) | |
]} | |
/> | |
<Legend /> | |
{dataKeys.map((key, index) => ( | |
<Bar | |
key={key} | |
dataKey={key} | |
stackId="a" | |
fill={COLORS[index % COLORS.length]} | |
name={key.charAt(0).toUpperCase() + key.slice(1)} | |
/> | |
))} | |
</BarChart> | |
</ResponsiveContainer> | |
</div> | |
</div> | |
); | |
}; | |
// Main Dashboard Component | |
const ComprehensiveDashboard = () => { | |
return ( | |
<div className="w-full p-4"> | |
<h2 className="text-xl font-bold mb-4 text-center">Company Performance Dashboard</h2> | |
<div className="w-full mb-8"> | |
<DynamicLineChart | |
data={DATA} | |
title="Trends over Time" | |
height={250} | |
/> | |
</div> | |
<div className="w-full mb-8"> | |
<DynamicStackedBarChart data={DATA} /> | |
</div> | |
<div className="w-full"> | |
<MultiPieCharts | |
data={DATA} | |
height={220} | |
/> | |
</div> | |
</div> | |
); | |
}; | |
export default ComprehensiveDashboard; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment