Erste Schritte mit benutzerdefinierten Visualisierungen in Looker

Die Looker Visualization API ist eine JavaScript API, die in einem Sandbox-iFrame ausgeführt wird und in der Looker-Anwendung gehostet wird.

Sie können denselben Visualisierungscode verwenden, um eine Visualisierung an beliebiger Stelle in Looker bereitzustellen: in Explores, Looks, Dashboards, Einbettungen oder PDF- oder gerenderten Bildern.

Jede Visualisierung stellt eine Ansicht einer einzelnen Looker-Abfrage dar. Looker führt die Abfrage aus und übergibt die Ergebnisse an Ihren Visualisierungscode. Looker übergibt auch ein DOM-Element, in das Ihr Visualisierungscode gezeichnet werden kann.

Voraussetzungen

Bevor Sie beginnen, müssen die folgenden Voraussetzungen erfüllt sein:

  • Einige Kenntnisse in JavaScript und Webentwicklung sind erforderlich.
  • Für das Erstellen und Aktualisieren von LookML-Projektmanifestdateien ist Looker-Administratorzugriff erforderlich.

„Hello World“-Visualisierung erstellen

In diesem Abschnitt wird beschrieben, wie Sie ein benutzerdefiniertes Visualisierungsskript erstellen, das die erste Dimension einer bestimmten Abfrage anzeigt.

Das Endergebnis sollte so aussehen wie im folgenden Bild:

Einrichtung

Sie haben zwei Möglichkeiten, eine Visualisierung in Looker zu entwickeln und zu testen:

Nachdem Sie eine dieser Optionen konfiguriert haben, können Sie dem Beispiel in diesem Abschnitt folgen, um hello_world.js zu erstellen.

Grundlegende Codestruktur

Den endgültigen Quellcode für dieses Beispiel finden Sie im GitHub-Repository.

Erstellen Sie im Ordner, in dem Sie hosten, eine neue leere JavaScript-Datei und nennen Sie sie hello_world.js.

Wenn Sie eine neue benutzerdefinierte Visualisierung bei Looker registrieren möchten, rufen Sie die Funktion looker.plugins.visualizations.add auf und übergeben Sie ihr ein Visualisierungsobjekt. Dieses Objekt enthält die Definition Ihrer Visualisierung und die zugehörige Konfigurations-UI.

Das folgende Beispiel zeigt das Grundgerüst einer Visualisierung mit allen erforderlichen Eigenschaften. Es enthält eine create-Funktion und eine updateAsync-Funktion, in die Sie Ihren Visualisierungscode schreiben können:

looker.plugins.visualizations.add({
  create: function(element, config) {

  },
  updateAsync: function(data, element, config, queryResponse, details, done) {

  }
})

Dieser Code ist eine gültige Looker-Visualisierung, aber er ist noch nicht sichtbar und wird als leeres Feld angezeigt.

Definition des Koordinatensystems

Die Funktion create hat zwei Argumente: element und config.

Looker stellt ein element bereit, das das DOM-Element ist, in das Sie Ihre Visualisierung einfügen müssen. Looker erstellt dieses Element und legt die richtige Größe fest. Sie müssen Inhalte darin platzieren.

Die Funktion create bietet die Möglichkeit, die erste Einrichtung Ihres Elements vorzunehmen. In diesem Beispiel möchten Sie ein Diagramm erstellen, das der folgenden HTML-Struktur ähnelt:

<style>
  /* custom styles for your chart */
</style>
<div class="hello-world-vis">
  <div>Data Goes Here</div>
</div>

Mit JavaScript können Sie Elemente in Ihr DOM-Element einfügen, um dieser Struktur zu entsprechen.

Das folgende Beispiel zeigt diese Funktion mit weiteren Details:

create: function(element, config) {

  // Insert a <style> tag with some styles to use later.
  var css = element.innerHTML = `
    <style>
      .hello-world-vis {
        /* Vertical centering */
        height: 100%;
        display: flex;
        flex-direction: column;
        justify-content: center;
        text-align: center;
      }
    </style>
  `;

  // Create a container element to center the text.
  var container = element.appendChild(document.createElement("div"));
  container.className = "hello-world-vis";

  // Create an element to contain the text.
  this._textElement = container.appendChild(document.createElement("div"));

},

Dieser Code fügt CSS hinzu, erstellt den Container hello-world-vis und fügt darin ein div hinzu.

