Obsah článku / Contents
Každý manager miluje grafy: Chart.js za 15 minút

Každý manager miluje grafy: Chart.js za 15 minút

"Daj mi graf tých čísel!" 📊

Tieto slová som počul už stokrát. Manager príde, chce dashboard, deadline je včera. A viete čo? S Chart.js to nie je problém.

Prológ: Pondelková realita

javascript
// Pondelok ráno 9:00
manager = "Potrebujem dashboard s grafmi!"
ja = "OK, aké grafy?"
manager = "Predaje, usery, performance, všetko!"
ja = "Deadline?"
manager = "Do obeda!"
ja = "😰"

// Pondelok 9:05
ja = "import Chart from 'chart.js'"

// Pondelok 11:45
manager = "WOW! Úžasné! 🤩"

// Chart.js pre výhru! 🎉

Prečo práve Chart.js?

javascript
alternativy = {
    "Excel grafy": "❌ Nie je v appke",
    "D3.js": "❌ Príliš komplexné (3 dni učenia)",
    "Google Charts": "❌ Externá závislosť",
    "Vlastné SVG": "❌ Znovuvynachádzanie kolesa",
    "Chart.js": "✅ 15 minút a hotovo!"
}

verdikt = "Chart.js víťazí! 🏆"

Poďme na to!


Kapitola 1: Rýchly štart (5 minút)

Krok 1: Inštalácia

bash
# NPM
npm install chart.js

# CDN (pre rýchle testovanie)
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>

Krok 2: Prvý graf

html
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
    <title>Môj prvý graf</title>
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
</head>
<body>
    <canvas id="myChart" width="400" height="200"></canvas>
    
    <script>
        const ctx = document.getElementById('myChart');
        
        new Chart(ctx, {
            type: 'bar',
            data: {
                labels: ['Jan', 'Feb', 'Mar', 'Apr', 'Máj', 'Jún'],
                datasets: [{
                    label: 'Predaje 2024',
                    data: [12, 19, 3, 5, 2, 3],
                    backgroundColor: 'rgba(54, 162, 235, 0.5)',
                    borderColor: 'rgba(54, 162, 235, 1)',
                    borderWidth: 1
                }]
            },
            options: {
                responsive: true,
                scales: {
                    y: {
                        beginAtZero: true
                    }
                }
            }
        });
    </script>
</body>
</html>

Celkový čas: 2 minúty!

Otvoríš v prehliadači → Graf je hotový! 🎉


Kapitola 2: Základné typy grafov

Bar Chart (Stĺpcový graf)

Klasika. Každý manager ho pozná, každý mu rozumie.

javascript
const salesChart = new Chart(ctx, {
    type: 'bar',
    data: {
        labels: ['Q1', 'Q2', 'Q3', 'Q4'],
        datasets: [{
            label: 'Príjmy (€)',
            data: [45000, 52000, 48000, 67000],
            backgroundColor: [
                'rgba(255, 99, 132, 0.6)',
                'rgba(54, 162, 235, 0.6)',
                'rgba(255, 206, 86, 0.6)',
                'rgba(75, 192, 192, 0.6)'
            ],
            borderColor: [
                'rgba(255, 99, 132, 1)',
                'rgba(54, 162, 235, 1)',
                'rgba(255, 206, 86, 1)',
                'rgba(75, 192, 192, 1)'
            ],
            borderWidth: 2
        }]
    },
    options: {
        responsive: true,
        plugins: {
            title: {
                display: true,
                text: 'Kvartálne príjmy 2024'
            },
            legend: {
                display: true,
                position: 'bottom'
            }
        },
        scales: {
            y: {
                beginAtZero: true,
                ticks: {
                    callback: function(value) {
                        return '€' + value.toLocaleString();
                    }
                }
            }
        }
    }
});

Kedy použiť:

✅ Porovnanie hodnôt (kvartály, produkty, tímy)
✅ Časové série (mesačné predaje)
✅ Rebríčky (top produkty)

Line Chart (Čiarový graf)

Keď chcete ukázať trend. Ide to hore? Dole? Manager to uvidí okamžite.

