Premiers pas avec les visualisations personnalisées dans Looker

L'API Looker Visualization est une API JavaScript qui s'exécute dans un iFrame en bac à sable et qui est hébergée dans l'application Looker.

Vous pouvez utiliser le même code de visualisation pour fournir une visualisation n'importe où dans Looker : explorations, présentations, tableaux de bord, intégrations, PDF ou images rendues.

Chaque visualisation représente une vue d'une seule requête Looker. Looker exécute la requête et transmet les résultats à votre code de visualisation. Looker transmet également un élément DOM dans lequel votre code de visualisation peut dessiner.

Conditions requises

Avant de commencer, assurez-vous de répondre aux exigences suivantes :

  • Une certaine connaissance de JavaScript et du développement Web est nécessaire.
  • Un accès administrateur Looker est requis pour créer et mettre à jour des fichiers manifestes de projet LookML.

Créer une visualisation Hello World

Cette section explique comment créer un script de visualisation personnalisé qui affiche la première dimension d'une requête donnée.

Le résultat final doit ressembler à l'image suivante :

Configuration

Pour développer et tester une visualisation dans Looker, vous avez deux options :

Une fois que vous avez configuré l'une de ces options, vous pouvez suivre l'exemple de cette section pour créer hello_world.js.

Structure de code essentielle

Pour afficher le code source final de cet exemple, consultez le dépôt GitHub.

Dans le dossier que vous hébergez, créez un fichier JavaScript vide et nommez-le hello_world.js.

Pour enregistrer une nouvelle visualisation personnalisée auprès de Looker, appelez la fonction looker.plugins.visualizations.add et transmettez-lui un objet de visualisation. Cet objet contient la définition de votre visualisation et de son interface utilisateur de configuration.

L'exemple suivant montre le squelette d'une visualisation avec toutes les propriétés requises renseignées. Il contient une fonction create et une fonction updateAsync dans lesquelles vous pouvez écrire votre code de visualisation :

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

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

  }
})

Ce code est une visualisation Looker valide, mais il n'est pas encore visuel et apparaît sous la forme d'une zone vide.

Préparation

Considérez la fonction create, qui comporte deux arguments : element et config.

Looker provides an element, which is the DOM element that Looker requires you to place your visualization into. Looker crée cet élément et lui donne la taille appropriée. Vous devez y placer du contenu.

La fonction create vous permet d'effectuer la configuration initiale de votre élément. Dans cet exemple, vous allez créer un graphique qui ressemble à la structure HTML suivante :

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

À l'aide de JavaScript, vous pouvez insérer des éléments dans votre élément DOM pour qu'ils correspondent à cette structure.

L'exemple suivant montre cette fonction avec plus de détails ajoutés :

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"));

},

Ce code ajoute du code CSS, crée le conteneur hello-world-vis et y ajoute un div.

Le code attribue également this._textElement au conteneur dans lequel vous souhaitez effectuer le rendu. Cela vous évite d'avoir à le rechercher ultérieurement lorsque le graphique commence à s'afficher.

La fonction create est un emplacement pratique pour effectuer des tâches de configuration qui ne doivent être effectuées qu'une seule fois.

Rendu

Cette section explique comment développer la méthode updateAsync pour visualiser les données. Cette méthode est appelée chaque fois que le graphique doit visualiser des modifications ou lorsqu'un autre événement se produit et peut affecter le rendu de votre graphique (par exemple, le graphique est redimensionné ou une option de configuration est modifiée).

Dans cet exemple, vous ne devez trouver que la première dimension dans la première cellule. Pour ce faire, vous pouvez utiliser data, qui est un tableau de chaque ligne de l'ensemble de données, et queryResponse, qui contient des métadonnées sur la requête, telles que les noms et les types de champs.

Vous pouvez également utiliser une méthode d'assistance appelée LookerCharts.Utils.htmlForCell pour fournir la représentation HTML appropriée du point de données dans cette cellule. Cette méthode gère automatiquement les éléments tels que les liens d'exploration, la mise en forme et les actions sur les données :

  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()
  }