Der Code weist this._textElement auch dem Container zu, in den Sie rendern möchten. Das ist praktisch, da Sie ihn später nicht noch einmal suchen müssen, wenn das Diagramm gerendert wird.

Die Funktion create ist ein praktischer Ort, um Einrichtungsvorgänge auszuführen, die nur einmal ausgeführt werden müssen.

Rendering

In diesem Abschnitt wird beschrieben, wie Sie die Methode updateAsync erweitern, um Daten zu visualisieren. Diese Methode wird immer dann aufgerufen, wenn im Diagramm Änderungen visualisiert werden müssen oder wenn ein anderes Ereignis eintritt, das sich auf die Darstellung des Diagramms auswirken kann (z. B. wenn die Größe des Diagramms geändert wird oder sich eine Konfigurationsoption ändert).

In diesem Beispiel müssen Sie nur die erste Dimension in der ersten Zelle finden. Dazu können Sie data verwenden, ein Array mit jeder Zeile des Datasets, und queryResponse, das Metadaten zur Abfrage enthält, z. B. Feldnamen und -typen.

Sie können auch eine Hilfsmethode namens LookerCharts.Utils.htmlForCell verwenden, um die richtige HTML-Darstellung des Datenpunkts in dieser Zelle bereitzustellen. Diese Methode verarbeitet automatisch Elemente wie Drill-Links, Formatierung und Datenaktionen:

  updateAsync: function(data, element, config, queryResponse, details, done) {

    // Grab the first cell of the data.
    var firstRow = data[0];
    var firstCell = firstRow[queryResponse.fields.dimensions[0].name];

    // Insert the data into the page.
    this._textElement.innerHTML = LookerCharts.Utils.htmlForCell(firstCell);

    // Always call done to indicate a visualization has finished rendering.
    done()
  }

Damit sind die Schritte abgeschlossen, die für eine funktionierende benutzerdefinierte Visualisierung erforderlich sind. Es ist jedoch wichtig, eine Methode zur Fehlerbehebung einzufügen.

Fehlerbehebung

Der Code updateAsync ruft die erste Datenzeile ab. Es können jedoch Fehler auftreten, wenn die Abfrage keine Ergebnisse zurückgibt oder keine Dimensionen enthält.

Ohne Fehlerbehandlung wird in der Browserkonsole ein JavaScript-Fehler angezeigt, der Nutzer verwirren kann, wenn das Diagramm nicht gerendert wird.

In Diagrammen können benutzerdefinierte Fehlermeldungen angezeigt werden, wenn beim Rendern Probleme auftreten. Looker fügt Ihrem Visualisierungsobjekt zwei Funktionen hinzu: addError und clearErrors. Mit diesen Funktionen können Sie eine Fehlermeldung anzeigen, die für alle Nutzer verständlich ist.

Da diese Funktionen dem Visualisierungsobjekt hinzugefügt werden, sind sie über das Objekt this aus dem Kontext Ihrer Funktion updateAsync verfügbar.

