@mamrp/components 1.7.52 → 1.7.54

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.
File without changes
File without changes
@@ -66,23 +66,80 @@ function BarChart({ labels, datasets, height }) {
66
66
  );
67
67
  const minValue = allValues.length ? Math.min(...allValues) : 0;
68
68
  const maxValue = allValues.length ? Math.max(...allValues) : 1;
69
+ const hasNegativeData = minValue < 0;
70
+ const hasPositiveData = maxValue > 0;
69
71
  const useLogScale = maxValue / (minValue || 1) > 50;
70
72
  const scaleType = useLogScale ? "logarithmic" : "linear";
71
73
  let yMin = minValue;
72
74
  let yMax = maxValue;
73
75
  let stepSize = 1;
74
76
  if (scaleType === "linear") {
75
- const range = yMax - yMin;
76
- const targetLines = 8;
77
- let rawStep = range / targetLines;
78
- const magnitude = Math.pow(10, Math.floor(Math.log10(rawStep)));
79
- const normalized = rawStep / magnitude;
80
- if (normalized <= 1) stepSize = 1 * magnitude;
81
- else if (normalized <= 2) stepSize = 2 * magnitude;
82
- else if (normalized <= 5) stepSize = 5 * magnitude;
83
- else stepSize = 10 * magnitude;
84
- yMin = Math.floor(yMin / stepSize) * stepSize;
85
- yMax = Math.ceil(yMax / stepSize) * stepSize;
77
+ if (hasNegativeData && hasPositiveData) {
78
+ const negativeRange = Math.abs(minValue);
79
+ const positiveRange = Math.abs(maxValue);
80
+ const maxRange = Math.max(negativeRange, positiveRange);
81
+ const targetLines = 5;
82
+ let rawStep = maxRange / targetLines;
83
+ if (maxRange < 0.01) {
84
+ stepSize = 1e-3;
85
+ } else if (maxRange < 0.05) {
86
+ stepSize = 5e-3;
87
+ } else if (maxRange < 0.1) {
88
+ stepSize = 0.01;
89
+ } else if (maxRange < 0.5) {
90
+ stepSize = 0.05;
91
+ } else if (maxRange < 1) {
92
+ stepSize = 0.1;
93
+ } else if (maxRange < 2) {
94
+ stepSize = 0.2;
95
+ } else if (maxRange < 5) {
96
+ stepSize = 0.5;
97
+ } else if (maxRange < 10) {
98
+ stepSize = 1;
99
+ } else {
100
+ const magnitude = Math.pow(10, Math.floor(Math.log10(rawStep)));
101
+ const normalized = rawStep / magnitude;
102
+ if (normalized <= 1) stepSize = 1 * magnitude;
103
+ else if (normalized <= 2) stepSize = 2 * magnitude;
104
+ else if (normalized <= 5) stepSize = 5 * magnitude;
105
+ else stepSize = 10 * magnitude;
106
+ }
107
+ yMin = Math.floor(minValue / stepSize) * stepSize - stepSize;
108
+ yMax = Math.ceil(maxValue / stepSize) * stepSize + stepSize;
109
+ } else {
110
+ const range = maxValue - minValue;
111
+ const targetLines = 10;
112
+ let rawStep = range / targetLines;
113
+ if (range < 0.01) {
114
+ stepSize = 1e-3;
115
+ } else if (range < 0.05) {
116
+ stepSize = 5e-3;
117
+ } else if (range < 0.1) {
118
+ stepSize = 0.01;
119
+ } else if (range < 0.5) {
120
+ stepSize = 0.05;
121
+ } else if (range < 1) {
122
+ stepSize = 0.1;
123
+ } else if (range < 2) {
124
+ stepSize = 0.2;
125
+ } else if (range < 5) {
126
+ stepSize = 0.5;
127
+ } else if (range < 10) {
128
+ stepSize = 1;
129
+ } else {
130
+ const magnitude = Math.pow(10, Math.floor(Math.log10(rawStep)));
131
+ const normalized = rawStep / magnitude;
132
+ if (normalized <= 1) stepSize = 1 * magnitude;
133
+ else if (normalized <= 2) stepSize = 2 * magnitude;
134
+ else if (normalized <= 5) stepSize = 5 * magnitude;
135
+ else stepSize = 10 * magnitude;
136
+ }
137
+ yMin = Math.floor(minValue / stepSize) * stepSize - stepSize;
138
+ yMax = Math.ceil(maxValue / stepSize) * stepSize + stepSize;
139
+ if (!hasNegativeData && yMin < 0) {
140
+ yMin = 0;
141
+ }
142
+ }
86
143
  } else {
87
144
  yMin = Math.max(minValue, 1);
88
145
  yMax = maxValue;
@@ -97,22 +154,42 @@ function BarChart({ labels, datasets, height }) {
97
154
  type: scaleType,
98
155
  min: yMin,
99
156
  max: yMax,
157
+ grid: {
158
+ color: (context) => {
159
+ if (hasNegativeData && context.tick && Math.abs(context.tick.value) < 1e-4) {
160
+ return "rgba(0, 0, 0, 0.5)";
161
+ }
162
+ return "rgba(0, 0, 0, 0.1)";
163
+ },
164
+ lineWidth: (context) => {
165
+ if (hasNegativeData && context.tick && Math.abs(context.tick.value) < 1e-4) {
166
+ return 2;
167
+ }
168
+ return 1;
169
+ }
170
+ },
100
171
  ticks: {
101
- ...stepSize !== void 0 ? { stepSize } : {},
102
172
  callback: (value) => {
103
173
  const num = Number(value);
104
174
  if (scaleType === "logarithmic") return num.toLocaleString();
105
- if (num >= 1e3) return num.toLocaleString();
106
- if (stepSize && stepSize < 1) return num.toFixed(2);
175
+ if (Math.abs(num) >= 1e3) return num.toLocaleString();
176
+ if (stepSize !== void 0) {
177
+ if (stepSize < 0.01) return num.toFixed(3);
178
+ if (stepSize < 0.1) return num.toFixed(2);
179
+ if (stepSize < 1) return num.toFixed(1);
180
+ }
181
+ if (Math.abs(num) < 1 && num !== 0) {
182
+ return num.toFixed(2);
183
+ }
107
184
  return num;
108
185
  },
109
- font: { family: "'Vazir', sans-serif", size: 14 }
186
+ font: { family: "vazirmatn", size: 14 }
110
187
  }
111
188
  },
112
189
  x: {
113
190
  ticks: {
114
191
  autoSkip: false,
115
- font: { family: "'Vazir', sans-serif", size: 13 }
192
+ font: { family: "vazirmatn", size: 13 }
116
193
  }
117
194
  }
118
195
  },