Vous avez ainsi terminé les étapes nécessaires pour disposer d'une visualisation personnalisée fonctionnelle. Toutefois, il est important d'inclure une méthode de gestion des erreurs.

Traiter les erreurs

Le code updateAsync récupère la première ligne de données, mais des erreurs peuvent se produire si la requête ne renvoie aucun résultat ou ne contient aucune dimension.

Sans gestion des exceptions, une erreur JavaScript s'affiche dans la console du navigateur, ce qui peut dérouter les utilisateurs lorsque le graphique ne s'affiche pas.

Les graphiques peuvent afficher des messages d'erreur personnalisés s'ils rencontrent des problèmes lors du rendu. Looker ajoute deux fonctions à votre objet de visualisation : addError et clearErrors. Vous pouvez utiliser ces fonctions pour afficher un message d'erreur compréhensible pour tous les utilisateurs.

Étant donné que ces fonctions sont ajoutées à l'objet de visualisation, elles sont disponibles à partir du contexte de votre fonction updateAsync via l'objet this.

Vous pouvez modifier le début de votre méthode updateAsync pour détecter une condition d'erreur, informer l'utilisateur d'un problème et quitter au lieu de tenter d'effectuer le rendu :

  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 ...

Si l'utilisateur crée une requête qui ne contient que des mesures, il voit un message d'erreur semblable à celui-ci :

Rendu asynchrone et exportations PDF

Dans l'exemple "Hello World" précédent, la fonction done() est appelée immédiatement après la mise à jour du DOM. Cette approche est appropriée, car la définition de innerHTML est synchrone.

Toutefois, si vous utilisez des bibliothèques de graphiques telles que D3.js, Chart.js ou React, votre rendu est probablement asynchrone. Si vous appelez done() en bas de votre script, Looker peut capturer la capture d'écran pour une exportation PDF ou PNG avant que votre graphique ne soit terminé, ce qui peut entraîner une vignette vide.

Lorsque Looker exporte un tableau de bord, il utilise un navigateur sans interface graphique et s'appuie sur le rappel done() pour savoir quand il est possible de prendre une capture d'écran.

Pour vous assurer que vos graphiques sont exportés correctement, vous devez lier le rappel done() à l'événement de fin de votre bibliothèque et désactiver les animations lors des exportations à l'aide de l'option details.print.

L'exemple suivant montre comment gérer le rendu asynchrone à l'aide de D3.js :

  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();
        });
    }
  }

Si vous utilisez React, assurez-vous de transmettre le rappel done comme troisième argument à votre fonction de rendu afin que Looker attende que React monte les composants :

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

Configuration

Vous pouvez autoriser les utilisateurs à personnaliser certains aspects de leur visualisation.

Outre les autres propriétés de votre objet de visualisation, une propriété nommée options est disponible.

Vous pouvez utiliser cette propriété pour spécifier le type d'options requis par le graphique :

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 ...

Cet exemple crée une option font_size qui s'affiche sous forme de cases d'option, permettant aux utilisateurs de choisir entre les tailles de police "petite" et "grande".

La spécification de la propriété options est requise pour ajouter l'option au sélecteur de visualisation.

Pour utiliser cette option dans votre code, rappelez-vous que dans la méthode updateAsync, il existe un paramètre config. Ce paramètre contient les options sélectionnées suivantes :

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

L'objet config ressemble à ce qui suit :

{font_size: "large"}

Lorsque vous mettez à jour le graphique, vous pouvez vérifier cet objet et répondre en conséquence. Ajoutez la vérification suivante à la fin de la méthode de mise à jour pour implémenter les modifications de la taille de la police :

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

Vous devez également mettre à jour la balise <style> ajoutée dans la méthode create pour définir les classes CSS hello-world-text-small et hello-world-text-large :

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

Étant donné que la fonction updateAsync est appelée chaque fois que la configuration change et que Looker enregistre automatiquement la configuration, il vous suffit de répondre aux paramètres de configuration.

Étapes suivantes

Vous pouvez afficher le code source complet de cette visualisation "Hello World" dans le dépôt GitHub Open Source de Looker.

Pour en savoir plus sur les fonctionnalités supplémentaires, consultez la documentation de référence de l'API Visualization.