Datenvisualisierungen mit AngularJS

Avatar of Nick Moreton
Nick Moreton am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

Der folgende Beitrag ist ein Gastbeitrag von Nick Moreton. Ich muss sagen, ich finde diese Idee ziemlich faszinierend. Ich weiß, dass ich gerne mit HTML, SVG und CSS arbeite, daher spricht es mich an, wenn Nick erzählt, dass wir diese für die Struktur nutzen und die Daten direkt zur Gestaltung eines Diagramms verwenden können. Und dann zu wissen, dass das Diagramm dank Angular automatisch geändert werden kann, wenn sich die Daten ändern... das ist einfach verdammt cool.

Sobald ich mit AngularJS zu experimentieren begann, fiel mir auf, dass seine Fähigkeit, Daten zu erfassen und direkt in Markup zu verwenden, eine sehr schnelle und einfache Möglichkeit zur Erstellung von Datenvisualisierungen bieten könnte.

In diesem Tutorial werde ich die Erstellung von drei verschiedenen Arten von Diagrammen mit sowohl Inline-CSS als auch SVG durchgehen.

Warum Angular?

Wenn Sie jemals aus JavaScript oder jQuery in das DOM geschrieben haben, wissen Sie, wie schnell Ihr Code unübersichtlich werden kann, besonders wenn Sie mehrere Variablen verwenden. Angular ermöglicht die direkte Verwendung von Daten im Markup, was zu sauberem, leicht lesbarem und verständlichem Code führt.

Es gibt auch einige großartige Visualisierungsbibliotheken, aber diese bringen von Haus aus viel Standard-Styling mit. Durch die Verwendung von Angular sind die Visualisierungen völlig unvoreingenommen und übernehmen sofort Ihren Stil.

Ich sage nicht, dass dies die beste Methode zur Erstellung von Datenvisualisierungen ist, aber sie spricht mich definitiv an!

Hinweis: Ich werde hier nicht jeden Aspekt von Angular durchgehen, wie z. B. wie Apps, Controller usw. funktionieren – ich werde mich auf die Daten konzentrieren. Ich habe ‘A Hello World In AngularJS’ geschrieben, das Ihnen vielleicht hilft, einige dieser Dinge zu verstehen, und es gibt viele andere großartige Ressourcen, um mit Angular zu beginnen.

Einrichten unserer Angular App

Grundlegende App-Einrichtung

Zuerst müssen wir eine Angular-App und einen Controller einrichten, um unsere Funktionalität und Daten zu beherbergen.

(function(){

  var app = angular.module('graphApp',[]);

  app.controller('graphController', function($scope){

  // Code goes here!

  });

})();

Standardoptionen

Als Nächstes richten wir einige Standardvariablen ein, die an den Controller $scope gebunden sind und mit denen wir die Größe unseres Diagramms sowie Beschriftungen für die X- und Y-Achse steuern.

$scope.width = 600;
$scope.height = 400;
$scope.yAxis = "Sales";
$scope.xAxis = "2014"

Daten

Anschließend fügen wir unsere Daten hinzu, geschrieben in JSON, gebunden an den $scope unseres Controllers.

$scope.data = [
  {
    label: 'January',
    value: 36
  },
  {
    label: 'February',
    value: 54
  },

  // .... and so on .....

  {
    label: 'November',
    value: 252
  },
  {
    label: 'December',
    value: 342
  }
];

Das Maximum finden

Schließlich schreiben wir eine Schleife, um unsere Daten zu durchlaufen, den Maximalwert zu finden und ihn als Variable festzulegen. Dies werden wir später verwenden, um die Elemente in unseren Visualisierungen zu positionieren.

$scope.max = 0;

var arrLength = $scope.data.length;
for (var i = 0; i < arrLength; i++) {
  // Find Maximum X Axis Value
  if ($scope.data[i].value > $scope.max)
  $scope.max = $scope.data[i].value;
}

Das war's für unser JavaScript. Das Ganze dreht sich eigentlich nur darum, unsere Daten und Variablen für die spätere Verwendung in unserem Markup vorzubereiten.

Markup, Templating und CSS einrichten

Nun müssen wir das Markup und CSS für unsere Visualisierungs-App einrichten.

<div ng-app="graphApp">

  <div ng-controller="graphController as graph">

    <div class="graph" style="width:{{width}}px; height:{{height}}px;" >

      <div class="y" style="width:{{height}}px;">{{yAxis}}</div>

      <div class="x">{{xAxis}}</div>

    </div>

  </div>

</div>