@@ -120,8 +197,7 @@ function BarChart({ labels, datasets, height }) {
120
197
  legend: {
121
198
  labels: {
122
199
  usePointStyle: true,
123
- // دایره‌ای
124
- font: { size: 16, family: "'Vazir', sans-serif" }
200
+ font: { size: 16, family: "vazirmatn" }
125
201
  },
126
202
  onClick: (e, legendItem, legend) => {
127
203
  const index = legendItem.datasetIndex;
@@ -132,8 +208,16 @@ function BarChart({ labels, datasets, height }) {
132
208
  }
133
209
  },
134
210
  tooltip: {
135
- bodyFont: { family: "'Vazir', sans-serif", size: 14 },
136
- titleFont: { family: "'Vazir', sans-serif", size: 16 }
211
+ bodyFont: { family: "vazirmatn", size: 14 },
212
+ titleFont: { family: "vazirmatn", size: 16 },
213
+ callbacks: {
214
+ label: (context) => {
215
+ const label = context.dataset.label ?? "";
216
+ const value = context.parsed.y;
217
+ const formattedValue = typeof value === "number" ? value.toLocaleString("fa-IR") : value;
218
+ return `${label}: ${formattedValue}`;
219
+ }
220
+ }
137
221
  },
138
222
  datalabels: { display: false }
139
223
  }
@@ -168,7 +252,8 @@ var import_material2 = require("@mui/material");
168
252
  var import_image = __toESM(require("next/image"));
169
253
  var import_chartjs_plugin_datalabels = __toESM(require("chartjs-plugin-datalabels"));
170
254
  import_chart2.Chart.register(import_chart2.ArcElement, import_chart2.Tooltip, import_chart2.Legend, import_chartjs_plugin_datalabels.default);
171
- import_chart2.Chart.defaults.font.family = "Vazir, sans-serif";
255
+ import_chart2.Chart.defaults.font.family = "vazirmatn";
256
+ import_chart2.Chart.defaults.font.family = "'vazirmatn'";
172
257
  function PieChart({
173
258
  labels,
174
259
  datasets,
@@ -217,7 +302,12 @@ function PieChart({
217
302
  } else {
218
303
  text = String(value);
219
304
  }
220
- newLabels.push({ left: leftRelative, top: topRelative, text, opacity: 1 });
305
+ newLabels.push({
306
+ left: leftRelative,
307
+ top: topRelative,
308
+ text,
309
+ opacity: 1
310
+ });
221
311
  });
222
312
  setDataLabels(newLabels);
223
313
  };
@@ -267,71 +357,86 @@ function PieChart({
267
357
  chart.update = originalUpdate;
268
358
  };
269
359
  }, [showDataLabels, showPercentage]);
