|
@@ -696,7 +696,6 @@
|
|
|
|
|
|
|
|
const participantData = courseData.datasets.find(d => d.participantData)?.participantData || [];
|
|
const participantData = courseData.datasets.find(d => d.participantData)?.participantData || [];
|
|
|
|
|
|
|
|
-
|
|
|
|
|
const ctx = canvasElement.getContext('2d');
|
|
const ctx = canvasElement.getContext('2d');
|
|
|
|
|
|
|
|
const earnedGradient = ctx.createLinearGradient(0, 0, 0, 400);
|
|
const earnedGradient = ctx.createLinearGradient(0, 0, 0, 400);
|
|
@@ -706,104 +705,7 @@
|
|
|
const totalData = courseData.datasets.find(d => d.label === 'Pagamenti Attesi')?.data || [];
|
|
const totalData = courseData.datasets.find(d => d.label === 'Pagamenti Attesi')?.data || [];
|
|
|
const earnedData = courseData.datasets.find(d => d.label === 'Pagamenti Effettuati')?.data || [];
|
|
const earnedData = courseData.datasets.find(d => d.label === 'Pagamenti Effettuati')?.data || [];
|
|
|
|
|
|
|
|
- const verticalMissingLinesPlugin = {
|
|
|
|
|
- id: 'verticalMissingLines',
|
|
|
|
|
- beforeDatasetsDraw: function (chart) { // Changed from afterDatasetsDraw to beforeDatasetsDraw
|
|
|
|
|
- const ctx = chart.ctx;
|
|
|
|
|
- const meta0 = chart.getDatasetMeta(0); // Bar dataset (Pagamenti Effettuati)
|
|
|
|
|
- const meta1 = chart.getDatasetMeta(1); // Line dataset (Pagamenti Attesi)
|
|
|
|
|
-
|
|
|
|
|
- ctx.save();
|
|
|
|
|
- ctx.strokeStyle = 'rgba(239, 68, 68, 0.8)'; // Red color
|
|
|
|
|
- ctx.lineWidth = 2;
|
|
|
|
|
- ctx.setLineDash([6, 4]); // Dashed pattern
|
|
|
|
|
-
|
|
|
|
|
- // Draw vertical lines for each data point
|
|
|
|
|
- totalData.forEach((totalValue, index) => {
|
|
|
|
|
- const earnedValue = parseFloat(earnedData[index]) || 0;
|
|
|
|
|
- const totalVal = parseFloat(totalValue) || 0;
|
|
|
|
|
-
|
|
|
|
|
- // Draw red line if there's any expected payment (even if earned is 0)
|
|
|
|
|
- if (totalVal > 0 && totalVal > earnedValue) {
|
|
|
|
|
- // Get the x position from either the bar (if exists) or calculate it
|
|
|
|
|
- let barX;
|
|
|
|
|
- if (meta0.data[index] && earnedValue > 0) {
|
|
|
|
|
- barX = meta0.data[index].x;
|
|
|
|
|
- } else {
|
|
|
|
|
- // Calculate x position manually when there's no bar
|
|
|
|
|
- const chartArea = chart.chartArea;
|
|
|
|
|
- const xScale = chart.scales.x;
|
|
|
|
|
- barX = xScale.getPixelForValue(index);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // Get the starting Y position (top of bar or zero line)
|
|
|
|
|
- let startY;
|
|
|
|
|
- if (meta0.data[index] && earnedValue > 0) {
|
|
|
|
|
- startY = meta0.data[index].y; // Top of the bar
|
|
|
|
|
- } else {
|
|
|
|
|
- // Start from zero line
|
|
|
|
|
- const yScale = chart.scales.y;
|
|
|
|
|
- startY = yScale.getPixelForValue(0);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // Get the ending Y position (expected payment line)
|
|
|
|
|
- const linePoint = meta1.data[index];
|
|
|
|
|
- if (linePoint) {
|
|
|
|
|
- const endY = linePoint.y;
|
|
|
|
|
-
|
|
|
|
|
- // Only draw the line if it won't overlap with the bar
|
|
|
|
|
- // When there's a bar, draw only the portion above the bar
|
|
|
|
|
- if (earnedValue > 0 && meta0.data[index]) {
|
|
|
|
|
- // Draw line from top of bar to expected line
|
|
|
|
|
- ctx.beginPath();
|
|
|
|
|
- ctx.moveTo(barX, startY);
|
|
|
|
|
- ctx.lineTo(barX, endY);
|
|
|
|
|
- ctx.stroke();
|
|
|
|
|
-
|
|
|
|
|
- // Top cap only (bottom will be hidden by bar)
|
|
|
|
|
- ctx.setLineDash([]);
|
|
|
|
|
- ctx.lineWidth = 1;
|
|
|
|
|
- ctx.beginPath();
|
|
|
|
|
- ctx.moveTo(barX - 3, endY);
|
|
|
|
|
- ctx.lineTo(barX + 3, endY);
|
|
|
|
|
- ctx.stroke();
|
|
|
|
|
- ctx.setLineDash([6, 4]);
|
|
|
|
|
- ctx.lineWidth = 2;
|
|
|
|
|
- } else {
|
|
|
|
|
- // Draw full line from zero to expected (no bar present)
|
|
|
|
|
- ctx.beginPath();
|
|
|
|
|
- ctx.moveTo(barX, startY);
|
|
|
|
|
- ctx.lineTo(barX, endY);
|
|
|
|
|
- ctx.stroke();
|
|
|
|
|
-
|
|
|
|
|
- // Add caps at both ends
|
|
|
|
|
- ctx.setLineDash([]);
|
|
|
|
|
- ctx.lineWidth = 1;
|
|
|
|
|
-
|
|
|
|
|
- // Top cap
|
|
|
|
|
- ctx.beginPath();
|
|
|
|
|
- ctx.moveTo(barX - 3, endY);
|
|
|
|
|
- ctx.lineTo(barX + 3, endY);
|
|
|
|
|
- ctx.stroke();
|
|
|
|
|
-
|
|
|
|
|
- // Bottom cap
|
|
|
|
|
- ctx.beginPath();
|
|
|
|
|
- ctx.moveTo(barX - 3, startY);
|
|
|
|
|
- ctx.lineTo(barX + 3, startY);
|
|
|
|
|
- ctx.stroke();
|
|
|
|
|
-
|
|
|
|
|
- ctx.setLineDash([6, 4]);
|
|
|
|
|
- ctx.lineWidth = 2;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- ctx.restore();
|
|
|
|
|
- }
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- Chart.register(verticalMissingLinesPlugin);
|
|
|
|
|
|
|
+ // REMOVED: verticalMissingLinesPlugin completely
|
|
|
|
|
|
|
|
this.charts[chartId] = new Chart(ctx, {
|
|
this.charts[chartId] = new Chart(ctx, {
|
|
|
type: 'bar',
|
|
type: 'bar',
|
|
@@ -902,20 +804,7 @@
|
|
|
usePointStyle: true,
|
|
usePointStyle: true,
|
|
|
padding: 15,
|
|
padding: 15,
|
|
|
font: { weight: '500', size: 12 },
|
|
font: { weight: '500', size: 12 },
|
|
|
- generateLabels: function (chart) {
|
|
|
|
|
- const original = Chart.defaults.plugins.legend.labels.generateLabels(chart);
|
|
|
|
|
-
|
|
|
|
|
- original.push({
|
|
|
|
|
- text: 'Pagamenti Mancanti',
|
|
|
|
|
- fillStyle: 'transparent',
|
|
|
|
|
- strokeStyle: 'rgba(239, 68, 68, 0.8)',
|
|
|
|
|
- lineDash: [6, 4],
|
|
|
|
|
- lineWidth: 2,
|
|
|
|
|
- pointStyle: 'line'
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- return original;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // REMOVED: custom generateLabels function that added red dashed line legend
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
tooltip: {
|
|
tooltip: {
|