Mémo Chart.js
Michel Llibre, mai 2025.
Pour pouvoir utiliser la librairie graphique Chart.js une méthode simple consiste à inclure la ligne suivante dans le head de la page html :
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
Les graphiques chart.js sont crées dans un élément Canvas du DOM (Document object Model).
Le constructeur Chart du graphique est appélé comme suit :
const chart = new Chart(canvas, config);
Il a pour premier argument un élément Canvas du DOM et pour deuxième argument l'objet JSON de configuration du graphique à tracer. Ici config
, chart
et canvas
sont des noms d'instance arbitraires. L'instance canvas
a, par exemple, été créé au préalable par l'instruction :
const canvas = document.getElementById('myCanvas');
dans le cas où l'élément Canvas aurait été inclus dans la partie HTML du body par l'instruction :
<canvas id="myCanvas" class ="chart-container"></canvas>
Le deuxième argument du constructeur Chart, config
, est un objet JSON préalablement créé qui a deux attributs obligatoires : type et data, et un troisième attribut optionnel options :
const config = {
type: 'line',
data: MesData,
options : {} // non requis
};
C'est par le biais de ces 3 attributs que le graphique est spécifié.
Avant d'entrer dans le détail de la définition d'un graphique, notons qu'un graphique étant spécifié et tracé, on peut modifier un quelconque de ses éléments et mettre à jour le tracé à l'aide de la méthode Chart.update().
En suivant la tendance générale, nous noterons Chart l'élément racine de l'objet qui décrit la configuration. Il aurait peut-être été plus judicieux de le noter Config. Avec cette notation universelle, le type de graphique est spécifié par un string (line
, bar
...) affecté à l'attribut Chart.type. Voici la liste des principaux strings définissant un type de graphique :
Les données numériques du tracé sont incluses dans un objet JSON affecté à l'attribut Chart.data. Les deux principaux attributs de cet objet sont labels généralement utilisé pour les données en abscisse et datasets généralement utilisé pour les données des différents graphes en ordonnées :
const MesData = {
labels : tX,
datasets: myDatasets
}
Généralement les abscisses sont un simple tableau de nombres ou de strings affecté à l'attribut Chart.data.labels. Ci dessus, il est noté tX
.
Comme plusieurs graphes peuvent être affichés simultanément, les ordonnées sont toujours associées à un attribut chart.data.datasets qui est un tableau, même s’il ne contient qu’un seul jeu de données. Dans ce dernier cas le tableau est de dimension 1.
Exemple : Voici en préalable la génération d'un tableau d'abscisses tX
et de deux tableaux d'ordonnées tY[0]
et tY[1]
qui seront utilisés ensuite dans la définition des attributs labels et datasets de l'objet Chart.data :
const tX = new Array(), tY = new Array();
tY[0] = new Array(), tY[1] = new Array();
for (let i = 0; i <= 40; i++) {
x = i - 20; tX[i] = x;
tY[0][i] = x * x;
tY[1][i] = 16 * (x + 20);
}
const myDatasets = tY.map(vals => ({ data:vals }));
L'objet datasets
a de nombreux attributs. Ci-dessus nous en construisons une instance myDatasets
qui est un tableau de 2 d'objets qui n'ont qu'un seul attribut data
auquel est affecté le tableau des ordonnées correspondantes. Cette syntaxe très concise est assez obscure. Une syntaxe plus explicite aurait consisté à écrire :
const myDatasets = new Array();
myDatasets[0] = {data: tY[0]}
myDatasets[1] = {data: tY[1]}
et ci-dessous une syntaxe encore plus concise et obscure :
const myDatasets = tY.map(data => ({data}));
Voici une vision plus globale de l'objet configuration :
const config = {
type: 'line',
data: {// Objet JSON décrivant les données
labels : tX, // Les abscisses
datasets : [// tableau configuration des ordonnées
{ // [0]
data: tY[0]
},
// [1]
{
data: tY[1]
}
],
}
};
On peut définir des courbes dont les ordonnées ne correspondents pas aux mêmes abscisses, comme ceci :
data: {
datasets: [
{
label: "Azimut",
data: [
{ x: 1.0, y: 10 },
{ x: 1.5, y: 20 },
{ x: 2.0, y: 30 }
]
},
{
label: "Hauteur",
data: [
{ x: 1.2, y: 5 },
{ x: 1.5, y: 10 },
{ x: 1.8, y: 15 }
]
}
]
}
Au lieu de fournir pour chaque chart.data.datasets.data un tableau tY[]
d'ordonnées simples, on fournit un tableau d'objets points {x:valX, y:valY}.
Chaque élément d'un datasets
est un objet JSON ayant de nombreuses attributs en plus de l'attribut' data
déjà vu. Voici les plus utiles, avec la signification de leur valeur.
line
la tension (0 à 1) permet de spécifier le lissage de l'interpolation entre les points. Pour 0 les points sont anguleux reliés en ligne droite, puis en augmentant la tension la courbe est de plus en plus lissée (type spline ou courbe de Bézier).Voici les valeurs utilisables pour pointStyle :
On peut utiliser une image personnalisée en fournissant un objet Image ou un chemin vers une image.
Exemple de configuration pour un graphique en lignes :
// Configuration du graphique
const config = {
type: 'line',
data: {
labels: tX,
datasets: [{
label: "Dataset 1",
data: tY[0],
borderColor: "yellow",
borderWidth: 2,
pointStyle : "rect",
pointBorderColor: "red",
pointBackgroundColor: "green",
pointRadius : 10
}, {
label: "Dataset 2",
data: tY[1],
backgroundColor: "yellow",
borderColor: "blue",
borderWidth: 2
}]
}
};
Le troisième attribut options de l'argument config
du constructeur est, comme son nom l'indique, optionnel. Il permet de configurer divers aspects du graphique, tels que les échelles, les légendes, les titres, et bien plus encore.
Voici quelques-uns des principaux attributs que l'on peut utiliser dans cet objet :
datasets.data
en horizontal.layout: {
padding: {left: 10, right: 10, top: 10, bottom: 10}
}
elements: {
line: {tension: 0.4, borderWidth: 2},
point: {radius: 5, backgroundColor: 'rgba(0, 0, 0, 1)'
}
}
Les graduations des échelles sont configurées au moyen de l'objet attribué à la propriété Chart.options.scales. cet objet possède les attributs x pour l'échelle des abscisses, y pour l'échelle des ordonnées et r dans le cas d'un graphique de type radial
.
Les principaux attributs que l'on utilise pour x, y et r sont :
linear
linéaire par défaut, logarithmic
, (autres ?)true
par défaut, false
pour cacher l'échellebottom
par défaut pour x et left
par défaut pour y.false
par défaut, true
si on veut imposer que la graduation commence à 0.Exemple :
scales: {
x: {beginAtZero: true, type: 'linear', position: 'bottom'},
y: {min: -10, max: 40, position: 'right'}
}
Pour la légende de l'axe (title) on utilise les attributs classique d'une légenge. Exemple :
x: {
title: {
display: true, // ← rend le titre visible, invisible par défaut
text: 'Temps (s)', // ← le texte du titre
color: 'black',
font: {size: 14, weight: 'bold'}
}
},
y: {
title: {
display: true,
text: 'Vitesse (m/s)'
}
}
Les attributs x
et y
sont des attributs par défaut offerts pour les labels et l'ensemble des datasets, mais on peut définir un échelle individualisée pour un dataset en fournissant un nom d'attribut d'échelle spécifique pour ce dataset, à l'aide de l'attribut Chart.data.datasets[i].yAxisID. Par défaut on a yAxisID:'y'
quand rien n'est spécifié, mais on peut mettre yAxisID:'y2'
ce qui permet ensuite d'utiliser y2
comme attribut pour définir les échelles de ce dataset :
options: {
scales: {
y: {type: 'linear', display: true, position: 'left',
},
y2: {type: 'linear', display: true, position: 'right',
grid: {drawOnChartArea: false,}, // Désactive le quadrillage pour cet axe
},
x: {type: 'category',display: true,}
}
L'attribut Chart.options.plugins permet de préciser de nombreux éléments du graphique, comme les légendes des différentes courbes, le titre général, les tooltips....
Cette rubrique fixe les propriétés des légendes également appelés labels qui sont les noms associés à chaque graphe ou courbe, ainsi que le titre général. Les légendes sont configurées par Chart.defaults.plugins.legend (on n'intervient généralement pas à ce niveau) et par Chart.options.plugins.legend, à l'aide des attributs suivants :
true
par défaut, les labels sont affichés, sinon invisible.true
la boîte prendra toute la largeur/hauteur du canvas (à confirmer).false
par défaut, si true affiche la légende en ordre inverse.false
par défaut, si vrai, l'ordre des légendes sera inversé.Les propriétés du titre sont définies dans Chart.options.plugins.legend.title. Ses principaux attributs sont :
center
par défaut permet (?) de définir l'alignement du titre.true
par défaut, le titre est affichée, sinon NON.true
la boîte prendra toute la largeur/hauteur du canvas (?).Chart.defaults.font
.Ce sont les étiquettes affichant les noms de chacune des courbes. Leurs propriétés globales sont fixées par les attributs de Chart.options.plugins.legend. L'attribut spécifique Chart.options.plugins.legend.labels permet d'agir individuellement sur chacun d'eux par le biais da la fonction Filter décrite ci'après.
La fonction filter permet de masquer sélectivement certains éléments, comme des légendes ou des graduations. Pour cela, dans le champ options.plugins.legend.labels, on utilise l'attribut filter :
avec pour valeur une callback function(item, chart) où l'argument item est le label testé (le deuxième argument chart qui est l'objet Chart est facultatif). Cette callback renvoie true si le label doit être pris en compte et false s'il doit être ignoré. Ainsi, pour ne pas écrire la légende du label intitulé "Graphique 2", on ajoutera le couple :
filter: item => item.text !== 'Graphique 2'
qui est un raccouci pour :
filter: function(item) {return item.text !== 'Graphique 2';}
En plus de
'options.plugins.legend.labels.filter
,
la fonction filter peut être utilisée pour valider/invalider des ticks en x ou en y, avec :
options.scales.x.ticks.filter
et
options.scales.y.ticks.filter
.
Dans la rubrique de l'attribut tooltip
on peut au moyen de l'attibut callbacks faire de nombreuses modifications. Voici par exemple comment modifier le texte des popups qui affichent les coordonnées des points sélectionnés qui en standard sont limités à :
x: <valeur>
<label du dataset>: <valeur y>
Pour ajouter un texte devant la valeur des abscisses on fera :
options: {
plugins: {
tooltip: {
callbacks: {
title: function(tooltipItems) {
// tooltipItems est un tableau, on prend le premier (il y en a un par point survolé)
const xValue = tooltipItems[0].parsed.x;
return 'Temps : ' + xValue.toFixed(1) + ' s';
}
}
}
}
}
Pour modifier le label qui apparait devant la valeur des ordonnées c'est un peu plus complexe lorsqu'il y a plusieurs courbes. Voici un exemple qui correspond au fait qu'o a deux courbes dans la rubrique datasets avec pour labels 'Azimut' et 'Hauteur', comme ceci :
datasets: [
{
label: 'Azimut',
.............
},
{
label: 'Hauteur',
......
}
La modification des labels des tooltips se fera par exemple comme ceci :
tooltip: {
callbacks: {
title: function(tooltipItems) { // Modif label des x
const xValue = tooltipItems[0].parsed.x;
return 'Angle hor. : ' + xValue.toFixed(3) + ' h';
},
label: function(tooltipItem) { // Modif label des y
const y = tooltipItem.parsed.y;
const datasetLabel = tooltipItem.dataset.label;
if (datasetLabel === 'Azimut') {
return 'Azimut : ' + y.toFixed(2) + '°';
} else if (datasetLabel === 'Hauteur') {
return 'Hauteur : ' + y.toFixed(2) + '°';
} else {
return datasetLabel + ' : ' + y.toFixed(2);
}
}
}
}
modification qui nécessite de tester le tooltipItem.dataset.label
pour savoir pour quelle des 2 courbes la callback est appelée.
l’attribut Chart.options.animations permet d’animer toutes les propriétés numériques, toutes les couleurs, toutes les propriétés définies dans les datasets ou dans les éléments de type (comme elements.line
, elements.point
...).
Attention : Même non renseignée, une animation par défaut est appliquée à chaque update du graphique pour le rendre plus fluide, ce qui ralentit considérablement cet update. Il faut donc donner la valeur false à animation pour interdire des interpolations entre l'ancien graphique et le nouveau lorsqu'on désire des updates instantanés.
Voici une liste des attributs couramment utilisés pour des animations :
La valeur modifiée l'est par le biais d'un objet animation ayant les attributs suivants :
true
l'animation moucle indéfiniment.Pour aller, sur la durée duration, de la valeur initiale à la valeur finale, on utilise une des fonctions d'avance temporelle suivantes :
Annotations est un plugin additionnel qui permet d'ajouter des lignes, des marques, du texte... que l'on peut utiliser en incluant le script :
<script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-annotation/1.4.0/chartjs-plugin-annotation.js"></script>
ou bien :
src="https://cdn.jsdelivr.net/npm/chartjs-plugin-annotation@1.4.0/dist/chartjs-plugin-annotation.min.js"></script>
Les éléments additionnels sont définis dans Chart.options.plugins.annotation.annotations sous un nom d’attribut arbitraire. Ce nom est libre (ex. maLigne) et c’est le contenu de l’objet qui en détermine la nature.. Exemple pour ajouter une ligne horizontale d'ordonnée y = 20 :
options: { plugins: { annotation: {annotations: {
maLigne: {type: 'line', yMin: 20, yMax: 20}}}}}
Les attributs les plus fréquemment utilisés pour spécifier les éléments additionnels sont :
start
pour xValue-yValue en top-left, end
pour xValue-yValue en bottom-right et center
pour xValue-yValue en center.line
. On le définit comme un objet avec les attributs content
, position
et enabled
.Dans le cas d'une ligne horizontale, on n'utilisera que yMin et yMax avec la même valeur. Dans le cas d'une ligne verticale, on n'utilisera que xMin et xMax avec la même valeur.
Des problèmes de positionnement (offsets) peuvent survenir si les axes (scales) ne sont pas explicitement définis.
Pour l'interaction avec la souris, lors d'un événement mousedown, pour savoir où il s'est produit on utilise la méthode getElementsAtEvent:
const tabElem = chart.getElementsAtEventForMode(event, mode, options, useFinalPosition)
où :
event
: est l'événement de souris ou tactile, ex. depuis mousedown, mousemove, etc.
mode
: est un string spécifiant le mode de sélection (voir ci-dessous).
options
: est un objet précisant des options complémentaires pour la détection, généralement {intersect: true}
.
useFinalPosition
: est un booléen, si true, utilise la position finale du point, sinon ne tient pas compte de la position interpolée en cours d'animation. true est utilisé pour les graphiques animés.
Les mode les plus utiles sont les suivants :
nearest
: Trouve l'élément le plus proche du curseur, si intersect: true, uniquement si le curseur est dessus.
index
: Retourne tous les éléments à une abscisse donnée (utile pour lignes multiples).
dataset
: Retourne tous les éléments de la série (dataset) sous la souris.
point
: Retourne tous les éléments exactement sous la souris (peu courant).
x
: Retourne tous les points alignés verticalement à la souris.
y
: Idem mais horizontalement.
La méthode renvoie un tableau, disons tabElem
dont chaque élément est un objet de la forme :
{
datasetIndex: 0, // Index de la courbe (du dataset)
index: 3, // index de l'abscisse de l'élément
element: {...} // objet graphique (point, barre…)
}
Généralement on cherche à obtenir les coordonnées d'un point du graphique. Elles sont obtenues par :
let di = tabElem.datasetIndex; // série concernée
let pi = tabElem.index; // position dans cette série
let x = chart.data.labels[pi];
let valeur = chart.data.datasets[di].data[pi];
Pour placer un point au niveau de la souris, il faut convertir les coordonnées souris en coordonnées graphique. Les coordonnées de la souris sont données par :
mouseX = evt.offsetX;
mouseY = evt.offsetY;
Il faut vérifier que ces coordonnées sont à l'intérieur du domaine graphique :
(mouseX >= chart.chartArea.left && mouseX <= chart.chartArea.right)
(mouseY >= chart.chartArea.top && mouseY <= chart.chartArea.bottom)
Elles sont converties en coordonnées trajectoire par :
const xValue = (chart.scales.x).getValueForPixel(mouseX);
const yValue = (chart.scales.y).getValueForPixel(mouseY);