javascript
const performanceChart = new Chart(ctx, {
    type: 'line',
    data: {
        labels: ['Jan', 'Feb', 'Mar', 'Apr', 'Máj', 'Jún', 'Júl', 'Aug', 'Sep', 'Okt', 'Nov', 'Dec'],
        datasets: [
            {
                label: 'Užívatelia 2024',
                data: [1200, 1350, 1400, 1380, 1500, 1650, 1800, 1950, 2100, 2250, 2400, 2600],
                borderColor: 'rgb(75, 192, 192)',
                backgroundColor: 'rgba(75, 192, 192, 0.1)',
                fill: true,
                tension: 0.4  // Hladká krivka
            },
            {
                label: 'Užívatelia 2023',
                data: [800, 850, 900, 920, 950, 1000, 1050, 1100, 1150, 1200, 1250, 1300],
                borderColor: 'rgb(255, 99, 132)',
                backgroundColor: 'rgba(255, 99, 132, 0.1)',
                fill: true,
                tension: 0.4,
                borderDash: [5, 5]  // Prerušovaná čiara
            }
        ]
    },
    options: {
        responsive: true,
        plugins: {
            title: {
                display: true,
                text: 'Porovnanie rastu užívateľov',
                font: {
                    size: 18
                }
            },
            tooltip: {
                mode: 'index',
                intersect: false
            }
        },
        scales: {
            y: {
                beginAtZero: true,
                ticks: {
                    callback: function(value) {
                        return value.toLocaleString() + ' užívateľov';
                    }
                }
            }
        }
    }
});

Kedy použiť:

✅ Trendy v čase (rast, pokles)
✅ Porovnanie období (medziročne, medzimesačne)
✅ Prognózy (s budúcimi projekciami)

Pie Chart (Koláčový graf)

Manažérsky favorit. Vždy funguje. Percentá na prvý pohľad.

javascript
const marketShareChart = new Chart(ctx, {
    type: 'pie',
    data: {
        labels: ['Produkt A', 'Produkt B', 'Produkt C', 'Produkt D', 'Ostatné'],
        datasets: [{
            label: 'Podiel na trhu',
            data: [35, 25, 20, 12, 8],
            backgroundColor: [
                'rgba(255, 99, 132, 0.8)',
                'rgba(54, 162, 235, 0.8)',
                'rgba(255, 206, 86, 0.8)',
                'rgba(75, 192, 192, 0.8)',
                'rgba(153, 102, 255, 0.8)'
            ],
            borderColor: [
                'rgba(255, 99, 132, 1)',
                'rgba(54, 162, 235, 1)',
                'rgba(255, 206, 86, 1)',
                'rgba(75, 192, 192, 1)',
                'rgba(153, 102, 255, 1)'
            ],
            borderWidth: 2
        }]
    },
    options: {
        responsive: true,
        plugins: {
            title: {
                display: true,
                text: 'Rozdelenie podielu na trhu'
            },
            legend: {
                position: 'right'
            },
            tooltip: {
                callbacks: {
                    label: function(context) {
                        const label = context.label || '';
                        const value = context.parsed || 0;
                        const total = context.dataset.data.reduce((a, b) => a + b, 0);
                        const percentage = ((value / total) * 100).toFixed(1);
                        return `${label}: ${percentage}%`;
                    }
                }
            }
        }
    }
});

Kedy použiť:

✅ Percentuálne rozdelenie (podiel na trhu, rozpočet)
✅ Zloženie (štruktúra tímu, tech stack)
✅ Proporcie (zdroje návštevnosti)

Doughnut Chart (Krúžkový graf)

Ako koláčový, ale vyzerá modernejšie. Manažéri ho milujú.

