Introduction
Les étiquettes dans les graphiques à barres rencontrent souvent des problèmes de lisibilité lorsque le graphique est redimensionné, affiché sur différentes résolutions d'écran ou zoomé à l'aide des contrôles de zoom d'amCharts. Par défaut, les étiquettes dans amCharts 4 ont une largeur fixe, ce qui peut entraîner des chevauchements, des coupures ou un texte illisible sur les petits écrans.
Pour rendre les étiquettes véritablement réactives, nous devons :
- Calculer dynamiquement la largeur maximale des étiquettes en fonction de la taille du graphique et de la largeur des colonnes.
- Couper les longues étiquettes si nécessaire pour éviter le débordement.
- Utiliser des hooks d'événements pour s'assurer que les étiquettes s'ajustent correctement lorsque :
- Le graphique est redimensionné.
- Un zoom/défilement se produit.
- Les données se mettent à jour dynamiquement.
Dans cet article, nous allons explorer comment ajuster dynamiquement la largeur des étiquettes et couper les étiquettes si nécessaire en utilisant les événements d'amCharts 4.
Code d'implémentation avec le problème :
am4core.ready(function () {
// Créer l'instance du graphique
let chart = am4core.create("chartdiv", am4charts.XYChart);
chart.hiddenState.properties.opacity = 0; // Effet d'apparition initial
chart.logo.disabled = true;
chart.responsive.enabled = true; // Activer le comportement réactif
// Données du graphique
chart.data = [
{ company: "Apple Inc.", visits: 23725 },
{ company: "Microsoft Corporation", visits: 1882 },
{ company: "Alphabet Inc. (Google)", visits: 1809 },
{ company: "Amazon.com, Inc.", visits: 1322 },
{ company: "Tesla, Inc.", visits: 1122 },
{ company: "Meta Platforms, Inc. (Facebook)", visits: 1114 },
{ company: "Berkshire Hathaway Inc.", visits: 711 },
{ company: "PepsiCo, Inc.", visits: 443 },
{ company: "Johnson & Johnson Services, Inc.", visits: 350 },
{ company: "McDonald's Corporation", visits: 298 },
{ company: "NVIDIA Corporation", visits: 150 },
{ company: "Netflix, Inc.", visits: 100 }
];
// Créer l'Axe Catégorie (Axe X)
let categoryAxis = chart.xAxes.push(new am4charts.CategoryAxis());
categoryAxis.dataFields.category = "company";
categoryAxis.renderer.grid.template.location = 0;
categoryAxis.renderer.minGridDistance = 40;
categoryAxis.fontSize = 11;
categoryAxis.renderer.labels.template.wrap = true;
categoryAxis.renderer.labels.template.maxWidth = 80;
categoryAxis.renderer.labels.template.padding(10, 0, 0, 0); // Définir tous les côtés à 0
// Créer l'Axe Valeur (Axe Y)
let valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
valueAxis.min = 0;
valueAxis.max = 24000;
valueAxis.strictMinMax = true;
valueAxis.renderer.minGridDistance = 30;
// Créer la Série de Colonnes
let series = chart.series.push(new am4charts.ColumnSeries());
series.dataFields.categoryX = "company";
series.dataFields.valueY = "visits";
series.columns.template.tooltipText = "{valueY.value}";
series.columns.template.tooltipY = 0;
series.columns.template.strokeOpacity = 0;
// Appliquer des couleurs différentes à chaque colonne
series.columns.template.adapter.add("fill", function (fill, target) {
return chart.colors.getIndex(target.dataItem.index);
});
// Ajouter une barre de défilement
chart.scrollbarX = new am4core.Scrollbar();
chart.scrollbarX.marginTop = 30;
chart.scrollbarX.parent = chart.bottomAxesContainer;
// Ajouter une coupure d'axe pour les grandes valeurs
let axisBreak = valueAxis.axisBreaks.create();
axisBreak.startValue = 2100;
axisBreak.endValue = 22900;
// Ajuster la taille de la coupure d'axe
let d = (axisBreak.endValue - axisBreak.startValue) / (valueAxis.max - valueAxis.min);
axisBreak.breakSize = 0.05 * (1 - d) / d; // Augmenter la taille de la coupure pour une meilleure visibilité
// Ajuster l'effet de survol pour une meilleure interaction
let hoverState = axisBreak.states.create("hover");
hoverState.properties.breakSize = 1; // Coupure légèrement plus grande lorsqu'elle est survolée
hoverState.properties.opacity = 0.1;
hoverState.transitionDuration = 1500;
axisBreak.defaultState.transitionDuration = 1000;
}); // fin am4core.ready()
Définir une largeur maximale réactive pour les étiquettes
Dans amCharts 4, les étiquettes pour l'xAxis dans un graphique en colonnes ont une largeur maximale fixe. Cependant, comme cette largeur ne s'ajuste pas dynamiquement, nous devons la calculer en fonction de la largeur des colonnes et de la taille du graphique.
Pour y parvenir, nous nous accrochons aux événements rangechangeended et sizechanged, vérifions la largeur des colonnes et définissons la largeur maximale en conséquence.
Implémentation
// Fonction pour mettre à jour la largeur maximale des étiquettes en fonction de la colonne la plus large
const updateLabelMaxWidth = () => {
let maxColumnWidth = 0;
// Boucle à travers chaque colonne et trouve la largeur maximale
series.columns.each(function (column) {
if (column && column.pixelWidth > maxColumnWidth) {
maxColumnWidth = column.pixelWidth;
}
});
// Appliquer la largeur maximale aux étiquettes
categoryAxis.renderer.labels.template.maxWidth = maxColumnWidth;
console.log("Largeur maximale des étiquettes mise à jour : " + maxColumnWidth);
// Forcer le traitement des étiquettes
categoryAxis.invalidateLabels();
}
// Déclencher la mise à jour de la largeur des étiquettes lors du zoom/défilement
categoryAxis.events.on("rangechangeended", function () {
updateLabelMaxWidth();
});
// Déclencher la mise à jour de la largeur des étiquettes lors du redimensionnement de l'écran
chart.events.on("sizechanged", function () {
updateLabelMaxWidth();
});
Explication
La fonction updateLabelMaxWidth ajuste dynamiquement la largeur des étiquettes de l'axe x en fonction de la colonne la plus large dans le graphique. Elle parcourt toutes les colonnes, trouve la largeur maximale et l'applique aux étiquettes pour éviter les chevauchements.
Hooks d'événements :
- rangechangeended → Met à jour la largeur des étiquettes lors du zoom/défilement.
- sizechanged → Ajuste les étiquettes lorsque le graphique est redimensionné.
Cela garantit que les étiquettes se redimensionnent dynamiquement en fonction de l'espace disponible.
Couper les longues étiquettes pour une meilleure lisibilité
Même avec une largeur maximale dynamique, certaines étiquettes peuvent encore être trop longues et causer un encombrement. Pour y remédier, nous coupons les étiquettes lorsqu'elles dépassent une certaine longueur.
Implémentation
categoryAxis.renderer.labels.template.adapter.add("textOutput", function(text, target) {
let maxLabelLength = 10; // Définir le nombre maximum de caractères avant la coupure
if (text.length > maxLabelLength) {
return text.substring(0, maxLabelLength) + "..."; // Couper et ajouter des points de suspension
}
return text; // Retourner le texte original s'il est dans la limite
});
Explication
- Cette fonction vérifie la longueur de chaque étiquette.
- Si l'étiquette est trop longue, elle coupe le texte au premier mot et ajoute ".." à la fin.
- Les étiquettes dans la limite de caractères maximale restent inchangées.
Cela garantit que les longues étiquettes ne se chevauchent pas tout en fournissant suffisamment d'informations et en restant réactives lorsqu'elles sont redimensionnées ou zoomées.
Code d'implémentation complet après application de la solution
am4core.ready(function () {
// Créer l'instance du graphique
let chart = am4core.create("chartdiv", am4charts.XYChart);
chart.hiddenState.properties.opacity = 0; // Effet d'apparition initial
chart.logo.disabled = true;
chart.responsive.enabled = true; // Activer le comportement réactif
// Données du graphique
chart.data = [
{ company: "Apple Inc.", visits: 23725 },
{ company: "Microsoft Corporation", visits: 1882 },
{ company: "Alphabet Inc. (Google)", visits: 1809 },
{ company: "Amazon.com, Inc.", visits: 1322 },
{ company: "Tesla, Inc.", visits: 1122 },
{ company: "Meta Platforms, Inc. (Facebook)", visits: 1114 },
{ company: "Berkshire Hathaway Inc.", visits: 711 },
{ company: "PepsiCo, Inc.", visits: 443 },
{ company: "Johnson & Johnson Services, Inc.", visits: 350 },
{ company: "McDonald's Corporation", visits: 298 },
{ company: "NVIDIA Corporation", visits: 150 },
{ company: "Netflix, Inc.", visits: 100 }
];
// Créer l'Axe Catégorie (Axe X)
let categoryAxis = chart.xAxes.push(new am4charts.CategoryAxis());
categoryAxis.dataFields.category = "company";
categoryAxis.renderer.grid.template.location = 0;
categoryAxis.renderer.minGridDistance = 40;
categoryAxis.fontSize = 11;
categoryAxis.renderer.labels.template.wrap = true;
categoryAxis.renderer.labels.template.maxWidth = 80;
categoryAxis.renderer.labels.template.padding(10, 0, 0, 0); // Définir tous les côtés à 0
// Créer l'Axe Valeur (Axe Y)
let valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
valueAxis.min = 0;
valueAxis.max = 24000;
valueAxis.strictMinMax = true;
valueAxis.renderer.minGridDistance = 30;
// Fonction pour mettre à jour la largeur maximale des étiquettes en fonction de la colonne la plus large
const updateLabelMaxWidth = () => {
let maxColumnWidth = 0;
// Boucle à travers chaque colonne et trouve la largeur maximale
series.columns.each(function (column) {
if (column && column.pixelWidth > maxColumnWidth) {
maxColumnWidth = column.pixelWidth;
}
});
// Appliquer la largeur maximale aux étiquettes
categoryAxis.renderer.labels.template.maxWidth = maxColumnWidth;
console.log("Largeur maximale des étiquettes mise à jour : " + maxColumnWidth);
// Forcer le traitement des étiquettes
categoryAxis.invalidateLabels();
}
// Déclencher la mise à jour de la largeur des étiquettes lors du zoom/défilement
categoryAxis.events.on("rangechangeended", function () {
updateLabelMaxWidth();
});
// Déclencher la mise à jour de la largeur des étiquettes lors du redimensionnement de l'écran
chart.events.on("sizechanged", function () {
updateLabelMaxWidth();
});
// Couper les étiquettes à la fin du premier mot si nécessaire
categoryAxis.renderer.labels.template.adapter.add("textOutput", function (text, target) {
let labelMaxWidth = target.maxWidth;
if (labelMaxWidth < 60 && text) { // Vérifier si la largeur de l'étiquette est inférieure à 60 pixels
let words = text.split(" "); // Diviser le texte en mots
return words.length > 1 ? words[0] + ".." : text; // Garder seulement le premier mot avec ".."
}
return text;
});
// Créer la Série de Colonnes
let series = chart.series.push(new am4charts.ColumnSeries());
series.dataFields.categoryX = "company";
series.dataFields.valueY = "visits";
series.columns.template.tooltipText = "{valueY.value}";
series.columns.template.tooltipY = 0;
series.columns.template.strokeOpacity = 0;
// Appliquer des couleurs différentes à chaque colonne
series.columns.template.adapter.add("fill", function (fill, target) {
return chart.colors.getIndex(target.dataItem.index);
});
// Ajouter une barre de défilement
chart.scrollbarX = new am4core.Scrollbar();
chart.scrollbarX.marginTop = 30;
chart.scrollbarX.parent = chart.bottomAxesContainer;
// Ajouter une coupure d'axe pour les grandes valeurs
let axisBreak = valueAxis.axisBreaks.create();
axisBreak.startValue = 2100;
axisBreak.endValue = 22900;
// Ajuster la taille de la coupure d'axe
let d = (axisBreak.endValue - axisBreak.startValue) / (valueAxis.max - valueAxis.min);
axisBreak.breakSize = 0.05 * (1 - d) / d; // Augmenter la taille de la coupure pour une meilleure visibilité
// Ajuster l'effet de survol pour une meilleure interaction
let hoverState = axisBreak.states.create("hover");
hoverState.properties.breakSize = 1; // Coupure légèrement plus grande lorsqu'elle est survolée
hoverState.properties.opacity = 0.1;
hoverState.transitionDuration = 1500;
axisBreak.defaultState.transitionDuration = 1000;
}); // fin am4core.ready()
Avec ces ajustements, notre graphique s'adapte parfaitement—les étiquettes restent lisibles, plus de chevauchements inesthétiques, et tout se redimensionne en douceur. En ajustant dynamiquement les largeurs, en coupant les longs noms et en utilisant des événements, nous avons veillé à ce que le graphique soit superbe sur n'importe quel écran. Maintenant, allez-y et essayez-le !