Sie können den Anfang Ihrer Methode updateAsync so ändern, dass eine Fehlersituation erkannt wird, der Nutzer über ein Problem benachrichtigt wird und die Methode beendet wird, anstatt zu versuchen, zu rendern:

  updateAsync: function(data, element, config, queryResponse, details, done) {

    // Clear any errors from previous updates.
    this.clearErrors();

    // Throw some errors and exit if the shape of the data isn't what this chart needs.
    if (queryResponse.fields.dimensions.length == 0) {
      this.addError({title: "No Dimensions", message: "This chart requires dimensions."});
      // Always call done() before exiting early to avoid dashboard exports hanging
      done();
      return;
    }

    if (!data || data.length === 0) {
      this.addError({title: "No Data", message: "The query returned no results."});
      done();
      return;
    }

    // ... the rest of the update code here ...

Wenn der Nutzer eine Abfrage erstellt, die nur Messwerte enthält, wird eine Fehlermeldung ähnlich der folgenden angezeigt:

Asynchrones Rendering und PDF-Exporte

Im vorherigen „Hello World“-Beispiel wird die Funktion done() sofort nach dem Aktualisieren des DOM aufgerufen. Dieser Ansatz ist geeignet, da das Festlegen von innerHTML synchron erfolgt.

Wenn Sie jedoch Diagrammbibliotheken wie D3.js, Chart.js oder React verwenden, ist das Rendering wahrscheinlich asynchron. Wenn Sie done() am Ende Ihres Skripts aufrufen, erfasst Looker möglicherweise den Screenshot für einen PDF- oder PNG-Export, bevor das Diagramm fertig gezeichnet ist. Das kann zu einer leeren Kachel führen.

Wenn Looker ein Dashboard exportiert, wird ein Headless-Browser verwendet und der done()-Callback wird verwendet, um zu ermitteln, wann es sicher ist, einen Screenshot zu erstellen.

Damit Ihre Diagramme korrekt exportiert werden, müssen Sie den done()-Callback an das Abschlussereignis Ihrer Bibliothek binden und Animationen während des Exports mit dem Flag details.print deaktivieren.

Das folgende Beispiel zeigt, wie Sie das asynchrone Rendering mit D3.js verarbeiten:

  updateAsync: function(data, element, config, queryResponse, details, done) {
    this.clearErrors();

    // Check if Looker is exporting the chart to a PDF/PNG
    const isExport = details && details.print === true;

    // Clear previous elements
    this.svg.selectAll("*").remove();

    const circle = this.svg.append("circle")
      .attr("cx", 50)
      .attr("cy", 50);

    if (isExport) {
      // Instant render for exports. Draw the final state immediately with no transitions
      circle.attr("r", 40);

      // Tell Looker to take the screenshot right now
      done();
    } else {
      // If it's for the browser, start small and animate
      circle.attr("r", 0)
        .transition()
        .duration(1000)
        .attr("r", 40)
        .on("end", () => {
           // Tell Looker the animation is fully complete
           done();
        });
    }
  }

Wenn Sie React verwenden, müssen Sie den done-Callback als drittes Argument an Ihre Rendering-Funktion übergeben, damit Looker wartet, bis die Komponenten eingebunden sind:

  this.chart = ReactDOM.render(
    <MyCustomChart data={data} />,
    element,
    done // Looker waits for React to finish
  );

Konfiguration

Sie können Nutzern erlauben, Aspekte ihrer Visualisierung anzupassen.

Zusätzlich zu den anderen Eigenschaften Ihres Visualisierungsobjekts ist eine Eigenschaft namens options verfügbar.

Mit dieser Eigenschaft können Sie angeben, welche Art von Optionen für das Diagramm erforderlich sind:

looker.plugins.visualizations.add({
  options: {
    font_size: {
      type: "string",
      label: "Font Size",
      values: [
        {"Large": "large"},
        {"Small": "small"}
      ],
      display: "radio",
      default: "large"
    }
  },
  // ... rest of visualization object ...

In diesem Beispiel wird eine Option font_size erstellt, die als Optionsfelder angezeigt wird, sodass Nutzer zwischen den Schriftgrößen „klein“ und „groß“ wählen können.

Die Eigenschaft options muss angegeben werden, damit die Option in der Visualisierungsauswahl hinzugefügt werden kann.

Wenn Sie diese Option in Ihrem Code verwenden möchten, denken Sie daran, dass die Methode updateAsync einen Parameter config enthält. Dieser Parameter enthält die folgenden ausgewählten Optionen:

updateAsync: function(data, element, config, queryResponse, details, done) {

Das Objekt config sieht so aus:

{font_size: "large"}

Wenn Sie das Diagramm aktualisieren, können Sie dieses Objekt prüfen und entsprechend reagieren. Fügen Sie am Ende der Aktualisierungsmethode die folgende Prüfung hinzu, um Änderungen an der Schriftgröße zu implementieren:

if (config.font_size == "small") {
  this._textElement.className = "hello-world-text-small";
} else {
  this._textElement.className = "hello-world-text-large";
}

Sie sollten auch das Tag <style> aktualisieren, das in der Methode create hinzugefügt wurde, um die CSS-Klassen hello-world-text-small und hello-world-text-large zu definieren:

.hello-world-text-large {
  font-size: 72px;
}
.hello-world-text-small {
  font-size: 18px;
}

Da die Funktion updateAsync immer dann aufgerufen wird, wenn sich die Konfiguration ändert, und Looker die Konfiguration automatisch speichert, müssen Sie nichts weiter tun, um auf Konfigurationseinstellungen zu reagieren.

Nächste Schritte

Den vollständigen Quellcode für diese „Hello World“-Visualisierung finden Sie im Open-Source-GitHub-Repository von Looker.

Weitere Informationen zu zusätzlichen Funktionen finden Sie in der Referenz zur Visualization API.