javascript
const budgetChart = new Chart(ctx, {
    type: 'doughnut',
    data: {
        labels: ['Vývoj', 'Marketing', 'Prevádzka', 'Predaj', 'HR'],
        datasets: [{
            label: 'Rozdelenie rozpočtu',
            data: [40, 25, 15, 12, 8],
            backgroundColor: [
                'rgba(255, 99, 132, 0.8)',
                'rgba(54, 162, 235, 0.8)',
                'rgba(255, 206, 86, 0.8)',
                'rgba(75, 192, 192, 0.8)',
                'rgba(153, 102, 255, 0.8)'
            ],
            hoverOffset: 4
        }]
    },
    options: {
        responsive: true,
        plugins: {
            title: {
                display: true,
                text: 'Ročný rozpočet 2024'
            },
            legend: {
                position: 'bottom'
            }
        }
    }
});

Kedy použiť:

✅ Podobné ako pie chart (ale krajšie! 😎)
✅ Viac datasetov (vnútorný + vonkajší kruh)

Kapitola 3: Dashboard z reálneho sveta

Tu je to, čo manager naozaj chce vidieť - kompletný dashboard.

Predajný dashboard

html
<!DOCTYPE html>
<html>
<head>
    <title>Predajný Dashboard</title>
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
    <style>
        body {
            font-family: Arial, sans-serif;
            padding: 20px;
            background: #f5f5f5;
        }
        .dashboard {
            display: grid;
            grid-template-columns: 2fr 1fr;
            gap: 20px;
            max-width: 1400px;
            margin: 0 auto;
        }
        .card {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }
        .card.full-width {
            grid-column: 1 / -1;
        }
        h1 {
            text-align: center;
            color: #333;
        }
        .stats {
            display: grid;
            grid-template-columns: repeat(4, 1fr);
            gap: 20px;
            margin-bottom: 20px;
        }
        .stat-card {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
            text-align: center;
        }
        .stat-value {
            font-size: 32px;
            font-weight: bold;
            color: #4CAF50;
        }
        .stat-label {
            color: #666;
            font-size: 14px;
            margin-top: 5px;
        }
    </style>
</head>
<body>
    <h1>📊 Predajný Dashboard 2024</h1>
    
    <!-- KPI karty -->
    <div class="stats">
        <div class="stat-card">
            <div class="stat-value">€212K</div>
            <div class="stat-label">Celkové príjmy</div>
        </div>
        <div class="stat-card">
            <div class="stat-value">2 547</div>
            <div class="stat-label">Celkové objednávky</div>
        </div>
        <div class="stat-card">
            <div class="stat-value">€83</div>
            <div class="stat-label">Priem. hodnota objednávky</div>
        </div>
        <div class="stat-card">
            <div class="stat-value">+23%</div>
            <div class="stat-label">Medziročný rast</div>
        </div>
    </div>
    
    <!-- Grafy -->
    <div class="dashboard">
        <div class="card full-width">
            <canvas id="revenueChart"></canvas>
        </div>
        
        <div class="card">
            <canvas id="productChart"></canvas>
        </div>
        
        <div class="card">
            <canvas id="regionChart"></canvas>
        </div>
    </div>
    
    <script src="dashboard.js"></script>
</body>
</html>
javascript
// dashboard.js

// Graf príjmov (čiarový)
const revenueCtx = document.getElementById('revenueChart');
new Chart(revenueCtx, {
    type: 'line',
    data: {
        labels: ['Jan', 'Feb', 'Mar', 'Apr', 'Máj', 'Jún', 'Júl', 'Aug', 'Sep', 'Okt', 'Nov', 'Dec'],
        datasets: [
            {
                label: 'Príjmy 2024',
                data: [15000, 18000, 16000, 22000, 19000, 25000, 28000, 26000, 30000, 32000, 35000, 38000],
                borderColor: 'rgb(75, 192, 192)',
                backgroundColor: 'rgba(75, 192, 192, 0.1)',
                fill: true,
                tension: 0.4
            },
            {
                label: 'Cieľ',
                data: [20000, 20000, 20000, 20000, 20000, 25000, 25000, 25000, 30000, 30000, 35000, 35000],
                borderColor: 'rgba(255, 99, 132, 0.5)',
                borderDash: [10, 5],
                fill: false,
                pointRadius: 0
            }
        ]
    },
    options: {
        responsive: true,
        plugins: {
            title: {
                display: true,
                text: 'Mesačné príjmy vs Cieľ',
                font: { size: 18 }
            },
            tooltip: {
                callbacks: {
                    label: function(context) {
                        return context.dataset.label + ': €' + context.parsed.y.toLocaleString();
                    }
                }
            }
        },
        scales: {
            y: {
                beginAtZero: true,
                ticks: {
                    callback: function(value) {
                        return '€' + (value / 1000) + 'K';
                    }
                }
            }
        }
    }
});

