Introdução
Os rótulos em gráficos de barras frequentemente enfrentam problemas de legibilidade quando o gráfico é redimensionado, exibido em diferentes resoluções de tela ou ampliado/reduzido usando os controles de zoom do amCharts. Por padrão, os rótulos em amCharts 4 têm uma largura fixa, o que pode levar a sobreposição, truncamento ou texto ilegível em telas pequenas.
Para tornar os rótulos realmente responsivos, precisamos:
- Calcular dinamicamente a largura máxima dos rótulos com base no tamanho do gráfico e na largura da coluna.
- Truncar rótulos longos se necessário para evitar transbordamento.
- Usar ganchos de evento para garantir que os rótulos se ajustem corretamente quando:
- O gráfico é redimensionado.
- O zoom/pan ocorre.
- Os dados são atualizados dinamicamente.
Neste artigo, vamos explorar como ajustar a largura dos rótulos dinamicamente e truncar rótulos quando necessário usando eventos do amCharts 4.
Código de implementação com o problema:
am4core.ready(function () {
// Criar a instância do gráfico
let chart = am4core.create("chartdiv", am4charts.XYChart);
chart.hiddenState.properties.opacity = 0; // Fade-in inicial
chart.logo.disabled = true;
chart.responsive.enabled = true; // Habilitar comportamento responsivo
// Dados do gráfico
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 }
];
// Criar Eixo de Categoria (Eixo 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); // Definir todos os lados como 0
// Criar Eixo de Valor (Eixo Y)
let valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
valueAxis.min = 0;
valueAxis.max = 24000;
valueAxis.strictMinMax = true;
valueAxis.renderer.minGridDistance = 30;
// Criar Série de Colunas
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;
// Aplicar cores diferentes a cada coluna
series.columns.template.adapter.add("fill", function (fill, target) {
return chart.colors.getIndex(target.dataItem.index);
});
// Adicionar Barra de Rolagem
chart.scrollbarX = new am4core.Scrollbar();
chart.scrollbarX.marginTop = 30;
chart.scrollbarX.parent = chart.bottomAxesContainer;
// Adicionar Quebra de Eixo para valores grandes
let axisBreak = valueAxis.axisBreaks.create();
axisBreak.startValue = 2100;
axisBreak.endValue = 22900;
// Ajustar Tamanho da Quebra de Eixo
let d = (axisBreak.endValue - axisBreak.startValue) / (valueAxis.max - valueAxis.min);
axisBreak.breakSize = 0.05 * (1 - d) / d; // Aumentar tamanho da quebra para melhor visibilidade
// Ajustar efeito de hover para melhor interação
let hoverState = axisBreak.states.create("hover");
hoverState.properties.breakSize = 1; // Quebra ligeiramente maior quando sobreposta
hoverState.properties.opacity = 0.1;
hoverState.transitionDuration = 1500;
axisBreak.defaultState.transitionDuration = 1000;
}); // fim am4core.ready()
Definindo uma Largura Máxima Responsiva para Rótulos
Em amCharts 4, os rótulos para o xAxis em um gráfico de colunas têm uma largura máxima fixa. No entanto, como essa largura não se ajusta dinamicamente, precisamos calculá-la com base na largura da coluna e no tamanho do gráfico.
Para conseguir isso, conectamos aos eventos rangechangeended e sizechanged , verificamos a largura das colunas e definimos a largura máxima de acordo.
Implementação
// Função para atualizar a largura máxima do rótulo com base na coluna mais larga
const updateLabelMaxWidth = () => {
let maxColumnWidth = 0;
// Loop através de cada coluna e encontrar a largura máxima
series.columns.each(function (column) {
if (column && column.pixelWidth > maxColumnWidth) {
maxColumnWidth = column.pixelWidth;
}
});
// Aplicar largura máxima aos rótulos
categoryAxis.renderer.labels.template.maxWidth = maxColumnWidth;
console.log("Largura Máxima do Rótulo Atualizada: " + maxColumnWidth);
// Forçar rótulo a ser reprocessado
categoryAxis.invalidateLabels();
}
// Disparar atualização da largura do rótulo no zoom/pan
categoryAxis.events.on("rangechangeended", function () {
updateLabelMaxWidth();
});
// Disparar atualização da largura do rótulo ao redimensionar a tela
chart.events.on("sizechanged", function () {
updateLabelMaxWidth();
});
Explicação
A função updateLabelMaxWidth ajusta dinamicamente a largura dos rótulos do eixo x com base na coluna mais larga do gráfico. Ela percorre todas as colunas, encontra a largura máxima e a aplica aos rótulos para evitar sobreposição.
Ganchos de Evento:
- rangechangeended → Atualiza a largura do rótulo ao fazer zoom/pan.
- sizechanged → Ajusta os rótulos quando o gráfico é redimensionado.
Isso garante que os rótulos redimensionem dinamicamente com base no espaço disponível.
Truncando Rótulos Longos para Melhor Legibilidade
Mesmo com uma largura máxima dinâmica, alguns rótulos ainda podem ser muito longos e causar desordem. Para lidar com isso, truncamos rótulos quando eles excedem um certo comprimento.
Implementação
categoryAxis.renderer.labels.template.adapter.add("textOutput", function(text, target) {
let maxLabelLength = 10; // Definir o número máximo de caracteres antes do truncamento
if (text.length > maxLabelLength) {
return text.substring(0, maxLabelLength) + "..."; // Truncar e adicionar reticências
}
return text; // Retornar texto original se estiver dentro do limite
});
Explicação
- Essa função verifica o comprimento de cada rótulo.
- Se o rótulo for muito longo, ele trunca o texto para a primeira palavra e adiciona ".." no final.
- Rótulos dentro do limite máximo de caracteres permanecem inalterados.
Isso garante que rótulos longos não se sobreponham, enquanto ainda fornecem informações suficientes e permanecem responsivos quando redimensionados ou ampliados/reduzidos.
Código de Implementação Completo após aplicar a solução
am4core.ready(function () {
// Criar a instância do gráfico
let chart = am4core.create("chartdiv", am4charts.XYChart);
chart.hiddenState.properties.opacity = 0; // Fade-in inicial
chart.logo.disabled = true;
chart.responsive.enabled = true; // Habilitar comportamento responsivo
// Dados do gráfico
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 }
];
// Criar Eixo de Categoria (Eixo 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); // Definir todos os lados como 0
// Criar Eixo de Valor (Eixo Y)
let valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
valueAxis.min = 0;
valueAxis.max = 24000;
valueAxis.strictMinMax = true;
valueAxis.renderer.minGridDistance = 30;
// Função para atualizar a largura máxima do rótulo com base na coluna mais larga
const updateLabelMaxWidth = () => {
let maxColumnWidth = 0;
// Loop através de cada coluna e encontrar a largura máxima
series.columns.each(function (column) {
if (column && column.pixelWidth > maxColumnWidth) {
maxColumnWidth = column.pixelWidth;
}
});
// Aplicar largura máxima aos rótulos
categoryAxis.renderer.labels.template.maxWidth = maxColumnWidth;
console.log("Largura Máxima do Rótulo Atualizada: " + maxColumnWidth);
// Forçar rótulo a ser reprocessado
categoryAxis.invalidateLabels();
}
// Disparar atualização da largura do rótulo no zoom/pan
categoryAxis.events.on("rangechangeended", function () {
updateLabelMaxWidth();
});
// Disparar atualização da largura do rótulo ao redimensionar a tela
chart.events.on("sizechanged", function () {
updateLabelMaxWidth();
});
// Truncar rótulos no final da primeira palavra quando necessário
categoryAxis.renderer.labels.template.adapter.add("textOutput", function (text, target) {
let labelMaxWidth = target.maxWidth;
if (labelMaxWidth < 60 && text) { // Verificar se a largura do rótulo é menor que 60 pixels
let words = text.split(" "); // Dividir texto em palavras
return words.length > 1 ? words[0] + ".." : text; // Manter apenas a primeira palavra com ".."
}
return text;
});
// Criar Série de Colunas
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;
// Aplicar cores diferentes a cada coluna
series.columns.template.adapter.add("fill", function (fill, target) {
return chart.colors.getIndex(target.dataItem.index);
});
// Adicionar Barra de Rolagem
chart.scrollbarX = new am4core.Scrollbar();
chart.scrollbarX.marginTop = 30;
chart.scrollbarX.parent = chart.bottomAxesContainer;
// Adicionar Quebra de Eixo para valores grandes
let axisBreak = valueAxis.axisBreaks.create();
axisBreak.startValue = 2100;
axisBreak.endValue = 22900;
// Ajustar Tamanho da Quebra de Eixo
let d = (axisBreak.endValue - axisBreak.startValue) / (valueAxis.max - valueAxis.min);
axisBreak.breakSize = 0.05 * (1 - d) / d; // Aumentar tamanho da quebra para melhor visibilidade
// Ajustar efeito de hover para melhor interação
let hoverState = axisBreak.states.create("hover");
hoverState.properties.breakSize = 1; // Quebra ligeiramente maior quando sobreposta
hoverState.properties.opacity = 0.1;
hoverState.transitionDuration = 1500;
axisBreak.defaultState.transitionDuration = 1000;
}); // fim am4core.ready()
Com essas melhorias, nosso gráfico agora se adapta perfeitamente—os rótulos permanecem legíveis, sem mais sobreposições feias, e tudo redimensiona suavemente. Ao ajustar dinamicamente as larguras, truncar nomes longos e conectar-se a eventos, garantimos que o gráfico fique ótimo em qualquer tela. Agora, vá em frente e experimente!