Your commit message
This commit is contained in:
@@ -0,0 +1,130 @@
|
||||
import React, { useEffect, useRef, useMemo } from "react";
|
||||
import { Chart } from "chart.js/auto";
|
||||
import { useThemeStore } from "../../../../../store/useThemeStore";
|
||||
|
||||
// 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);
|
||||
const { themeColor } = useThemeStore();
|
||||
|
||||
// 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)
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,28 @@
|
||||
import { useState } from "react";
|
||||
import ToggleHeader from "../../../../ui/inputs/ToggleHeader";
|
||||
import Widgets2D from "./Widgets2D";
|
||||
import Widgets3D from "./Widgets3D";
|
||||
import WidgetsTemplate from "./WidgetsTemplate";
|
||||
|
||||
const Widgets = () => {
|
||||
const [activeOption, setActiveOption] = useState("2D");
|
||||
|
||||
const handleToggleClick = (option: string) => {
|
||||
setActiveOption(option);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="widget-left-sideBar">
|
||||
<ToggleHeader
|
||||
options={["2D", "3D", "Templates"]}
|
||||
activeOption={activeOption}
|
||||
handleClick={handleToggleClick}
|
||||
/>
|
||||
{activeOption === "2D" && <Widgets2D />}
|
||||
{activeOption === "3D" && <Widgets3D />}
|
||||
{activeOption === "Templates" && <WidgetsTemplate />}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Widgets;
|
||||
@@ -0,0 +1,138 @@
|
||||
import React from "react";
|
||||
import { useWidgetStore } from "../../../../../store/useWidgetStore";
|
||||
import { ChartType } from "chart.js/auto";
|
||||
import ChartComponent from "./ChartComponent";
|
||||
|
||||
const chartTypes: ChartType[] = [
|
||||
"bar",
|
||||
"line",
|
||||
"pie",
|
||||
"doughnut",
|
||||
"radar",
|
||||
"polarArea",
|
||||
];
|
||||
|
||||
const sampleData = {
|
||||
labels: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul"],
|
||||
datasets: [
|
||||
{
|
||||
data: [65, 59, 80, 81, 56, 55, 40],
|
||||
backgroundColor: "#6f42c1",
|
||||
borderColor: "#ffffff",
|
||||
borderWidth: 1,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
interface WidgetProps {
|
||||
type: ChartType;
|
||||
index: number;
|
||||
title: string;
|
||||
}
|
||||
|
||||
const ChartWidget: React.FC<WidgetProps> = ({ type, index, title }) => {
|
||||
const { setDraggedAsset } = useWidgetStore((state) => state);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`chart chart-${index + 1}`}
|
||||
draggable
|
||||
onDragStart={() => {
|
||||
setDraggedAsset({
|
||||
type,
|
||||
id: `widget-${index + 1}`,
|
||||
title,
|
||||
panel: "top",
|
||||
data: sampleData,
|
||||
});
|
||||
}}
|
||||
onDragEnd={() => setDraggedAsset(null)}
|
||||
>
|
||||
<ChartComponent type={type} title={title} data={sampleData} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const ProgressBarWidget = ({
|
||||
id,
|
||||
title,
|
||||
data,
|
||||
}: {
|
||||
id: string;
|
||||
title: string;
|
||||
data: any;
|
||||
}) => {
|
||||
const { setDraggedAsset } = useWidgetStore((state) => state);
|
||||
|
||||
return (
|
||||
<div
|
||||
className="chart progressBar"
|
||||
draggable
|
||||
onDragStart={() => {
|
||||
setDraggedAsset({
|
||||
type: "progress",
|
||||
id,
|
||||
title,
|
||||
panel: "top",
|
||||
data,
|
||||
});
|
||||
}}
|
||||
onDragEnd={() => setDraggedAsset(null)}
|
||||
>
|
||||
<div className="header">{title}</div>
|
||||
{data.stocks.map((stock: any, index: number) => (
|
||||
<div className="stock" key={index}>
|
||||
<span className="stock-item">
|
||||
<span className="stockValues">
|
||||
<div className="key">{stock.key}</div>
|
||||
<div className="value">{stock.value}</div>
|
||||
</span>
|
||||
<div className="stock-description">{stock.description}</div>
|
||||
</span>
|
||||
<div className="icon">Icon</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const Widgets2D = () => {
|
||||
return (
|
||||
<div className="widget2D">
|
||||
<div className="chart-container">
|
||||
{chartTypes.map((type, index) => {
|
||||
const widgetTitle = `Widget ${index + 1}`;
|
||||
return (
|
||||
<ChartWidget
|
||||
key={index}
|
||||
type={type}
|
||||
index={index}
|
||||
title={widgetTitle}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
<ProgressBarWidget
|
||||
id="widget-7"
|
||||
title="Widget 7"
|
||||
data={{
|
||||
stocks: [
|
||||
{ key: "units", value: 1000, description: "Initial stock" },
|
||||
],
|
||||
}}
|
||||
/>
|
||||
<ProgressBarWidget
|
||||
id="widget-8"
|
||||
title="Widget 8"
|
||||
data={{
|
||||
stocks: [
|
||||
{ key: "units", value: 1000, description: "Initial stock" },
|
||||
{ key: "units", value: 500, description: "Additional stock" },
|
||||
],
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Widgets2D;
|
||||
@@ -0,0 +1,11 @@
|
||||
import React from 'react'
|
||||
|
||||
const Widgets3D = () => {
|
||||
return (
|
||||
<div>
|
||||
Widgets3D
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Widgets3D
|
||||
@@ -0,0 +1,12 @@
|
||||
import React from 'react'
|
||||
|
||||
const WidgetsTemplate = () => {
|
||||
return (
|
||||
<div>
|
||||
WidgetsTemplate
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default WidgetsTemplate
|
||||
Reference in New Issue
Block a user