// Rozdelenie produktov (krúžkový)
const productCtx = document.getElementById('productChart');
new Chart(productCtx, {
    type: 'doughnut',
    data: {
        labels: ['Produkt A', 'Produkt B', 'Produkt C', 'Produkt D', 'Ostatné'],
        datasets: [{
            data: [35, 28, 18, 12, 7],
            backgroundColor: [
                'rgba(255, 99, 132, 0.8)',
                'rgba(54, 162, 235, 0.8)',
                'rgba(255, 206, 86, 0.8)',
                'rgba(75, 192, 192, 0.8)',
                'rgba(153, 102, 255, 0.8)'
            ]
        }]
    },
    options: {
        responsive: true,
        plugins: {
            title: {
                display: true,
                text: 'Predaje podľa produktu'
            },
            legend: {
                position: 'bottom'
            }
        }
    }
});

// Regionálne predaje (stĺpcový)
const regionCtx = document.getElementById('regionChart');
new Chart(regionCtx, {
    type: 'bar',
    data: {
        labels: ['Európa', 'Severná Amerika', 'Ázia', 'Južná Amerika', 'Afrika'],
        datasets: [{
            label: 'Predaje (€)',
            data: [85000, 72000, 58000, 32000, 15000],
            backgroundColor: 'rgba(54, 162, 235, 0.6)',
            borderColor: 'rgba(54, 162, 235, 1)',
            borderWidth: 2
        }]
    },
    options: {
        responsive: true,
        plugins: {
            title: {
                display: true,
                text: 'Predaje podľa regiónu'
            },
            legend: {
                display: false
            }
        },
        scales: {
            y: {
                beginAtZero: true,
                ticks: {
                    callback: function(value) {
                        return '€' + (value / 1000) + 'K';
                    }
                }
            }
        }
    }
});

Kapitola 4: Interaktivita

Grafy nie sú len na pozeranie. Dajme im život.

Aktualizácia dát

javascript
let myChart = new Chart(ctx, {
    type: 'bar',
    data: {
        labels: ['Jan', 'Feb', 'Mar', 'Apr', 'Máj', 'Jún'],
        datasets: [{
            label: 'Predaje',
            data: [12, 19, 3, 5, 2, 3]
        }]
    }
});

// Aktualizácia dát
function updateChart() {
    myChart.data.datasets[0].data = [15, 23, 8, 12, 7, 9];
    myChart.update();
}

// Pridanie dát
function addData() {
    myChart.data.labels.push('Júl');
    myChart.data.datasets[0].data.push(14);
    myChart.update();
}

// Odstránenie dát
function removeData() {
    myChart.data.labels.pop();
    myChart.data.datasets[0].data.pop();
    myChart.update();
}

Live dáta

Toto je to, čo manažérov naozaj ohúri - dáta v reálnom čase.

html
<!DOCTYPE html>
<html>
<body>
    <canvas id="liveChart"></canvas>
    <button onclick="startLiveData()">Štart</button>
    <button onclick="stopLiveData()">Stop</button>
    
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
    <script>
        const ctx = document.getElementById('liveChart');
        
        const liveChart = new Chart(ctx, {
            type: 'line',
            data: {
                labels: [],
                datasets: [{
                    label: 'Dáta v reálnom čase',
                    data: [],
                    borderColor: 'rgb(75, 192, 192)',
                    tension: 0.4
                }]
            },
            options: {
                responsive: true,
                scales: {
                    x: { display: true },
                    y: { beginAtZero: true }
                },
                animation: {
                    duration: 0  // Vypnuté pre real-time
                }
            }
        });
        
        let interval;
        
        function startLiveData() {
            interval = setInterval(() => {
                const now = new Date();
                const timeLabel = now.toLocaleTimeString();
                const value = Math.floor(Math.random() * 100);
                
                // Pridať nové dáta
                liveChart.data.labels.push(timeLabel);
                liveChart.data.datasets[0].data.push(value);
                
                // Ponechať len posledných 10 bodov
                if (liveChart.data.labels.length > 10) {
                    liveChart.data.labels.shift();
                    liveChart.data.datasets[0].data.shift();
                }
                
                liveChart.update();
            }, 1000);  // Aktualizácia každú sekundu
        }
        
        function stopLiveData() {
            clearInterval(interval);
        }
    </script>
