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
// 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?
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
# NPM
npm install chart.js
# CDN (pre rýchle testovanie)
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>Krok 2: Prvý graf
<!-- 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.
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.
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.
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ú.
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
<!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>// 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
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.
<!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
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
// 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
// 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
<!-- 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ý.
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
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.
# Inštalácia pluginu
npm install chartjs-plugin-annotationimport 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:
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.
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.
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
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
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 ✅
// 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 farbocituNEROBTE ❌
// 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
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
✅ PluginyZdroje:
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. 📈