@mamrp/components 1.7.32 → 1.7.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/charts/index.d.mts +87 -0
- package/dist/charts/index.d.ts +87 -0
- package/dist/charts/index.js +36 -6
- package/dist/charts/index.js.map +1 -1
- package/dist/charts/index.mjs +36 -6
- package/dist/charts/index.mjs.map +1 -1
- package/dist/index.js +8 -9
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +8 -9
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/charts/index.d.mts
CHANGED
|
@@ -17,6 +17,93 @@ interface Props$1 {
|
|
|
17
17
|
datasets: Dataset[];
|
|
18
18
|
height?: number;
|
|
19
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* 📊 BarChart — کامپوننت نمودار میلهای (Bar / Combo Bar+Line)
|
|
22
|
+
*
|
|
23
|
+
* @component BarChart
|
|
24
|
+
*
|
|
25
|
+
* @param {string[]} labels
|
|
26
|
+
* آرایهای از برچسبهای محور افقی (X). طول این آرایه مبنای تمام دادههاست.
|
|
27
|
+
*
|
|
28
|
+
* @param {Array<{
|
|
29
|
+
* label: string,
|
|
30
|
+
* data: (number | null)[],
|
|
31
|
+
* backgroundColor: string,
|
|
32
|
+
* borderColor?: string,
|
|
33
|
+
* borderWidth?: number,
|
|
34
|
+
* type?: "line",
|
|
35
|
+
* order?: number,
|
|
36
|
+
* tension?: number,
|
|
37
|
+
* pointRadius?: number,
|
|
38
|
+
* fill?: boolean
|
|
39
|
+
* }>} datasets
|
|
40
|
+
*
|
|
41
|
+
* آرایهای از سریهای داده برای نمایش در نمودار.
|
|
42
|
+
* هر آبجکت یک سری داده است که میتواند میلهای (Bar) یا خطی (Line) باشد:
|
|
43
|
+
*
|
|
44
|
+
* - ● **label**: عنوان سری (نمایش در Legend)
|
|
45
|
+
* - ● **data**: مقادیر هر نقطه – مقدار `null` باعث حذف نقطه از نمودار میشود.
|
|
46
|
+
* - ● **backgroundColor**: رنگ میله یا رنگ پرشدگی خط
|
|
47
|
+
* - ● **borderColor**: (اختیاری) رنگ خط دور میله یا خط
|
|
48
|
+
* - ● **borderWidth**: (اختیاری) ضخامت خط دور میله یا خط
|
|
49
|
+
* - ● **type**: اگر `"line"` باشد، سری به صورت نمودار خطی نمایش داده میشود (Combo chart)
|
|
50
|
+
* - ● **order**: ترتیب رسم (سری با order بزرگتر روی سایر سریها قرار میگیرد)
|
|
51
|
+
* - ● **tension**: (خطی) میزان خمیدگی منحنی (۰ = خط صاف)
|
|
52
|
+
* - ● **pointRadius**: (خطی) شعاع نقاط
|
|
53
|
+
* - ● **fill**: (خطی) پر شدن زیر نمودار خطی
|
|
54
|
+
*
|
|
55
|
+
*
|
|
56
|
+
* @param {number} [height=600]
|
|
57
|
+
* ارتفاع نمودار بر حسب پیکسل.
|
|
58
|
+
*
|
|
59
|
+
*
|
|
60
|
+
* @description
|
|
61
|
+
* این کامپوننت یک نمودار میلهای (BarChart) با پشتیبانی از **نمودار ترکیبی Bar + Line**
|
|
62
|
+
* است و برای نمایش دادهها در محیط فارسی و راستچین بهینهسازی شده است.
|
|
63
|
+
*
|
|
64
|
+
* ✔ پشتیبانی از فونت وزیر
|
|
65
|
+
* ✔ پشتیبانی از RTL
|
|
66
|
+
* ✔ امکان ترکیب چند سری میلهای یا خطی
|
|
67
|
+
* ✔ مقیاسدهی خودکار محور Y
|
|
68
|
+
* ✔ تشخیص خودکار بین `linear` و `logarithmic`
|
|
69
|
+
* (اگر اختلاف min/max بیش از ۵۰ برابر باشد، محور Y به حالت لگاریتمی تغییر میکند)
|
|
70
|
+
*
|
|
71
|
+
* 🔹 تعامل Legend:
|
|
72
|
+
* کلیک روی هر سری در Legend آن را مخفی/ظاهر میکند و محور Y با توجه به مقدار سریهای
|
|
73
|
+
* قابلمشاهده مجدداً محاسبه میشود.
|
|
74
|
+
*
|
|
75
|
+
*
|
|
76
|
+
* @returns {JSX.Element}
|
|
77
|
+
* یک نمودار میلهای یا ترکیبی با قابلیت شخصیسازی کامل.
|
|
78
|
+
*
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```jsx
|
|
82
|
+
* <BarChart
|
|
83
|
+
* labels={["شنبه", "یکشنبه", "دوشنبه"]}
|
|
84
|
+
* datasets={[
|
|
85
|
+
* {
|
|
86
|
+
* label: "فروش",
|
|
87
|
+
* data: [10, 20, 15],
|
|
88
|
+
* backgroundColor: "rgba(75,192,192,0.7)",
|
|
89
|
+
* },
|
|
90
|
+
* {
|
|
91
|
+
* label: "میانگین",
|
|
92
|
+
* data: [12, 18, 14],
|
|
93
|
+
* type: "line",
|
|
94
|
+
* borderColor: "red",
|
|
95
|
+
* backgroundColor: "transparent",
|
|
96
|
+
* borderWidth: 3,
|
|
97
|
+
* tension: 0.4,
|
|
98
|
+
* pointRadius: 4,
|
|
99
|
+
* fill: false,
|
|
100
|
+
* order: 0
|
|
101
|
+
* }
|
|
102
|
+
* ]}
|
|
103
|
+
* height={400}
|
|
104
|
+
* />
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
20
107
|
declare function BarChart({ labels, datasets, height }: Props$1): React.JSX.Element;
|
|
21
108
|
|
|
22
109
|
interface Props {
|
package/dist/charts/index.d.ts
CHANGED
|
@@ -17,6 +17,93 @@ interface Props$1 {
|
|
|
17
17
|
datasets: Dataset[];
|
|
18
18
|
height?: number;
|
|
19
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* 📊 BarChart — کامپوننت نمودار میلهای (Bar / Combo Bar+Line)
|
|
22
|
+
*
|
|
23
|
+
* @component BarChart
|
|
24
|
+
*
|
|
25
|
+
* @param {string[]} labels
|
|
26
|
+
* آرایهای از برچسبهای محور افقی (X). طول این آرایه مبنای تمام دادههاست.
|
|
27
|
+
*
|
|
28
|
+
* @param {Array<{
|
|
29
|
+
* label: string,
|
|
30
|
+
* data: (number | null)[],
|
|
31
|
+
* backgroundColor: string,
|
|
32
|
+
* borderColor?: string,
|
|
33
|
+
* borderWidth?: number,
|
|
34
|
+
* type?: "line",
|
|
35
|
+
* order?: number,
|
|
36
|
+
* tension?: number,
|
|
37
|
+
* pointRadius?: number,
|
|
38
|
+
* fill?: boolean
|
|
39
|
+
* }>} datasets
|
|
40
|
+
*
|
|
41
|
+
* آرایهای از سریهای داده برای نمایش در نمودار.
|
|
42
|
+
* هر آبجکت یک سری داده است که میتواند میلهای (Bar) یا خطی (Line) باشد:
|
|
43
|
+
*
|
|
44
|
+
* - ● **label**: عنوان سری (نمایش در Legend)
|
|
45
|
+
* - ● **data**: مقادیر هر نقطه – مقدار `null` باعث حذف نقطه از نمودار میشود.
|
|
46
|
+
* - ● **backgroundColor**: رنگ میله یا رنگ پرشدگی خط
|
|
47
|
+
* - ● **borderColor**: (اختیاری) رنگ خط دور میله یا خط
|
|
48
|
+
* - ● **borderWidth**: (اختیاری) ضخامت خط دور میله یا خط
|
|
49
|
+
* - ● **type**: اگر `"line"` باشد، سری به صورت نمودار خطی نمایش داده میشود (Combo chart)
|
|
50
|
+
* - ● **order**: ترتیب رسم (سری با order بزرگتر روی سایر سریها قرار میگیرد)
|
|
51
|
+
* - ● **tension**: (خطی) میزان خمیدگی منحنی (۰ = خط صاف)
|
|
52
|
+
* - ● **pointRadius**: (خطی) شعاع نقاط
|
|
53
|
+
* - ● **fill**: (خطی) پر شدن زیر نمودار خطی
|
|
54
|
+
*
|
|
55
|
+
*
|
|
56
|
+
* @param {number} [height=600]
|
|
57
|
+
* ارتفاع نمودار بر حسب پیکسل.
|
|
58
|
+
*
|
|
59
|
+
*
|
|
60
|
+
* @description
|
|
61
|
+
* این کامپوننت یک نمودار میلهای (BarChart) با پشتیبانی از **نمودار ترکیبی Bar + Line**
|
|
62
|
+
* است و برای نمایش دادهها در محیط فارسی و راستچین بهینهسازی شده است.
|
|
63
|
+
*
|
|
64
|
+
* ✔ پشتیبانی از فونت وزیر
|
|
65
|
+
* ✔ پشتیبانی از RTL
|
|
66
|
+
* ✔ امکان ترکیب چند سری میلهای یا خطی
|
|
67
|
+
* ✔ مقیاسدهی خودکار محور Y
|
|
68
|
+
* ✔ تشخیص خودکار بین `linear` و `logarithmic`
|
|
69
|
+
* (اگر اختلاف min/max بیش از ۵۰ برابر باشد، محور Y به حالت لگاریتمی تغییر میکند)
|
|
70
|
+
*
|
|
71
|
+
* 🔹 تعامل Legend:
|
|
72
|
+
* کلیک روی هر سری در Legend آن را مخفی/ظاهر میکند و محور Y با توجه به مقدار سریهای
|
|
73
|
+
* قابلمشاهده مجدداً محاسبه میشود.
|
|
74
|
+
*
|
|
75
|
+
*
|
|
76
|
+
* @returns {JSX.Element}
|
|
77
|
+
* یک نمودار میلهای یا ترکیبی با قابلیت شخصیسازی کامل.
|
|
78
|
+
*
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```jsx
|
|
82
|
+
* <BarChart
|
|
83
|
+
* labels={["شنبه", "یکشنبه", "دوشنبه"]}
|
|
84
|
+
* datasets={[
|
|
85
|
+
* {
|
|
86
|
+
* label: "فروش",
|
|
87
|
+
* data: [10, 20, 15],
|
|
88
|
+
* backgroundColor: "rgba(75,192,192,0.7)",
|
|
89
|
+
* },
|
|
90
|
+
* {
|
|
91
|
+
* label: "میانگین",
|
|
92
|
+
* data: [12, 18, 14],
|
|
93
|
+
* type: "line",
|
|
94
|
+
* borderColor: "red",
|
|
95
|
+
* backgroundColor: "transparent",
|
|
96
|
+
* borderWidth: 3,
|
|
97
|
+
* tension: 0.4,
|
|
98
|
+
* pointRadius: 4,
|
|
99
|
+
* fill: false,
|
|
100
|
+
* order: 0
|
|
101
|
+
* }
|
|
102
|
+
* ]}
|
|
103
|
+
* height={400}
|
|
104
|
+
* />
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
20
107
|
declare function BarChart({ labels, datasets, height }: Props$1): React.JSX.Element;
|
|
21
108
|
|
|
22
109
|
interface Props {
|
package/dist/charts/index.js
CHANGED
|
@@ -186,7 +186,6 @@ function PieChart({
|
|
|
186
186
|
const chart = chartRef.current;
|
|
187
187
|
const meta = chart.getDatasetMeta(0);
|
|
188
188
|
const data = chart.data.datasets[0].data;
|
|
189
|
-
const chartArea = chart.chartArea;
|
|
190
189
|
const visibleTotal = data.reduce((sum, val, index) => {
|
|
191
190
|
if (!meta.data[index] || meta.data[index].hidden !== true) {
|
|
192
191
|
return sum + val;
|
|
@@ -194,14 +193,23 @@ function PieChart({
|
|
|
194
193
|
return sum;
|
|
195
194
|
}, 0);
|
|
196
195
|
const newLabels = [];
|
|
196
|
+
const canvas = chart.canvas;
|
|
197
|
+
const canvasRect = canvas.getBoundingClientRect();
|
|
198
|
+
const containerRect = containerRef.current.getBoundingClientRect();
|
|
199
|
+
const scaleX = chart.width / canvasRect.width;
|
|
200
|
+
const scaleY = chart.height / canvasRect.height;
|
|
197
201
|
meta.data.forEach((arc, index) => {
|
|
198
202
|
if (arc.hidden) return;
|
|
199
203
|
const value = data[index];
|
|
200
204
|
if (value === 0) return;
|
|
201
205
|
const centerAngle = (arc.startAngle + arc.endAngle) / 2;
|
|
202
206
|
const midRadius = arc.innerRadius + (arc.outerRadius - arc.innerRadius) * 0.65;
|
|
203
|
-
const
|
|
204
|
-
const
|
|
207
|
+
const xInternal = arc.x - Math.cos(centerAngle) * midRadius;
|
|
208
|
+
const yInternal = arc.y + Math.sin(centerAngle) * midRadius;
|
|
209
|
+
const xDom = canvasRect.left + xInternal / scaleX;
|
|
210
|
+
const yDom = canvasRect.top + yInternal / scaleY;
|
|
211
|
+
const leftRelative = xDom - containerRect.left;
|
|
212
|
+
const topRelative = yDom - containerRect.top;
|
|
205
213
|
let text;
|
|
206
214
|
if (showPercentage) {
|
|
207
215
|
const percentage = (value / visibleTotal * 100).toFixed(1);
|
|
@@ -209,7 +217,7 @@ function PieChart({
|
|
|
209
217
|
} else {
|
|
210
218
|
text = String(value);
|
|
211
219
|
}
|
|
212
|
-
newLabels.push({
|
|
220
|
+
newLabels.push({ left: leftRelative, top: topRelative, text, opacity: 1 });
|
|
213
221
|
});
|
|
214
222
|
setDataLabels(newLabels);
|
|
215
223
|
};
|
|
@@ -223,6 +231,27 @@ function PieChart({
|
|
|
223
231
|
}, 500);
|
|
224
232
|
return () => clearTimeout(timeout);
|
|
225
233
|
}, [datasets, showDataLabels, showPercentage]);
|
|
234
|
+
(0, import_react2.useEffect)(() => {
|
|
235
|
+
const chart = chartRef.current;
|
|
236
|
+
if (!chart) return;
|
|
237
|
+
const prevOnComplete = chart.options.animation?.onComplete;
|
|
238
|
+
chart.options.animation = {
|
|
239
|
+
...chart.options.animation,
|
|
240
|
+
onComplete: () => {
|
|
241
|
+
try {
|
|
242
|
+
prevOnComplete && prevOnComplete();
|
|
243
|
+
} catch (e) {
|
|
244
|
+
}
|
|
245
|
+
calculateLabels();
|
|
246
|
+
}
|
|
247
|
+
};
|
|
248
|
+
chart.update();
|
|
249
|
+
return () => {
|
|
250
|
+
if (chart && chart.options && chart.options.animation) {
|
|
251
|
+
chart.options.animation.onComplete = prevOnComplete;
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
}, [showDataLabels, showPercentage, datasets]);
|
|
226
255
|
(0, import_react2.useEffect)(() => {
|
|
227
256
|
if (!chartRef.current || !showDataLabels) return;
|
|
228
257
|
const chart = chartRef.current;
|
|
@@ -246,6 +275,7 @@ function PieChart({
|
|
|
246
275
|
animateRotate: true,
|
|
247
276
|
animateScale: true,
|
|
248
277
|
duration: 400
|
|
278
|
+
// onComplete تنظیم میشود در useEffect بالا تا فقط رفتار محاسبه لیبل را تحت تاثیر قرار دهیم
|
|
249
279
|
},
|
|
250
280
|
plugins: {
|
|
251
281
|
tooltip: {
|
|
@@ -341,8 +371,8 @@ function PieChart({
|
|
|
341
371
|
key: index,
|
|
342
372
|
sx: {
|
|
343
373
|
position: "absolute",
|
|
344
|
-
left: label.
|
|
345
|
-
top: label.
|
|
374
|
+
left: label.left,
|
|
375
|
+
top: label.top,
|
|
346
376
|
transform: "translate(-50%, -50%)",
|
|
347
377
|
color: "#fff",
|
|
348
378
|
fontWeight: "bold",
|
package/dist/charts/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/charts/index.ts","../../react-shim.js","../../src/charts/bar/index.tsx","../../src/charts/pie/index.tsx"],"sourcesContent":["export { default as BarChart } from \"./bar\";\nexport { default as PieChart } from \"./pie\";\n","import * as React from \"react\";\nexport { React };\n","\"use client\";\nimport { useRef, useState } from \"react\";\nimport { Chart } from \"react-chartjs-2\";\nimport {\n Chart as ChartJS,\n CategoryScale,\n LinearScale,\n LogarithmicScale,\n BarElement,\n LineElement,\n PointElement,\n Tooltip,\n Legend,\n BarController,\n LineController,\n Chart as ChartType,\n} from \"chart.js\";\nimport { Box } from \"@mui/material\";\n\nChartJS.register(\n CategoryScale,\n LinearScale,\n LogarithmicScale,\n BarElement,\n LineElement,\n PointElement,\n Tooltip,\n Legend,\n BarController,\n LineController\n);\n\ninterface Dataset {\n label: string;\n data: (number | null)[];\n backgroundColor: string;\n borderColor?: string;\n borderWidth?: number;\n type?: \"line\";\n order?: number;\n tension?: number;\n pointRadius?: number;\n fill?: boolean;\n}\n\ninterface Props {\n labels: string[];\n datasets: Dataset[];\n height?: number;\n}\n\nexport default function BarChart({ labels, datasets, height }: Props) {\n const chartRef = useRef<ChartType | null>(null);\n const [hiddenIndices, setHiddenIndices] = useState<Set<number>>(new Set());\n\n // --- دادههای visible ---\n const visibleDatasets = datasets.filter((_, i) => !hiddenIndices.has(i));\n const allValues = ([] as number[]).concat(\n ...visibleDatasets.map((ds) =>\n ds.data.filter((v): v is number => v !== null)\n )\n );\n\n const minValue = allValues.length ? Math.min(...allValues) : 0;\n const maxValue = allValues.length ? Math.max(...allValues) : 1;\n\n // --- تصمیم هوشمند برای scale ---\n const useLogScale = maxValue / (minValue || 1) > 50; // اگر اختلاف >50 برابر باشد log scale\n const scaleType: \"linear\" | \"logarithmic\" = useLogScale\n ? \"logarithmic\"\n : \"linear\";\n\n // --- محاسبه محور Y ---\n let yMin = minValue;\n let yMax = maxValue;\n let stepSize: number | undefined = 1;\n\n if (scaleType === \"linear\") {\n const range = yMax - yMin;\n const targetLines = 8;\n let rawStep = range / targetLines;\n\n const magnitude = Math.pow(10, Math.floor(Math.log10(rawStep)));\n const normalized = rawStep / magnitude;\n if (normalized <= 1) stepSize = 1 * magnitude;\n else if (normalized <= 2) stepSize = 2 * magnitude;\n else if (normalized <= 5) stepSize = 5 * magnitude;\n else stepSize = 10 * magnitude;\n\n yMin = Math.floor(yMin / stepSize) * stepSize;\n yMax = Math.ceil(yMax / stepSize) * stepSize;\n } else {\n yMin = Math.max(minValue, 1);\n yMax = maxValue;\n stepSize = undefined;\n }\n\n // --- تنظیمات Chart.js ---\n const options = {\n responsive: true,\n maintainAspectRatio: false,\n animation: { duration: 500 },\n scales: {\n y: {\n type: scaleType,\n min: yMin,\n max: yMax,\n ticks: {\n ...(stepSize !== undefined ? { stepSize } : {}),\n callback: (value: any) => {\n // محدود کردن تعداد اعشار به حداکثر 2\n const num = Number(value);\n if (scaleType === \"logarithmic\") return num.toLocaleString();\n // اگر عدد خیلی بزرگ است، بدون اعشار\n if (num >= 1000) return num.toLocaleString();\n // اعشار برای اعداد کوچک\n if (stepSize && stepSize < 1) return num.toFixed(2);\n return num;\n },\n font: { family: \"'Vazir', sans-serif\", size: 14 },\n },\n },\n x: {\n ticks: {\n autoSkip: false,\n font: { family: \"'Vazir', sans-serif\", size: 13 },\n },\n },\n },\n plugins: {\n legend: {\n labels: {\n usePointStyle: true, // دایرهای\n font: { size: 16, family: \"'Vazir', sans-serif\" },\n },\n onClick: (e: any, legendItem: any, legend: any) => {\n const index = legendItem.datasetIndex as number;\n const newHidden = new Set(hiddenIndices);\n if (hiddenIndices.has(index)) newHidden.delete(index);\n else newHidden.add(index);\n setHiddenIndices(newHidden);\n },\n },\n tooltip: {\n bodyFont: { family: \"'Vazir', sans-serif\", size: 14 },\n titleFont: { family: \"'Vazir', sans-serif\", size: 16 },\n },\n datalabels: { display: false },\n },\n };\n\n // --- تنظیمات نقاط ---\n ChartJS.defaults.elements.point.radius = 5;\n ChartJS.defaults.elements.point.hoverRadius = 9;\n ChartJS.defaults.elements.point.borderWidth = 0.2;\n ChartJS.defaults.elements.point.backgroundColor = \"red\";\n ChartJS.defaults.elements.point.borderColor = \"black\";\n\n return (\n <Box height={height ?? 600}>\n <Chart\n ref={chartRef}\n type=\"bar\"\n data={{\n labels,\n datasets: datasets.map((ds, i) => ({\n ...ds,\n hidden: hiddenIndices.has(i),\n })),\n }}\n options={options}\n />\n </Box>\n );\n}\n","'use client'\nimport { Pie } from \"react-chartjs-2\";\nimport { Chart as ChartJS, ArcElement, Tooltip, Legend, Chart } from \"chart.js\";\nimport { useMemo, useRef, useEffect, useState } from \"react\";\nimport { Box, Typography } from \"@mui/material\";\nimport Image from \"next/image\";\nimport ChartDataLabels from \"chartjs-plugin-datalabels\";\n\nChartJS.register(ArcElement, Tooltip, Legend, ChartDataLabels);\n\n// تنظیم فونت پیشفرض Chart.js به Vazir\nChartJS.defaults.font.family = \"Vazir, sans-serif\";\n\ninterface Props {\n labels: string[];\n datasets: {\n label: string;\n data: number[];\n backgroundColor: string | string[];\n borderWidth?: number;\n }[];\n height?: number;\n disableLogo?: boolean;\n logoSRC?: string;\n showDataLabels?: boolean;\n showPercentage?: boolean;\n}\n/**\n * 📊 PieChart — کامپوننت نمودار دایرهای (Pie)\n *\n * @component PieChart\n *\n * @param {string[]} labels - آرایهای از برچسبها برای هر بخش نمودار.\n * @param {boolean} [showDataLabels] - نمایش یا عدم نمایش برچسبهای دادهها\n * @param {boolean} [showPercentage] - نمایش درصد به جای مقدار عددی در برچسبهای دادهها (در صورت فعال بودن showDataLabels). درصد بر اساس دادههای قابل مشاهده محاسبه میشود.\n * @param {Array<{\n * label: string,\n * data: number[],\n * backgroundColor: string[],\n * borderWidth?: number\n * }>} datasets - آرایهای شامل یک آبجکت داده برای مقداردهی بخشهای نمودار.\n * - label: عنوان دادهها (نمایش در legend)\n * - data: آرایهای از مقادیر هر بخش\n * - backgroundColor: آرایهای از رنگها برای هر بخش\n * - borderWidth: (اختیاری) ضخامت خط دور هر بخش\n * @param {number} [height] - ارتفاع نمودار (پیشفرض: 600 پیکسل)\n *\n * @description\n * این کامپوننت یک نمودار دایرهای با قابلیت شخصیسازی رنگ، داده و فونت (هماهنگ با وزیر) است.\n * - ریسپانسیو و مناسب صفحات فارسی\n * - امکان نمایش لوگو یا کامپوننت دلخواه در مرکز نمودار\n * - امکان نمایش درصد یا مقدار عددی در برچسبهای دادهها بر اساس دادههای قابل مشاهده\n *\n * @returns {JSX.Element} یک نمودار دایرهای با دادههای ورودی\n *\n * @example\n * ```jsx\n * <PieChart\n * labels={[\"بخش اول\", \"بخش دوم\", \"بخش سوم\"]}\n * datasets={[\n * {\n * label: \"مقدار\",\n * data: [10, 20, 30],\n * backgroundColor: [\n * \"rgba(75,192,192,1)\",\n * \"rgba(255,99,132,1)\",\n * \"rgba(153,102,255,1)\",\n * ],\n * borderWidth: 2,\n * },\n * ]}\n * showDataLabels={true}\n * showPercentage={true}\n * />\n * ```\n */\nexport default function PieChart({\n labels,\n datasets,\n height,\n disableLogo,\n logoSRC,\n showDataLabels = false,\n showPercentage = false,\n}: Props) {\n const chartRef = useRef<ChartJS<\"pie\">>(null);\n const [dataLabels, setDataLabels] = useState<{ x: number; y: number; text: string; opacity: number }[]>([]);\n const containerRef = useRef<HTMLDivElement>(null);\n\n // تابع محاسبه موقعیت لیبلها\n const calculateLabels = () => {\n if (!showDataLabels || !chartRef.current || !containerRef.current) return;\n\n const chart = chartRef.current;\n const meta = chart.getDatasetMeta(0);\n const data = chart.data.datasets[0].data as number[];\n\n // گرفتن اطلاعات chart area\n const chartArea = chart.chartArea;\n\n // محاسبه مجموع دادههای قابل مشاهده\n const visibleTotal = data.reduce((sum, val, index) => {\n if (!meta.data[index] || (meta.data[index] as any).hidden !== true) {\n return sum + val;\n }\n return sum;\n }, 0);\n\n const newLabels: { x: number; y: number; text: string; opacity: number }[] = [];\n\n meta.data.forEach((arc: any, index: number) => {\n if (arc.hidden) return;\n\n const value = data[index];\n if (value === 0) return;\n\n // محاسبه مرکز arc\n const centerAngle = (arc.startAngle + arc.endAngle) / 2;\n // نزدیکتر به دیواره (0.7 = بین مرکز و لبه، هرچه بیشتر به 1 نزدیکتر = نزدیکتر به لبه)\n const midRadius = arc.innerRadius + (arc.outerRadius - arc.innerRadius) * 0.65;\n\n // موقعیت در chart area - آینه کردن روی محور X\n const x = arc.x - Math.cos(centerAngle) * midRadius;\n const y = arc.y + Math.sin(centerAngle) * midRadius;\n\n let text: string;\n if (showPercentage) {\n const percentage = ((value / visibleTotal) * 100).toFixed(1);\n text = percentage + \"%\";\n } else {\n text = String(value);\n }\n\n newLabels.push({ x, y, text, opacity: 1 });\n });\n\n setDataLabels(newLabels);\n };\n\n // محاسبه موقعیت لیبلها بعد از اتمام انیمیشن\n useEffect(() => {\n if (!showDataLabels) {\n setDataLabels([]);\n return;\n }\n\n // صبر برای اتمام انیمیشن اولیه (500ms)\n const timeout = setTimeout(() => {\n calculateLabels();\n }, 500);\n\n return () => clearTimeout(timeout);\n }, [datasets, showDataLabels, showPercentage]);\n\n // آپدیت لیبلها بعد از هر تغییر در chart (مثل کلیک روی legend)\n useEffect(() => {\n if (!chartRef.current || !showDataLabels) return;\n\n const chart = chartRef.current;\n const originalUpdate = chart.update.bind(chart);\n\n chart.update = function (...args: any[]) {\n // مخفی کردن لیبلها قبل از آپدیت\n setDataLabels(prev => prev.map(l => ({ ...l, opacity: 0 })));\n\n originalUpdate(...args);\n\n // محاسبه مجدد لیبلها بعد از انیمیشن\n setTimeout(() => {\n calculateLabels();\n }, 250);\n };\n\n return () => {\n chart.update = originalUpdate;\n };\n }, [showDataLabels, showPercentage]);\n\n const options = useMemo(() => ({\n responsive: true,\n maintainAspectRatio: false,\n cutout: !disableLogo ? \"59%\" : \"0%\",\n animation: {\n animateRotate: true,\n animateScale: true,\n duration: 400,\n },\n plugins: {\n tooltip: {\n bodyFont: {\n family: \"Vazir, sans-serif\",\n size: 14,\n },\n titleFont: {\n family: \"Vazir, sans-serif\",\n size: 16,\n },\n },\n legend: {\n labels: {\n padding: 15,\n usePointStyle: true,\n color: '#666', // رنگ متن legend را نرمتر میکند\n font: {\n size: 16,\n family: \"Vazir, sans-serif\",\n },\n boxWidth: 40,\n paddingBottom: 10,\n generateLabels: (chart: any) => {\n const data = chart.data;\n const meta = chart.getDatasetMeta(0);\n return data.labels.map((label: string, index: number) => {\n const hidden = meta.data[index] ? meta.data[index].hidden : false;\n return {\n text: label,\n fillStyle: data.datasets[0].backgroundColor[index] || '#000',\n hidden: hidden,\n index: index,\n datasetIndex: 0,\n textDecoration: hidden ? 'line-through' : undefined,\n };\n });\n },\n },\n onClick: (e: any, legendItem: any, legend: any) => {\n const ci = legend.chart;\n const meta = ci.getDatasetMeta(legendItem.datasetIndex || 0);\n const index = legendItem.index;\n if (meta.data[index]) {\n meta.data[index].hidden = !meta.data[index].hidden;\n }\n ci.update();\n },\n },\n datalabels: {\n display: false, // غیرفعال - لیبلها با React رندر میشوند\n },\n },\n }), [disableLogo]);\n\n // کامپوننتی که میخواهید در مرکز نمودار نمایش داده شود\n const CenterComponent = () => {\n return (\n <div\n style={{\n padding: \"10px\",\n borderRadius: \"8px\",\n textAlign: \"center\",\n width: 220,\n }}\n >\n <Image\n alt=\"\"\n width={220}\n height={220}\n src={logoSRC ?? \"/assets/images/pilogo.png\"}\n unoptimized\n />\n </div>\n );\n };\n\n return (\n <Box ref={containerRef} height={height ?? 600} sx={{ position: \"relative\" }}>\n <Pie\n ref={chartRef}\n data={{\n labels: labels,\n datasets: datasets,\n }}\n options={options}\n />\n {/* لیبلهای سفارشی با فونت Vazir */}\n {showDataLabels && dataLabels.map((label, index) => (\n <Typography\n key={index}\n sx={{\n position: \"absolute\",\n left: label.x / (window.devicePixelRatio || 1),\n top: label.y / (window.devicePixelRatio || 1),\n transform: \"translate(-50%, -50%)\",\n color: \"#fff\",\n fontWeight: \"bold\",\n fontSize: 14,\n fontFamily: \"Vazir, sans-serif\",\n pointerEvents: \"none\",\n textShadow: \"0 1px 2px rgba(0,0,0,0.5)\",\n opacity: label.opacity,\n transition: \"opacity 0.2s ease-in-out, left 0.2s ease-in-out, top 0.2s ease-in-out\",\n }}\n >\n {label.text}\n </Typography>\n ))}\n {!disableLogo && (\n <div\n style={{\n position: \"absolute\",\n top: \"53%\",\n left: \"50%\",\n transform: \"translate(-50%, -50%)\",\n pointerEvents: \"none\", // جلوگیری از دریافت event روی این لایه\n }}\n >\n <CenterComponent />\n </div>\n )}\n </Box>\n );\n}\n"],"mappings":"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","names":["ChartJS","import_react_chartjs_2","import_chart","import_react","import_material","ChartJS","ChartDataLabels","Image"]}
|
|
1
|
+
{"version":3,"sources":["../../src/charts/index.ts","../../react-shim.js","../../src/charts/bar/index.tsx","../../src/charts/pie/index.tsx"],"sourcesContent":["export { default as BarChart } from \"./bar\";\nexport { default as PieChart } from \"./pie\";\n","import * as React from \"react\";\nexport { React };\n","\"use client\";\nimport { useRef, useState } from \"react\";\nimport { Chart } from \"react-chartjs-2\";\nimport {\n Chart as ChartJS,\n CategoryScale,\n LinearScale,\n LogarithmicScale,\n BarElement,\n LineElement,\n PointElement,\n Tooltip,\n Legend,\n BarController,\n LineController,\n Chart as ChartType,\n} from \"chart.js\";\nimport { Box } from \"@mui/material\";\n\nChartJS.register(\n CategoryScale,\n LinearScale,\n LogarithmicScale,\n BarElement,\n LineElement,\n PointElement,\n Tooltip,\n Legend,\n BarController,\n LineController\n);\n\ninterface Dataset {\n label: string;\n data: (number | null)[];\n backgroundColor: string;\n borderColor?: string;\n borderWidth?: number;\n type?: \"line\";\n order?: number;\n tension?: number;\n pointRadius?: number;\n fill?: boolean;\n}\n\ninterface Props {\n labels: string[];\n datasets: Dataset[];\n height?: number;\n}\n/**\n * 📊 BarChart — کامپوننت نمودار میلهای (Bar / Combo Bar+Line)\n *\n * @component BarChart\n *\n * @param {string[]} labels\n * آرایهای از برچسبهای محور افقی (X). طول این آرایه مبنای تمام دادههاست.\n *\n * @param {Array<{\n * label: string,\n * data: (number | null)[],\n * backgroundColor: string,\n * borderColor?: string,\n * borderWidth?: number,\n * type?: \"line\",\n * order?: number,\n * tension?: number,\n * pointRadius?: number,\n * fill?: boolean\n * }>} datasets\n *\n * آرایهای از سریهای داده برای نمایش در نمودار.\n * هر آبجکت یک سری داده است که میتواند میلهای (Bar) یا خطی (Line) باشد:\n *\n * - ● **label**: عنوان سری (نمایش در Legend)\n * - ● **data**: مقادیر هر نقطه – مقدار `null` باعث حذف نقطه از نمودار میشود.\n * - ● **backgroundColor**: رنگ میله یا رنگ پرشدگی خط\n * - ● **borderColor**: (اختیاری) رنگ خط دور میله یا خط\n * - ● **borderWidth**: (اختیاری) ضخامت خط دور میله یا خط\n * - ● **type**: اگر `\"line\"` باشد، سری به صورت نمودار خطی نمایش داده میشود (Combo chart)\n * - ● **order**: ترتیب رسم (سری با order بزرگتر روی سایر سریها قرار میگیرد)\n * - ● **tension**: (خطی) میزان خمیدگی منحنی (۰ = خط صاف)\n * - ● **pointRadius**: (خطی) شعاع نقاط\n * - ● **fill**: (خطی) پر شدن زیر نمودار خطی\n *\n *\n * @param {number} [height=600]\n * ارتفاع نمودار بر حسب پیکسل.\n *\n *\n * @description\n * این کامپوننت یک نمودار میلهای (BarChart) با پشتیبانی از **نمودار ترکیبی Bar + Line**\n * است و برای نمایش دادهها در محیط فارسی و راستچین بهینهسازی شده است.\n *\n * ✔ پشتیبانی از فونت وزیر \n * ✔ پشتیبانی از RTL \n * ✔ امکان ترکیب چند سری میلهای یا خطی \n * ✔ مقیاسدهی خودکار محور Y \n * ✔ تشخیص خودکار بین `linear` و `logarithmic` \n * (اگر اختلاف min/max بیش از ۵۰ برابر باشد، محور Y به حالت لگاریتمی تغییر میکند)\n *\n * 🔹 تعامل Legend:\n * کلیک روی هر سری در Legend آن را مخفی/ظاهر میکند و محور Y با توجه به مقدار سریهای\n * قابلمشاهده مجدداً محاسبه میشود.\n *\n *\n * @returns {JSX.Element}\n * یک نمودار میلهای یا ترکیبی با قابلیت شخصیسازی کامل.\n *\n *\n * @example\n * ```jsx\n * <BarChart\n * labels={[\"شنبه\", \"یکشنبه\", \"دوشنبه\"]}\n * datasets={[\n * {\n * label: \"فروش\",\n * data: [10, 20, 15],\n * backgroundColor: \"rgba(75,192,192,0.7)\",\n * },\n * {\n * label: \"میانگین\",\n * data: [12, 18, 14],\n * type: \"line\",\n * borderColor: \"red\",\n * backgroundColor: \"transparent\",\n * borderWidth: 3,\n * tension: 0.4,\n * pointRadius: 4,\n * fill: false,\n * order: 0\n * }\n * ]}\n * height={400}\n * />\n * ```\n */\n\nexport default function BarChart({ labels, datasets, height }: Props) {\n const chartRef = useRef<ChartType | null>(null);\n const [hiddenIndices, setHiddenIndices] = useState<Set<number>>(new Set());\n\n // --- دادههای visible ---\n const visibleDatasets = datasets.filter((_, i) => !hiddenIndices.has(i));\n const allValues = ([] as number[]).concat(\n ...visibleDatasets.map((ds) =>\n ds.data.filter((v): v is number => v !== null)\n )\n );\n\n const minValue = allValues.length ? Math.min(...allValues) : 0;\n const maxValue = allValues.length ? Math.max(...allValues) : 1;\n\n // --- تصمیم هوشمند برای scale ---\n const useLogScale = maxValue / (minValue || 1) > 50; // اگر اختلاف >50 برابر باشد log scale\n const scaleType: \"linear\" | \"logarithmic\" = useLogScale\n ? \"logarithmic\"\n : \"linear\";\n\n // --- محاسبه محور Y ---\n let yMin = minValue;\n let yMax = maxValue;\n let stepSize: number | undefined = 1;\n\n if (scaleType === \"linear\") {\n const range = yMax - yMin;\n const targetLines = 8;\n let rawStep = range / targetLines;\n\n const magnitude = Math.pow(10, Math.floor(Math.log10(rawStep)));\n const normalized = rawStep / magnitude;\n if (normalized <= 1) stepSize = 1 * magnitude;\n else if (normalized <= 2) stepSize = 2 * magnitude;\n else if (normalized <= 5) stepSize = 5 * magnitude;\n else stepSize = 10 * magnitude;\n\n yMin = Math.floor(yMin / stepSize) * stepSize;\n yMax = Math.ceil(yMax / stepSize) * stepSize;\n } else {\n yMin = Math.max(minValue, 1);\n yMax = maxValue;\n stepSize = undefined;\n }\n\n // --- تنظیمات Chart.js ---\n const options = {\n responsive: true,\n maintainAspectRatio: false,\n animation: { duration: 500 },\n scales: {\n y: {\n type: scaleType,\n min: yMin,\n max: yMax,\n ticks: {\n ...(stepSize !== undefined ? { stepSize } : {}),\n callback: (value: any) => {\n // محدود کردن تعداد اعشار به حداکثر 2\n const num = Number(value);\n if (scaleType === \"logarithmic\") return num.toLocaleString();\n // اگر عدد خیلی بزرگ است، بدون اعشار\n if (num >= 1000) return num.toLocaleString();\n // اعشار برای اعداد کوچک\n if (stepSize && stepSize < 1) return num.toFixed(2);\n return num;\n },\n font: { family: \"'Vazir', sans-serif\", size: 14 },\n },\n },\n x: {\n ticks: {\n autoSkip: false,\n font: { family: \"'Vazir', sans-serif\", size: 13 },\n },\n },\n },\n plugins: {\n legend: {\n labels: {\n usePointStyle: true, // دایرهای\n font: { size: 16, family: \"'Vazir', sans-serif\" },\n },\n onClick: (e: any, legendItem: any, legend: any) => {\n const index = legendItem.datasetIndex as number;\n const newHidden = new Set(hiddenIndices);\n if (hiddenIndices.has(index)) newHidden.delete(index);\n else newHidden.add(index);\n setHiddenIndices(newHidden);\n },\n },\n tooltip: {\n bodyFont: { family: \"'Vazir', sans-serif\", size: 14 },\n titleFont: { family: \"'Vazir', sans-serif\", size: 16 },\n },\n datalabels: { display: false },\n },\n };\n\n // --- تنظیمات نقاط ---\n ChartJS.defaults.elements.point.radius = 5;\n ChartJS.defaults.elements.point.hoverRadius = 9;\n ChartJS.defaults.elements.point.borderWidth = 0.2;\n ChartJS.defaults.elements.point.backgroundColor = \"red\";\n ChartJS.defaults.elements.point.borderColor = \"black\";\n\n return (\n <Box height={height ?? 600}>\n <Chart\n ref={chartRef}\n type=\"bar\"\n data={{\n labels,\n datasets: datasets.map((ds, i) => ({\n ...ds,\n hidden: hiddenIndices.has(i),\n })),\n }}\n options={options}\n />\n </Box>\n );\n}\n","'use client'\nimport { Pie } from \"react-chartjs-2\";\nimport { Chart as ChartJS, ArcElement, Tooltip, Legend, Chart } from \"chart.js\";\nimport { useMemo, useRef, useEffect, useState } from \"react\";\nimport { Box, Typography } from \"@mui/material\";\nimport Image from \"next/image\";\nimport ChartDataLabels from \"chartjs-plugin-datalabels\";\n\nChartJS.register(ArcElement, Tooltip, Legend, ChartDataLabels);\n\n// تنظیم فونت پیشفرض Chart.js به Vazir\nChartJS.defaults.font.family = \"Vazir, sans-serif\";\n\ninterface Props {\n labels: string[];\n datasets: {\n label: string;\n data: number[];\n backgroundColor: string | string[];\n borderWidth?: number;\n }[];\n height?: number;\n disableLogo?: boolean;\n logoSRC?: string;\n showDataLabels?: boolean;\n showPercentage?: boolean;\n}\n/**\n * 📊 PieChart — کامپوننت نمودار دایرهای (Pie)\n *\n * @component PieChart\n *\n * @param {string[]} labels - آرایهای از برچسبها برای هر بخش نمودار.\n * @param {boolean} [showDataLabels] - نمایش یا عدم نمایش برچسبهای دادهها\n * @param {boolean} [showPercentage] - نمایش درصد به جای مقدار عددی در برچسبهای دادهها (در صورت فعال بودن showDataLabels). درصد بر اساس دادههای قابل مشاهده محاسبه میشود.\n * @param {Array<{\n * label: string,\n * data: number[],\n * backgroundColor: string[],\n * borderWidth?: number\n * }>} datasets - آرایهای شامل یک آبجکت داده برای مقداردهی بخشهای نمودار.\n * - label: عنوان دادهها (نمایش در legend)\n * - data: آرایهای از مقادیر هر بخش\n * - backgroundColor: آرایهای از رنگها برای هر بخش\n * - borderWidth: (اختیاری) ضخامت خط دور هر بخش\n * @param {number} [height] - ارتفاع نمودار (پیشفرض: 600 پیکسل)\n *\n * @description\n * این کامپوننت یک نمودار دایرهای با قابلیت شخصیسازی رنگ، داده و فونت (هماهنگ با وزیر) است.\n * - ریسپانسیو و مناسب صفحات فارسی\n * - امکان نمایش لوگو یا کامپوننت دلخواه در مرکز نمودار\n * - امکان نمایش درصد یا مقدار عددی در برچسبهای دادهها بر اساس دادههای قابل مشاهده\n *\n * @returns {JSX.Element} یک نمودار دایرهای با دادههای ورودی\n *\n * @example\n * ```jsx\n * <PieChart\n * labels={[\"بخش اول\", \"بخش دوم\", \"بخش سوم\"]}\n * datasets={[\n * {\n * label: \"مقدار\",\n * data: [10, 20, 30],\n * backgroundColor: [\n * \"rgba(75,192,192,1)\",\n * \"rgba(255,99,132,1)\",\n * \"rgba(153,102,255,1)\",\n * ],\n * borderWidth: 2,\n * },\n * ]}\n * showDataLabels={true}\n * showPercentage={true}\n * />\n * ```\n */\nexport default function PieChart({\n labels,\n datasets,\n height,\n disableLogo,\n logoSRC,\n showDataLabels = false,\n showPercentage = false,\n}: Props) {\n const chartRef = useRef<ChartJS<\"pie\">>(null);\n const [dataLabels, setDataLabels] = useState<{ left: number; top: number; text: string; opacity: number }[]>([]);\n const containerRef = useRef<HTMLDivElement>(null);\n\n // تابع محاسبه موقعیت لیبلها\n const calculateLabels = () => {\n if (!showDataLabels || !chartRef.current || !containerRef.current) return;\n\n const chart = chartRef.current;\n const meta = chart.getDatasetMeta(0);\n const data = chart.data.datasets[0].data as number[];\n\n // گرفتن اطلاعات chart area\n // محاسبه مجموع دادههای قابل مشاهده\n const visibleTotal = data.reduce((sum, val, index) => {\n if (!meta.data[index] || (meta.data[index] as any).hidden !== true) {\n return sum + val;\n }\n return sum;\n }, 0);\n\n const newLabels: { left: number; top: number; text: string; opacity: number }[] = [];\n\n // ابعاد و scale برای تبدیل مختصات داخلی canvas به مختصات DOM\n const canvas = chart.canvas as HTMLCanvasElement;\n const canvasRect = canvas.getBoundingClientRect();\n const containerRect = containerRef.current.getBoundingClientRect();\n\n // chart.width/chart.height => internal canvas pixel size (device pixel scaled)\n // canvasRect.width/canvasRect.height => displayed CSS size\n const scaleX = chart.width / canvasRect.width;\n const scaleY = chart.height / canvasRect.height;\n\n meta.data.forEach((arc: any, index: number) => {\n if (arc.hidden) return;\n\n const value = data[index];\n if (value === 0) return;\n\n // محاسبه مرکز arc در واحد internal canvas pixels\n const centerAngle = (arc.startAngle + arc.endAngle) / 2;\n const midRadius = arc.innerRadius + (arc.outerRadius - arc.innerRadius) * 0.65;\n\n const xInternal = arc.x - Math.cos(centerAngle) * midRadius;\n const yInternal = arc.y + Math.sin(centerAngle) * midRadius;\n\n // تبدیل به مختصات DOM (نسبت به viewport)\n const xDom = canvasRect.left + (xInternal / scaleX);\n const yDom = canvasRect.top + (yInternal / scaleY);\n\n // تبدیل به مختصات نسبی به container (برای absolute positioning داخل container)\n const leftRelative = xDom - containerRect.left;\n const topRelative = yDom - containerRect.top;\n\n let text: string;\n if (showPercentage) {\n const percentage = ((value / visibleTotal) * 100).toFixed(1);\n text = percentage + \"%\";\n } else {\n text = String(value);\n }\n\n newLabels.push({ left: leftRelative, top: topRelative, text, opacity: 1 });\n });\n\n setDataLabels(newLabels);\n };\n\n // محاسبه موقعیت لیبلها بعد از اتمام انیمیشن\n useEffect(() => {\n if (!showDataLabels) {\n setDataLabels([]);\n return;\n }\n\n // صبر برای اتمام انیمیشن اولیه (فقط fallback) — animation.onComplete نیز تنظیم میشود.\n const timeout = setTimeout(() => {\n calculateLabels();\n }, 500);\n\n return () => clearTimeout(timeout);\n }, [datasets, showDataLabels, showPercentage]);\n\n // ثبت callback برای onComplete انیمیشن تا دقیقاً بعد از پایان انیمیشن محاسبه انجام شود\n useEffect(() => {\n const chart = chartRef.current;\n if (!chart) return;\n\n // نگهداری مقدار قبلی تا در cleanup به حالت قبل برگردد\n const prevOnComplete = (chart.options.animation as any)?.onComplete;\n\n (chart.options.animation as any) = {\n ...(chart.options.animation as any),\n onComplete: () => {\n // اگر callback قبلی هم بود، آن را اجرا کن\n try { prevOnComplete && prevOnComplete(); } catch (e) { /* ignore */ }\n calculateLabels();\n },\n };\n\n // اعمال تغییرات در chart (بدون trigger کردن انیمیشن)\n chart.update();\n\n return () => {\n // بازیابی onComplete قبلی (در صورت وجود)\n if (chart && chart.options && chart.options.animation) {\n (chart.options.animation as any).onComplete = prevOnComplete;\n }\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [showDataLabels, showPercentage, datasets]);\n\n // آپدیت لیبلها بعد از هر تغییر در chart (مثل کلیک روی legend)\n useEffect(() => {\n if (!chartRef.current || !showDataLabels) return;\n\n const chart = chartRef.current;\n const originalUpdate = chart.update.bind(chart);\n\n chart.update = function (...args: any[]) {\n // مخفی کردن لیبلها قبل از آپدیت\n setDataLabels(prev => prev.map(l => ({ ...l, opacity: 0 })));\n\n originalUpdate(...args);\n\n // محاسبه مجدد لیبلها بعد از انیمیشن\n setTimeout(() => {\n calculateLabels();\n }, 250);\n };\n\n return () => {\n chart.update = originalUpdate;\n };\n }, [showDataLabels, showPercentage]);\n\n const options = useMemo(() => ({\n responsive: true,\n maintainAspectRatio: false,\n cutout: !disableLogo ? \"59%\" : \"0%\",\n animation: {\n animateRotate: true,\n animateScale: true,\n duration: 400,\n // onComplete تنظیم میشود در useEffect بالا تا فقط رفتار محاسبه لیبل را تحت تاثیر قرار دهیم\n },\n plugins: {\n tooltip: {\n bodyFont: {\n family: \"Vazir, sans-serif\",\n size: 14,\n },\n titleFont: {\n family: \"Vazir, sans-serif\",\n size: 16,\n },\n },\n legend: {\n labels: {\n padding: 15,\n usePointStyle: true,\n color: '#666', // رنگ متن legend را نرمتر میکند\n font: {\n size: 16,\n family: \"Vazir, sans-serif\",\n },\n boxWidth: 40,\n paddingBottom: 10,\n generateLabels: (chart: any) => {\n const data = chart.data;\n const meta = chart.getDatasetMeta(0);\n return data.labels.map((label: string, index: number) => {\n const hidden = meta.data[index] ? meta.data[index].hidden : false;\n return {\n text: label,\n fillStyle: data.datasets[0].backgroundColor[index] || '#000',\n hidden: hidden,\n index: index,\n datasetIndex: 0,\n textDecoration: hidden ? 'line-through' : undefined,\n };\n });\n },\n },\n onClick: (e: any, legendItem: any, legend: any) => {\n const ci = legend.chart;\n const meta = ci.getDatasetMeta(legendItem.datasetIndex || 0);\n const index = legendItem.index;\n if (meta.data[index]) {\n meta.data[index].hidden = !meta.data[index].hidden;\n }\n ci.update();\n },\n },\n datalabels: {\n display: false, // غیرفعال - لیبلها با React رندر میشوند\n },\n },\n }), [disableLogo]);\n\n // کامپوننتی که میخواهید در مرکز نمودار نمایش داده شود\n const CenterComponent = () => {\n return (\n <div\n style={{\n padding: \"10px\",\n borderRadius: \"8px\",\n textAlign: \"center\",\n width: 220,\n }}\n >\n <Image\n alt=\"\"\n width={220}\n height={220}\n src={logoSRC ?? \"/assets/images/pilogo.png\"}\n unoptimized\n />\n </div>\n );\n };\n\n return (\n <Box ref={containerRef} height={height ?? 600} sx={{ position: \"relative\" }}>\n <Pie\n ref={chartRef}\n data={{\n labels: labels,\n datasets: datasets,\n }}\n options={options}\n />\n {/* لیبلهای سفارشی با فونت Vazir */}\n {showDataLabels && dataLabels.map((label, index) => (\n <Typography\n key={index}\n sx={{\n position: \"absolute\",\n left: label.left,\n top: label.top,\n transform: \"translate(-50%, -50%)\",\n color: \"#fff\",\n fontWeight: \"bold\",\n fontSize: 14,\n fontFamily: \"Vazir, sans-serif\",\n pointerEvents: \"none\",\n textShadow: \"0 1px 2px rgba(0,0,0,0.5)\",\n opacity: label.opacity,\n transition: \"opacity 0.2s ease-in-out, left 0.2s ease-in-out, top 0.2s ease-in-out\",\n }}\n >\n {label.text}\n </Typography>\n ))}\n {!disableLogo && (\n <div\n style={{\n position: \"absolute\",\n top: \"53%\",\n left: \"50%\",\n transform: \"translate(-50%, -50%)\",\n pointerEvents: \"none\", // جلوگیری از دریافت event روی این لایه\n }}\n >\n <CenterComponent />\n </div>\n )}\n </Box>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,YAAuB;;;ACCvB,mBAAiC;AACjC,6BAAsB;AACtB,mBAaO;AACP,sBAAoB;AAEpB,aAAAA,MAAQ;AAAA,EACN;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AA4Ge,SAAR,SAA0B,EAAE,QAAQ,UAAU,OAAO,GAAU;AACpE,QAAM,eAAW,qBAAyB,IAAI;AAC9C,QAAM,CAAC,eAAe,gBAAgB,QAAI,uBAAsB,oBAAI,IAAI,CAAC;AAGzE,QAAM,kBAAkB,SAAS,OAAO,CAAC,GAAG,MAAM,CAAC,cAAc,IAAI,CAAC,CAAC;AACvE,QAAM,YAAa,CAAC,EAAe;AAAA,IACjC,GAAG,gBAAgB;AAAA,MAAI,CAAC,OACtB,GAAG,KAAK,OAAO,CAAC,MAAmB,MAAM,IAAI;AAAA,IAC/C;AAAA,EACF;AAEA,QAAM,WAAW,UAAU,SAAS,KAAK,IAAI,GAAG,SAAS,IAAI;AAC7D,QAAM,WAAW,UAAU,SAAS,KAAK,IAAI,GAAG,SAAS,IAAI;AAG7D,QAAM,cAAc,YAAY,YAAY,KAAK;AACjD,QAAM,YAAsC,cACxC,gBACA;AAGJ,MAAI,OAAO;AACX,MAAI,OAAO;AACX,MAAI,WAA+B;AAEnC,MAAI,cAAc,UAAU;AAC1B,UAAM,QAAQ,OAAO;AACrB,UAAM,cAAc;AACpB,QAAI,UAAU,QAAQ;AAEtB,UAAM,YAAY,KAAK,IAAI,IAAI,KAAK,MAAM,KAAK,MAAM,OAAO,CAAC,CAAC;AAC9D,UAAM,aAAa,UAAU;AAC7B,QAAI,cAAc,EAAG,YAAW,IAAI;AAAA,aAC3B,cAAc,EAAG,YAAW,IAAI;AAAA,aAChC,cAAc,EAAG,YAAW,IAAI;AAAA,QACpC,YAAW,KAAK;AAErB,WAAO,KAAK,MAAM,OAAO,QAAQ,IAAI;AACrC,WAAO,KAAK,KAAK,OAAO,QAAQ,IAAI;AAAA,EACtC,OAAO;AACL,WAAO,KAAK,IAAI,UAAU,CAAC;AAC3B,WAAO;AACP,eAAW;AAAA,EACb;AAGA,QAAM,UAAU;AAAA,IACd,YAAY;AAAA,IACZ,qBAAqB;AAAA,IACrB,WAAW,EAAE,UAAU,IAAI;AAAA,IAC3B,QAAQ;AAAA,MACN,GAAG;AAAA,QACD,MAAM;AAAA,QACN,KAAK;AAAA,QACL,KAAK;AAAA,QACL,OAAO;AAAA,UACL,GAAI,aAAa,SAAY,EAAE,SAAS,IAAI,CAAC;AAAA,UAC7C,UAAU,CAAC,UAAe;AAExB,kBAAM,MAAM,OAAO,KAAK;AACxB,gBAAI,cAAc,cAAe,QAAO,IAAI,eAAe;AAE3D,gBAAI,OAAO,IAAM,QAAO,IAAI,eAAe;AAE3C,gBAAI,YAAY,WAAW,EAAG,QAAO,IAAI,QAAQ,CAAC;AAClD,mBAAO;AAAA,UACT;AAAA,UACA,MAAM,EAAE,QAAQ,uBAAuB,MAAM,GAAG;AAAA,QAClD;AAAA,MACF;AAAA,MACA,GAAG;AAAA,QACD,OAAO;AAAA,UACL,UAAU;AAAA,UACV,MAAM,EAAE,QAAQ,uBAAuB,MAAM,GAAG;AAAA,QAClD;AAAA,MACF;AAAA,IACF;AAAA,IACA,SAAS;AAAA,MACP,QAAQ;AAAA,QACN,QAAQ;AAAA,UACN,eAAe;AAAA;AAAA,UACf,MAAM,EAAE,MAAM,IAAI,QAAQ,sBAAsB;AAAA,QAClD;AAAA,QACA,SAAS,CAAC,GAAQ,YAAiB,WAAgB;AACjD,gBAAM,QAAQ,WAAW;AACzB,gBAAM,YAAY,IAAI,IAAI,aAAa;AACvC,cAAI,cAAc,IAAI,KAAK,EAAG,WAAU,OAAO,KAAK;AAAA,cAC/C,WAAU,IAAI,KAAK;AACxB,2BAAiB,SAAS;AAAA,QAC5B;AAAA,MACF;AAAA,MACA,SAAS;AAAA,QACP,UAAU,EAAE,QAAQ,uBAAuB,MAAM,GAAG;AAAA,QACpD,WAAW,EAAE,QAAQ,uBAAuB,MAAM,GAAG;AAAA,MACvD;AAAA,MACA,YAAY,EAAE,SAAS,MAAM;AAAA,IAC/B;AAAA,EACF;AAGA,eAAAA,MAAQ,SAAS,SAAS,MAAM,SAAS;AACzC,eAAAA,MAAQ,SAAS,SAAS,MAAM,cAAc;AAC9C,eAAAA,MAAQ,SAAS,SAAS,MAAM,cAAc;AAC9C,eAAAA,MAAQ,SAAS,SAAS,MAAM,kBAAkB;AAClD,eAAAA,MAAQ,SAAS,SAAS,MAAM,cAAc;AAE9C,SACE,oCAAC,uBAAI,QAAQ,UAAU,OACrB;AAAA,IAAC;AAAA;AAAA,MACC,KAAK;AAAA,MACL,MAAK;AAAA,MACL,MAAM;AAAA,QACJ;AAAA,QACA,UAAU,SAAS,IAAI,CAAC,IAAI,OAAO;AAAA,UACjC,GAAG;AAAA,UACH,QAAQ,cAAc,IAAI,CAAC;AAAA,QAC7B,EAAE;AAAA,MACJ;AAAA,MACA;AAAA;AAAA,EACF,CACF;AAEJ;;;ACpQA,IAAAC,0BAAoB;AACpB,IAAAC,gBAAqE;AACrE,IAAAC,gBAAqD;AACrD,IAAAC,mBAAgC;AAChC,mBAAkB;AAClB,uCAA4B;AAE5B,cAAAC,MAAQ,SAAS,0BAAY,uBAAS,sBAAQ,iCAAAC,OAAe;AAG7D,cAAAD,MAAQ,SAAS,KAAK,SAAS;AAiEhB,SAAR,SAA0B;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,iBAAiB;AAAA,EACjB,iBAAiB;AACnB,GAAU;AACR,QAAM,eAAW,sBAAuB,IAAI;AAC5C,QAAM,CAAC,YAAY,aAAa,QAAI,wBAAyE,CAAC,CAAC;AAC/G,QAAM,mBAAe,sBAAuB,IAAI;AAGhD,QAAM,kBAAkB,MAAM;AAC5B,QAAI,CAAC,kBAAkB,CAAC,SAAS,WAAW,CAAC,aAAa,QAAS;AAEnE,UAAM,QAAQ,SAAS;AACvB,UAAM,OAAO,MAAM,eAAe,CAAC;AACnC,UAAM,OAAO,MAAM,KAAK,SAAS,CAAC,EAAE;AAIpC,UAAM,eAAe,KAAK,OAAO,CAAC,KAAK,KAAK,UAAU;AACpD,UAAI,CAAC,KAAK,KAAK,KAAK,KAAM,KAAK,KAAK,KAAK,EAAU,WAAW,MAAM;AAClE,eAAO,MAAM;AAAA,MACf;AACA,aAAO;AAAA,IACT,GAAG,CAAC;AAEJ,UAAM,YAA4E,CAAC;AAGnF,UAAM,SAAS,MAAM;AACrB,UAAM,aAAa,OAAO,sBAAsB;AAChD,UAAM,gBAAgB,aAAa,QAAQ,sBAAsB;AAIjE,UAAM,SAAS,MAAM,QAAQ,WAAW;AACxC,UAAM,SAAS,MAAM,SAAS,WAAW;AAEzC,SAAK,KAAK,QAAQ,CAAC,KAAU,UAAkB;AAC7C,UAAI,IAAI,OAAQ;AAEhB,YAAM,QAAQ,KAAK,KAAK;AACxB,UAAI,UAAU,EAAG;AAGjB,YAAM,eAAe,IAAI,aAAa,IAAI,YAAY;AACtD,YAAM,YAAY,IAAI,eAAe,IAAI,cAAc,IAAI,eAAe;AAE1E,YAAM,YAAY,IAAI,IAAI,KAAK,IAAI,WAAW,IAAI;AAClD,YAAM,YAAY,IAAI,IAAI,KAAK,IAAI,WAAW,IAAI;AAGlD,YAAM,OAAO,WAAW,OAAQ,YAAY;AAC5C,YAAM,OAAO,WAAW,MAAO,YAAY;AAG3C,YAAM,eAAe,OAAO,cAAc;AAC1C,YAAM,cAAc,OAAO,cAAc;AAEzC,UAAI;AACJ,UAAI,gBAAgB;AAClB,cAAM,cAAe,QAAQ,eAAgB,KAAK,QAAQ,CAAC;AAC3D,eAAO,aAAa;AAAA,MACtB,OAAO;AACL,eAAO,OAAO,KAAK;AAAA,MACrB;AAEA,gBAAU,KAAK,EAAE,MAAM,cAAc,KAAK,aAAa,MAAM,SAAS,EAAE,CAAC;AAAA,IAC3E,CAAC;AAED,kBAAc,SAAS;AAAA,EACzB;AAGA,+BAAU,MAAM;AACd,QAAI,CAAC,gBAAgB;AACnB,oBAAc,CAAC,CAAC;AAChB;AAAA,IACF;AAGA,UAAM,UAAU,WAAW,MAAM;AAC/B,sBAAgB;AAAA,IAClB,GAAG,GAAG;AAEN,WAAO,MAAM,aAAa,OAAO;AAAA,EACnC,GAAG,CAAC,UAAU,gBAAgB,cAAc,CAAC;AAG7C,+BAAU,MAAM;AACd,UAAM,QAAQ,SAAS;AACvB,QAAI,CAAC,MAAO;AAGZ,UAAM,iBAAkB,MAAM,QAAQ,WAAmB;AAEzD,IAAC,MAAM,QAAQ,YAAoB;AAAA,MACjC,GAAI,MAAM,QAAQ;AAAA,MAClB,YAAY,MAAM;AAEhB,YAAI;AAAE,4BAAkB,eAAe;AAAA,QAAG,SAAS,GAAG;AAAA,QAAe;AACrE,wBAAgB;AAAA,MAClB;AAAA,IACF;AAGA,UAAM,OAAO;AAEb,WAAO,MAAM;AAEX,UAAI,SAAS,MAAM,WAAW,MAAM,QAAQ,WAAW;AACrD,QAAC,MAAM,QAAQ,UAAkB,aAAa;AAAA,MAChD;AAAA,IACF;AAAA,EAEF,GAAG,CAAC,gBAAgB,gBAAgB,QAAQ,CAAC;AAG7C,+BAAU,MAAM;AACd,QAAI,CAAC,SAAS,WAAW,CAAC,eAAgB;AAE1C,UAAM,QAAQ,SAAS;AACvB,UAAM,iBAAiB,MAAM,OAAO,KAAK,KAAK;AAE9C,UAAM,SAAS,YAAa,MAAa;AAEvC,oBAAc,UAAQ,KAAK,IAAI,QAAM,EAAE,GAAG,GAAG,SAAS,EAAE,EAAE,CAAC;AAE3D,qBAAe,GAAG,IAAI;AAGtB,iBAAW,MAAM;AACf,wBAAgB;AAAA,MAClB,GAAG,GAAG;AAAA,IACR;AAEA,WAAO,MAAM;AACX,YAAM,SAAS;AAAA,IACjB;AAAA,EACF,GAAG,CAAC,gBAAgB,cAAc,CAAC;AAEnC,QAAM,cAAU,uBAAQ,OAAO;AAAA,IAC7B,YAAY;AAAA,IACZ,qBAAqB;AAAA,IACrB,QAAQ,CAAC,cAAc,QAAQ;AAAA,IAC/B,WAAW;AAAA,MACT,eAAe;AAAA,MACf,cAAc;AAAA,MACd,UAAU;AAAA;AAAA,IAEZ;AAAA,IACA,SAAS;AAAA,MACP,SAAS;AAAA,QACP,UAAU;AAAA,UACR,QAAQ;AAAA,UACR,MAAM;AAAA,QACR;AAAA,QACA,WAAW;AAAA,UACT,QAAQ;AAAA,UACR,MAAM;AAAA,QACR;AAAA,MACF;AAAA,MACA,QAAQ;AAAA,QACN,QAAQ;AAAA,UACN,SAAS;AAAA,UACT,eAAe;AAAA,UACf,OAAO;AAAA;AAAA,UACP,MAAM;AAAA,YACJ,MAAM;AAAA,YACN,QAAQ;AAAA,UACV;AAAA,UACA,UAAU;AAAA,UACV,eAAe;AAAA,UACf,gBAAgB,CAAC,UAAe;AAC9B,kBAAM,OAAO,MAAM;AACnB,kBAAM,OAAO,MAAM,eAAe,CAAC;AACnC,mBAAO,KAAK,OAAO,IAAI,CAAC,OAAe,UAAkB;AACvD,oBAAM,SAAS,KAAK,KAAK,KAAK,IAAI,KAAK,KAAK,KAAK,EAAE,SAAS;AAC5D,qBAAO;AAAA,gBACL,MAAM;AAAA,gBACN,WAAW,KAAK,SAAS,CAAC,EAAE,gBAAgB,KAAK,KAAK;AAAA,gBACtD;AAAA,gBACA;AAAA,gBACA,cAAc;AAAA,gBACd,gBAAgB,SAAS,iBAAiB;AAAA,cAC5C;AAAA,YACF,CAAC;AAAA,UACH;AAAA,QACF;AAAA,QACA,SAAS,CAAC,GAAQ,YAAiB,WAAgB;AACjD,gBAAM,KAAK,OAAO;AAClB,gBAAM,OAAO,GAAG,eAAe,WAAW,gBAAgB,CAAC;AAC3D,gBAAM,QAAQ,WAAW;AACzB,cAAI,KAAK,KAAK,KAAK,GAAG;AACpB,iBAAK,KAAK,KAAK,EAAE,SAAS,CAAC,KAAK,KAAK,KAAK,EAAE;AAAA,UAC9C;AACA,aAAG,OAAO;AAAA,QACZ;AAAA,MACF;AAAA,MACA,YAAY;AAAA,QACV,SAAS;AAAA;AAAA,MACX;AAAA,IACF;AAAA,EACF,IAAI,CAAC,WAAW,CAAC;AAGjB,QAAM,kBAAkB,MAAM;AAC5B,WACE;AAAA,MAAC;AAAA;AAAA,QACC,OAAO;AAAA,UACL,SAAS;AAAA,UACT,cAAc;AAAA,UACd,WAAW;AAAA,UACX,OAAO;AAAA,QACT;AAAA;AAAA,MAEA;AAAA,QAAC,aAAAE;AAAA,QAAA;AAAA,UACC,KAAI;AAAA,UACJ,OAAO;AAAA,UACP,QAAQ;AAAA,UACR,KAAK,WAAW;AAAA,UAChB,aAAW;AAAA;AAAA,MACb;AAAA,IACF;AAAA,EAEJ;AAEA,SACE,oCAAC,wBAAI,KAAK,cAAc,QAAQ,UAAU,KAAK,IAAI,EAAE,UAAU,WAAW,KACxE;AAAA,IAAC;AAAA;AAAA,MACC,KAAK;AAAA,MACL,MAAM;AAAA,QACJ;AAAA,QACA;AAAA,MACF;AAAA,MACA;AAAA;AAAA,EACF,GAEC,kBAAkB,WAAW,IAAI,CAAC,OAAO,UACxC;AAAA,IAAC;AAAA;AAAA,MACC,KAAK;AAAA,MACL,IAAI;AAAA,QACF,UAAU;AAAA,QACV,MAAM,MAAM;AAAA,QACZ,KAAK,MAAM;AAAA,QACX,WAAW;AAAA,QACX,OAAO;AAAA,QACP,YAAY;AAAA,QACZ,UAAU;AAAA,QACV,YAAY;AAAA,QACZ,eAAe;AAAA,QACf,YAAY;AAAA,QACZ,SAAS,MAAM;AAAA,QACf,YAAY;AAAA,MACd;AAAA;AAAA,IAEC,MAAM;AAAA,EACT,CACD,GACA,CAAC,eACA;AAAA,IAAC;AAAA;AAAA,MACC,OAAO;AAAA,QACL,UAAU;AAAA,QACV,KAAK;AAAA,QACL,MAAM;AAAA,QACN,WAAW;AAAA,QACX,eAAe;AAAA;AAAA,MACjB;AAAA;AAAA,IAEA,oCAAC,qBAAgB;AAAA,EACnB,CAEJ;AAEJ;","names":["ChartJS","import_react_chartjs_2","import_chart","import_react","import_material","ChartJS","ChartDataLabels","Image"]}
|
package/dist/charts/index.mjs
CHANGED
|
@@ -161,7 +161,6 @@ function PieChart({
|
|
|
161
161
|
const chart = chartRef.current;
|
|
162
162
|
const meta = chart.getDatasetMeta(0);
|
|
163
163
|
const data = chart.data.datasets[0].data;
|
|
164
|
-
const chartArea = chart.chartArea;
|
|
165
164
|
const visibleTotal = data.reduce((sum, val, index) => {
|
|
166
165
|
if (!meta.data[index] || meta.data[index].hidden !== true) {
|
|
167
166
|
return sum + val;
|
|
@@ -169,14 +168,23 @@ function PieChart({
|
|
|
169
168
|
return sum;
|
|
170
169
|
}, 0);
|
|
171
170
|
const newLabels = [];
|
|
171
|
+
const canvas = chart.canvas;
|
|
172
|
+
const canvasRect = canvas.getBoundingClientRect();
|
|
173
|
+
const containerRect = containerRef.current.getBoundingClientRect();
|
|
174
|
+
const scaleX = chart.width / canvasRect.width;
|
|
175
|
+
const scaleY = chart.height / canvasRect.height;
|
|
172
176
|
meta.data.forEach((arc, index) => {
|
|
173
177
|
if (arc.hidden) return;
|
|
174
178
|
const value = data[index];
|
|
175
179
|
if (value === 0) return;
|
|
176
180
|
const centerAngle = (arc.startAngle + arc.endAngle) / 2;
|
|
177
181
|
const midRadius = arc.innerRadius + (arc.outerRadius - arc.innerRadius) * 0.65;
|
|
178
|
-
const
|
|
179
|
-
const
|
|
182
|
+
const xInternal = arc.x - Math.cos(centerAngle) * midRadius;
|
|
183
|
+
const yInternal = arc.y + Math.sin(centerAngle) * midRadius;
|
|
184
|
+
const xDom = canvasRect.left + xInternal / scaleX;
|
|
185
|
+
const yDom = canvasRect.top + yInternal / scaleY;
|
|
186
|
+
const leftRelative = xDom - containerRect.left;
|
|
187
|
+
const topRelative = yDom - containerRect.top;
|
|
180
188
|
let text;
|
|
181
189
|
if (showPercentage) {
|
|
182
190
|
const percentage = (value / visibleTotal * 100).toFixed(1);
|
|
@@ -184,7 +192,7 @@ function PieChart({
|
|
|
184
192
|
} else {
|
|
185
193
|
text = String(value);
|
|
186
194
|
}
|
|
187
|
-
newLabels.push({
|
|
195
|
+
newLabels.push({ left: leftRelative, top: topRelative, text, opacity: 1 });
|
|
188
196
|
});
|
|
189
197
|
setDataLabels(newLabels);
|
|
190
198
|
};
|
|
@@ -198,6 +206,27 @@ function PieChart({
|
|
|
198
206
|
}, 500);
|
|
199
207
|
return () => clearTimeout(timeout);
|
|
200
208
|
}, [datasets, showDataLabels, showPercentage]);
|
|
209
|
+
useEffect(() => {
|
|
210
|
+
const chart = chartRef.current;
|
|
211
|
+
if (!chart) return;
|
|
212
|
+
const prevOnComplete = chart.options.animation?.onComplete;
|
|
213
|
+
chart.options.animation = {
|
|
214
|
+
...chart.options.animation,
|
|
215
|
+
onComplete: () => {
|
|
216
|
+
try {
|
|
217
|
+
prevOnComplete && prevOnComplete();
|
|
218
|
+
} catch (e) {
|
|
219
|
+
}
|
|
220
|
+
calculateLabels();
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
chart.update();
|
|
224
|
+
return () => {
|
|
225
|
+
if (chart && chart.options && chart.options.animation) {
|
|
226
|
+
chart.options.animation.onComplete = prevOnComplete;
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
}, [showDataLabels, showPercentage, datasets]);
|
|
201
230
|
useEffect(() => {
|
|
202
231
|
if (!chartRef.current || !showDataLabels) return;
|
|
203
232
|
const chart = chartRef.current;
|
|
@@ -221,6 +250,7 @@ function PieChart({
|
|
|
221
250
|
animateRotate: true,
|
|
222
251
|
animateScale: true,
|
|
223
252
|
duration: 400
|
|
253
|
+
// onComplete تنظیم میشود در useEffect بالا تا فقط رفتار محاسبه لیبل را تحت تاثیر قرار دهیم
|
|
224
254
|
},
|
|
225
255
|
plugins: {
|
|
226
256
|
tooltip: {
|
|
@@ -316,8 +346,8 @@ function PieChart({
|
|
|
316
346
|
key: index,
|
|
317
347
|
sx: {
|
|
318
348
|
position: "absolute",
|
|
319
|
-
left: label.
|
|
320
|
-
top: label.
|
|
349
|
+
left: label.left,
|
|
350
|
+
top: label.top,
|
|
321
351
|
transform: "translate(-50%, -50%)",
|
|
322
352
|
color: "#fff",
|
|
323
353
|
fontWeight: "bold",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../react-shim.js","../../src/charts/bar/index.tsx","../../src/charts/pie/index.tsx"],"sourcesContent":["import * as React from \"react\";\nexport { React };\n","\"use client\";\nimport { useRef, useState } from \"react\";\nimport { Chart } from \"react-chartjs-2\";\nimport {\n Chart as ChartJS,\n CategoryScale,\n LinearScale,\n LogarithmicScale,\n BarElement,\n LineElement,\n PointElement,\n Tooltip,\n Legend,\n BarController,\n LineController,\n Chart as ChartType,\n} from \"chart.js\";\nimport { Box } from \"@mui/material\";\n\nChartJS.register(\n CategoryScale,\n LinearScale,\n LogarithmicScale,\n BarElement,\n LineElement,\n PointElement,\n Tooltip,\n Legend,\n BarController,\n LineController\n);\n\ninterface Dataset {\n label: string;\n data: (number | null)[];\n backgroundColor: string;\n borderColor?: string;\n borderWidth?: number;\n type?: \"line\";\n order?: number;\n tension?: number;\n pointRadius?: number;\n fill?: boolean;\n}\n\ninterface Props {\n labels: string[];\n datasets: Dataset[];\n height?: number;\n}\n\nexport default function BarChart({ labels, datasets, height }: Props) {\n const chartRef = useRef<ChartType | null>(null);\n const [hiddenIndices, setHiddenIndices] = useState<Set<number>>(new Set());\n\n // --- دادههای visible ---\n const visibleDatasets = datasets.filter((_, i) => !hiddenIndices.has(i));\n const allValues = ([] as number[]).concat(\n ...visibleDatasets.map((ds) =>\n ds.data.filter((v): v is number => v !== null)\n )\n );\n\n const minValue = allValues.length ? Math.min(...allValues) : 0;\n const maxValue = allValues.length ? Math.max(...allValues) : 1;\n\n // --- تصمیم هوشمند برای scale ---\n const useLogScale = maxValue / (minValue || 1) > 50; // اگر اختلاف >50 برابر باشد log scale\n const scaleType: \"linear\" | \"logarithmic\" = useLogScale\n ? \"logarithmic\"\n : \"linear\";\n\n // --- محاسبه محور Y ---\n let yMin = minValue;\n let yMax = maxValue;\n let stepSize: number | undefined = 1;\n\n if (scaleType === \"linear\") {\n const range = yMax - yMin;\n const targetLines = 8;\n let rawStep = range / targetLines;\n\n const magnitude = Math.pow(10, Math.floor(Math.log10(rawStep)));\n const normalized = rawStep / magnitude;\n if (normalized <= 1) stepSize = 1 * magnitude;\n else if (normalized <= 2) stepSize = 2 * magnitude;\n else if (normalized <= 5) stepSize = 5 * magnitude;\n else stepSize = 10 * magnitude;\n\n yMin = Math.floor(yMin / stepSize) * stepSize;\n yMax = Math.ceil(yMax / stepSize) * stepSize;\n } else {\n yMin = Math.max(minValue, 1);\n yMax = maxValue;\n stepSize = undefined;\n }\n\n // --- تنظیمات Chart.js ---\n const options = {\n responsive: true,\n maintainAspectRatio: false,\n animation: { duration: 500 },\n scales: {\n y: {\n type: scaleType,\n min: yMin,\n max: yMax,\n ticks: {\n ...(stepSize !== undefined ? { stepSize } : {}),\n callback: (value: any) => {\n // محدود کردن تعداد اعشار به حداکثر 2\n const num = Number(value);\n if (scaleType === \"logarithmic\") return num.toLocaleString();\n // اگر عدد خیلی بزرگ است، بدون اعشار\n if (num >= 1000) return num.toLocaleString();\n // اعشار برای اعداد کوچک\n if (stepSize && stepSize < 1) return num.toFixed(2);\n return num;\n },\n font: { family: \"'Vazir', sans-serif\", size: 14 },\n },\n },\n x: {\n ticks: {\n autoSkip: false,\n font: { family: \"'Vazir', sans-serif\", size: 13 },\n },\n },\n },\n plugins: {\n legend: {\n labels: {\n usePointStyle: true, // دایرهای\n font: { size: 16, family: \"'Vazir', sans-serif\" },\n },\n onClick: (e: any, legendItem: any, legend: any) => {\n const index = legendItem.datasetIndex as number;\n const newHidden = new Set(hiddenIndices);\n if (hiddenIndices.has(index)) newHidden.delete(index);\n else newHidden.add(index);\n setHiddenIndices(newHidden);\n },\n },\n tooltip: {\n bodyFont: { family: \"'Vazir', sans-serif\", size: 14 },\n titleFont: { family: \"'Vazir', sans-serif\", size: 16 },\n },\n datalabels: { display: false },\n },\n };\n\n // --- تنظیمات نقاط ---\n ChartJS.defaults.elements.point.radius = 5;\n ChartJS.defaults.elements.point.hoverRadius = 9;\n ChartJS.defaults.elements.point.borderWidth = 0.2;\n ChartJS.defaults.elements.point.backgroundColor = \"red\";\n ChartJS.defaults.elements.point.borderColor = \"black\";\n\n return (\n <Box height={height ?? 600}>\n <Chart\n ref={chartRef}\n type=\"bar\"\n data={{\n labels,\n datasets: datasets.map((ds, i) => ({\n ...ds,\n hidden: hiddenIndices.has(i),\n })),\n }}\n options={options}\n />\n </Box>\n );\n}\n","'use client'\nimport { Pie } from \"react-chartjs-2\";\nimport { Chart as ChartJS, ArcElement, Tooltip, Legend, Chart } from \"chart.js\";\nimport { useMemo, useRef, useEffect, useState } from \"react\";\nimport { Box, Typography } from \"@mui/material\";\nimport Image from \"next/image\";\nimport ChartDataLabels from \"chartjs-plugin-datalabels\";\n\nChartJS.register(ArcElement, Tooltip, Legend, ChartDataLabels);\n\n// تنظیم فونت پیشفرض Chart.js به Vazir\nChartJS.defaults.font.family = \"Vazir, sans-serif\";\n\ninterface Props {\n labels: string[];\n datasets: {\n label: string;\n data: number[];\n backgroundColor: string | string[];\n borderWidth?: number;\n }[];\n height?: number;\n disableLogo?: boolean;\n logoSRC?: string;\n showDataLabels?: boolean;\n showPercentage?: boolean;\n}\n/**\n * 📊 PieChart — کامپوننت نمودار دایرهای (Pie)\n *\n * @component PieChart\n *\n * @param {string[]} labels - آرایهای از برچسبها برای هر بخش نمودار.\n * @param {boolean} [showDataLabels] - نمایش یا عدم نمایش برچسبهای دادهها\n * @param {boolean} [showPercentage] - نمایش درصد به جای مقدار عددی در برچسبهای دادهها (در صورت فعال بودن showDataLabels). درصد بر اساس دادههای قابل مشاهده محاسبه میشود.\n * @param {Array<{\n * label: string,\n * data: number[],\n * backgroundColor: string[],\n * borderWidth?: number\n * }>} datasets - آرایهای شامل یک آبجکت داده برای مقداردهی بخشهای نمودار.\n * - label: عنوان دادهها (نمایش در legend)\n * - data: آرایهای از مقادیر هر بخش\n * - backgroundColor: آرایهای از رنگها برای هر بخش\n * - borderWidth: (اختیاری) ضخامت خط دور هر بخش\n * @param {number} [height] - ارتفاع نمودار (پیشفرض: 600 پیکسل)\n *\n * @description\n * این کامپوننت یک نمودار دایرهای با قابلیت شخصیسازی رنگ، داده و فونت (هماهنگ با وزیر) است.\n * - ریسپانسیو و مناسب صفحات فارسی\n * - امکان نمایش لوگو یا کامپوننت دلخواه در مرکز نمودار\n * - امکان نمایش درصد یا مقدار عددی در برچسبهای دادهها بر اساس دادههای قابل مشاهده\n *\n * @returns {JSX.Element} یک نمودار دایرهای با دادههای ورودی\n *\n * @example\n * ```jsx\n * <PieChart\n * labels={[\"بخش اول\", \"بخش دوم\", \"بخش سوم\"]}\n * datasets={[\n * {\n * label: \"مقدار\",\n * data: [10, 20, 30],\n * backgroundColor: [\n * \"rgba(75,192,192,1)\",\n * \"rgba(255,99,132,1)\",\n * \"rgba(153,102,255,1)\",\n * ],\n * borderWidth: 2,\n * },\n * ]}\n * showDataLabels={true}\n * showPercentage={true}\n * />\n * ```\n */\nexport default function PieChart({\n labels,\n datasets,\n height,\n disableLogo,\n logoSRC,\n showDataLabels = false,\n showPercentage = false,\n}: Props) {\n const chartRef = useRef<ChartJS<\"pie\">>(null);\n const [dataLabels, setDataLabels] = useState<{ x: number; y: number; text: string; opacity: number }[]>([]);\n const containerRef = useRef<HTMLDivElement>(null);\n\n // تابع محاسبه موقعیت لیبلها\n const calculateLabels = () => {\n if (!showDataLabels || !chartRef.current || !containerRef.current) return;\n\n const chart = chartRef.current;\n const meta = chart.getDatasetMeta(0);\n const data = chart.data.datasets[0].data as number[];\n\n // گرفتن اطلاعات chart area\n const chartArea = chart.chartArea;\n\n // محاسبه مجموع دادههای قابل مشاهده\n const visibleTotal = data.reduce((sum, val, index) => {\n if (!meta.data[index] || (meta.data[index] as any).hidden !== true) {\n return sum + val;\n }\n return sum;\n }, 0);\n\n const newLabels: { x: number; y: number; text: string; opacity: number }[] = [];\n\n meta.data.forEach((arc: any, index: number) => {\n if (arc.hidden) return;\n\n const value = data[index];\n if (value === 0) return;\n\n // محاسبه مرکز arc\n const centerAngle = (arc.startAngle + arc.endAngle) / 2;\n // نزدیکتر به دیواره (0.7 = بین مرکز و لبه، هرچه بیشتر به 1 نزدیکتر = نزدیکتر به لبه)\n const midRadius = arc.innerRadius + (arc.outerRadius - arc.innerRadius) * 0.65;\n\n // موقعیت در chart area - آینه کردن روی محور X\n const x = arc.x - Math.cos(centerAngle) * midRadius;\n const y = arc.y + Math.sin(centerAngle) * midRadius;\n\n let text: string;\n if (showPercentage) {\n const percentage = ((value / visibleTotal) * 100).toFixed(1);\n text = percentage + \"%\";\n } else {\n text = String(value);\n }\n\n newLabels.push({ x, y, text, opacity: 1 });\n });\n\n setDataLabels(newLabels);\n };\n\n // محاسبه موقعیت لیبلها بعد از اتمام انیمیشن\n useEffect(() => {\n if (!showDataLabels) {\n setDataLabels([]);\n return;\n }\n\n // صبر برای اتمام انیمیشن اولیه (500ms)\n const timeout = setTimeout(() => {\n calculateLabels();\n }, 500);\n\n return () => clearTimeout(timeout);\n }, [datasets, showDataLabels, showPercentage]);\n\n // آپدیت لیبلها بعد از هر تغییر در chart (مثل کلیک روی legend)\n useEffect(() => {\n if (!chartRef.current || !showDataLabels) return;\n\n const chart = chartRef.current;\n const originalUpdate = chart.update.bind(chart);\n\n chart.update = function (...args: any[]) {\n // مخفی کردن لیبلها قبل از آپدیت\n setDataLabels(prev => prev.map(l => ({ ...l, opacity: 0 })));\n\n originalUpdate(...args);\n\n // محاسبه مجدد لیبلها بعد از انیمیشن\n setTimeout(() => {\n calculateLabels();\n }, 250);\n };\n\n return () => {\n chart.update = originalUpdate;\n };\n }, [showDataLabels, showPercentage]);\n\n const options = useMemo(() => ({\n responsive: true,\n maintainAspectRatio: false,\n cutout: !disableLogo ? \"59%\" : \"0%\",\n animation: {\n animateRotate: true,\n animateScale: true,\n duration: 400,\n },\n plugins: {\n tooltip: {\n bodyFont: {\n family: \"Vazir, sans-serif\",\n size: 14,\n },\n titleFont: {\n family: \"Vazir, sans-serif\",\n size: 16,\n },\n },\n legend: {\n labels: {\n padding: 15,\n usePointStyle: true,\n color: '#666', // رنگ متن legend را نرمتر میکند\n font: {\n size: 16,\n family: \"Vazir, sans-serif\",\n },\n boxWidth: 40,\n paddingBottom: 10,\n generateLabels: (chart: any) => {\n const data = chart.data;\n const meta = chart.getDatasetMeta(0);\n return data.labels.map((label: string, index: number) => {\n const hidden = meta.data[index] ? meta.data[index].hidden : false;\n return {\n text: label,\n fillStyle: data.datasets[0].backgroundColor[index] || '#000',\n hidden: hidden,\n index: index,\n datasetIndex: 0,\n textDecoration: hidden ? 'line-through' : undefined,\n };\n });\n },\n },\n onClick: (e: any, legendItem: any, legend: any) => {\n const ci = legend.chart;\n const meta = ci.getDatasetMeta(legendItem.datasetIndex || 0);\n const index = legendItem.index;\n if (meta.data[index]) {\n meta.data[index].hidden = !meta.data[index].hidden;\n }\n ci.update();\n },\n },\n datalabels: {\n display: false, // غیرفعال - لیبلها با React رندر میشوند\n },\n },\n }), [disableLogo]);\n\n // کامپوننتی که میخواهید در مرکز نمودار نمایش داده شود\n const CenterComponent = () => {\n return (\n <div\n style={{\n padding: \"10px\",\n borderRadius: \"8px\",\n textAlign: \"center\",\n width: 220,\n }}\n >\n <Image\n alt=\"\"\n width={220}\n height={220}\n src={logoSRC ?? \"/assets/images/pilogo.png\"}\n unoptimized\n />\n </div>\n );\n };\n\n return (\n <Box ref={containerRef} height={height ?? 600} sx={{ position: \"relative\" }}>\n <Pie\n ref={chartRef}\n data={{\n labels: labels,\n datasets: datasets,\n }}\n options={options}\n />\n {/* لیبلهای سفارشی با فونت Vazir */}\n {showDataLabels && dataLabels.map((label, index) => (\n <Typography\n key={index}\n sx={{\n position: \"absolute\",\n left: label.x / (window.devicePixelRatio || 1),\n top: label.y / (window.devicePixelRatio || 1),\n transform: \"translate(-50%, -50%)\",\n color: \"#fff\",\n fontWeight: \"bold\",\n fontSize: 14,\n fontFamily: \"Vazir, sans-serif\",\n pointerEvents: \"none\",\n textShadow: \"0 1px 2px rgba(0,0,0,0.5)\",\n opacity: label.opacity,\n transition: \"opacity 0.2s ease-in-out, left 0.2s ease-in-out, top 0.2s ease-in-out\",\n }}\n >\n {label.text}\n </Typography>\n ))}\n {!disableLogo && (\n <div\n style={{\n position: \"absolute\",\n top: \"53%\",\n left: \"50%\",\n transform: \"translate(-50%, -50%)\",\n pointerEvents: \"none\", // جلوگیری از دریافت event روی این لایه\n }}\n >\n <CenterComponent />\n </div>\n )}\n </Box>\n );\n}\n"],"mappings":"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","names":["ChartJS","Tooltip","Legend","useRef","useState","Box"]}
|
|
1
|
+
{"version":3,"sources":["../../react-shim.js","../../src/charts/bar/index.tsx","../../src/charts/pie/index.tsx"],"sourcesContent":["import * as React from \"react\";\nexport { React };\n","\"use client\";\nimport { useRef, useState } from \"react\";\nimport { Chart } from \"react-chartjs-2\";\nimport {\n Chart as ChartJS,\n CategoryScale,\n LinearScale,\n LogarithmicScale,\n BarElement,\n LineElement,\n PointElement,\n Tooltip,\n Legend,\n BarController,\n LineController,\n Chart as ChartType,\n} from \"chart.js\";\nimport { Box } from \"@mui/material\";\n\nChartJS.register(\n CategoryScale,\n LinearScale,\n LogarithmicScale,\n BarElement,\n LineElement,\n PointElement,\n Tooltip,\n Legend,\n BarController,\n LineController\n);\n\ninterface Dataset {\n label: string;\n data: (number | null)[];\n backgroundColor: string;\n borderColor?: string;\n borderWidth?: number;\n type?: \"line\";\n order?: number;\n tension?: number;\n pointRadius?: number;\n fill?: boolean;\n}\n\ninterface Props {\n labels: string[];\n datasets: Dataset[];\n height?: number;\n}\n/**\n * 📊 BarChart — کامپوننت نمودار میلهای (Bar / Combo Bar+Line)\n *\n * @component BarChart\n *\n * @param {string[]} labels\n * آرایهای از برچسبهای محور افقی (X). طول این آرایه مبنای تمام دادههاست.\n *\n * @param {Array<{\n * label: string,\n * data: (number | null)[],\n * backgroundColor: string,\n * borderColor?: string,\n * borderWidth?: number,\n * type?: \"line\",\n * order?: number,\n * tension?: number,\n * pointRadius?: number,\n * fill?: boolean\n * }>} datasets\n *\n * آرایهای از سریهای داده برای نمایش در نمودار.\n * هر آبجکت یک سری داده است که میتواند میلهای (Bar) یا خطی (Line) باشد:\n *\n * - ● **label**: عنوان سری (نمایش در Legend)\n * - ● **data**: مقادیر هر نقطه – مقدار `null` باعث حذف نقطه از نمودار میشود.\n * - ● **backgroundColor**: رنگ میله یا رنگ پرشدگی خط\n * - ● **borderColor**: (اختیاری) رنگ خط دور میله یا خط\n * - ● **borderWidth**: (اختیاری) ضخامت خط دور میله یا خط\n * - ● **type**: اگر `\"line\"` باشد، سری به صورت نمودار خطی نمایش داده میشود (Combo chart)\n * - ● **order**: ترتیب رسم (سری با order بزرگتر روی سایر سریها قرار میگیرد)\n * - ● **tension**: (خطی) میزان خمیدگی منحنی (۰ = خط صاف)\n * - ● **pointRadius**: (خطی) شعاع نقاط\n * - ● **fill**: (خطی) پر شدن زیر نمودار خطی\n *\n *\n * @param {number} [height=600]\n * ارتفاع نمودار بر حسب پیکسل.\n *\n *\n * @description\n * این کامپوننت یک نمودار میلهای (BarChart) با پشتیبانی از **نمودار ترکیبی Bar + Line**\n * است و برای نمایش دادهها در محیط فارسی و راستچین بهینهسازی شده است.\n *\n * ✔ پشتیبانی از فونت وزیر \n * ✔ پشتیبانی از RTL \n * ✔ امکان ترکیب چند سری میلهای یا خطی \n * ✔ مقیاسدهی خودکار محور Y \n * ✔ تشخیص خودکار بین `linear` و `logarithmic` \n * (اگر اختلاف min/max بیش از ۵۰ برابر باشد، محور Y به حالت لگاریتمی تغییر میکند)\n *\n * 🔹 تعامل Legend:\n * کلیک روی هر سری در Legend آن را مخفی/ظاهر میکند و محور Y با توجه به مقدار سریهای\n * قابلمشاهده مجدداً محاسبه میشود.\n *\n *\n * @returns {JSX.Element}\n * یک نمودار میلهای یا ترکیبی با قابلیت شخصیسازی کامل.\n *\n *\n * @example\n * ```jsx\n * <BarChart\n * labels={[\"شنبه\", \"یکشنبه\", \"دوشنبه\"]}\n * datasets={[\n * {\n * label: \"فروش\",\n * data: [10, 20, 15],\n * backgroundColor: \"rgba(75,192,192,0.7)\",\n * },\n * {\n * label: \"میانگین\",\n * data: [12, 18, 14],\n * type: \"line\",\n * borderColor: \"red\",\n * backgroundColor: \"transparent\",\n * borderWidth: 3,\n * tension: 0.4,\n * pointRadius: 4,\n * fill: false,\n * order: 0\n * }\n * ]}\n * height={400}\n * />\n * ```\n */\n\nexport default function BarChart({ labels, datasets, height }: Props) {\n const chartRef = useRef<ChartType | null>(null);\n const [hiddenIndices, setHiddenIndices] = useState<Set<number>>(new Set());\n\n // --- دادههای visible ---\n const visibleDatasets = datasets.filter((_, i) => !hiddenIndices.has(i));\n const allValues = ([] as number[]).concat(\n ...visibleDatasets.map((ds) =>\n ds.data.filter((v): v is number => v !== null)\n )\n );\n\n const minValue = allValues.length ? Math.min(...allValues) : 0;\n const maxValue = allValues.length ? Math.max(...allValues) : 1;\n\n // --- تصمیم هوشمند برای scale ---\n const useLogScale = maxValue / (minValue || 1) > 50; // اگر اختلاف >50 برابر باشد log scale\n const scaleType: \"linear\" | \"logarithmic\" = useLogScale\n ? \"logarithmic\"\n : \"linear\";\n\n // --- محاسبه محور Y ---\n let yMin = minValue;\n let yMax = maxValue;\n let stepSize: number | undefined = 1;\n\n if (scaleType === \"linear\") {\n const range = yMax - yMin;\n const targetLines = 8;\n let rawStep = range / targetLines;\n\n const magnitude = Math.pow(10, Math.floor(Math.log10(rawStep)));\n const normalized = rawStep / magnitude;\n if (normalized <= 1) stepSize = 1 * magnitude;\n else if (normalized <= 2) stepSize = 2 * magnitude;\n else if (normalized <= 5) stepSize = 5 * magnitude;\n else stepSize = 10 * magnitude;\n\n yMin = Math.floor(yMin / stepSize) * stepSize;\n yMax = Math.ceil(yMax / stepSize) * stepSize;\n } else {\n yMin = Math.max(minValue, 1);\n yMax = maxValue;\n stepSize = undefined;\n }\n\n // --- تنظیمات Chart.js ---\n const options = {\n responsive: true,\n maintainAspectRatio: false,\n animation: { duration: 500 },\n scales: {\n y: {\n type: scaleType,\n min: yMin,\n max: yMax,\n ticks: {\n ...(stepSize !== undefined ? { stepSize } : {}),\n callback: (value: any) => {\n // محدود کردن تعداد اعشار به حداکثر 2\n const num = Number(value);\n if (scaleType === \"logarithmic\") return num.toLocaleString();\n // اگر عدد خیلی بزرگ است، بدون اعشار\n if (num >= 1000) return num.toLocaleString();\n // اعشار برای اعداد کوچک\n if (stepSize && stepSize < 1) return num.toFixed(2);\n return num;\n },\n font: { family: \"'Vazir', sans-serif\", size: 14 },\n },\n },\n x: {\n ticks: {\n autoSkip: false,\n font: { family: \"'Vazir', sans-serif\", size: 13 },\n },\n },\n },\n plugins: {\n legend: {\n labels: {\n usePointStyle: true, // دایرهای\n font: { size: 16, family: \"'Vazir', sans-serif\" },\n },\n onClick: (e: any, legendItem: any, legend: any) => {\n const index = legendItem.datasetIndex as number;\n const newHidden = new Set(hiddenIndices);\n if (hiddenIndices.has(index)) newHidden.delete(index);\n else newHidden.add(index);\n setHiddenIndices(newHidden);\n },\n },\n tooltip: {\n bodyFont: { family: \"'Vazir', sans-serif\", size: 14 },\n titleFont: { family: \"'Vazir', sans-serif\", size: 16 },\n },\n datalabels: { display: false },\n },\n };\n\n // --- تنظیمات نقاط ---\n ChartJS.defaults.elements.point.radius = 5;\n ChartJS.defaults.elements.point.hoverRadius = 9;\n ChartJS.defaults.elements.point.borderWidth = 0.2;\n ChartJS.defaults.elements.point.backgroundColor = \"red\";\n ChartJS.defaults.elements.point.borderColor = \"black\";\n\n return (\n <Box height={height ?? 600}>\n <Chart\n ref={chartRef}\n type=\"bar\"\n data={{\n labels,\n datasets: datasets.map((ds, i) => ({\n ...ds,\n hidden: hiddenIndices.has(i),\n })),\n }}\n options={options}\n />\n </Box>\n );\n}\n","'use client'\nimport { Pie } from \"react-chartjs-2\";\nimport { Chart as ChartJS, ArcElement, Tooltip, Legend, Chart } from \"chart.js\";\nimport { useMemo, useRef, useEffect, useState } from \"react\";\nimport { Box, Typography } from \"@mui/material\";\nimport Image from \"next/image\";\nimport ChartDataLabels from \"chartjs-plugin-datalabels\";\n\nChartJS.register(ArcElement, Tooltip, Legend, ChartDataLabels);\n\n// تنظیم فونت پیشفرض Chart.js به Vazir\nChartJS.defaults.font.family = \"Vazir, sans-serif\";\n\ninterface Props {\n labels: string[];\n datasets: {\n label: string;\n data: number[];\n backgroundColor: string | string[];\n borderWidth?: number;\n }[];\n height?: number;\n disableLogo?: boolean;\n logoSRC?: string;\n showDataLabels?: boolean;\n showPercentage?: boolean;\n}\n/**\n * 📊 PieChart — کامپوننت نمودار دایرهای (Pie)\n *\n * @component PieChart\n *\n * @param {string[]} labels - آرایهای از برچسبها برای هر بخش نمودار.\n * @param {boolean} [showDataLabels] - نمایش یا عدم نمایش برچسبهای دادهها\n * @param {boolean} [showPercentage] - نمایش درصد به جای مقدار عددی در برچسبهای دادهها (در صورت فعال بودن showDataLabels). درصد بر اساس دادههای قابل مشاهده محاسبه میشود.\n * @param {Array<{\n * label: string,\n * data: number[],\n * backgroundColor: string[],\n * borderWidth?: number\n * }>} datasets - آرایهای شامل یک آبجکت داده برای مقداردهی بخشهای نمودار.\n * - label: عنوان دادهها (نمایش در legend)\n * - data: آرایهای از مقادیر هر بخش\n * - backgroundColor: آرایهای از رنگها برای هر بخش\n * - borderWidth: (اختیاری) ضخامت خط دور هر بخش\n * @param {number} [height] - ارتفاع نمودار (پیشفرض: 600 پیکسل)\n *\n * @description\n * این کامپوننت یک نمودار دایرهای با قابلیت شخصیسازی رنگ، داده و فونت (هماهنگ با وزیر) است.\n * - ریسپانسیو و مناسب صفحات فارسی\n * - امکان نمایش لوگو یا کامپوننت دلخواه در مرکز نمودار\n * - امکان نمایش درصد یا مقدار عددی در برچسبهای دادهها بر اساس دادههای قابل مشاهده\n *\n * @returns {JSX.Element} یک نمودار دایرهای با دادههای ورودی\n *\n * @example\n * ```jsx\n * <PieChart\n * labels={[\"بخش اول\", \"بخش دوم\", \"بخش سوم\"]}\n * datasets={[\n * {\n * label: \"مقدار\",\n * data: [10, 20, 30],\n * backgroundColor: [\n * \"rgba(75,192,192,1)\",\n * \"rgba(255,99,132,1)\",\n * \"rgba(153,102,255,1)\",\n * ],\n * borderWidth: 2,\n * },\n * ]}\n * showDataLabels={true}\n * showPercentage={true}\n * />\n * ```\n */\nexport default function PieChart({\n labels,\n datasets,\n height,\n disableLogo,\n logoSRC,\n showDataLabels = false,\n showPercentage = false,\n}: Props) {\n const chartRef = useRef<ChartJS<\"pie\">>(null);\n const [dataLabels, setDataLabels] = useState<{ left: number; top: number; text: string; opacity: number }[]>([]);\n const containerRef = useRef<HTMLDivElement>(null);\n\n // تابع محاسبه موقعیت لیبلها\n const calculateLabels = () => {\n if (!showDataLabels || !chartRef.current || !containerRef.current) return;\n\n const chart = chartRef.current;\n const meta = chart.getDatasetMeta(0);\n const data = chart.data.datasets[0].data as number[];\n\n // گرفتن اطلاعات chart area\n // محاسبه مجموع دادههای قابل مشاهده\n const visibleTotal = data.reduce((sum, val, index) => {\n if (!meta.data[index] || (meta.data[index] as any).hidden !== true) {\n return sum + val;\n }\n return sum;\n }, 0);\n\n const newLabels: { left: number; top: number; text: string; opacity: number }[] = [];\n\n // ابعاد و scale برای تبدیل مختصات داخلی canvas به مختصات DOM\n const canvas = chart.canvas as HTMLCanvasElement;\n const canvasRect = canvas.getBoundingClientRect();\n const containerRect = containerRef.current.getBoundingClientRect();\n\n // chart.width/chart.height => internal canvas pixel size (device pixel scaled)\n // canvasRect.width/canvasRect.height => displayed CSS size\n const scaleX = chart.width / canvasRect.width;\n const scaleY = chart.height / canvasRect.height;\n\n meta.data.forEach((arc: any, index: number) => {\n if (arc.hidden) return;\n\n const value = data[index];\n if (value === 0) return;\n\n // محاسبه مرکز arc در واحد internal canvas pixels\n const centerAngle = (arc.startAngle + arc.endAngle) / 2;\n const midRadius = arc.innerRadius + (arc.outerRadius - arc.innerRadius) * 0.65;\n\n const xInternal = arc.x - Math.cos(centerAngle) * midRadius;\n const yInternal = arc.y + Math.sin(centerAngle) * midRadius;\n\n // تبدیل به مختصات DOM (نسبت به viewport)\n const xDom = canvasRect.left + (xInternal / scaleX);\n const yDom = canvasRect.top + (yInternal / scaleY);\n\n // تبدیل به مختصات نسبی به container (برای absolute positioning داخل container)\n const leftRelative = xDom - containerRect.left;\n const topRelative = yDom - containerRect.top;\n\n let text: string;\n if (showPercentage) {\n const percentage = ((value / visibleTotal) * 100).toFixed(1);\n text = percentage + \"%\";\n } else {\n text = String(value);\n }\n\n newLabels.push({ left: leftRelative, top: topRelative, text, opacity: 1 });\n });\n\n setDataLabels(newLabels);\n };\n\n // محاسبه موقعیت لیبلها بعد از اتمام انیمیشن\n useEffect(() => {\n if (!showDataLabels) {\n setDataLabels([]);\n return;\n }\n\n // صبر برای اتمام انیمیشن اولیه (فقط fallback) — animation.onComplete نیز تنظیم میشود.\n const timeout = setTimeout(() => {\n calculateLabels();\n }, 500);\n\n return () => clearTimeout(timeout);\n }, [datasets, showDataLabels, showPercentage]);\n\n // ثبت callback برای onComplete انیمیشن تا دقیقاً بعد از پایان انیمیشن محاسبه انجام شود\n useEffect(() => {\n const chart = chartRef.current;\n if (!chart) return;\n\n // نگهداری مقدار قبلی تا در cleanup به حالت قبل برگردد\n const prevOnComplete = (chart.options.animation as any)?.onComplete;\n\n (chart.options.animation as any) = {\n ...(chart.options.animation as any),\n onComplete: () => {\n // اگر callback قبلی هم بود، آن را اجرا کن\n try { prevOnComplete && prevOnComplete(); } catch (e) { /* ignore */ }\n calculateLabels();\n },\n };\n\n // اعمال تغییرات در chart (بدون trigger کردن انیمیشن)\n chart.update();\n\n return () => {\n // بازیابی onComplete قبلی (در صورت وجود)\n if (chart && chart.options && chart.options.animation) {\n (chart.options.animation as any).onComplete = prevOnComplete;\n }\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [showDataLabels, showPercentage, datasets]);\n\n // آپدیت لیبلها بعد از هر تغییر در chart (مثل کلیک روی legend)\n useEffect(() => {\n if (!chartRef.current || !showDataLabels) return;\n\n const chart = chartRef.current;\n const originalUpdate = chart.update.bind(chart);\n\n chart.update = function (...args: any[]) {\n // مخفی کردن لیبلها قبل از آپدیت\n setDataLabels(prev => prev.map(l => ({ ...l, opacity: 0 })));\n\n originalUpdate(...args);\n\n // محاسبه مجدد لیبلها بعد از انیمیشن\n setTimeout(() => {\n calculateLabels();\n }, 250);\n };\n\n return () => {\n chart.update = originalUpdate;\n };\n }, [showDataLabels, showPercentage]);\n\n const options = useMemo(() => ({\n responsive: true,\n maintainAspectRatio: false,\n cutout: !disableLogo ? \"59%\" : \"0%\",\n animation: {\n animateRotate: true,\n animateScale: true,\n duration: 400,\n // onComplete تنظیم میشود در useEffect بالا تا فقط رفتار محاسبه لیبل را تحت تاثیر قرار دهیم\n },\n plugins: {\n tooltip: {\n bodyFont: {\n family: \"Vazir, sans-serif\",\n size: 14,\n },\n titleFont: {\n family: \"Vazir, sans-serif\",\n size: 16,\n },\n },\n legend: {\n labels: {\n padding: 15,\n usePointStyle: true,\n color: '#666', // رنگ متن legend را نرمتر میکند\n font: {\n size: 16,\n family: \"Vazir, sans-serif\",\n },\n boxWidth: 40,\n paddingBottom: 10,\n generateLabels: (chart: any) => {\n const data = chart.data;\n const meta = chart.getDatasetMeta(0);\n return data.labels.map((label: string, index: number) => {\n const hidden = meta.data[index] ? meta.data[index].hidden : false;\n return {\n text: label,\n fillStyle: data.datasets[0].backgroundColor[index] || '#000',\n hidden: hidden,\n index: index,\n datasetIndex: 0,\n textDecoration: hidden ? 'line-through' : undefined,\n };\n });\n },\n },\n onClick: (e: any, legendItem: any, legend: any) => {\n const ci = legend.chart;\n const meta = ci.getDatasetMeta(legendItem.datasetIndex || 0);\n const index = legendItem.index;\n if (meta.data[index]) {\n meta.data[index].hidden = !meta.data[index].hidden;\n }\n ci.update();\n },\n },\n datalabels: {\n display: false, // غیرفعال - لیبلها با React رندر میشوند\n },\n },\n }), [disableLogo]);\n\n // کامپوننتی که میخواهید در مرکز نمودار نمایش داده شود\n const CenterComponent = () => {\n return (\n <div\n style={{\n padding: \"10px\",\n borderRadius: \"8px\",\n textAlign: \"center\",\n width: 220,\n }}\n >\n <Image\n alt=\"\"\n width={220}\n height={220}\n src={logoSRC ?? \"/assets/images/pilogo.png\"}\n unoptimized\n />\n </div>\n );\n };\n\n return (\n <Box ref={containerRef} height={height ?? 600} sx={{ position: \"relative\" }}>\n <Pie\n ref={chartRef}\n data={{\n labels: labels,\n datasets: datasets,\n }}\n options={options}\n />\n {/* لیبلهای سفارشی با فونت Vazir */}\n {showDataLabels && dataLabels.map((label, index) => (\n <Typography\n key={index}\n sx={{\n position: \"absolute\",\n left: label.left,\n top: label.top,\n transform: \"translate(-50%, -50%)\",\n color: \"#fff\",\n fontWeight: \"bold\",\n fontSize: 14,\n fontFamily: \"Vazir, sans-serif\",\n pointerEvents: \"none\",\n textShadow: \"0 1px 2px rgba(0,0,0,0.5)\",\n opacity: label.opacity,\n transition: \"opacity 0.2s ease-in-out, left 0.2s ease-in-out, top 0.2s ease-in-out\",\n }}\n >\n {label.text}\n </Typography>\n ))}\n {!disableLogo && (\n <div\n style={{\n position: \"absolute\",\n top: \"53%\",\n left: \"50%\",\n transform: \"translate(-50%, -50%)\",\n pointerEvents: \"none\", // جلوگیری از دریافت event روی این لایه\n }}\n >\n <CenterComponent />\n </div>\n )}\n </Box>\n );\n}\n"],"mappings":"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","names":["ChartJS","Tooltip","Legend","useRef","useState","Box"]}
|