</body>
</html>

Klikateľné grafy

javascript
const clickableChart = new Chart(ctx, {
    type: 'bar',
    data: {
        labels: ['Q1', 'Q2', 'Q3', 'Q4'],
        datasets: [{
            label: 'Príjmy',
            data: [45000, 52000, 48000, 67000]
        }]
    },
    options: {
        onClick: (event, elements) => {
            if (elements.length > 0) {
                const element = elements[0];
                const datasetIndex = element.datasetIndex;
                const index = element.index;
                const label = clickableChart.data.labels[index];
                const value = clickableChart.data.datasets[datasetIndex].data[index];
                
                alert(`${label}: €${value.toLocaleString()}`);
                
                // Alebo navigácia na detail
                // window.location.href = `/detail/${label}`;
            }
        }
    }
});

Kapitola 5: Integrácia s frameworkami

Angular

typescript
// chart.component.ts

import { Component, OnInit, ViewChild, ElementRef, OnDestroy } from '@angular/core';
import { Chart, registerables } from 'chart.js';

Chart.register(...registerables);

@Component({
  selector: 'app-chart',
  template: `
    <div class="chart-container">
      <canvas #chartCanvas></canvas>
    </div>
  `,
  styles: [`
    .chart-container {
      position: relative;
      height: 400px;
      width: 100%;
    }
  `]
})
export class ChartComponent implements OnInit, OnDestroy {
  @ViewChild('chartCanvas') chartCanvas!: ElementRef<HTMLCanvasElement>;
  private chart?: Chart;
  
  ngOnInit() {
    this.createChart();
  }
  
  private createChart() {
    const ctx = this.chartCanvas.nativeElement.getContext('2d');
    
    if (ctx) {
      this.chart = new Chart(ctx, {
        type: 'line',
        data: {
          labels: ['Jan', 'Feb', 'Mar', 'Apr', 'Máj', 'Jún'],
          datasets: [{
            label: 'Predaje 2024',
            data: [12, 19, 3, 5, 2, 3],
            borderColor: 'rgb(75, 192, 192)',
            tension: 0.4
          }]
        },
        options: {
          responsive: true,
          maintainAspectRatio: false
        }
      });
    }
  }
  
  updateData(newData: number[]) {
    if (this.chart) {
      this.chart.data.datasets[0].data = newData;
      this.chart.update();
    }
  }
  
  ngOnDestroy() {
    if (this.chart) {
      this.chart.destroy();
    }
  }
}

React

jsx
// ChartComponent.jsx

import React, { useEffect, useRef } from 'react';
import { Chart, registerables } from 'chart.js';

Chart.register(...registerables);

function ChartComponent({ data, labels }) {
  const chartRef = useRef(null);
  const chartInstance = useRef(null);
  
  useEffect(() => {
    if (chartRef.current) {
      const ctx = chartRef.current.getContext('2d');
      
      // Zničiť existujúci graf
      if (chartInstance.current) {
        chartInstance.current.destroy();
      }
      
      // Vytvoriť nový graf
      chartInstance.current = new Chart(ctx, {
        type: 'bar',
        data: {
          labels: labels,
          datasets: [{
            label: 'Predaje',
            data: data,
            backgroundColor: 'rgba(54, 162, 235, 0.6)'
          }]
        },
        options: {
          responsive: true,
          maintainAspectRatio: false
        }
      });
    }
    
    // Cleanup
    return () => {
      if (chartInstance.current) {
        chartInstance.current.destroy();
      }
    };
  }, [data, labels]);
  
  return (
    <div style={{ position: 'relative', height: '400px' }}>
      <canvas ref={chartRef}></canvas>
    </div>
  );
}

