|
|
@@ -708,62 +708,93 @@
|
|
|
|
|
|
const verticalMissingLinesPlugin = {
|
|
|
id: 'verticalMissingLines',
|
|
|
- afterDatasetsDraw: function (chart) {
|
|
|
+ beforeDatasetsDraw: function (chart) { // Changed from afterDatasetsDraw to beforeDatasetsDraw
|
|
|
const ctx = chart.ctx;
|
|
|
- const meta0 = chart.getDatasetMeta(0);
|
|
|
- const meta1 = chart.getDatasetMeta(1);
|
|
|
+ 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)';
|
|
|
+ ctx.strokeStyle = 'rgba(239, 68, 68, 0.8)'; // Red color
|
|
|
ctx.lineWidth = 2;
|
|
|
- ctx.setLineDash([6, 4]);
|
|
|
+ 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;
|
|
|
+ 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;
|
|
|
|
|
|
- ctx.beginPath();
|
|
|
- ctx.moveTo(barX, startY);
|
|
|
- ctx.lineTo(barX, endY);
|
|
|
- ctx.stroke();
|
|
|
-
|
|
|
- ctx.setLineDash([]);
|
|
|
- ctx.lineWidth = 1;
|
|
|
-
|
|
|
- ctx.beginPath();
|
|
|
- ctx.moveTo(barX - 3, endY);
|
|
|
- ctx.lineTo(barX + 3, endY);
|
|
|
- ctx.stroke();
|
|
|
-
|
|
|
- ctx.beginPath();
|
|
|
- ctx.moveTo(barX - 3, startY);
|
|
|
- ctx.lineTo(barX + 3, startY);
|
|
|
- ctx.stroke();
|
|
|
-
|
|
|
- ctx.setLineDash([6, 4]);
|
|
|
- ctx.lineWidth = 2;
|
|
|
+ // 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;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
});
|