270
- const options = (0, import_react2.useMemo)(() => ({
271
- responsive: true,
272
- maintainAspectRatio: false,
273
- cutout: !disableLogo ? "59%" : "0%",
274
- animation: {
275
- animateRotate: true,
276
- animateScale: true,
277
- duration: 400
278
- // onComplete تنظیم می‌شود در useEffect بالا تا فقط رفتار محاسبه لیبل را تحت تاثیر قرار دهیم
279
- },
280
- plugins: {
281
- tooltip: {
282
- bodyFont: {
283
- family: "Vazir, sans-serif",
284
- size: 14
285
- },
286
- titleFont: {
287
- family: "Vazir, sans-serif",
288
- size: 16
289
- }
360
+ const options = (0, import_react2.useMemo)(
361
+ () => ({
362
+ responsive: true,
363
+ maintainAspectRatio: false,
364
+ cutout: !disableLogo ? "59%" : "0%",
365
+ animation: {
366
+ animateRotate: true,
367
+ animateScale: true,
368
+ duration: 400
369
+ // onComplete تنظیم می‌شود در useEffect بالا تا فقط رفتار محاسبه لیبل را تحت تاثیر قرار دهیم
290
370
  },
291
- legend: {
292
- labels: {
293
- padding: 15,
294
- usePointStyle: true,
295
- color: "#666",
296
- // رنگ متن legend را نرم‌تر می‌کند
297
- font: {
298
- size: 16,
299
- family: "Vazir, sans-serif"
371
+ plugins: {
372
+ tooltip: {
373
+ bodyFont: {
374
+ family: "vazirmatn",
375
+ size: 14
376
+ },
377
+ titleFont: {
378
+ family: "vazirmatn",
379
+ size: 16
300
380
  },
301
- boxWidth: 40,
302
- paddingBottom: 10,
303
- generateLabels: (chart) => {
304
- const data = chart.data;
305
- const meta = chart.getDatasetMeta(0);
306
- return data.labels.map((label, index) => {
307
- const hidden = meta.data[index] ? meta.data[index].hidden : false;
308
- return {
309
- text: label,
310
- fillStyle: data.datasets[0].backgroundColor[index] || "#000",
311
- hidden,
312
- index,
313
- datasetIndex: 0,
314
- textDecoration: hidden ? "line-through" : void 0
315
- };
316
- });
381
+ callbacks: {
382
+ label: (context) => {
383
+ const label = context.dataset?.label ?? "";
384
+ const parsed = context.parsed;
385
+ const yAxisID = context.dataset?.yAxisID === "y1" ? " %" : "";
386
+ const y = typeof parsed === "number" ? parsed : typeof parsed === "object" && parsed !== null ? parsed.y : null;
387
+ if (typeof y === "number") {
388
+ return `${label}: ${yAxisID}${y.toLocaleString("fa-IR")}`;
389
+ }
390
+ return label;
391
+ }
317
392
  }
318
393
  },
319
- onClick: (e, legendItem, legend) => {
320
- const ci = legend.chart;
321
- const meta = ci.getDatasetMeta(legendItem.datasetIndex || 0);
322
- const index = legendItem.index;
323
- if (meta.data[index]) {
324
- meta.data[index].hidden = !meta.data[index].hidden;
394
+ legend: {
395
+ labels: {
396
+ padding: 15,
397
+ usePointStyle: true,
398
+ color: "#666",
399
+ // رنگ متن legend را نرم‌تر می‌کند
400
+ font: {
401
+ size: 16,
402
+ family: "vazirmatn"
403
+ },
404
+ boxWidth: 40,
405
+ paddingBottom: 10,
406
+ generateLabels: (chart) => {
407
+ const data = chart.data;
408
+ const meta = chart.getDatasetMeta(0);
409
+ return data.labels.map((label, index) => {
410
+ const hidden = meta.data[index] ? meta.data[index].hidden : false;
411
+ return {
412
+ text: label,
413
+ fillStyle: data.datasets[0].backgroundColor[index] || "#000",
414
+ hidden,
415
+ index,
416
+ datasetIndex: 0,
417
+ textDecoration: hidden ? "line-through" : void 0
418
+ };
419
+ });
420
+ }
421
+ },
422
+ onClick: (e, legendItem, legend) => {
423
+ const ci = legend.chart;
424
+ const meta = ci.getDatasetMeta(legendItem.datasetIndex || 0);
425
+ const index = legendItem.index;
426
+ if (meta.data[index]) {
427
+ meta.data[index].hidden = !meta.data[index].hidden;
428
+ }
429
+ ci.update();
325
430
  }
326
- ci.update();
431
+ },
432
+ datalabels: {
433
+ display: false
434
+ // غیرفعال - لیبل‌ها با React رندر می‌شوند
327
435
  }
328
- },
329
- datalabels: {
330
- display: false
331
- // غیرفعال - لیبل‌ها با React رندر می‌شوند
332
436
  }
333
- }
334
- }), [disableLogo]);
437
+ }),
438
+ [disableLogo]
439
+ );
335
440
  const CenterComponent = () => {
336
441
  return /* @__PURE__ */ React.createElement(
337
442
  "div",
@@ -355,50 +460,60 @@ function PieChart({
355
460
  )
356
461
  );
357
462
  };
358
- return /* @__PURE__ */ React.createElement(import_material2.Box, { ref: containerRef, height: height ?? 600, sx: { position: "relative" } }, /* @__PURE__ */ React.createElement(
359
- import_react_chartjs_22.Pie,
463
+ return /* @__PURE__ */ React.createElement(
464
+ import_material2.Box,
360
465
  {
361
- ref: chartRef,
362
- data: {
363
- labels,
364
- datasets
365
- },
366
- options
367
- }
368
- ), showDataLabels && dataLabels.map((label, index) => /* @__PURE__ */ React.createElement(
369
- import_material2.Typography,
370
- {
371
- key: index,
372
- sx: {
373
- position: "absolute",
374
- left: label.left,
375
- top: label.top,
376
- transform: "translate(-50%, -50%)",
377
- color: "#fff",
378
- fontWeight: "bold",
379
- fontSize: 14,
380
- fontFamily: "Vazir, sans-serif",
381
- pointerEvents: "none",
382
- textShadow: "0 1px 2px rgba(0,0,0,0.5)",
383
- opacity: label.opacity,
384
- transition: "opacity 0.2s ease-in-out, left 0.2s ease-in-out, top 0.2s ease-in-out"
385
- }
466
+ ref: containerRef,
467
+ height: height ?? 600,
468
+ sx: { position: "relative" }
386
469
  },
387
- label.text
388
- )), !disableLogo && /* @__PURE__ */ React.createElement(
389
- "div",
390
- {
391
- style: {
392
- position: "absolute",
393
- top: "53%",
394
- left: "50%",
395
- transform: "translate(-50%, -50%)",
396
- pointerEvents: "none"
397
- // جلوگیری از دریافت event روی این لایه
470
+ /* @__PURE__ */ React.createElement(
471
+ import_react_chartjs_22.Pie,
472
+ {
473
+ ref: chartRef,
474
+ data: {
475
+ labels,
476
+ datasets
477
+ },
478
+ options
398
479
  }
399
- },
400
- /* @__PURE__ */ React.createElement(CenterComponent, null)
401
- ));
480
+ ),
481
+ showDataLabels && dataLabels.map((label, index) => /* @__PURE__ */ React.createElement(
482
+ import_material2.Typography,
483
+ {
484
+ key: index,
485
+ sx: {
486
+ position: "absolute",
487
+ left: label.left,
488
+ top: label.top,
489
+ transform: "translate(-50%, -50%)",
490
+ color: "#fff",
491
+ fontWeight: "bold",
492
+ fontSize: 14,
493
+ fontFamily: "vazirmatn, sans-serif",
494
+ pointerEvents: "none",
495
+ textShadow: "0 1px 2px rgba(0,0,0,0.5)",
496
+ opacity: label.opacity,
497
+ transition: "opacity 0.2s ease-in-out, left 0.2s ease-in-out, top 0.2s ease-in-out"
498
+ }
499
+ },
500
+ label.text
501
+ )),
502
+ !disableLogo && /* @__PURE__ */ React.createElement(
503
+ "div",
504
+ {
505
+ style: {
506
+ position: "absolute",
507
+ top: "53%",
508
+ left: "50%",
509
+ transform: "translate(-50%, -50%)",
510
+ pointerEvents: "none"
511
+ // جلوگیری از دریافت event روی این لایه
512
+ }
513
+ },
514
+ /* @__PURE__ */ React.createElement(CenterComponent, null)
515
+ )
516
+ );
402
517
  }
403
518
  // Annotate the CommonJS export names for ESM import in node:
404
519
  0 && (module.exports = {
@@ -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/**\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","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 const hasNegativeData = minValue < 0;\n const hasPositiveData = maxValue > 0;\n\n // --- تصمیم هوشمند برای scale ---\n const useLogScale = maxValue / (minValue || 1) > 50;\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 // const hasNegativeData = minValue < 0;\n // const hasPositiveData = maxValue > 0;\n\n if (scaleType === \"linear\") {\n // اگر هم منفی و هم مثبت داریم، باید دو طرف صفر رو جداگانه محاسبه کنیم\n if (hasNegativeData && hasPositiveData) {\n // محاسبه range برای طرف منفی و مثبت\n const negativeRange = Math.abs(minValue);\n const positiveRange = Math.abs(maxValue);\n const maxRange = Math.max(negativeRange, positiveRange);\n\n // تعداد خطوط هدف برای هر طرف\n const targetLines = 5;\n let rawStep = maxRange / targetLines;\n\n // محاسبه stepSize بر اساس بزرگترین range\n if (maxRange < 0.01) {\n stepSize = 0.001;\n } else if (maxRange < 0.05) {\n stepSize = 0.005;\n } else if (maxRange < 0.1) {\n stepSize = 0.01;\n } else if (maxRange < 0.5) {\n stepSize = 0.05;\n } else if (maxRange < 1) {\n stepSize = 0.1;\n } else if (maxRange < 2) {\n stepSize = 0.2;\n } else if (maxRange < 5) {\n stepSize = 0.5;\n } else if (maxRange < 10) {\n stepSize = 1;\n } else {\n const magnitude = Math.pow(10, Math.floor(Math.log10(rawStep)));\n const normalized = rawStep / magnitude;\n\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\n // محاسبه yMin و yMax متقارن نسبت به صفر با padding\n yMin = Math.floor(minValue / stepSize) * stepSize - stepSize;\n yMax = Math.ceil(maxValue / stepSize) * stepSize + stepSize;\n } else {\n // فقط مثبت یا فقط منفی\n const range = maxValue - minValue;\n const targetLines = 10;\n let rawStep = range / targetLines;\n\n if (range < 0.01) {\n stepSize = 0.001;\n } else if (range < 0.05) {\n stepSize = 0.005;\n } else if (range < 0.1) {\n stepSize = 0.01;\n } else if (range < 0.5) {\n stepSize = 0.05;\n } else if (range < 1) {\n stepSize = 0.1;\n } else if (range < 2) {\n stepSize = 0.2;\n } else if (range < 5) {\n stepSize = 0.5;\n } else if (range < 10) {\n stepSize = 1;\n } else {\n const magnitude = Math.pow(10, Math.floor(Math.log10(rawStep)));\n const normalized = rawStep / magnitude;\n\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\n // محاسبه yMin و yMax با padding\n yMin = Math.floor(minValue / stepSize) * stepSize - stepSize;\n yMax = Math.ceil(maxValue / stepSize) * stepSize + stepSize;\n\n // اگر فقط مثبت داریم و yMin منفی شده، از صفر شروع کنیم\n if (!hasNegativeData && yMin < 0) {\n yMin = 0;\n }\n }\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 grid: {\n color: (context: any) => {\n // خط صفر را فقط وقتی پررنگ می‌کنیم که داده منفی داشته باشیم\n if (\n hasNegativeData &&\n context.tick &&\n Math.abs(context.tick.value) < 0.0001\n ) {\n return \"rgba(0, 0, 0, 0.5)\";\n }\n return \"rgba(0, 0, 0, 0.1)\";\n },\n lineWidth: (context: any) => {\n if (\n hasNegativeData &&\n context.tick &&\n Math.abs(context.tick.value) < 0.0001\n ) {\n return 2;\n }\n return 1;\n },\n },\n ticks: {\n callback: (value: any) => {\n const num = Number(value);\n if (scaleType === \"logarithmic\") return num.toLocaleString();\n\n if (Math.abs(num) >= 1000) return num.toLocaleString();\n\n if (stepSize !== undefined) {\n if (stepSize < 0.01) return num.toFixed(3);\n if (stepSize < 0.1) return num.toFixed(2);\n if (stepSize < 1) return num.toFixed(1);\n }\n\n if (Math.abs(num) < 1 && num !== 0) {\n return num.toFixed(2);\n }\n\n return num;\n },\n font: { family: \"vazirmatn\", size: 14 },\n },\n },\n x: {\n ticks: {\n autoSkip: false,\n font: { family: \"vazirmatn\", size: 13 },\n },\n },\n },\n plugins: {\n legend: {\n labels: {\n usePointStyle: true,\n font: { size: 16, family: \"vazirmatn\" },\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: \"vazirmatn\", size: 14 },\n titleFont: { family: \"vazirmatn\", size: 16 },\n callbacks: {\n label: (context:any) => {\n const label = context.dataset.label ?? \"\";\n const value = context.parsed.y;\n\n // تبدیل عدد به رشته با locale فارسی (اختیاری)\n const formattedValue =\n typeof value === \"number\" ? value.toLocaleString(\"fa-IR\") : value;\n\n return `${label}: ${formattedValue}`;\n },\n },\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 به vazirmatn\nChartJS.defaults.font.family = \"vazirmatn\";\nChart.defaults.font.family = \"'vazirmatn'\"; //\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<\n { left: number; top: number; text: string; opacity: number }[]\n >([]);\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: {\n left: number;\n top: number;\n text: string;\n opacity: number;\n }[] = [];\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 =\n 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({\n left: leftRelative,\n top: topRelative,\n text,\n opacity: 1,\n });\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 {\n prevOnComplete && prevOnComplete();\n } catch (e) {\n /* ignore */\n }\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 () => ({\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: \"vazirmatn\",\n size: 14,\n },\n titleFont: {\n family: \"vazirmatn\",\n size: 16,\n },\n callbacks: {\n label: (context: any) => {\n const label = context.dataset?.label ?? \"\";\n const parsed = context.parsed;\n const yAxisID = context.dataset?.yAxisID === \"y1\" ? \" %\" : \"\";\n const y =\n typeof parsed === \"number\"\n ? parsed\n : typeof parsed === \"object\" && parsed !== null\n ? parsed.y\n : null;\n\n if (typeof y === \"number\") {\n return `${label}: ${yAxisID}${y.toLocaleString(\"fa-IR\")}`;\n }\n\n return label;\n },\n },\n },\n legend: {\n labels: {\n padding: 15,\n usePointStyle: true,\n color: \"#666\", // رنگ متن legend را نرم‌تر می‌کند\n font: {\n size: 16,\n family: \"vazirmatn\",\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]\n ? meta.data[index].hidden\n : 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 }),\n [disableLogo]\n );\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\n ref={containerRef}\n height={height ?? 600}\n sx={{ position: \"relative\" }}\n >\n <Pie\n ref={chartRef}\n data={{\n labels: labels,\n datasets: datasets,\n }}\n options={options}\n />\n {/* لیبل‌های سفارشی با فونت vazirmatn */}\n {showDataLabels &&\n 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: \"vazirmatn, sans-serif\",\n pointerEvents: \"none\",\n textShadow: \"0 1px 2px rgba(0,0,0,0.5)\",\n opacity: label.opacity,\n transition:\n \"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"]}