export default ChartComponent;

Vue

vue
<!-- ChartComponent.vue -->

<template>
  <div class="chart-container">
    <canvas ref="chartCanvas"></canvas>
  </div>
</template>

<script>
import { Chart, registerables } from 'chart.js';

Chart.register(...registerables);

export default {
  name: 'ChartComponent',
  props: {
    data: { type: Array, required: true },
    labels: { type: Array, required: true }
  },
  data() {
    return { chart: null };
  },
  mounted() {
    this.createChart();
  },
  watch: {
    data() {
      this.updateChart();
    }
  },
  methods: {
    createChart() {
      const ctx = this.$refs.chartCanvas.getContext('2d');
      
      this.chart = new Chart(ctx, {
        type: 'line',
        data: {
          labels: this.labels,
          datasets: [{
            label: 'Dáta',
            data: this.data,
            borderColor: 'rgb(75, 192, 192)',
            tension: 0.4
          }]
        },
        options: { responsive: true }
      });
    },
    updateChart() {
      if (this.chart) {
        this.chart.data.datasets[0].data = this.data;
        this.chart.update();
      }
    }
  },
  beforeUnmount() {
    if (this.chart) {
      this.chart.destroy();
    }
  }
};
</script>

<style scoped>
.chart-container {
  position: relative;
  height: 400px;
}
</style>

Kapitola 6: Pokročilá customizácia

Gradienty

Toto vyzerá profesionálne. Manager bude ohromený.

javascript
const ctx = document.getElementById('myChart');

// Vytvorenie gradientu
const gradient = ctx.getContext('2d').createLinearGradient(0, 0, 0, 400);
gradient.addColorStop(0, 'rgba(75, 192, 192, 0.8)');
gradient.addColorStop(0.5, 'rgba(75, 192, 192, 0.4)');
gradient.addColorStop(1, 'rgba(75, 192, 192, 0.1)');

new Chart(ctx, {
    type: 'line',
    data: {
        labels: ['Jan', 'Feb', 'Mar', 'Apr', 'Máj', 'Jún'],
        datasets: [{
            label: 'Príjmy',
            data: [15, 23, 18, 28, 32, 38],
            backgroundColor: gradient,  // Použitie gradientu
            borderColor: 'rgb(75, 192, 192)',
            fill: true,
            tension: 0.4
        }]
    }
});

Vlastné tooltipy

javascript
new Chart(ctx, {
    type: 'line',
    data: { /* ... */ },
    options: {
        plugins: {
            tooltip: {
                enabled: true,
                backgroundColor: 'rgba(0, 0, 0, 0.9)',
                titleColor: '#fff',
                bodyColor: '#fff',
                borderColor: '#4CAF50',
                borderWidth: 2,
                displayColors: true,
                padding: 15,
                callbacks: {
                    title: function(context) {
                        return 'Mesiac: ' + context[0].label;
                    },
                    label: function(context) {
                        return 'Príjmy: €' + context.parsed.y.toLocaleString();
                    },
                    afterLabel: function(context) {
                        const total = context.dataset.data.reduce((a, b) => a + b, 0);
                        const percentage = ((context.parsed.y / total) * 100).toFixed(1);
                        return `(${percentage}% z celku)`;
                    }
                }
            }
        }
    }
});

Anotácie

Cieľové čiary, zvýraznené obdobia - to je to, čo odlišuje amatérsky graf od profesionálneho.

bash
# Inštalácia pluginu
npm install chartjs-plugin-annotation
javascript
import annotationPlugin from 'chartjs-plugin-annotation';
Chart.register(annotationPlugin);

