Einführung

Beschriftungen in Säulendiagrammen haben oft Lesbarkeitsprobleme, wenn das Diagramm verkleinert, auf verschiedenen Bildschirmauflösungen angezeigt oder mit den Zoom-Steuerelementen von amCharts hinein- oder herausgezoomt wird. Standardmäßig haben Beschriftungen in amCharts 4 eine feste Breite, was zu Überlappungen, Abschneidungen oder unleserlichem Text auf kleinen Bildschirmen führen kann.

Um Beschriftungen wirklich responsive zu gestalten, müssen wir:

  • Die maximale Breite der Beschriftungen dynamisch basierend auf der Diagrammgröße und der Säulenbreite berechnen.
  • Lange Beschriftungen bei Bedarf abschneiden, um Überlauf zu verhindern.
  • Verwenden Sie Ereignis-Hooks, um sicherzustellen, dass die Beschriftungen richtig angepasst werden, wenn:
    • Das Diagramm wird neu dimensioniert.
    • Zoom/Panning erfolgt.
    • Daten werden dynamisch aktualisiert.

In diesem Artikel werden wir untersuchen, wie man die Beschriftungsbreite dynamisch anpasst und Beschriftungen bei Bedarf abschneidet mithilfe von amCharts 4-Ereignissen.

Ein Beispiel für überlappende Beschriftungen und fehlende Reaktionsfähigkeit in einem Säulendiagramm

Implementierungscode mit dem Problem:


am4core.ready(function () {
    // Erstellen Sie die Diagramminstanz
    let chart = am4core.create("chartdiv", am4charts.XYChart);
    chart.hiddenState.properties.opacity = 0; // Anfangs einblenden
    chart.logo.disabled = true;
    chart.responsive.enabled = true; // Reaktionsfähigkeit aktivieren

    // Diagrammdaten
    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 }
    ];

    // Erstellen Sie die Kategoriewachse (X-Achse)
    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); // Alle Seiten auf 0 setzen

    // Erstellen Sie die Wertachse (Y-Achse)
    let valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
    valueAxis.min = 0;
    valueAxis.max = 24000;
    valueAxis.strictMinMax = true;
    valueAxis.renderer.minGridDistance = 30;

    // Erstellen Sie die Säulensammlung
    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;

    // Wenden Sie unterschiedliche Farben auf jede Säule an
    series.columns.template.adapter.add("fill", function (fill, target) {
      return chart.colors.getIndex(target.dataItem.index);
    });

    // Fügen Sie eine Bildlaufleiste hinzu
    chart.scrollbarX = new am4core.Scrollbar();
    chart.scrollbarX.marginTop = 30;
    chart.scrollbarX.parent = chart.bottomAxesContainer;

    // Fügen Sie eine Achsenunterbrechung für große Werte hinzu
    let axisBreak = valueAxis.axisBreaks.create();
    axisBreak.startValue = 2100;
    axisBreak.endValue = 22900;

    // Passen Sie die Größe der Achsenunterbrechung an
    let d = (axisBreak.endValue - axisBreak.startValue) / (valueAxis.max - valueAxis.min);
    axisBreak.breakSize = 0.05 * (1 - d) / d; // Erhöhte Unterbrechungsgröße für bessere Sichtbarkeit

    // Passen Sie den Hover-Effekt für bessere Interaktion an
    let hoverState = axisBreak.states.create("hover");
    hoverState.properties.breakSize = 1; // Etwas größere Unterbrechung beim Hover
    hoverState.properties.opacity = 0.1;
    hoverState.transitionDuration = 1500;

    axisBreak.defaultState.transitionDuration = 1000;

}); // Ende am4core.ready()

Einstellen einer responsiven maximalen Breite für Beschriftungen

In amCharts 4 haben Beschriftungen für die xAxis in einem Säulendiagramm eine feste maxWidth. Da diese Breite jedoch nicht dynamisch angepasst wird, müssen wir sie basierend auf der Säulenbreite und der Diagrammgröße berechnen.

