@mamrp/components 1.7.28 → 1.7.30
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 +67 -11
- package/dist/charts/index.d.ts +67 -11
- package/dist/charts/index.js +207 -43
- package/dist/charts/index.js.map +1 -1
- package/dist/charts/index.mjs +209 -44
- package/dist/charts/index.mjs.map +1 -1
- package/dist/date-pickers/index.d.mts +13 -0
- package/dist/date-pickers/index.d.ts +13 -0
- package/dist/date-pickers/index.js +3 -1
- package/dist/date-pickers/index.js.map +1 -1
- package/dist/date-pickers/index.mjs +3 -1
- package/dist/date-pickers/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/charts/index.d.mts
CHANGED
|
@@ -15,6 +15,36 @@ interface Props$1 {
|
|
|
15
15
|
fill?: boolean;
|
|
16
16
|
}[];
|
|
17
17
|
height?: number;
|
|
18
|
+
/**
|
|
19
|
+
* حداقل مقدار محور Y (اختیاری)
|
|
20
|
+
* اگر ست نشود، Chart.js خودش محاسبه میکند
|
|
21
|
+
* ⚠️ نکته: اگر این مقدار ست شود، beginAtZero نادیده گرفته میشود
|
|
22
|
+
*/
|
|
23
|
+
yAxisMin?: number;
|
|
24
|
+
/**
|
|
25
|
+
* حداکثر مقدار محور Y (اختیاری)
|
|
26
|
+
* اگر ست نشود، Chart.js خودش محاسبه میکند
|
|
27
|
+
*/
|
|
28
|
+
yAxisMax?: number;
|
|
29
|
+
/**
|
|
30
|
+
* آیا محور Y از صفر شروع شود؟
|
|
31
|
+
* پیشفرض: true
|
|
32
|
+
* ⚠️ نکته: اگر yAxisMin ست شود، این گزینه نادیده گرفته میشود
|
|
33
|
+
*/
|
|
34
|
+
beginAtZero?: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* استفاده از مقیاس لگاریتمی برای محور Y
|
|
37
|
+
* مناسب برای دادههایی که اختلاف خیلی زیادی دارند
|
|
38
|
+
* پیشفرض: false
|
|
39
|
+
* ⚠️ نکته: مقادیر 0 یا منفی در مقیاس لگاریتمی نمایش داده نمیشوند
|
|
40
|
+
*/
|
|
41
|
+
logarithmic?: boolean;
|
|
42
|
+
/**
|
|
43
|
+
* حداقل ارتفاع میله برای دادههای خیلی کوچک (پیکسل)
|
|
44
|
+
* مقادیر خیلی کوچک (مثل 1) در کنار مقادیر بزرگ (مثل 10000) گم نمیشوند
|
|
45
|
+
* پیشفرض: 0 (غیرفعال)
|
|
46
|
+
*/
|
|
47
|
+
minBarLength?: number;
|
|
18
48
|
}
|
|
19
49
|
/**
|
|
20
50
|
* 📊 BarChart — کامپوننت نمودار میلهای (Bar/Combo)
|
|
@@ -46,6 +76,11 @@ interface Props$1 {
|
|
|
46
76
|
* - fill: (اختیاری) پر شدن زیر خط (برای سریهای خطی)
|
|
47
77
|
*
|
|
48
78
|
* @param {number} [height] - ارتفاع نمودار (پیشفرض: 600 پیکسل)
|
|
79
|
+
* @param {number} [yAxisMin] - حداقل مقدار محور Y (نادیدهگرفتن beginAtZero)
|
|
80
|
+
* @param {number} [yAxisMax] - حداکثر مقدار محور Y
|
|
81
|
+
* @param {boolean} [beginAtZero=true] - آیا محور Y از صفر شروع شود؟ (اگر yAxisMin ست شود نادیده گرفته میشود)
|
|
82
|
+
* @param {boolean} [logarithmic=false] - استفاده از مقیاس لگاریتمی (مقادیر 0 یا منفی نمایش داده نمیشوند)
|
|
83
|
+
* @param {number} [minBarLength=0] - حداقل ارتفاع میله (پیکسل) - برای جلوگیری از گم شدن دادههای کوچک
|
|
49
84
|
*
|
|
50
85
|
* @description
|
|
51
86
|
* این کامپوننت یک نمودار میلهای (Bar) یا ترکیبی Bar/Line با قابلیت شخصیسازی کامل است.
|
|
@@ -53,11 +88,14 @@ interface Props$1 {
|
|
|
53
88
|
* - ریسپانسیو و مناسب صفحات فارسی
|
|
54
89
|
* - امکان نمایش چند سری داده به صورت میلهای و خطی همزمان (Combo)
|
|
55
90
|
* - شخصیسازی رنگ، ضخامت، ترتیب و استایل هر سری
|
|
91
|
+
* - پشتیبانی از مقیاس لگاریتمی برای دادههای با اختلاف زیاد
|
|
92
|
+
* - minBarLength برای نمایش دادههای خیلی کوچک در کنار بزرگها
|
|
56
93
|
*
|
|
57
94
|
* @returns {JSX.Element} یک نمودار میلهای یا ترکیبی با دادههای ورودی
|
|
58
95
|
*
|
|
59
96
|
* @example
|
|
60
97
|
* ```jsx
|
|
98
|
+
* // نمودار ساده
|
|
61
99
|
* <BarChart
|
|
62
100
|
* labels={["شنبه", "یکشنبه", "دوشنبه"]}
|
|
63
101
|
* datasets={[
|
|
@@ -66,24 +104,42 @@ interface Props$1 {
|
|
|
66
104
|
* data: [10, 20, 15],
|
|
67
105
|
* backgroundColor: "rgba(75,192,192,0.7)",
|
|
68
106
|
* },
|
|
107
|
+
* ]}
|
|
108
|
+
* height={400}
|
|
109
|
+
* />
|
|
110
|
+
*
|
|
111
|
+
* // نمودار با دادههای اختلاف زیاد (مقیاس لگاریتمی)
|
|
112
|
+
* <BarChart
|
|
113
|
+
* labels={["A", "B", "C", "D"]}
|
|
114
|
+
* datasets={[
|
|
115
|
+
* {
|
|
116
|
+
* label: "مقادیر",
|
|
117
|
+
* data: [5, 50, 5000, 50000],
|
|
118
|
+
* backgroundColor: "rgba(75,192,192,0.7)",
|
|
119
|
+
* },
|
|
120
|
+
* ]}
|
|
121
|
+
* logarithmic={true}
|
|
122
|
+
* height={400}
|
|
123
|
+
* />
|
|
124
|
+
*
|
|
125
|
+
* // نمودار با کنترل دستی بازه محور Y
|
|
126
|
+
* <BarChart
|
|
127
|
+
* labels={["A", "B", "C"]}
|
|
128
|
+
* datasets={[
|
|
69
129
|
* {
|
|
70
|
-
* label: "
|
|
71
|
-
* data: [
|
|
72
|
-
*
|
|
73
|
-
* backgroundColor: "transparent",
|
|
74
|
-
* type: "line",
|
|
75
|
-
* order: 0,
|
|
76
|
-
* borderWidth: 3,
|
|
77
|
-
* tension: 0.4,
|
|
78
|
-
* pointRadius: 4,
|
|
79
|
-
* fill: false,
|
|
130
|
+
* label: "مقادیر",
|
|
131
|
+
* data: [100, 150, 120],
|
|
132
|
+
* backgroundColor: "rgba(75,192,192,0.7)",
|
|
80
133
|
* },
|
|
81
134
|
* ]}
|
|
135
|
+
* yAxisMin={80}
|
|
136
|
+
* yAxisMax={200}
|
|
137
|
+
* beginAtZero={false}
|
|
82
138
|
* height={400}
|
|
83
139
|
* />
|
|
84
140
|
* ```
|
|
85
141
|
*/
|
|
86
|
-
declare function BarChart({ labels, datasets, height }: Props$1): React.JSX.Element;
|
|
142
|
+
declare function BarChart({ labels, datasets, height, yAxisMin, yAxisMax, beginAtZero, logarithmic, minBarLength, }: Props$1): React.JSX.Element;
|
|
87
143
|
|
|
88
144
|
interface Props {
|
|
89
145
|
labels: string[];
|
package/dist/charts/index.d.ts
CHANGED
|
@@ -15,6 +15,36 @@ interface Props$1 {
|
|
|
15
15
|
fill?: boolean;
|
|
16
16
|
}[];
|
|
17
17
|
height?: number;
|
|
18
|
+
/**
|
|
19
|
+
* حداقل مقدار محور Y (اختیاری)
|
|
20
|
+
* اگر ست نشود، Chart.js خودش محاسبه میکند
|
|
21
|
+
* ⚠️ نکته: اگر این مقدار ست شود، beginAtZero نادیده گرفته میشود
|
|
22
|
+
*/
|
|
23
|
+
yAxisMin?: number;
|
|
24
|
+
/**
|
|
25
|
+
* حداکثر مقدار محور Y (اختیاری)
|
|
26
|
+
* اگر ست نشود، Chart.js خودش محاسبه میکند
|
|
27
|
+
*/
|
|
28
|
+
yAxisMax?: number;
|
|
29
|
+
/**
|
|
30
|
+
* آیا محور Y از صفر شروع شود؟
|
|
31
|
+
* پیشفرض: true
|
|
32
|
+
* ⚠️ نکته: اگر yAxisMin ست شود، این گزینه نادیده گرفته میشود
|
|
33
|
+
*/
|
|
34
|
+
beginAtZero?: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* استفاده از مقیاس لگاریتمی برای محور Y
|
|
37
|
+
* مناسب برای دادههایی که اختلاف خیلی زیادی دارند
|
|
38
|
+
* پیشفرض: false
|
|
39
|
+
* ⚠️ نکته: مقادیر 0 یا منفی در مقیاس لگاریتمی نمایش داده نمیشوند
|
|
40
|
+
*/
|
|
41
|
+
logarithmic?: boolean;
|
|
42
|
+
/**
|
|
43
|
+
* حداقل ارتفاع میله برای دادههای خیلی کوچک (پیکسل)
|
|
44
|
+
* مقادیر خیلی کوچک (مثل 1) در کنار مقادیر بزرگ (مثل 10000) گم نمیشوند
|
|
45
|
+
* پیشفرض: 0 (غیرفعال)
|
|
46
|
+
*/
|
|
47
|
+
minBarLength?: number;
|
|
18
48
|
}
|
|
19
49
|
/**
|
|
20
50
|
* 📊 BarChart — کامپوننت نمودار میلهای (Bar/Combo)
|
|
@@ -46,6 +76,11 @@ interface Props$1 {
|
|
|
46
76
|
* - fill: (اختیاری) پر شدن زیر خط (برای سریهای خطی)
|
|
47
77
|
*
|
|
48
78
|
* @param {number} [height] - ارتفاع نمودار (پیشفرض: 600 پیکسل)
|
|
79
|
+
* @param {number} [yAxisMin] - حداقل مقدار محور Y (نادیدهگرفتن beginAtZero)
|
|
80
|
+
* @param {number} [yAxisMax] - حداکثر مقدار محور Y
|
|
81
|
+
* @param {boolean} [beginAtZero=true] - آیا محور Y از صفر شروع شود؟ (اگر yAxisMin ست شود نادیده گرفته میشود)
|
|
82
|
+
* @param {boolean} [logarithmic=false] - استفاده از مقیاس لگاریتمی (مقادیر 0 یا منفی نمایش داده نمیشوند)
|
|
83
|
+
* @param {number} [minBarLength=0] - حداقل ارتفاع میله (پیکسل) - برای جلوگیری از گم شدن دادههای کوچک
|
|
49
84
|
*
|
|
50
85
|
* @description
|
|
51
86
|
* این کامپوننت یک نمودار میلهای (Bar) یا ترکیبی Bar/Line با قابلیت شخصیسازی کامل است.
|
|
@@ -53,11 +88,14 @@ interface Props$1 {
|
|
|
53
88
|
* - ریسپانسیو و مناسب صفحات فارسی
|
|
54
89
|
* - امکان نمایش چند سری داده به صورت میلهای و خطی همزمان (Combo)
|
|
55
90
|
* - شخصیسازی رنگ، ضخامت، ترتیب و استایل هر سری
|
|
91
|
+
* - پشتیبانی از مقیاس لگاریتمی برای دادههای با اختلاف زیاد
|
|
92
|
+
* - minBarLength برای نمایش دادههای خیلی کوچک در کنار بزرگها
|
|
56
93
|
*
|
|
57
94
|
* @returns {JSX.Element} یک نمودار میلهای یا ترکیبی با دادههای ورودی
|
|
58
95
|
*
|
|
59
96
|
* @example
|
|
60
97
|
* ```jsx
|
|
98
|
+
* // نمودار ساده
|
|
61
99
|
* <BarChart
|
|
62
100
|
* labels={["شنبه", "یکشنبه", "دوشنبه"]}
|
|
63
101
|
* datasets={[
|
|
@@ -66,24 +104,42 @@ interface Props$1 {
|
|
|
66
104
|
* data: [10, 20, 15],
|
|
67
105
|
* backgroundColor: "rgba(75,192,192,0.7)",
|
|
68
106
|
* },
|
|
107
|
+
* ]}
|
|
108
|
+
* height={400}
|
|
109
|
+
* />
|
|
110
|
+
*
|
|
111
|
+
* // نمودار با دادههای اختلاف زیاد (مقیاس لگاریتمی)
|
|
112
|
+
* <BarChart
|
|
113
|
+
* labels={["A", "B", "C", "D"]}
|
|
114
|
+
* datasets={[
|
|
115
|
+
* {
|
|
116
|
+
* label: "مقادیر",
|
|
117
|
+
* data: [5, 50, 5000, 50000],
|
|
118
|
+
* backgroundColor: "rgba(75,192,192,0.7)",
|
|
119
|
+
* },
|
|
120
|
+
* ]}
|
|
121
|
+
* logarithmic={true}
|
|
122
|
+
* height={400}
|
|
123
|
+
* />
|
|
124
|
+
*
|
|
125
|
+
* // نمودار با کنترل دستی بازه محور Y
|
|
126
|
+
* <BarChart
|
|
127
|
+
* labels={["A", "B", "C"]}
|
|
128
|
+
* datasets={[
|
|
69
129
|
* {
|
|
70
|
-
* label: "
|
|
71
|
-
* data: [
|
|
72
|
-
*
|
|
73
|
-
* backgroundColor: "transparent",
|
|
74
|
-
* type: "line",
|
|
75
|
-
* order: 0,
|
|
76
|
-
* borderWidth: 3,
|
|
77
|
-
* tension: 0.4,
|
|
78
|
-
* pointRadius: 4,
|
|
79
|
-
* fill: false,
|
|
130
|
+
* label: "مقادیر",
|
|
131
|
+
* data: [100, 150, 120],
|
|
132
|
+
* backgroundColor: "rgba(75,192,192,0.7)",
|
|
80
133
|
* },
|
|
81
134
|
* ]}
|
|
135
|
+
* yAxisMin={80}
|
|
136
|
+
* yAxisMax={200}
|
|
137
|
+
* beginAtZero={false}
|
|
82
138
|
* height={400}
|
|
83
139
|
* />
|
|
84
140
|
* ```
|
|
85
141
|
*/
|
|
86
|
-
declare function BarChart({ labels, datasets, height }: Props$1): React.JSX.Element;
|
|
142
|
+
declare function BarChart({ labels, datasets, height, yAxisMin, yAxisMax, beginAtZero, logarithmic, minBarLength, }: Props$1): React.JSX.Element;
|
|
87
143
|
|
|
88
144
|
interface Props {
|
|
89
145
|
labels: string[];
|
package/dist/charts/index.js
CHANGED
|
@@ -42,9 +42,11 @@ var React = __toESM(require("react"));
|
|
|
42
42
|
var import_react_chartjs_2 = require("react-chartjs-2");
|
|
43
43
|
var import_chart = require("chart.js");
|
|
44
44
|
var import_material = require("@mui/material");
|
|
45
|
+
var import_react = require("react");
|
|
45
46
|
import_chart.Chart.register(
|
|
46
47
|
import_chart.CategoryScale,
|
|
47
48
|
import_chart.LinearScale,
|
|
49
|
+
import_chart.LogarithmicScale,
|
|
48
50
|
import_chart.BarElement,
|
|
49
51
|
import_chart.LineElement,
|
|
50
52
|
import_chart.PointElement,
|
|
@@ -53,16 +55,113 @@ import_chart.Chart.register(
|
|
|
53
55
|
import_chart.BarController,
|
|
54
56
|
import_chart.LineController
|
|
55
57
|
);
|
|
56
|
-
|
|
58
|
+
import_chart.Chart.defaults.font.family = "Vazir, sans-serif";
|
|
59
|
+
function BarChart({
|
|
60
|
+
labels,
|
|
61
|
+
datasets,
|
|
62
|
+
height,
|
|
63
|
+
yAxisMin,
|
|
64
|
+
yAxisMax,
|
|
65
|
+
beginAtZero = true,
|
|
66
|
+
logarithmic = false,
|
|
67
|
+
minBarLength = 0
|
|
68
|
+
}) {
|
|
69
|
+
const chartRef = (0, import_react.useRef)(null);
|
|
70
|
+
const [fontLoaded, setFontLoaded] = (0, import_react.useState)(false);
|
|
71
|
+
(0, import_react.useEffect)(() => {
|
|
72
|
+
let isMounted = true;
|
|
73
|
+
const loadFont = async () => {
|
|
74
|
+
if (typeof document !== "undefined" && document.fonts) {
|
|
75
|
+
try {
|
|
76
|
+
await document.fonts.load("16px Vazir");
|
|
77
|
+
await document.fonts.ready;
|
|
78
|
+
} catch (e) {
|
|
79
|
+
}
|
|
80
|
+
if (isMounted) {
|
|
81
|
+
setFontLoaded(true);
|
|
82
|
+
setTimeout(() => {
|
|
83
|
+
if (chartRef.current) {
|
|
84
|
+
chartRef.current.update();
|
|
85
|
+
}
|
|
86
|
+
}, 100);
|
|
87
|
+
}
|
|
88
|
+
} else {
|
|
89
|
+
if (isMounted) setFontLoaded(true);
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
loadFont();
|
|
93
|
+
return () => {
|
|
94
|
+
isMounted = false;
|
|
95
|
+
};
|
|
96
|
+
}, []);
|
|
97
|
+
const getVisibleData = () => {
|
|
98
|
+
if (!chartRef.current) return [];
|
|
99
|
+
return datasets.reduce((acc, ds, i) => {
|
|
100
|
+
if ((ds.type === void 0 || ds.type === "bar") && chartRef.current && typeof chartRef.current.isDatasetVisible === "function" && chartRef.current.isDatasetVisible(i)) {
|
|
101
|
+
ds.data.forEach((v) => {
|
|
102
|
+
if (typeof v === "number" && v > 0) acc.push(v);
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
return acc;
|
|
106
|
+
}, []);
|
|
107
|
+
};
|
|
108
|
+
let autoMin = yAxisMin;
|
|
109
|
+
let autoMax = yAxisMax;
|
|
110
|
+
if (logarithmic && yAxisMin === void 0 && yAxisMax === void 0) {
|
|
111
|
+
const visibleData = getVisibleData();
|
|
112
|
+
if (visibleData.length) {
|
|
113
|
+
const minVal = Math.min(...visibleData);
|
|
114
|
+
const maxVal = Math.max(...visibleData);
|
|
115
|
+
autoMin = minVal < 1 ? 0.5 : minVal * 0.7;
|
|
116
|
+
autoMax = minVal === maxVal ? maxVal * 1.2 : maxVal * 1.1;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
(0, import_react.useEffect)(() => {
|
|
120
|
+
if (!logarithmic || yAxisMin !== void 0 || yAxisMax !== void 0) return;
|
|
121
|
+
if (!chartRef.current) return;
|
|
122
|
+
const handler = () => {
|
|
123
|
+
const visibleData = getVisibleData();
|
|
124
|
+
if (visibleData.length && chartRef.current && chartRef.current.options && chartRef.current.options.scales && chartRef.current.options.scales.y) {
|
|
125
|
+
const minVal = Math.min(...visibleData);
|
|
126
|
+
const maxVal = Math.max(...visibleData);
|
|
127
|
+
chartRef.current.options.scales.y.min = minVal < 1 ? 0.5 : minVal * 0.7;
|
|
128
|
+
chartRef.current.options.scales.y.max = minVal === maxVal ? maxVal * 1.2 : maxVal * 1.1;
|
|
129
|
+
chartRef.current.update();
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
chartRef.current?.canvas?.addEventListener("click", handler);
|
|
133
|
+
return () => {
|
|
134
|
+
chartRef.current?.canvas?.removeEventListener("click", handler);
|
|
135
|
+
};
|
|
136
|
+
}, [logarithmic, yAxisMin, yAxisMax, datasets]);
|
|
57
137
|
const options = {
|
|
58
138
|
responsive: true,
|
|
59
139
|
maintainAspectRatio: false,
|
|
60
140
|
scales: {
|
|
61
141
|
y: {
|
|
142
|
+
type: logarithmic ? "logarithmic" : "linear",
|
|
143
|
+
...yAxisMin === void 0 && yAxisMax === void 0 && !logarithmic && {
|
|
144
|
+
beginAtZero
|
|
145
|
+
},
|
|
146
|
+
...autoMin !== void 0 && { min: autoMin },
|
|
147
|
+
...autoMax !== void 0 && { max: autoMax },
|
|
62
148
|
ticks: {
|
|
63
149
|
font: {
|
|
64
|
-
family: "
|
|
150
|
+
family: "Vazir, sans-serif",
|
|
65
151
|
size: 14
|
|
152
|
+
},
|
|
153
|
+
...logarithmic && {
|
|
154
|
+
callback: function(value) {
|
|
155
|
+
const numValue = Number(value);
|
|
156
|
+
if (numValue === 0) return null;
|
|
157
|
+
const log10 = Math.log10(numValue);
|
|
158
|
+
if (Math.abs(log10 - Math.round(log10)) < 1e-4) {
|
|
159
|
+
if (numValue >= 1e6) return (numValue / 1e6).toFixed(1) + "M";
|
|
160
|
+
if (numValue >= 1e3) return (numValue / 1e3).toFixed(1) + "K";
|
|
161
|
+
return numValue;
|
|
162
|
+
}
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
66
165
|
}
|
|
67
166
|
}
|
|
68
167
|
},
|
|
@@ -70,7 +169,7 @@ function BarChart({ labels, datasets, height }) {
|
|
|
70
169
|
ticks: {
|
|
71
170
|
autoSkip: false,
|
|
72
171
|
font: {
|
|
73
|
-
family: "
|
|
172
|
+
family: "Vazir, sans-serif",
|
|
74
173
|
size: 13
|
|
75
174
|
}
|
|
76
175
|
}
|
|
@@ -83,11 +182,11 @@ function BarChart({ labels, datasets, height }) {
|
|
|
83
182
|
},
|
|
84
183
|
tooltip: {
|
|
85
184
|
bodyFont: {
|
|
86
|
-
family: "
|
|
185
|
+
family: "Vazir, sans-serif",
|
|
87
186
|
size: 14
|
|
88
187
|
},
|
|
89
188
|
titleFont: {
|
|
90
|
-
family: "
|
|
189
|
+
family: "Vazir, sans-serif",
|
|
91
190
|
size: 16
|
|
92
191
|
}
|
|
93
192
|
},
|
|
@@ -106,7 +205,7 @@ function BarChart({ labels, datasets, height }) {
|
|
|
106
205
|
usePointStyle: true,
|
|
107
206
|
font: {
|
|
108
207
|
size: 16,
|
|
109
|
-
family: "
|
|
208
|
+
family: "Vazir, sans-serif"
|
|
110
209
|
},
|
|
111
210
|
boxWidth: 40,
|
|
112
211
|
paddingBottom: 10
|
|
@@ -114,16 +213,22 @@ function BarChart({ labels, datasets, height }) {
|
|
|
114
213
|
}
|
|
115
214
|
}
|
|
116
215
|
};
|
|
117
|
-
|
|
216
|
+
const processedDatasets = datasets.map((ds) => ({
|
|
217
|
+
...ds,
|
|
218
|
+
minBarLength
|
|
219
|
+
}));
|
|
220
|
+
return /* @__PURE__ */ React.createElement(import_material.Box, { height: height ?? 600 }, fontLoaded && /* @__PURE__ */ React.createElement(import_react_chartjs_2.Chart, { ref: chartRef, type: "bar", data: { labels, datasets: processedDatasets }, options }));
|
|
118
221
|
}
|
|
119
222
|
|
|
120
223
|
// src/charts/pie/index.tsx
|
|
121
224
|
var import_react_chartjs_22 = require("react-chartjs-2");
|
|
122
225
|
var import_chart2 = require("chart.js");
|
|
226
|
+
var import_react2 = require("react");
|
|
123
227
|
var import_material2 = require("@mui/material");
|
|
124
228
|
var import_image = __toESM(require("next/image"));
|
|
125
229
|
var import_chartjs_plugin_datalabels = __toESM(require("chartjs-plugin-datalabels"));
|
|
126
230
|
import_chart2.Chart.register(import_chart2.ArcElement, import_chart2.Tooltip, import_chart2.Legend, import_chartjs_plugin_datalabels.default);
|
|
231
|
+
import_chart2.Chart.defaults.font.family = "Vazir, sans-serif";
|
|
127
232
|
function PieChart({
|
|
128
233
|
labels,
|
|
129
234
|
datasets,
|
|
@@ -133,18 +238,83 @@ function PieChart({
|
|
|
133
238
|
showDataLabels = false,
|
|
134
239
|
showPercentage = false
|
|
135
240
|
}) {
|
|
136
|
-
const
|
|
241
|
+
const chartRef = (0, import_react2.useRef)(null);
|
|
242
|
+
const [dataLabels, setDataLabels] = (0, import_react2.useState)([]);
|
|
243
|
+
const containerRef = (0, import_react2.useRef)(null);
|
|
244
|
+
const calculateLabels = () => {
|
|
245
|
+
if (!showDataLabels || !chartRef.current || !containerRef.current) return;
|
|
246
|
+
const chart = chartRef.current;
|
|
247
|
+
const meta = chart.getDatasetMeta(0);
|
|
248
|
+
const data = chart.data.datasets[0].data;
|
|
249
|
+
const chartArea = chart.chartArea;
|
|
250
|
+
const visibleTotal = data.reduce((sum, val, index) => {
|
|
251
|
+
if (!meta.data[index] || meta.data[index].hidden !== true) {
|
|
252
|
+
return sum + val;
|
|
253
|
+
}
|
|
254
|
+
return sum;
|
|
255
|
+
}, 0);
|
|
256
|
+
const newLabels = [];
|
|
257
|
+
meta.data.forEach((arc, index) => {
|
|
258
|
+
if (arc.hidden) return;
|
|
259
|
+
const value = data[index];
|
|
260
|
+
if (value === 0) return;
|
|
261
|
+
const centerAngle = (arc.startAngle + arc.endAngle) / 2;
|
|
262
|
+
const midRadius = arc.innerRadius + (arc.outerRadius - arc.innerRadius) * 0.65;
|
|
263
|
+
const x = arc.x - Math.cos(centerAngle) * midRadius;
|
|
264
|
+
const y = arc.y + Math.sin(centerAngle) * midRadius;
|
|
265
|
+
let text;
|
|
266
|
+
if (showPercentage) {
|
|
267
|
+
const percentage = (value / visibleTotal * 100).toFixed(1);
|
|
268
|
+
text = percentage + "%";
|
|
269
|
+
} else {
|
|
270
|
+
text = String(value);
|
|
271
|
+
}
|
|
272
|
+
newLabels.push({ x, y, text, opacity: 1 });
|
|
273
|
+
});
|
|
274
|
+
setDataLabels(newLabels);
|
|
275
|
+
};
|
|
276
|
+
(0, import_react2.useEffect)(() => {
|
|
277
|
+
if (!showDataLabels) {
|
|
278
|
+
setDataLabels([]);
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
const timeout = setTimeout(() => {
|
|
282
|
+
calculateLabels();
|
|
283
|
+
}, 500);
|
|
284
|
+
return () => clearTimeout(timeout);
|
|
285
|
+
}, [datasets, showDataLabels, showPercentage]);
|
|
286
|
+
(0, import_react2.useEffect)(() => {
|
|
287
|
+
if (!chartRef.current || !showDataLabels) return;
|
|
288
|
+
const chart = chartRef.current;
|
|
289
|
+
const originalUpdate = chart.update.bind(chart);
|
|
290
|
+
chart.update = function(...args) {
|
|
291
|
+
setDataLabels((prev) => prev.map((l) => ({ ...l, opacity: 0 })));
|
|
292
|
+
originalUpdate(...args);
|
|
293
|
+
setTimeout(() => {
|
|
294
|
+
calculateLabels();
|
|
295
|
+
}, 250);
|
|
296
|
+
};
|
|
297
|
+
return () => {
|
|
298
|
+
chart.update = originalUpdate;
|
|
299
|
+
};
|
|
300
|
+
}, [showDataLabels, showPercentage]);
|
|
301
|
+
const options = (0, import_react2.useMemo)(() => ({
|
|
137
302
|
responsive: true,
|
|
138
303
|
maintainAspectRatio: false,
|
|
139
304
|
cutout: !disableLogo ? "59%" : "0%",
|
|
305
|
+
animation: {
|
|
306
|
+
animateRotate: true,
|
|
307
|
+
animateScale: true,
|
|
308
|
+
duration: 400
|
|
309
|
+
},
|
|
140
310
|
plugins: {
|
|
141
311
|
tooltip: {
|
|
142
312
|
bodyFont: {
|
|
143
|
-
family: "
|
|
313
|
+
family: "Vazir, sans-serif",
|
|
144
314
|
size: 14
|
|
145
315
|
},
|
|
146
316
|
titleFont: {
|
|
147
|
-
family: "
|
|
317
|
+
family: "Vazir, sans-serif",
|
|
148
318
|
size: 16
|
|
149
319
|
}
|
|
150
320
|
},
|
|
@@ -156,7 +326,7 @@ function PieChart({
|
|
|
156
326
|
// رنگ متن legend را نرمتر میکند
|
|
157
327
|
font: {
|
|
158
328
|
size: 16,
|
|
159
|
-
family: "
|
|
329
|
+
family: "Vazir, sans-serif"
|
|
160
330
|
},
|
|
161
331
|
boxWidth: 40,
|
|
162
332
|
paddingBottom: 10,
|
|
@@ -187,38 +357,11 @@ function PieChart({
|
|
|
187
357
|
}
|
|
188
358
|
},
|
|
189
359
|
datalabels: {
|
|
190
|
-
display:
|
|
191
|
-
|
|
192
|
-
},
|
|
193
|
-
color: "#fff",
|
|
194
|
-
font: {
|
|
195
|
-
size: 14,
|
|
196
|
-
weight: "bold",
|
|
197
|
-
family: "'Vazir', sans-serif"
|
|
198
|
-
},
|
|
199
|
-
anchor: "center",
|
|
200
|
-
// ← روی مرکز هر تکه
|
|
201
|
-
align: "center",
|
|
202
|
-
offset: 20,
|
|
203
|
-
// فاصله از مرکز (میتونی کم/زیاد کنی)
|
|
204
|
-
formatter: showPercentage ? (value, context) => {
|
|
205
|
-
if (value === 0) return "";
|
|
206
|
-
const total = context.chart.data.datasets[context.datasetIndex].data.reduce(
|
|
207
|
-
(sum, val, index) => {
|
|
208
|
-
const meta = context.chart.getDatasetMeta(context.datasetIndex);
|
|
209
|
-
if (!meta.data[index] || meta.data[index].hidden !== true) {
|
|
210
|
-
return sum + val;
|
|
211
|
-
}
|
|
212
|
-
return sum;
|
|
213
|
-
},
|
|
214
|
-
0
|
|
215
|
-
);
|
|
216
|
-
const percentage = (value / total * 100).toFixed(1);
|
|
217
|
-
return percentage + "%";
|
|
218
|
-
} : (value) => value === 0 ? "" : value
|
|
360
|
+
display: false
|
|
361
|
+
// غیرفعال - لیبلها با React رندر میشوند
|
|
219
362
|
}
|
|
220
363
|
}
|
|
221
|
-
};
|
|
364
|
+
}), [disableLogo]);
|
|
222
365
|
const CenterComponent = () => {
|
|
223
366
|
return /* @__PURE__ */ React.createElement(
|
|
224
367
|
"div",
|
|
@@ -242,16 +385,37 @@ function PieChart({
|
|
|
242
385
|
)
|
|
243
386
|
);
|
|
244
387
|
};
|
|
245
|
-
return /* @__PURE__ */ React.createElement(import_material2.Box, { height: height ?? 600, sx: { position: "relative" } }, /* @__PURE__ */ React.createElement(
|
|
388
|
+
return /* @__PURE__ */ React.createElement(import_material2.Box, { ref: containerRef, height: height ?? 600, sx: { position: "relative" } }, /* @__PURE__ */ React.createElement(
|
|
246
389
|
import_react_chartjs_22.Pie,
|
|
247
390
|
{
|
|
391
|
+
ref: chartRef,
|
|
248
392
|
data: {
|
|
249
393
|
labels,
|
|
250
394
|
datasets
|
|
251
395
|
},
|
|
252
396
|
options
|
|
253
397
|
}
|
|
254
|
-
),
|
|
398
|
+
), showDataLabels && dataLabels.map((label, index) => /* @__PURE__ */ React.createElement(
|
|
399
|
+
import_material2.Typography,
|
|
400
|
+
{
|
|
401
|
+
key: index,
|
|
402
|
+
sx: {
|
|
403
|
+
position: "absolute",
|
|
404
|
+
left: label.x / (window.devicePixelRatio || 1),
|
|
405
|
+
top: label.y / (window.devicePixelRatio || 1),
|
|
406
|
+
transform: "translate(-50%, -50%)",
|
|
407
|
+
color: "#fff",
|
|
408
|
+
fontWeight: "bold",
|
|
409
|
+
fontSize: 14,
|
|
410
|
+
fontFamily: "Vazir, sans-serif",
|
|
411
|
+
pointerEvents: "none",
|
|
412
|
+
textShadow: "0 1px 2px rgba(0,0,0,0.5)",
|
|
413
|
+
opacity: label.opacity,
|
|
414
|
+
transition: "opacity 0.2s ease-in-out, left 0.2s ease-in-out, top 0.2s ease-in-out"
|
|
415
|
+
}
|
|
416
|
+
},
|
|
417
|
+
label.text
|
|
418
|
+
)), !disableLogo && /* @__PURE__ */ React.createElement(
|
|
255
419
|
"div",
|
|
256
420
|
{
|
|
257
421
|
style: {
|