new Chart(ctx, {
    type: 'line',
    data: { /* ... */ },
    options: {
        plugins: {
            annotation: {
                annotations: {
                    // Horizontálna čiara (cieľ)
                    targetLine: {
                        type: 'line',
                        yMin: 25000,
                        yMax: 25000,
                        borderColor: 'red',
                        borderWidth: 2,
                        borderDash: [10, 5],
                        label: {
                            content: 'Cieľ: €25K',
                            enabled: true,
                            position: 'end'
                        }
                    },
                    // Zvýraznenie obdobia
                    summerHighlight: {
                        type: 'box',
                        xMin: 'Jún',
                        xMax: 'Aug',
                        backgroundColor: 'rgba(255, 206, 86, 0.2)',
                        borderColor: 'rgba(255, 206, 86, 0.5)',
                        borderWidth: 1,
                        label: {
                            content: 'Letná špička',
                            enabled: true,
                            position: 'center'
                        }
                    }
                }
            }
        }
    }
});

Kapitola 7: Tipy pre výkon

Veľké datasety

Keď máte tisíce bodov, graf sa môže spomaliť. Tu je riešenie:

javascript
const largeDataChart = new Chart(ctx, {
    type: 'line',
    data: {
        labels: Array.from({ length: 1000 }, (_, i) => i),
        datasets: [{
            label: 'Veľký dataset',
            data: Array.from({ length: 1000 }, () => Math.random() * 100),
            borderWidth: 1,
            pointRadius: 0  // ✅ Nevykresľovať body (rýchlejšie!)
        }]
    },
    options: {
        animation: false,  // ✅ Vypnúť animácie (rýchlejšie!)
        parsing: false,    // ✅ Predpokladať že dáta sú už sparsované
        normalized: true,  // ✅ Dáta sú už normalizované
        responsive: true,
        scales: {
            x: {
                type: 'linear',
                ticks: {
                    maxTicksLimit: 20  // ✅ Limitovať počet tickov
                }
            }
        }
    }
});

Lazy loading

Načítať graf len keď je viditeľný - šetrí zdroje.

javascript
const observer = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
        if (entry.isIntersecting) {
            // Graf je viditeľný, vytvoríme ho
            createChart();
            observer.unobserve(entry.target);
        }
    });
});

observer.observe(document.getElementById('myChart'));

function createChart() {
    // Vytvorenie grafu tu
}

Kapitola 8: Bežné prípady použitia

KPI Dashboard so sparklines

Malé grafy, veľký dojem.

javascript
function createSparkline(canvasId, data, color) {
    new Chart(document.getElementById(canvasId), {
        type: 'line',
        data: {
            labels: Array.from({ length: data.length }, (_, i) => i),
            datasets: [{
                data: data,
                borderColor: color,
                borderWidth: 2,
                fill: false,
                pointRadius: 0
            }]
        },
        options: {
            responsive: true,
            maintainAspectRatio: false,
            plugins: {
                legend: { display: false },
                tooltip: { enabled: false }
            },
            scales: {
                x: { display: false },
                y: { display: false }
            }
        }
    });
}

// Použitie:
createSparkline('revenueSparkline', [12, 15, 13, 17, 20, 18, 22], '#4CAF50');
createSparkline('usersSparkline', [100, 120, 115, 130, 145, 140, 160], '#2196F3');

Porovnávací graf

javascript
new Chart(ctx, {
    type: 'bar',
    data: {
        labels: ['Q1', 'Q2', 'Q3', 'Q4'],
        datasets: [
            {
                label: '2023',
                data: [45, 52, 48, 67],
                backgroundColor: 'rgba(255, 99, 132, 0.6)'
            },
            {
                label: '2024',
                data: [55, 62, 58, 77],
                backgroundColor: 'rgba(54, 162, 235, 0.6)'
            }
        ]
    },
    options: {
        responsive: true,
        plugins: {
            title: {
                display: true,
                text: 'Medziročné porovnanie'
            }
        },
        scales: {
            y: { beginAtZero: true }
        }
    }
});

Skladaný graf