Um dies zu erreichen, greifen wir auf das rangechangeended und sizechanged Ereignis zu, überprüfen die Breite der Säulen und setzen die maxWidth entsprechend.

Implementierung

// Funktion zur Aktualisierung der maximalen Breite der Beschriftung basierend auf der breitesten Säule
const updateLabelMaxWidth = () => {
  let maxColumnWidth = 0;

  // Durchlaufen Sie jede Säule und finden Sie die maximale Breite
  series.columns.each(function (column) {
    if (column && column.pixelWidth > maxColumnWidth) {
      maxColumnWidth = column.pixelWidth;
    }
  });

  // Wenden Sie die maximale Breite auf die Beschriftungen an
  categoryAxis.renderer.labels.template.maxWidth = maxColumnWidth;
  console.log("Aktualisierte maximale Beschriftungsbreite: " + maxColumnWidth);

  // Zwingen Sie die Beschriftung zur Neuberechnung
  categoryAxis.invalidateLabels();
}

// Auslösen der Aktualisierung der Beschriftungsbreite beim Zoom/Pan
categoryAxis.events.on("rangechangeended", function () {
  updateLabelMaxWidth();
});

// Auslösen der Aktualisierung der Beschriftungsbreite bei Bildschirmänderung
chart.events.on("sizechanged", function () {
  updateLabelMaxWidth();
});

Erläuterung

Die Funktion updateLabelMaxWidth passt die Breite der x-Achsenbeschriftungen dynamisch basierend auf der breitesten Säule im Diagramm an. Sie durchläuft alle Säulen, findet die maximale Breite und wendet sie auf die Beschriftungen an, um Überlappungen zu verhindern.

Ereignis-Hooks:

  • rangechangeended → Aktualisiert die Beschriftungsbreite beim Zoom/Pan.
  • sizechanged → Passt die Beschriftungen an, wenn das Diagramm neu dimensioniert wird.

Dies stellt sicher, dass die Beschriftungen dynamisch skaliert werden basierend auf dem verfügbaren Platz.

Lange Beschriftungen für bessere Lesbarkeit abschneiden

Selbst mit einer dynamischen maximalen Breite können einige Beschriftungen immer noch zu lang sein und Unordnung verursachen. Um dies zu handhaben, schneiden wir Beschriftungen ab, wenn sie eine bestimmte Länge überschreiten.

Implementierung

categoryAxis.renderer.labels.template.adapter.add("textOutput", function(text, target) {
    let maxLabelLength = 10; // Setzen Sie die maximale Anzahl von Zeichen vor dem Abschneiden

    if (text.length > maxLabelLength) {
        return text.substring(0, maxLabelLength) + "..."; // Abschneiden und Ellipse hinzufügen
    }
    return text; // Ursprünglichen Text zurückgeben, wenn er innerhalb des Limits liegt
});

Erläuterung

  • Diese Funktion prüft die Länge jeder Beschriftung.
  • Wenn die Beschriftung zu lang ist, wird der Text auf das erste Wort gekürzt und ".." am Ende hinzugefügt.
  • Beschriftungen innerhalb des maximalen Zeichenlimits bleiben unverändert.

Dies stellt sicher, dass lange Beschriftungen sich nicht überlappen, während sie dennoch genügend Informationen bieten und bei Größenänderungen oder Zoomvorgängen reaktionsfähig bleiben.

Endergebnis nach Anwendung der dynamischen Beschriftungsanpassungen

Vollständiger Implementierungscode nach Anwendung der Lösung


