|
|
|
|
|
|
|
|
|
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
|
|
initializeCharts();
|
|
});
|
|
|
|
|
|
|
|
|
|
function initializeCharts() {
|
|
|
|
if (typeof Chart === 'undefined') {
|
|
console.warn('مكتبة Chart.js غير متوفرة. لا يمكن تهيئة المخططات.');
|
|
return;
|
|
}
|
|
|
|
|
|
Chart.defaults.font.family = "'Tajawal', sans-serif";
|
|
Chart.defaults.font.size = 14;
|
|
Chart.defaults.color = '#333';
|
|
Chart.defaults.plugins.tooltip.rtl = true;
|
|
Chart.defaults.plugins.tooltip.titleAlign = 'right';
|
|
Chart.defaults.plugins.tooltip.bodyAlign = 'right';
|
|
Chart.defaults.plugins.legend.rtl = true;
|
|
Chart.defaults.plugins.legend.labels.textAlign = 'right';
|
|
|
|
|
|
initializeBarCharts();
|
|
initializeLineCharts();
|
|
initializePieCharts();
|
|
initializeRadarCharts();
|
|
initializeGaugeCharts();
|
|
initializeDashboardCharts();
|
|
}
|
|
|
|
|
|
|
|
|
|
function initializeBarCharts() {
|
|
const barChartElements = document.querySelectorAll('.bar-chart');
|
|
|
|
barChartElements.forEach(element => {
|
|
const ctx = element.getContext('2d');
|
|
const dataUrl = element.getAttribute('data-url');
|
|
|
|
|
|
if (dataUrl) {
|
|
fetch(dataUrl)
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
createBarChart(ctx, element, data);
|
|
})
|
|
.catch(error => {
|
|
console.error('خطأ في تحميل بيانات المخطط:', error);
|
|
|
|
createBarChart(ctx, element, getDefaultBarChartData());
|
|
});
|
|
} else {
|
|
|
|
let chartData;
|
|
try {
|
|
chartData = JSON.parse(element.getAttribute('data-config') || '{}');
|
|
} catch (e) {
|
|
console.error('تنسيق بيانات المخطط غير صالح:', e);
|
|
chartData = getDefaultBarChartData();
|
|
}
|
|
|
|
createBarChart(ctx, element, chartData);
|
|
}
|
|
});
|
|
}
|
|
|
|
|
|
|
|
|
|
function createBarChart(ctx, element, data) {
|
|
const isVertical = element.getAttribute('data-orientation') !== 'horizontal';
|
|
const isStacked = element.getAttribute('data-stacked') === 'true';
|
|
|
|
|
|
const options = {
|
|
indexAxis: isVertical ? 'x' : 'y',
|
|
scales: {
|
|
x: {
|
|
beginAtZero: true,
|
|
grid: {
|
|
display: false
|
|
}
|
|
},
|
|
y: {
|
|
beginAtZero: true,
|
|
grid: {
|
|
display: true,
|
|
color: '#f0f0f0'
|
|
}
|
|
}
|
|
},
|
|
plugins: {
|
|
title: {
|
|
display: data.title ? true : false,
|
|
text: data.title || '',
|
|
align: 'right',
|
|
font: {
|
|
size: 16,
|
|
weight: 'bold'
|
|
}
|
|
},
|
|
legend: {
|
|
display: (data.datasets && data.datasets.length > 1) ? true : false,
|
|
position: 'top',
|
|
align: 'end'
|
|
}
|
|
},
|
|
responsive: true,
|
|
maintainAspectRatio: false
|
|
};
|
|
|
|
|
|
if (isStacked) {
|
|
options.scales.x.stacked = true;
|
|
options.scales.y.stacked = true;
|
|
}
|
|
|
|
|
|
new Chart(ctx, {
|
|
type: 'bar',
|
|
data: {
|
|
labels: data.labels || [],
|
|
datasets: data.datasets || []
|
|
},
|
|
options: options
|
|
});
|
|
}
|
|
|
|
|
|
|
|
|
|
function initializeLineCharts() {
|
|
const lineChartElements = document.querySelectorAll('.line-chart');
|
|
|
|
lineChartElements.forEach(element => {
|
|
const ctx = element.getContext('2d');
|
|
const dataUrl = element.getAttribute('data-url');
|
|
|
|
|
|
if (dataUrl) {
|
|
fetch(dataUrl)
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
createLineChart(ctx, element, data);
|
|
})
|
|
.catch(error => {
|
|
console.error('خطأ في تحميل بيانات المخطط:', error);
|
|
createLineChart(ctx, element, getDefaultLineChartData());
|
|
});
|
|
} else {
|
|
|
|
let chartData;
|
|
try {
|
|
chartData = JSON.parse(element.getAttribute('data-config') || '{}');
|
|
} catch (e) {
|
|
console.error('تنسيق بيانات المخطط غير صالح:', e);
|
|
chartData = getDefaultLineChartData();
|
|
}
|
|
|
|
createLineChart(ctx, element, chartData);
|
|
}
|
|
});
|
|
}
|
|
|
|
|
|
|
|
|
|
function createLineChart(ctx, element, data) {
|
|
const isCurved = element.getAttribute('data-curved') === 'true';
|
|
const showPoints = element.getAttribute('data-points') !== 'false';
|
|
|
|
|
|
const options = {
|
|
scales: {
|
|
x: {
|
|
grid: {
|
|
display: false
|
|
}
|
|
},
|
|
y: {
|
|
beginAtZero: element.getAttribute('data-start-at-zero') === 'true',
|
|
grid: {
|
|
color: '#f0f0f0'
|
|
}
|
|
}
|
|
},
|
|
elements: {
|
|
line: {
|
|
tension: isCurved ? 0.4 : 0,
|
|
borderWidth: 2
|
|
},
|
|
point: {
|
|
radius: showPoints ? 4 : 0,
|
|
hoverRadius: showPoints ? 6 : 0
|
|
}
|
|
},
|
|
plugins: {
|
|
title: {
|
|
display: data.title ? true : false,
|
|
text: data.title || '',
|
|
align: 'right',
|
|
font: {
|
|
size: 16,
|
|
weight: 'bold'
|
|
}
|
|
},
|
|
legend: {
|
|
position: 'top',
|
|
align: 'end'
|
|
}
|
|
},
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
interaction: {
|
|
mode: 'index',
|
|
intersect: false
|
|
}
|
|
};
|
|
|
|
|
|
new Chart(ctx, {
|
|
type: 'line',
|
|
data: {
|
|
labels: data.labels || [],
|
|
datasets: data.datasets || []
|
|
},
|
|
options: options
|
|
});
|
|
}
|
|
|
|
|
|
|
|
|
|
function initializePieCharts() {
|
|
const pieChartElements = document.querySelectorAll('.pie-chart, .doughnut-chart');
|
|
|
|
pieChartElements.forEach(element => {
|
|
const ctx = element.getContext('2d');
|
|
const dataUrl = element.getAttribute('data-url');
|
|
const isDoughnut = element.classList.contains('doughnut-chart');
|
|
|
|
|
|
if (dataUrl) {
|
|
fetch(dataUrl)
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
createPieChart(ctx, element, data, isDoughnut);
|
|
})
|
|
.catch(error => {
|
|
console.error('خطأ في تحميل بيانات المخطط:', error);
|
|
createPieChart(ctx, element, getDefaultPieChartData(), isDoughnut);
|
|
});
|
|
} else {
|
|
|
|
let chartData;
|
|
try {
|
|
chartData = JSON.parse(element.getAttribute('data-config') || '{}');
|
|
} catch (e) {
|
|
console.error('تنسيق بيانات المخطط غير صالح:', e);
|
|
chartData = getDefaultPieChartData();
|
|
}
|
|
|
|
createPieChart(ctx, element, chartData, isDoughnut);
|
|
}
|
|
});
|
|
}
|
|
|
|
|
|
|
|
|
|
function createPieChart(ctx, element, data, isDoughnut) {
|
|
|
|
const options = {
|
|
plugins: {
|
|
title: {
|
|
display: data.title ? true : false,
|
|
text: data.title || '',
|
|
align: 'right',
|
|
font: {
|
|
size: 16,
|
|
weight: 'bold'
|
|
}
|
|
},
|
|
legend: {
|
|
position: 'bottom',
|
|
align: 'start',
|
|
rtl: true,
|
|
labels: {
|
|
boxWidth: 12,
|
|
padding: 15
|
|
}
|
|
}
|
|
},
|
|
responsive: true,
|
|
maintainAspectRatio: false
|
|
};
|
|
|
|
|
|
if (isDoughnut) {
|
|
options.cutout = '60%';
|
|
options.plugins.tooltip = {
|
|
callbacks: {
|
|
title: function(tooltipItems) {
|
|
return tooltipItems[0].label;
|
|
},
|
|
label: function(context) {
|
|
const value = context.raw;
|
|
const total = context.chart.getDatasetMeta(0).total;
|
|
const percentage = Math.round((value / total) * 100);
|
|
return percentage + '% (' + value + ')';
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
|
|
new Chart(ctx, {
|
|
type: isDoughnut ? 'doughnut' : 'pie',
|
|
data: {
|
|
labels: data.labels || [],
|
|
datasets: [{
|
|
data: data.values || [],
|
|
backgroundColor: data.colors || getDefaultColors(),
|
|
borderWidth: 1,
|
|
borderColor: '#fff'
|
|
}]
|
|
},
|
|
options: options
|
|
});
|
|
}
|
|
|
|
|
|
|
|
|
|
function initializeRadarCharts() {
|
|
const radarChartElements = document.querySelectorAll('.radar-chart');
|
|
|
|
radarChartElements.forEach(element => { |