javascript
new Chart(ctx, {
    type: 'bar',
    data: {
        labels: ['Jan', 'Feb', 'Mar', 'Apr', 'Máj', 'Jún'],
        datasets: [
            {
                label: 'Online predaje',
                data: [30, 35, 32, 38, 40, 45],
                backgroundColor: 'rgba(54, 162, 235, 0.8)'
            },
            {
                label: 'Predaje v obchode',
                data: [20, 22, 18, 25, 28, 30],
                backgroundColor: 'rgba(255, 206, 86, 0.8)'
            },
            {
                label: 'Partnerské predaje',
                data: [10, 12, 15, 14, 18, 20],
                backgroundColor: 'rgba(75, 192, 192, 0.8)'
            }
        ]
    },
    options: {
        responsive: true,
        scales: {
            x: { stacked: true },
            y: { stacked: true, beginAtZero: true }
        },
        plugins: {
            title: {
                display: true,
                text: 'Rozdelenie predajných kanálov'
            }
        }
    }
});

Kapitola 9: Najlepšie praktiky

ROBTE ✅

javascript
// 1. Zničte grafy keď nie sú potrebné
const myChart = new Chart(ctx, {...});

// Keď komponent zanikne:
myChart.destroy();  // ✅ Uvoľníme pamäť

// 2. Používajte responsive možnosti
options: {
    responsive: true,
    maintainAspectRatio: false  // Umožní kontrolu výšky
}

// 3. Formátujte veľké čísla
ticks: {
    callback: function(value) {
        return '€' + (value / 1000) + 'K';  // 25000 → €25K
    }
}

// 4. Nastavte beginAtZero pre stĺpcové/čiarové grafy
scales: {
    y: {
        beginAtZero: true  // ✅ Začať od 0
    }
}

// 5. Používajte správne farby (prístupnosť)
// Dobrý kontrast, paleta vhodná pre ľudí s poruchou farbocitu

NEROBTE ❌

javascript
// 1. Nevytvárajte viac grafov na tom istom canvas
const chart1 = new Chart(ctx, {...});
const chart2 = new Chart(ctx, {...});  // ❌ Rozbije sa!

// 2. Nezabúdajte aktualizovať po zmene dát
myChart.data.datasets[0].data = [1, 2, 3];
// Chýba: myChart.update();  // ❌

// 3. Nepoužívajte príliš veľa bodov bez decimácie
data: Array.from({ length: 100000 }, () => ...)  // ❌ Pomalé!

// 4. Nepoužívajte animácie pre real-time dáta
animation: {
    duration: 1000  // ❌ Laguje pri live aktualizáciách
}

// Namiesto toho:
animation: false  // ✅

Záver: Kontrolný zoznam pre manažéra

javascript
poziadavky_managera = {
    "Prehľadné grafy": "✅ Chart.js",
    "Rýchle vytvorenie": "✅ 15 minút",
    "Interaktívne": "✅ Klik, hover, zoom",
    "Responzívne": "✅ Funguje na mobile",
    "Prispôsobiteľné": "✅ Farby, štýly, tooltipy",
    "Dáta v reálnom čase": "✅ Live aktualizácie",
    "Export": "✅ PNG, PDF (pluginy)"
};

verdikt = "Manager je šťastný! 🎉";

Kľúčové poznatky:

Typy grafov:
- Bar: Porovnania
- Line: Trendy
- Pie/Doughnut: Proporcie
- Mixed: Komplexné dáta

Integrácia:
✅ Vanilla JS
✅ Angular
✅ React
✅ Vue

Výkon:
✅ Vypnúť animácie pre veľké dáta
✅ Použiť decimáciu
✅ Lazy loading
✅ Zničiť keď nie sú potrebné

Customizácia:
✅ Gradienty
✅ Vlastné tooltipy
✅ Anotácie
✅ Pluginy

Zdroje:

Dokumentácia: https://www.chartjs.org/docs/
Ukážky: https://www.chartjs.org/samples/
Pluginy: https://github.com/chartjs
CDN: https://cdn.jsdelivr.net/npm/chart.js

Článok napísal developer, ktorý vie že manažéri milujú grafy. Chart.js je odpoveď. 15 minút → Šťastný manager. 📊

P.S.: Každý meeting začína s "Ukáž mi graf". Buďte pripravení! 😊

P.P.S.: Pie chart je manažérsky favorit. Vždy funguje! 🥧

P.P.P.S.: Line chart s cieľmi = okamžité schválenie. Verte mi. 📈

Všetky články