Im HTML können wir beginnen, die Daten direkt aus JavaScript in das Markup zu ziehen, sowohl als Inhalt (wie die X- und Y-Achsenbeschriftungen) als auch als Inline-Stil, um die Höhe und Breite unseres Diagramms zu steuern.

Hinweis: Der ‘y’-Div verwendet die Variable {{height}} für die CSS-Eigenschaft width – das liegt daran, dass wir diesen in unserem CSS um 90 Grad gegen den Uhrzeigersinn drehen werden.
.chart {
  border-left: 1px solid black;
  border-bottom: 1px solid black;
  margin: 60px auto;
  position: relative;
}

.y {
  position: absolute;
  transform: rotate(-90deg);
  transform-origin: bottom left;
  bottom: 0;
  padding: 5px;
}

.x {
  position: absolute;
  top: 100%;
  width: 100%;
  padding: 5px;
}

Balkendiagramm

Um die Daten in unseren Diagrammen zu erstellen, verwenden wir die ng-repeat-Funktion von Angular. Diese durchläuft unser Datenarray und gibt jedes Markup aus, das wir in ng-repeat für jeden Eintrag einschließen.

Zuerst erstellen wir ein Balkendiagramm. Zunächst habe ich etwas Standard-CSS für die Klasse ‘bar’ eingerichtet, das die Position auf absolut setzt und eine Hintergrundfarbe hinzufügt.

.bar {
  background: blue;
  position: absolute;
  bottom: 0;
}

Dann würden wir mit ng-repeat, um für jeden Eintrag ein <div> mit der Klasse ‘bar’ zu erstellen, schreiben

<div ng-repeat="bar in data" class="bar"></div>

Dieser Code gehört in unser <div class="graph"></div>.

Wir können nun unsere Angular-Daten (und ein bisschen Mathematik!) in einem Inline-CSS verwenden, um die Höhe und Breite jedes Balkens zu steuern.

<div ng-repeat="bar in data" class="bar" style="height:{{bar.value / max * height}}px; width:{{width / data.length - 5}}px;"></div>

Die Höhe ist der Wert, geteilt durch das Maximum (wie in unserer Angular-App eingestellt), multipliziert mit der Gesamthöhe unseres Diagramms. Dies stellt sicher, dass der höchste Wert in unseren Daten die volle Höhe des Diagramms einnimmt.

Die Breite ist die Gesamtbreite geteilt durch die Anzahl der Einträge, abzüglich 5 Pixel, um etwas Abstand zu schaffen, sobald wir unsere Balken auf der X-Achse platzieren.

Schließlich müssen wir die Balken entlang der X-Achse mit der CSS-Eigenschaft left positionieren.

<div ng-repeat="bar in data" class="bar" style="height:{{bar.value / max * height}}px; width:{{width / data.length - 5}}px; left:{{$index / data.length * width}}px;"></div>

Hier verwenden wir $index, eine Angular-Variable, die bei 0 beginnt und für jeden nachfolgenden Balken steigt. Wir teilen den Index durch die Gesamtzahl der Einträge und multiplizieren dies mit der vollen Breite des Diagramms. Dies platziert den ersten Balken bei 0 und verteilt dann die restlichen Balken gleichmäßig über das Diagramm.

Es ist hier erwähnenswert, dass Sie, wenn Sie ein flüssiges Diagramm wünschen, mit 100 multiplizieren und % als Einheit anstelle von Pixeln verwenden könnten.

Und das war's – unser Balkendiagramm ist nun erstellt und Sie können mit Ihrem CSS kreativ werden, um es zu gestalten!

Der endgültige vollständige Diagramm-Code sieht so aus

<div class="chart" style="width:{{width}}px; height:{{height}}px;">

  <!-- Labels -->
  <div class="y" style="width:{{height}}px;">{{yAxis}}</div>
  <div class="x">{{xAxis}}</div>

  <!-- Data -->
  <div ng-repeat="bar in data" class="bar" style="height:{{bar.value / max * height}}px; width:{{width / data.length - 5}}px; left:{{$index / data.length * width}}px;"></div>

</div>

Siehe den Pen 1fe35094c4c1d447bdf59c5588167274 von Nick Moreton (@nickmoreton) auf CodePen.

Punkt-Diagramm

Die Methode für ein Punkt-Diagramm ist sehr ähnlich.

Auch hier habe ich etwas Standard-CSS für die Punkte.

.dot {
  background: blue;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  position: absolute;
}

Für die Punkte müssen wir uns nicht um Breiten oder Höhen kümmern, wir verwenden einfach dieselben Daten und mathematischen Berechnungen, um die Punkte von links und von unten zu positionieren.