am4core.ready(function () {
  // Erstellen Sie die Diagramminstanz
  let chart = am4core.create("chartdiv", am4charts.XYChart);
  chart.hiddenState.properties.opacity = 0; // Anfangs einblenden
  chart.logo.disabled = true;
  chart.responsive.enabled = true; // Reaktionsfähigkeit aktivieren

  // Diagrammdaten
  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 }
  ];

  // Erstellen Sie die Kategoriewachse (X-Achse)
  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); // Alle Seiten auf 0 setzen

  // Erstellen Sie die Wertachse (Y-Achse)
  let valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
  valueAxis.min = 0;
  valueAxis.max = 24000;
  valueAxis.strictMinMax = true;
  valueAxis.renderer.minGridDistance = 30;

  // Funktion zur Aktualisierung der maximalen Breite der Beschriftung basierend auf der breitesten Säule
  const updateLabelMaxWidth = () => {
    let maxColumnWidth = 0;

    // Durchlaufen Sie jede Säule und finden Sie die maximale Breite
    series.columns.each(function (column) {
      if (column && column.pixelWidth > maxColumnWidth) {
        maxColumnWidth = column.pixelWidth;
      }
    });

    // Wenden Sie die maximale Breite auf die Beschriftungen an
    categoryAxis.renderer.labels.template.maxWidth = maxColumnWidth;
    console.log("Aktualisierte maximale Beschriftungsbreite: " + maxColumnWidth);

    // Zwingen Sie die Beschriftung zur Neuberechnung
    categoryAxis.invalidateLabels();
  }

  // Auslösen der Aktualisierung der Beschriftungsbreite beim Zoom/Pan
  categoryAxis.events.on("rangechangeended", function () {
    updateLabelMaxWidth();
  });

  // Auslösen der Aktualisierung der Beschriftungsbreite bei Bildschirmänderung
  chart.events.on("sizechanged", function () {
    updateLabelMaxWidth();
  });

  // Beschriftungen am Ende des ersten Wortes bei Bedarf abschneiden
  categoryAxis.renderer.labels.template.adapter.add("textOutput", function (text, target) {
    let labelMaxWidth = target.maxWidth;

    if (labelMaxWidth < 60 && text) { // Überprüfen, ob die Beschriftungsbreite weniger als 60 Pixel beträgt
      let words = text.split(" "); // Text in Wörter aufteilen
      return words.length > 1 ? words[0] + ".." : text; // Nur das erste Wort mit ".." behalten
    }

    return text;
  });

  // Erstellen Sie die Säulensammlung
  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;

  // Wenden Sie unterschiedliche Farben auf jede Säule an
  series.columns.template.adapter.add("fill", function (fill, target) {
    return chart.colors.getIndex(target.dataItem.index);
  });

  // Fügen Sie eine Bildlaufleiste hinzu
  chart.scrollbarX = new am4core.Scrollbar();
  chart.scrollbarX.marginTop = 30;
  chart.scrollbarX.parent = chart.bottomAxesContainer;

  // Fügen Sie eine Achsenunterbrechung für große Werte hinzu
  let axisBreak = valueAxis.axisBreaks.create();
  axisBreak.startValue = 2100;
  axisBreak.endValue = 22900;

  // Passen Sie die Größe der Achsenunterbrechung an
  let d = (axisBreak.endValue - axisBreak.startValue) / (valueAxis.max - valueAxis.min);
  axisBreak.breakSize = 0.05 * (1 - d) / d; // Erhöhte Unterbrechungsgröße für bessere Sichtbarkeit

  // Passen Sie den Hover-Effekt für bessere Interaktion an
  let hoverState = axisBreak.states.create("hover");
  hoverState.properties.breakSize = 1; // Etwas größere Unterbrechung beim Hover
  hoverState.properties.opacity = 0.1;
  hoverState.transitionDuration = 1500;

  axisBreak.defaultState.transitionDuration = 1000;

}); // Ende am4core.ready()

Mit diesen Anpassungen passt sich unser Diagramm nun perfekt an—die Beschriftungen bleiben lesbar, keine hässlichen Überlappungen mehr, und alles wird reibungslos skaliert. Durch die dynamische Anpassung der Breiten, das Abschneiden langer Namen und das Einbinden von Ereignissen haben wir sichergestellt, dass das Diagramm auf jedem Bildschirm großartig aussieht. Probieren Sie es jetzt aus!