135 lines
3.4 KiB
JavaScript
135 lines
3.4 KiB
JavaScript
import React from "react";
|
|
import ReactApexChart from "react-apexcharts";
|
|
import PropTypes from "prop-types";
|
|
|
|
const HorizontalBarChart = ({
|
|
seriesData = [],
|
|
categories = [],
|
|
colors = [
|
|
"#1E90FF", "#00BFFF", "#9370DB", "#6A0DAD", "#A9A9A9",
|
|
"#6A5ACD", "#FFA500", "#FF4500", "#20B2AA", "#708090",
|
|
],
|
|
loading = false,
|
|
}) => {
|
|
// Show loading state
|
|
if (loading) {
|
|
return (
|
|
<div className="w-full h-[380px] flex items-center justify-center bg-gray-100 rounded-xl">
|
|
<span className="text-gray-500 text-sm">Loading chart...</span>
|
|
{/* Replace this with a skeleton or spinner if you prefer */}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// Guard clause for invalid or incomplete data
|
|
const hasValidData =
|
|
Array.isArray(seriesData) &&
|
|
seriesData.length > 0 &&
|
|
Array.isArray(categories) &&
|
|
categories.length === seriesData.length;
|
|
|
|
if (!hasValidData) {
|
|
return <div className="text-center text-gray-500">No data to display</div>;
|
|
}
|
|
|
|
// Combine seriesData and categories, then sort in descending order
|
|
const combined = seriesData.map((value, index) => ({
|
|
value,
|
|
label: categories[index],
|
|
}));
|
|
const sorted = combined.sort((a, b) => b.value - a.value);
|
|
|
|
// Extract sorted values
|
|
const sortedSeriesData = sorted.map(item => item.value);
|
|
const sortedCategories = sorted.map(item => item.label);
|
|
|
|
// Replace 0 with 1 for visual purposes, but display "0%" in labels
|
|
const adjustedSeriesData = sortedSeriesData.map(val => (val === 0 ? 1 : val));
|
|
|
|
// Dynamically adjust chart height if only one data point
|
|
const chartHeight = seriesData.length === 1 ? 80 : 380;
|
|
|
|
const chartOptions = {
|
|
chart: {
|
|
type: "bar",
|
|
height: chartHeight,
|
|
toolbar: { show: false },
|
|
},
|
|
grid: { show: false },
|
|
plotOptions: {
|
|
bar: {
|
|
barHeight: seriesData.length === 1 ? "30%" : "60%",
|
|
distributed: true,
|
|
horizontal: true,
|
|
borderRadius: 3,
|
|
borderRadiusApplication: "end",
|
|
dataLabels: {
|
|
position: "top",
|
|
},
|
|
},
|
|
},
|
|
colors,
|
|
dataLabels: {
|
|
enabled: true,
|
|
textAnchor: "center",
|
|
style: {
|
|
colors: ["#000"], // Black labels
|
|
fontSize: "8px",
|
|
},
|
|
formatter: function (_, opt) {
|
|
const originalVal = sortedSeriesData[opt.dataPointIndex]; // Show real value
|
|
return `${originalVal}%`;
|
|
},
|
|
offsetX: 10,
|
|
dropShadow: { enabled: false },
|
|
},
|
|
stroke: {
|
|
width: 1,
|
|
colors: ["#fff"],
|
|
},
|
|
xaxis: {
|
|
categories: sortedCategories,
|
|
axisBorder: { show: false },
|
|
axisTicks: { show: false },
|
|
labels: { show: false },
|
|
},
|
|
yaxis: {
|
|
labels: { show: false },
|
|
axisBorder: { show: false },
|
|
axisTicks: { show: false },
|
|
},
|
|
legend: {
|
|
show: true,
|
|
},
|
|
tooltip: {
|
|
theme: "dark",
|
|
x: { show: true },
|
|
y: {
|
|
title: {
|
|
formatter: () => "",
|
|
},
|
|
},
|
|
},
|
|
};
|
|
|
|
return (
|
|
<div className="w-full">
|
|
<ReactApexChart
|
|
options={chartOptions}
|
|
series={[{ data: adjustedSeriesData }]}
|
|
type="bar"
|
|
height={chartHeight}
|
|
/>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
HorizontalBarChart.propTypes = {
|
|
seriesData: PropTypes.arrayOf(PropTypes.number),
|
|
categories: PropTypes.arrayOf(PropTypes.string),
|
|
colors: PropTypes.arrayOf(PropTypes.string),
|
|
loading: PropTypes.bool,
|
|
};
|
|
|
|
export default HorizontalBarChart;
|