129 lines
3.7 KiB
TypeScript
129 lines
3.7 KiB
TypeScript
import React, { useEffect, useRef, useMemo } from "react";
|
|
import { Chart } from "chart.js/auto";
|
|
|
|
// Define Props Interface
|
|
interface ChartComponentProps {
|
|
type: any; // Type of chart (e.g., "bar", "line", etc.)
|
|
title: string; // Title of the chart
|
|
fontFamily?: string; // Optional font family for the chart title
|
|
fontSize?: string; // Optional font size for the chart title
|
|
fontWeight?: "Light" | "Regular" | "Bold"; // Optional font weight for the chart title
|
|
data: {
|
|
labels: string[]; // Labels for the x-axis
|
|
datasets: {
|
|
data: number[]; // Data points for the chart
|
|
backgroundColor: string; // Background color for the chart
|
|
borderColor: string; // Border color for the chart
|
|
borderWidth: number; // Border width for the chart
|
|
}[];
|
|
}; // Data for the chart
|
|
}
|
|
|
|
const ChartComponent = ({
|
|
type,
|
|
title,
|
|
fontFamily,
|
|
fontSize,
|
|
fontWeight = "Regular", // Default to "Regular"
|
|
data: propsData,
|
|
}: ChartComponentProps) => {
|
|
const canvasRef = useRef<HTMLCanvasElement>(null);
|
|
|
|
// Memoize Theme Colors to Prevent Unnecessary Recalculations
|
|
// const buttonActionColor = useMemo(
|
|
// () => themeColor[0] || "#5c87df",
|
|
// [themeColor]
|
|
// );
|
|
// const buttonAbortColor = useMemo(
|
|
// () => themeColor[1] || "#ffffff",
|
|
// [themeColor]
|
|
// );
|
|
|
|
// Memoize Font Weight Mapping
|
|
const chartFontWeightMap = useMemo(
|
|
() => ({
|
|
Light: "lighter" as const,
|
|
Regular: "normal" as const,
|
|
Bold: "bold" as const,
|
|
}),
|
|
[]
|
|
);
|
|
|
|
// Parse and Memoize Font Size
|
|
const fontSizeValue = useMemo(
|
|
() => (fontSize ? parseInt(fontSize) : 12),
|
|
[fontSize]
|
|
);
|
|
|
|
// Determine and Memoize Font Weight
|
|
const fontWeightValue = useMemo(
|
|
() => chartFontWeightMap[fontWeight],
|
|
[fontWeight, chartFontWeightMap]
|
|
);
|
|
|
|
// Memoize Chart Font Style
|
|
const chartFontStyle = useMemo(
|
|
() => ({
|
|
family: fontFamily ?? "Arial",
|
|
size: fontSizeValue,
|
|
weight: fontWeightValue,
|
|
color: "#2B3344",
|
|
}),
|
|
[fontFamily, fontSizeValue, fontWeightValue]
|
|
);
|
|
|
|
// Memoize Chart Data
|
|
const data = useMemo(() => propsData, [propsData]);
|
|
|
|
// Memoize Chart Options
|
|
const options = useMemo(
|
|
() => ({
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
plugins: {
|
|
title: {
|
|
display: true,
|
|
text: title,
|
|
font: chartFontStyle,
|
|
align: "start", // Left align the title
|
|
padding: {
|
|
top: 10, // Add padding above the title
|
|
bottom: 20, // Add padding between the title and the chart
|
|
},
|
|
},
|
|
legend: {
|
|
display: false,
|
|
},
|
|
},
|
|
}),
|
|
[title, chartFontStyle]
|
|
);
|
|
|
|
// Initialize Chart on Component Mount
|
|
useEffect(() => {
|
|
if (!canvasRef.current) return;
|
|
|
|
const ctx = canvasRef.current.getContext("2d");
|
|
if (!ctx) return;
|
|
|
|
const chart = new Chart(ctx, { type, data, options });
|
|
|
|
// Cleanup: Destroy the chart instance when the component unmounts
|
|
return () => chart.destroy();
|
|
}, [type, data, options]); // Only recreate the chart when these dependencies change
|
|
|
|
return <canvas ref={canvasRef} style={{ width: "100%", height: "100%" }} />;
|
|
};
|
|
|
|
export default React.memo(ChartComponent, (prevProps, nextProps) => {
|
|
// Custom comparison function to prevent unnecessary re-renders
|
|
return (
|
|
prevProps.type === nextProps.type &&
|
|
prevProps.title === nextProps.title &&
|
|
prevProps.fontFamily === nextProps.fontFamily &&
|
|
prevProps.fontSize === nextProps.fontSize &&
|
|
prevProps.fontWeight === nextProps.fontWeight &&
|
|
JSON.stringify(prevProps.data) === JSON.stringify(nextProps.data)
|
|
);
|
|
});
|