ferrari 5 месяцев назад
Родитель
Сommit
bf595ab0b0
3 измененных файлов с 335 добавлено и 109 удалено
  1. 65 0
      app/Http/Livewire/Reports.php
  2. 6 5
      public/css/chart-reports.css
  3. 264 104
      resources/views/livewire/reports.blade.php

+ 65 - 0
app/Http/Livewire/Reports.php

@@ -216,6 +216,71 @@ class Reports extends Component
             ]
         ];
     }
+    
+    public function getYearlyTotals()
+    {
+        Log::info('=== getyearlyTotals called ===');
+
+        $incomeRecords = DB::table('records')
+            ->join('records_rows', 'records.id', '=', 'records_rows.record_id')
+            ->where('records.type', 'IN')
+            ->selectRaw("
+                CASE
+                    WHEN MONTH(records.date) >= 9
+                        THEN CONCAT(YEAR(records.date), '/', YEAR(records.date) + 1)
+                    ELSE CONCAT(YEAR(records.date) - 1, '/', YEAR(records.date))
+                END AS year_num,
+                SUM(records_rows.amount) AS total
+            ")
+            ->groupBy('year_num')
+            ->get();
+
+        $expenseRecords = DB::table('records')
+            ->join('records_rows', 'records.id', '=', 'records_rows.record_id')
+            ->where('records.type', 'OUT')
+            ->selectRaw("
+                CASE
+                    WHEN MONTH(records.date) >= 9
+                        THEN CONCAT(YEAR(records.date), '/', YEAR(records.date) + 1)
+                    ELSE CONCAT(YEAR(records.date) - 1, '/', YEAR(records.date))
+                END AS year_num,
+                SUM(records_rows.amount) AS total
+            ")
+            ->groupBy('year_num')
+            ->get();
+        
+        // Mappa anno/totale
+        $incomeByYear = $incomeRecords->pluck('total', 'year_num');
+        $expenseByYear = $expenseRecords->pluck('total', 'year_num');
+
+        // Unione di tutti gli anni presenti ordinati
+        $allYears = $incomeByYear->keys()
+                                ->merge($expenseByYear->keys())
+                                ->unique()
+                                ->sort()
+                                ->values();
+
+        // Allineo i dati dei due array, se non presente l'anno: default 0
+        $incomeData  = $allYears->map(fn ($y) => (float) ($incomeByYear[$y]  ?? 0))->toArray();
+        $expenseData = $allYears->map(fn ($y) => (float) ($expenseByYear[$y] ?? 0))->toArray();
+
+
+        return [
+            'labels' => $allYears->toArray(),
+            'datasets' => [
+                [
+                    'label' => 'Entrate',
+                    'data' => $incomeData,
+                    'backgroundColor' => 'rgba(54, 162, 235, 0.5)',
+                ],
+                [
+                    'label' => 'Uscite',
+                    'data' => $expenseData,
+                    'backgroundColor' => 'rgba(255, 99, 132, 0.5)',
+                ],
+            ],
+        ];
+    }
 
     public function getYearlySummary()
     {

+ 6 - 5
public/css/chart-reports.css

@@ -1,9 +1,9 @@
 @charset "UTF-8";
 
 :root {
-    --primary-color: #6366f1;
-    --primary-light: #818cf8;
-    --primary-dark: #4f46e5;
+    --primary-color: #0c6197;
+    --primary-light: #3585b8;
+    --primary-dark: #074c77;
     --secondary-color: #64748b;
     --success-color: #10b981;
     --success-light: #34d399;
@@ -18,7 +18,8 @@
     --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
     --shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
     --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
-    --gradient-primary: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+    /* --gradient-primary: linear-gradient(135deg, #667eea 0%, #764ba2 100%); */
+    --gradient-primary: linear-gradient(135deg, #0c6197 0%, #0c6197 100%);
     --gradient-success: linear-gradient(135deg, #10b981 0%, #059669 100%);
     --gradient-danger: linear-gradient(135deg, #ef4444 0%, #dc2626 100%);
 }
@@ -979,4 +980,4 @@ canvas[id^="courses-chart-"] {
     overflow: hidden;
     position: relative;
     width: 100%;
-}
+}

+ 264 - 104
resources/views/livewire/reports.blade.php

@@ -4,19 +4,37 @@
     <link rel="stylesheet" href="/css/chart-reports.css">
 
     <div class="dashboard-container">
+
+        <div class="chart-row">
+            <div class="chart-card">
+                <div class="chart-header">
+                    <h3 class="chart-title">Tesserati per Stagione</h3>
+                </div>
+                <div class="chart-body">
+                    <div style="display: grid; grid-template-columns: 1fr 500px; gap: 1rem; align-items: start;">
+                        <div class="chart-container">
+                            <canvas id="members-chart"></canvas>
+                        </div>
+                        <div class="yearly-table-container" id="yearly-table">
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+
         <div class="controls-section">
             <div class="control-group">
                 <label for="season-filter">Stagione di Riferimento:</label>
                 <select class="form-select" wire:model="seasonFilter" wire:change="updateCharts">
                     @foreach($this->getAvailableSeasons() as $season)
-                        <option value="{{ $season }}">{{ $season }}</option>
+                    <option value="{{ $season }}">{{ $season }}</option>
                     @endforeach
                 </select>
             </div>
         </div>
 
         @php
-            $summary = $this->getYearlySummary();
+        $summary = $this->getYearlySummary();
         @endphp
         <div class="summary-cards">
             <div class="summary-card income">
@@ -37,8 +55,7 @@
             <div class="chart-row">
                 <div class="chart-card">
                     <div class="chart-header">
-                        <h3 class="chart-title">Entrate e Uscite Mensili - <span
-                                id="monthly-season-title">{{ $seasonFilter }}</span></h3>
+                        <h3 class="chart-title">Entrate e Uscite Mensili - <span id="monthly-season-title">{{ $seasonFilter }}</span></h3>
                     </div>
                     <div class="chart-body">
                         <div style="display: grid; grid-template-columns: 1fr 300px; align-items: start;">
@@ -55,8 +72,7 @@
             <div class="chart-row">
                 <div class="chart-card">
                     <div class="chart-header">
-                        <h3 class="chart-title">Causali Performanti - <span
-                                id="causals-season-title">{{ $seasonFilter }}</span></h3>
+                        <h3 class="chart-title">Causali Performanti - <span id="causals-season-title">{{ $seasonFilter }}</span></h3>
                     </div>
                     <div class="chart-body">
                         <div style="display: grid; grid-template-columns: 1fr 700px; gap: 1rem; align-items: start;">
@@ -79,7 +95,7 @@
                     <div class="chart-body">
                         <div style="display: grid; grid-template-columns: 1fr 500px; gap: 1rem; align-items: start;">
                             <div class="chart-container">
-                                <canvas id="members-chart-{{ str_replace('-', '', $seasonFilter) }}"></canvas>
+                                <canvas id="members-chart2"></canvas>
                             </div>
                             <div class="members-table-container" id="members-table">
                             </div>
@@ -90,51 +106,49 @@
         </div>
 
         @if(false)
-            <div class="chart-row">
-                <div class="chart-card modern-course-card">
-                    <div class="chart-header">
-                        <h3 class="chart-title">Analisi Corsi</h3>
-                    </div>
-                    <div class="chart-body">
-                        <div class="course-controls">
-                            <div class="control-group">
-                                <label>Seleziona Corso ({{ $seasonFilter }}):</label>
-                                <select class="form-select modern-select" wire:model.live="selectedCourse">
-                                    <option value="">Seleziona un Corso</option>
-                                    @foreach($this->getCoursesForSelect() as $course)
-                                        <option value="{{ $course['id'] }}">{{ $course['full_name'] }}</option>
-                                    @endforeach
-                                </select>
-                            </div>
+        <div class="chart-row">
+            <div class="chart-card modern-course-card">
+                <div class="chart-header">
+                    <h3 class="chart-title">Analisi Corsi</h3>
+                </div>
+                <div class="chart-body">
+                    <div class="course-controls">
+                        <div class="control-group">
+                            <label>Seleziona Corso ({{ $seasonFilter }}):</label>
+                            <select class="form-select modern-select" wire:model.live="selectedCourse">
+                                <option value="">Seleziona un Corso</option>
+                                @foreach($this->getCoursesForSelect() as $course)
+                                <option value="{{ $course['id'] }}">{{ $course['full_name'] }}</option>
+                                @endforeach
+                            </select>
                         </div>
+                    </div>
 
-                        @if($selectedCourse)
-                            <div wire:ignore wire:key="course-chart-{{ $seasonFilter }}-{{ $selectedCourse }}">
-                                <div class="modern-chart-layout">
-                                    <div class="course-delta-table"
-                                        id="course-delta-table-{{ str_replace('-', '', $seasonFilter) }}-{{ $selectedCourse }}">
-                                    </div>
-
-                                    <div class="modern-chart-container">
-                                        <canvas
-                                            id="courses-chart-{{ str_replace('-', '', $seasonFilter) }}-{{ $selectedCourse }}"></canvas>
-                                    </div>
-                                </div>
+                    @if($selectedCourse)
+                    <div wire:ignore wire:key="course-chart-{{ $seasonFilter }}-{{ $selectedCourse }}">
+                        <div class="modern-chart-layout">
+                            <div class="course-delta-table" id="course-delta-table-{{ str_replace('-', '', $seasonFilter) }}-{{ $selectedCourse }}">
                             </div>
-                        @else
-                            <div class="chart-placeholder">
-                                <div style="text-align: center;">
-                                    <div style="font-size: 3rem; margin-bottom: 1rem; opacity: 0.3;">📊</div>
-                                    <p style="font-size: 1.25rem; font-weight: 600; margin: 0;">Seleziona un corso per
-                                        visualizzare il grafico</p>
-                                    <p style="font-size: 1rem; opacity: 0.7; margin-top: 0.5rem;">Usa il menu a tendina sopra
-                                        per scegliere un corso</p>
-                                </div>
+
+                            <div class="modern-chart-container">
+                                <canvas id="courses-chart-{{ str_replace('-', '', $seasonFilter) }}-{{ $selectedCourse }}"></canvas>
                             </div>
-                        @endif
+                        </div>
                     </div>
+                    @else
+                    <div class="chart-placeholder">
+                        <div style="text-align: center;">
+                            <div style="font-size: 3rem; margin-bottom: 1rem; opacity: 0.3;">📊</div>
+                            <p style="font-size: 1.25rem; font-weight: 600; margin: 0;">Seleziona un corso per
+                                visualizzare il grafico</p>
+                            <p style="font-size: 1rem; opacity: 0.7; margin-top: 0.5rem;">Usa il menu a tendina sopra
+                                per scegliere un corso</p>
+                        </div>
+                    </div>
+                    @endif
                 </div>
             </div>
+        </div>
         @endif
     </div>
 
@@ -186,6 +200,11 @@
                     this.updateMonthlyTable(monthlyData);
                 });
 
+                @this.call('getYearlyTotals').then(yearlyData => {
+                    console.log('Got yearly data:', yearlyData);
+                    this.updateYearlyTable(yearlyData);
+                });
+
                 @this.call('getTopCausalsByAmount').then(causalsData => {
                     console.log('Got causals data:', causalsData);
                     this.createCausalsChart(originalSeasonKey, causalsData);
@@ -233,47 +252,58 @@
                                 data: monthlyData.datasets[0].data,
                                 backgroundColor: incomeGradient,
                                 borderColor: '#00b894',
-                                borderWidth: 2,
-                                borderRadius: 12,
+                                borderWidth: 0,
+                                borderRadius: 0,
                                 borderSkipped: false,
+                                barThickness: "flex",
+                                barPercentage: 0.65,
+                                categoryPercentage: 0.4,
                             },
                             {
                                 label: 'Uscite',
                                 data: monthlyData.datasets[1].data,
                                 backgroundColor: expenseGradient,
                                 borderColor: '#ff6b6b',
-                                borderWidth: 2,
-                                borderRadius: 12,
+                                borderWidth: 0,
+                                borderRadius: 0,
                                 borderSkipped: false,
+                                barThickness: "flex",
+                                barPercentage: 0.65,
+                                categoryPercentage: 0.4,
                             }
                         ]
                     },
                     options: {
                         responsive: true,
                         maintainAspectRatio: false,
+                        interaction: {
+                            mode: 'index',
+                            intersect: false,
+                        },
                         plugins: {
                             legend: {
-                                position: 'top',
+                                position: 'bottom',
                                 labels: {
                                     usePointStyle: true,
                                     padding: 20,
+                                    pointStyle: "rect",
                                     font: { weight: '500' }
                                 }
                             },
                             tooltip: {
-                                backgroundColor: 'rgba(255, 255, 255,1)',
+                                backgroundColor: 'rgba(255, 255, 255, 1)',
                                 titleColor: '#212529',
                                 bodyColor: '#495057',
                                 borderColor: '#e9ecef',
-                                borderWidth: 12,
-                                cornerRadius: 8,
+                                borderWidth: 2,
+                                cornerRadius: 0,
                                 callbacks: {
                                     label: function (context) {
                                         return context.dataset.label + ': €' +
                                             new Intl.NumberFormat('it-IT').format(context.parsed.y);
                                     }
                                 }
-                            }
+                            },
                         },
                         scales: {
                             x: {
@@ -332,6 +362,90 @@
                 const dataValues = causalsData.inData.map(item => parseFloat(item.value));
                 const total = dataValues.reduce((sum, value) => sum + value, 0);
 
+                // alwaysTooltip
+                const alwaysShowTooltip = {
+                    id: "alwaysShowTooltip",
+                    afterDraw(chart) {
+                        const { ctx } = chart;
+                        ctx.save();
+
+                        const linePad = 12; // distanza dal bordo della ciambella
+                        const textOffset = 20; // distanza fissa del testo dal bordo
+                        const lineGap = 8; // margine tra linea e testo
+                        const lineWidth = 1;
+
+                        chart.data.datasets.forEach((dataset, di) => {
+                            const meta = chart.getDatasetMeta(di);
+                            const total = dataset.data.reduce((s, v) => s + v, 0);
+
+                            meta.data.forEach((datapoint, index) => {
+                                const value = dataset.data[index];
+                                const perc = total > 0 ? (value / total) * 100 : 0;
+                                const text = `${perc.toFixed(1)}%`;
+
+                                // calcolo angolo e anchor
+                                const { x, y } = datapoint.tooltipPosition();
+                                const coords = outsideLabelPoint({
+                                    cx: datapoint.x,
+                                    cy: datapoint.y,
+                                    px: x,
+                                    py: y,
+                                    radius: datapoint.outerRadius,
+                                    pad: linePad,
+                                });
+
+                                const ux = Math.cos(coords.theta);
+                                const uy = Math.sin(coords.theta);
+
+                                const ax = coords.anchor.x;
+                                const ay = coords.anchor.y;
+
+                                // centro testo
+                                const tx = ax + ux * textOffset;
+                                const ty = ay + uy * textOffset;
+
+                                // fine della linea = poco prima del testo
+                                const lx = tx - ux * lineGap;
+                                const ly = ty - uy * lineGap;
+
+                                // linea: anchor -> vicino al testo
+                                ctx.lineWidth = lineWidth;
+                                ctx.strokeStyle = datapoint.options.borderColor;
+                                ctx.beginPath();
+                                ctx.moveTo(ax, ay);
+                                ctx.lineTo(lx, ly);
+                                ctx.stroke();
+
+                                // testo
+                                ctx.font = "12px greycliff-cf, sans-serif";
+                                ctx.fillStyle = datapoint.options.borderColor;
+                                ctx.textAlign = "center";
+                                ctx.textBaseline = "middle";
+                                ctx.fillText(text, tx, ty);
+                            });
+                        });
+
+                        ctx.restore();
+                    },
+                };
+
+                function outsideLabelPoint({ cx, cy, px, py, radius, pad = 20 }) {
+                    const theta = Math.atan2(py - cy, px - cx); // angolo rad
+                    const anchor = { // punto sul bordo del pie
+                        x: cx + radius * Math.cos(theta),
+                        y: cy + radius * Math.sin(theta)
+                    };
+                    const label = { // punto esterno per il tooltip/etichetta
+                        x: cx + (radius + pad) * Math.cos(theta),
+                        y: cy + (radius + pad) * Math.sin(theta)
+                    };
+                    const align = {
+                        textAlign: Math.cos(theta) >= 0 ? 'left' : 'right',
+                        textBaseline: Math.sin(theta) > 0 ? 'top' : 'bottom'
+                    };
+                    return { theta, anchor, label, align };
+                }
+
                 this.charts[chartId] = new Chart(ctx, {
                     type: 'doughnut',
                     data: {
@@ -351,10 +465,10 @@
                         cutout: '30%',
                         layout: {
                             padding: {
-                                top: 10,
-                                right: 10,
-                                bottom: 10,
-                                left: 10
+                                top: 30,
+                                right: 30,
+                                bottom: 30,
+                                left: 30
                             }
                         },
                         plugins: {
@@ -362,12 +476,12 @@
                                 display: false
                             },
                             tooltip: {
-                                backgroundColor: 'rgba(255, 255, 255, 0.95)',
+                                backgroundColor: 'rgba(255, 255, 255, 1)',
                                 titleColor: '#212529',
                                 bodyColor: '#495057',
                                 borderColor: '#e9ecef',
-                                borderWidth: 1,
-                                cornerRadius: 8,
+                                borderWidth: 2,
+                                cornerRadius: 0,
                                 titleFont: {
                                     size: 13,
                                     weight: 'bold'
@@ -399,7 +513,8 @@
                             animateRotate: true,
                             duration: 1000
                         }
-                    }
+                    },
+                    plugins: [alwaysShowTooltip]
                 });
 
                 this.updateCausalsTable(causalsData, dataValues, total);
@@ -447,13 +562,17 @@
                 container.innerHTML = tableHtml;
             },
             createMembersChart: function (seasonKey, membersData) {
-                const chartId = `members-chart-${seasonKey}`;
+                const chartId = `members-chart`;
+                const chartId2 = `members-chart2`;
                 const canvas = document.getElementById(chartId);
+                const canvas2 = document.getElementById(chartId2);
                 if (!canvas) return;
 
                 this.destroyChart(chartId);
+                this.destroyChart(chartId2);
 
                 const ctx = canvas.getContext('2d');
+                const ctx2 = canvas2.getContext('2d');
 
                 const gradient = ctx.createLinearGradient(0, 0, 0, 400);
                 gradient.addColorStop(0, 'rgba(59, 91, 219, 0.3)');
@@ -463,36 +582,37 @@
                     if (dataset.label === 'Totale Membri Tesserati') {
                         return {
                             ...dataset,
-                            backgroundColor: gradient,
-                            borderColor: '#3b5bdb',
-                            borderWidth: 3,
-                            pointBackgroundColor: '#3b5bdb',
-                            pointBorderColor: '#ffffff',
-                            pointBorderWidth: 2,
-                            pointRadius: 6,
-                            pointHoverRadius: 8,
-                            type: 'line',
+                            // backgroundColor: gradient,
+                            backgroundColor: dataset.borderColor,
+                            borderColor: dataset.borderColor,
+                            borderWidth: 0,
+                            type: 'bar',
                             order: 1,
-                            fill: true
+                            fill: true,
+                            barThickness: "flex",
+                            barPercentage: 0.65,
+                            categoryPercentage: 0.4,
+
                         };
                     } else {
                         return {
                             ...dataset,
-                            borderWidth: 2,
-                            pointRadius: 4,
-                            pointHoverRadius: 6,
-                            pointBorderColor: '#ffffff',
-                            pointBorderWidth: 1,
-                            type: 'line',
+                            backgroundColor: dataset.borderColor,
+                            borderColor: dataset.borderColor,
+                            borderWidth: 0,
+                            type: 'bar',
                             order: 2,
-                            fill: false,
-                            backgroundColor: 'transparent'
+                            fill: true,
+                            barThickness: "flex",
+                            barPercentage: 0.65,
+                            categoryPercentage: 0.4,
+
                         };
                     }
                 });
 
-                this.charts[chartId] = new Chart(ctx, {
-                    type: 'line',
+                let options = {
+                    type: 'bar',
                     data: {
                         labels: membersData.labels,
                         datasets: processedDatasets
@@ -506,21 +626,21 @@
                         },
                         plugins: {
                             legend: {
-                                display: true,
-                                position: 'top',
+                                position: 'bottom',
                                 labels: {
                                     usePointStyle: true,
-                                    padding: 15,
-                                    font: { weight: '500', size: 12 }
+                                    padding: 20,
+                                    pointStyle: "rect",
+                                    font: { weight: '500' }
                                 }
                             },
                             tooltip: {
-                                backgroundColor: 'rgba(255, 255, 255, 0.95)',
+                                backgroundColor: 'rgba(255, 255, 255, 1)',
                                 titleColor: '#212529',
                                 bodyColor: '#495057',
                                 borderColor: '#e9ecef',
-                                borderWidth: 1,
-                                cornerRadius: 8,
+                                borderWidth: 2,
+                                cornerRadius: 0,
                                 callbacks: {
                                     title: function (context) {
                                         return 'Stagione: ' + context[0].label;
@@ -554,7 +674,10 @@
                             easing: 'easeOutQuart'
                         }
                     }
-                });
+                };
+
+                this.charts[chartId] = new Chart(ctx, options);
+                this.charts[chartId2] = new Chart(ctx2, options);
             },
             updateMonthlyTable: function (monthlyData) {
                 const container = document.getElementById('monthly-table');
@@ -593,6 +716,43 @@
                 tableHtml += '</div>';
                 container.innerHTML = tableHtml;
             },
+            updateYearlyTable: function (yearlyData) {
+                const container = document.getElementById('yearly-table');
+                if (!container) return;
+
+                const incomeData = yearlyData.datasets[0].data;
+                const expenseData = yearlyData.datasets[1].data;
+                const years = yearlyData.labels;
+
+                let tableHtml = `
+                    <div class="monthly-table">
+                        <div class="table-header">
+                            <div class="table-cell month">Anno</div>
+                            <div class="table-cell">Entrate</div>
+                            <div class="table-cell">Uscite</div>
+                            <div class="table-cell">Delta</div>
+                        </div>
+                `;
+
+                years.forEach((year, index) => {
+                    const income = parseFloat(incomeData[index] || 0);
+                    const expense = parseFloat(expenseData[index] || 0);
+                    const net = income - expense;
+                    const rowClass = net < 0 ? 'negative' : (net > 0 ? 'positive' : 'neutral');
+
+                    tableHtml += `
+                        <div class="table-row ${rowClass}">
+                            <div class="table-cell month-name">${year}</div>
+                            <div class="table-cell income">€${new Intl.NumberFormat('it-IT').format(income)}</div>
+                            <div class="table-cell expense">€${new Intl.NumberFormat('it-IT').format(expense)}</div>
+                            <div class="table-cell net">€${new Intl.NumberFormat('it-IT').format(net)}</div>
+                        </div>
+                    `;
+                });
+
+                tableHtml += '</div>';
+                container.innerHTML = tableHtml;
+            },
 
             updateMembersTable: function (membersData) {
                 const container = document.getElementById('members-table');
@@ -610,7 +770,7 @@
                             <div class="table-cell">Stagione</div>
                             <div class="table-cell">Totale</div>
                             <div class="table-cell">Variazione</div>
-                            <div class="table-cell">Tipologie</div>
+                            <div class="table-cell">Ente</div>
                         </div>
                 `;
 
@@ -733,11 +893,11 @@
                         },
                         plugins: {
                             legend: {
-                                display: true,
-                                position: 'top',
+                                position: 'bottom',
                                 labels: {
                                     usePointStyle: true,
                                     padding: 20,
+                                    pointStyle: "rect",
                                     font: { weight: '500' }
                                 }
                             },
@@ -746,8 +906,8 @@
                                 titleColor: '#212529',
                                 bodyColor: '#495057',
                                 borderColor: '#e9ecef',
-                                borderWidth: 1,
-                                cornerRadius: 8,
+                                borderWidth: 2,
+                                cornerRadius: 0,
                                 callbacks: {
                                     label: function (context) {
                                         return context.dataset.label + ': €' +
@@ -945,21 +1105,21 @@
                             },
                             plugins: {
                                 legend: {
-                                    display: true,
-                                    position: 'top',
+                                    position: 'bottom',
                                     labels: {
                                         usePointStyle: true,
-                                        padding: 15,
-                                        font: { weight: '500', size: 12 },
+                                        padding: 20,
+                                        pointStyle: "rect",
+                                        font: { weight: '500' }
                                     }
                                 },
                                 tooltip: {
-                                    backgroundColor: 'rgba(255, 255, 255, 0.98)',
+                                    backgroundColor: 'rgba(255, 255, 255, 1)',
                                     titleColor: '#111827',
                                     bodyColor: '#374151',
                                     borderColor: 'rgba(229, 231, 235, 0.8)',
-                                    borderWidth: 1,
-                                    cornerRadius: 12,
+                                    borderWidth: 2,
+                                    cornerRadius: 0,
                                     titleFont: {
                                         weight: 'bold',
                                         size: 15
@@ -1129,4 +1289,4 @@
             });
         });
     </script>
-</div>
+</div>