Introduzione
Le etichette nei grafici a barre spesso affrontano problemi di leggibilità quando il grafico viene ridimensionato, visualizzato su diverse risoluzioni dello schermo o ingrandito/ridotto utilizzando i controlli di zoom di amCharts. Per impostazione predefinita, le etichette in amCharts 4 hanno una larghezza fissa, il che può portare a sovrapposizioni, troncamenti o testo illeggibile su schermi piccoli.
Per rendere le etichette veramente reattive, dobbiamo:
- Calcolare dinamicamente la larghezza massima delle etichette in base alle dimensioni del grafico e alla larghezza delle colonne.
- Truncare le etichette lunghe se necessario per prevenire il traboccamento.
- Utilizzare i ganci di evento per garantire che le etichette si adattino correttamente quando:
- Il grafico viene ridimensionato.
- Si verifica uno zoom/panning.
- I dati vengono aggiornati dinamicamente.
In questo articolo, esploreremo come regolare dinamicamente la larghezza delle etichette e truncare le etichette quando necessario utilizzando gli eventi di amCharts 4.
Codice di implementazione con il problema:
am4core.ready(function () {
// Crea l'istanza del grafico
let chart = am4core.create("chartdiv", am4charts.XYChart);
chart.hiddenState.properties.opacity = 0; // Inizio fade-in
chart.logo.disabled = true;
chart.responsive.enabled = true; // Abilita comportamento reattivo
// Dati del grafico
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 }
];
// Crea l'asse delle categorie (asse 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); // Imposta tutti i lati a 0
// Crea l'asse dei valori (asse Y)
let valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
valueAxis.min = 0;
valueAxis.max = 24000;
valueAxis.strictMinMax = true;
valueAxis.renderer.minGridDistance = 30;
// Crea la serie di colonne
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;
// Applica colori diversi a ciascuna colonna
series.columns.template.adapter.add("fill", function (fill, target) {
return chart.colors.getIndex(target.dataItem.index);
});
// Aggiungi la barra di scorrimento
chart.scrollbarX = new am4core.Scrollbar();
chart.scrollbarX.marginTop = 30;
chart.scrollbarX.parent = chart.bottomAxesContainer;
// Aggiungi una rottura dell'asse per valori elevati
let axisBreak = valueAxis.axisBreaks.create();
axisBreak.startValue = 2100;
axisBreak.endValue = 22900;
// Regola la dimensione della rottura dell'asse
let d = (axisBreak.endValue - axisBreak.startValue) / (valueAxis.max - valueAxis.min);
axisBreak.breakSize = 0.05 * (1 - d) / d; // Dimensione della rottura aumentata per una migliore visibilità
// Regola l'effetto hover per una migliore interazione
let hoverState = axisBreak.states.create("hover");
hoverState.properties.breakSize = 1; // Rottura leggermente più grande quando si passa sopra
hoverState.properties.opacity = 0.1;
hoverState.transitionDuration = 1500;
axisBreak.defaultState.transitionDuration = 1000;
}); // fine am4core.ready()
Impostare una larghezza massima reattiva per le etichette
In amCharts 4, le etichette per l'xAxis in un grafico a colonne hanno una larghezza massima fissa. Tuttavia, poiché questa larghezza non si adatta dinamicamente, dobbiamo calcolarla in base alla larghezza della colonna e alle dimensioni del grafico.
Per ottenere questo, ci colleghiamo agli eventi rangechangeended e sizechanged , controlliamo la larghezza delle colonne e impostiamo la larghezza massima di conseguenza.
Implementazione
// Funzione per aggiornare la larghezza massima delle etichette in base alla colonna più larga
const updateLabelMaxWidth = () => {
let maxColumnWidth = 0;
// Cicla attraverso ogni colonna e trova la larghezza massima
series.columns.each(function (column) {
if (column && column.pixelWidth > maxColumnWidth) {
maxColumnWidth = column.pixelWidth;
}
});
// Applica la larghezza massima alle etichette
categoryAxis.renderer.labels.template.maxWidth = maxColumnWidth;
console.log("Larghezza massima delle etichette aggiornata: " + maxColumnWidth);
// Forza la rielaborazione delle etichette
categoryAxis.invalidateLabels();
}
// Attiva l'aggiornamento della larghezza delle etichette su zoom/pan
categoryAxis.events.on("rangechangeended", function () {
updateLabelMaxWidth();
});
// Attiva l'aggiornamento della larghezza delle etichette su ridimensionamento dello schermo
chart.events.on("sizechanged", function () {
updateLabelMaxWidth();
});
Spiegazione
La funzione updateLabelMaxWidth regola dinamicamente la larghezza delle etichette dell'asse x in base alla colonna più larga nel grafico. Cicla attraverso tutte le colonne, trova la larghezza massima e la applica alle etichette per prevenire sovrapposizioni.
Ganci di evento:
- rangechangeended → Aggiorna la larghezza delle etichette durante lo zoom/panning.
- sizechanged → Regola le etichette quando il grafico viene ridimensionato.
Questo garantisce che le etichette si ridimensionino dinamicamente in base allo spazio disponibile.
Truncare le etichette lunghe per una migliore leggibilità
Anche con una larghezza massima dinamica, alcune etichette possono ancora essere troppo lunghe e causare confusione. Per gestire questo, trunciamo le etichette quando superano una certa lunghezza.
Implementazione
categoryAxis.renderer.labels.template.adapter.add("textOutput", function(text, target) {
let maxLabelLength = 10; // Imposta il numero massimo di caratteri prima del troncamento
if (text.length > maxLabelLength) {
return text.substring(0, maxLabelLength) + "..."; // Trunca e aggiungi ellissi
}
return text; // Restituisci il testo originale se è entro il limite
});
Spiegazione
- Questa funzione controlla la lunghezza di ciascuna etichetta.
- Se l'etichetta è troppo lunga, tronca il testo alla prima parola e aggiunge ".." alla fine.
- Le etichette all'interno del limite massimo di caratteri rimangono inalterate.
Questo garantisce che le etichette lunghe non si sovrappongano pur fornendo informazioni sufficienti e rimanendo reattive quando vengono ridimensionate o ingrandite/ridotte.
Codice di implementazione completo dopo aver applicato la soluzione
am4core.ready(function () {
// Crea l'istanza del grafico
let chart = am4core.create("chartdiv", am4charts.XYChart);
chart.hiddenState.properties.opacity = 0; // Inizio fade-in
chart.logo.disabled = true;
chart.responsive.enabled = true; // Abilita comportamento reattivo
// Dati del grafico
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 }
];
// Crea l'asse delle categorie (asse 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); // Imposta tutti i lati a 0
// Crea l'asse dei valori (asse Y)
let valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
valueAxis.min = 0;
valueAxis.max = 24000;
valueAxis.strictMinMax = true;
valueAxis.renderer.minGridDistance = 30;
// Funzione per aggiornare la larghezza massima delle etichette in base alla colonna più larga
const updateLabelMaxWidth = () => {
let maxColumnWidth = 0;
// Cicla attraverso ogni colonna e trova la larghezza massima
series.columns.each(function (column) {
if (column && column.pixelWidth > maxColumnWidth) {
maxColumnWidth = column.pixelWidth;
}
});
// Applica la larghezza massima alle etichette
categoryAxis.renderer.labels.template.maxWidth = maxColumnWidth;
console.log("Larghezza massima delle etichette aggiornata: " + maxColumnWidth);
// Forza la rielaborazione delle etichette
categoryAxis.invalidateLabels();
}
// Attiva l'aggiornamento della larghezza delle etichette su zoom/pan
categoryAxis.events.on("rangechangeended", function () {
updateLabelMaxWidth();
});
// Attiva l'aggiornamento della larghezza delle etichette su ridimensionamento dello schermo
chart.events.on("sizechanged", function () {
updateLabelMaxWidth();
});
// Trunca le etichette alla fine della prima parola quando necessario
categoryAxis.renderer.labels.template.adapter.add("textOutput", function (text, target) {
let labelMaxWidth = target.maxWidth;
if (labelMaxWidth < 60 && text) { // Controlla se la larghezza dell'etichetta è inferiore a 60 pixel
let words = text.split(" "); // Dividi il testo in parole
return words.length > 1 ? words[0] + ".." : text; // Mantieni solo la prima parola con ".."
}
return text;
});
// Crea la serie di colonne
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;
// Applica colori diversi a ciascuna colonna
series.columns.template.adapter.add("fill", function (fill, target) {
return chart.colors.getIndex(target.dataItem.index);
});
// Aggiungi la barra di scorrimento
chart.scrollbarX = new am4core.Scrollbar();
chart.scrollbarX.marginTop = 30;
chart.scrollbarX.parent = chart.bottomAxesContainer;
// Aggiungi una rottura dell'asse per valori elevati
let axisBreak = valueAxis.axisBreaks.create();
axisBreak.startValue = 2100;
axisBreak.endValue = 22900;
// Regola la dimensione della rottura dell'asse
let d = (axisBreak.endValue - axisBreak.startValue) / (valueAxis.max - valueAxis.min);
axisBreak.breakSize = 0.05 * (1 - d) / d; // Dimensione della rottura aumentata per una migliore visibilità
// Regola l'effetto hover per una migliore interazione
let hoverState = axisBreak.states.create("hover");
hoverState.properties.breakSize = 1; // Rottura leggermente più grande quando si passa sopra
hoverState.properties.opacity = 0.1;
hoverState.transitionDuration = 1500;
axisBreak.defaultState.transitionDuration = 1000;
}); // fine am4core.ready()
Con queste modifiche, il nostro grafico ora si adatta perfettamente—le etichette rimangono leggibili, niente più brutte sovrapposizioni, e tutto si ridimensiona senza problemi. Regolando dinamicamente le larghezze, troncando i nomi lunghi e collegandoci agli eventi, ci siamo assicurati che il grafico abbia un aspetto fantastico su qualsiasi schermo. Ora, prova a farlo tu stesso!