Der einzige Unterschied ist, dass wir 0,5 zu $index addieren, damit die Punkte in der Mitte des ihnen zugewiesenen Platzes positioniert werden.

<div ng-repeat="dot in data" class="dot" style="bottom:{{dot.value / max * height}}px; left:{{($index + 1) / data.length * width}}px;"></div>

Das vollständige Diagramm sieht so aus

<div class="chart" style="width:{{width}}px; height:{{height}}px;">

  <!-- Labels -->
  <div class="y" style="width:{{height}}px;">{{yAxis}}</div>
  <div class="x">{{xAxis}}</div>

  <!-- Data -->
  <div ng-repeat="dot in data" class="dot" style="bottom:{{dot.value / max * height}}px; left:{{($index + 0.5) / data.length * width}}px;"></div>

</div>

Siehe den Pen 0ee74365fd766311a52aa0d129c22ea8 von Nick Moreton (@nickmoreton) auf CodePen.

SVG-Linien-Diagramm

Neben Inline-CSS können wir Angular-Datenwerte in SVG-Daten verwenden.

Das CSS dafür ist

svg {
  position: absolute;
  transform: rotateX(180deg);
  left: 0;    
}

line  {
  stroke:red;
  stroke-width:3px;
}

Ich rotiere das SVG, da es standardmäßig Werte von oben verarbeitet und wir diese umgekehrt benötigen, um Werte vom Boden zu übernehmen.

Zuerst müssen wir ein SVG erstellen, das die gesamte Fläche unseres Diagramms einnimmt, und dann darin unsere ng-repeat-Schleife auf einem line-Element verwenden.

Jedes line-Element benötigt einen Start- und Endpunkt sowohl auf der X- (x1, x2) als auch auf der Y-Achse (y1, y2).

Die X-Achse ist ziemlich einfach – wir folgen demselben System wie zuvor, sodass jede Linie gleichmäßig über das Diagramm verteilt ist, beginnend bei 0 mit $index und endend dort, wo die nächste Linie beginnt, mit $index + 1.

Für die Y-Achse kommt die Variable $index hier voll zur Geltung, da sie uns erlaubt, Werte aus vorherigen oder nächsten Einträgen in unserem Array auszuwählen.

Der anfängliche Y-Punkt jeder Linie erhält den Wert vom vorherigen Datensatz über data[$index - 1].value, bevor wir dann ähnliche Berechnungen wie zuvor anwenden. Für den zweiten Y-Punkt können wir einfach den direkten Wert aus dem Eintrag verwenden.

Das mag kompliziert klingen (und ich versichere Ihnen, dass es eine ziemliche Kopfnuss war, es herauszufinden!), aber hoffentlich wird Ihnen diese Erklärung in Verbindung mit dem nachstehenden Code helfen, es zu verstehen!

<svg style="width:{{width}}px; height:{{height}}px;">

  <line ng-repeat="line in data" x1="{{$index / data.length * width}}" y1="{{data[$index - 1].value / max * height}}" x2="{{($index + 1) / data.length * width}}" y2="{{line.value / max * height}}">
  </line>

</svg>

Der endgültige Diagramm-Code sieht so aus

<div class="chart" style="width:{{width}}px; height:{{height}}px;">

  <!-- Labels -->
  <div class="y" style="width:{{height}}px;">{{yAxis}}</div>
  <div class="x">{{xAxis}}</div>

  <!-- Data -->
  <svg style="width:{{width}}px; height:{{height}}px;">

    <line ng-repeat="line in data" 
          x1="{{$index / data.length * width }}" 
          y1="{{data[$index - 1].value / max * height}}" 
          x2="{{($index + 1) / data.length * width}}" 
          y2="{{line.value / max * height}}">
    </line>

 </svg>

</div>

Siehe den Pen a3e89703d7671fa81d5c2ceb20f7b150 von Nick Moreton (@nickmoreton) auf CodePen.

Wo geht es weiter?

Sie können die Variable $index auch in Klassennamen verwenden, wie z. B. <element class="classname{{$index}}">, was eine präzise Steuerung jedes Balkens, Punkts oder jeder Linie ermöglicht – dies können wir zur Animation dieser Visualisierungen nutzen.

Ich habe ein vollständiges Dot/Line-Diagrammbeispiel mit Animation sowie CSS-Tooltips unter Verwendung der Beschriftungen aus jedem Eintrag in unseren Daten ausgearbeitet. Sie können es hier sehen.

Ich habe auch einen Pen mit all diesen Beispielen erstellt.

Ich hoffe, dieses Tutorial ist von Nutzen, und ich würde gerne hören, welche Visualisierungen Sie mit Angular erstellen!