diff --git a/src/components/TotalOrgSummary/DonutChart/DonutChart.jsx b/src/components/TotalOrgSummary/DonutChart/DonutChart.jsx
index 9fbd8eba09..24b96ba370 100644
--- a/src/components/TotalOrgSummary/DonutChart/DonutChart.jsx
+++ b/src/components/TotalOrgSummary/DonutChart/DonutChart.jsx
@@ -1,49 +1,92 @@
import PropTypes from 'prop-types';
import { Doughnut } from 'react-chartjs-2';
import ChartDataLabels from 'chartjs-plugin-datalabels';
-import { Chart, ArcElement } from 'chart.js';
+import { Chart, ArcElement, Tooltip, Legend } from 'chart.js';
import styles from './DonutChart.module.css';
-Chart.register(ArcElement);
+Chart.register(ArcElement, Tooltip, Legend);
function DonutChart(props) {
const { title, totalCount, percentageChange, data, colors, comparisonType, darkMode } = props;
+ const filtered = data
+ .map((item, i) => ({ item, color: colors[i] }))
+ .filter(({ item }) => (item.value / totalCount) * 100 >= 0.05);
+ const filteredData = filtered.map(({ item }) => item);
+ const filteredColors = filtered.map(({ color }) => color);
+
+ const effectiveTotal = filteredData.reduce((sum, item) => sum + item.value, 0) || totalCount || 0;
+
+ if (!filteredData.length) {
+ return (
+
+
+
+ {title}
+
+
No data available yet
+
+
+ );
+ }
+
const chartData = {
- labels: data.map(item => item.label),
+ labels: filteredData.map(item => item.label),
datasets: [
{
- data: data.map(item => item.value),
- backgroundColor: colors,
+ data: filteredData.map(item => item.value),
+ backgroundColor: filteredColors,
borderWidth: 1,
+ hoverOffset: 8,
},
],
};
+ const labelColor = darkMode ? '#F7FAFC' : '#1A202C';
+
const options = {
plugins: {
datalabels: {
- color: '#000000',
- font: {
- size: 16,
- },
+ color: labelColor,
+ font: { size: 12, weight: '500' },
formatter: value => {
- if (totalCount === 0 || isNaN(totalCount) || !isFinite(totalCount)) {
- return `${value}`;
- }
- const percentage = ((value / totalCount) * 100).toFixed(0);
- return `${value}\n(${percentage}%)`;
+ if (!effectiveTotal || value <= 0) return '';
+ const pct = (value / effectiveTotal) * 100;
+ return `${value}\n(${pct.toFixed(0)}%)`;
},
+ anchor: 'end',
+ align: 'end',
+ offset: 6,
+ clamp: false,
+ display: 'auto',
+ textStrokeColor: darkMode ? '#1A202C' : '#FFFFFF',
+ textStrokeWidth: 3,
},
legend: {
display: false,
},
tooltip: {
- enabled: false,
+ enabled: true,
+ callbacks: {
+ label: ctx => {
+ const label = ctx.label || '';
+ const value = ctx.parsed;
+ const pct = effectiveTotal ? ((value / effectiveTotal) * 100).toFixed(0) : 0;
+ return `${label}: ${value} (${pct}%)`;
+ },
+ },
},
},
maintainAspectRatio: false,
cutout: '55%',
+ layout: {
+ padding: 40,
+ },
+ onHover: (event, elements) => {
+ const target = event?.native?.target;
+ if (!target) return;
+ target.style.cursor = elements && elements.length ? 'pointer' : 'default';
+ },
};
const percentageChangeColor = percentageChange >= 0 ? 'var(--success)' : 'var(--danger)';
@@ -54,10 +97,12 @@ function DonutChart(props) {
-
+
{title}
- {totalCount}
+
+ {totalCount}
+
{comparisonType !== 'No Comparison' && (
+
- {data.map((item, index) => (
+ {filteredData.map((item, index) => (
- {item.label}
+ {item.label}
))}
@@ -98,6 +144,11 @@ DonutChart.propTypes = {
).isRequired,
colors: PropTypes.arrayOf(PropTypes.string.isRequired).isRequired,
comparisonType: PropTypes.string.isRequired,
+ darkMode: PropTypes.bool,
+};
+
+DonutChart.defaultProps = {
+ darkMode: false,
};
export default DonutChart;
diff --git a/src/components/TotalOrgSummary/DonutChart/DonutChart.module.css b/src/components/TotalOrgSummary/DonutChart/DonutChart.module.css
index 916bda89ea..d7de9274c1 100644
--- a/src/components/TotalOrgSummary/DonutChart/DonutChart.module.css
+++ b/src/components/TotalOrgSummary/DonutChart/DonutChart.module.css
@@ -8,21 +8,18 @@
margin-top: 20px;
margin-bottom: -35px;
}
-
.donutScrollable {
display: grid;
grid-template-columns: 3fr 2fr;
width: 100%;
}
-
.donutChart {
position: relative;
width: 100%;
- max-width: 21.25rem;
- height: 21.25rem;
+ max-width: 24rem;
+ height: 24rem;
margin-left: auto;
}
-
.donutCenter {
position: absolute;
top: 50%;
@@ -31,51 +28,41 @@
text-align: center;
font-size: 0.6em;
}
-
.donutCenter > * {
margin: 0.2rem;
}
-
.donutCenter :global(.donut-heading) {
- color: var(--text-secondary);
font-size: 0.88rem;
}
-
.donutCenter :global(.donut-count) {
- color: var(--text-primary);
font-size: 2rem;
}
-
.donutComparisonPercent {
font-size: 0.7rem;
}
-
.donutCenter div {
margin: 2px 0;
}
-
.donutLabels {
display: flex;
flex-direction: column;
justify-content: center;
margin-top: 1.8rem;
width: 100%;
- color: var(--text-primary);
}
-
.donutLabel {
display: flex;
align-items: center;
margin-left: 20px;
+ margin-bottom: 4px;
}
-
.donutColor {
display: inline-block;
min-width: 1rem;
min-height: 1rem;
margin-right: 1rem;
+ flex-shrink: 0;
}
-
.donutNoData {
display: flex;
flex-direction: column;
@@ -85,18 +72,15 @@
width: 100%;
text-align: center;
}
-
.noDataText {
- color: var(--text-primary);
font-size: 24px !important;
font-weight: 600;
margin-top: 1.5rem;
line-height: 1.2;
}
-
@media (width <= 615px) {
.donutContainer {
overflow-x: scroll;
justify-content: start;
}
-}
+}
\ No newline at end of file