開始在 Looker 中使用自訂圖表

Looker Visualization API 是 JavaScript API,會在沙箱 iframe 中執行,並託管於 Looker 應用程式中。

您可以使用相同的圖表程式碼,在 Looker 的任何位置提供圖表:探索、Look、資訊主頁、嵌入內容、PDF 或算繪圖片。

每個圖表都代表單一 Looker 查詢的檢視畫面。Looker 會執行查詢,並將結果傳遞至圖表程式碼。Looker 也會傳遞 DOM 元素,您的視覺化程式碼可繪製該元素。

需求條件

開始前,請確認您符合下列需求:

  • 您必須具備一些 JavaScript 和網頁開發知識。
  • 您必須具備 Looker 管理員存取權,才能建立及更新 LookML 專案資訊清單檔案。

建立 Hello World 圖表

本節說明如何建立自訂圖表指令碼,顯示指定查詢的第一個維度。

最終結果應如下圖所示:

設定

如要在 Looker 中開發及測試視覺化效果,有兩種做法:

設定其中一個選項後,您可以按照本節中的範例建立 hello_world.js。

基本程式碼結構

如要查看這個範例的最終原始碼,請參閱 GitHub 存放區。

在您代管的資料夾中,建立新的空白 JavaScript 檔案,並命名為 hello_world.js。

如要在 Looker 註冊新的自訂圖表,請呼叫 looker.plugins.visualizations.add 函式,並傳遞圖表物件。這個物件包含圖表定義和設定 UI。

以下範例顯示視覺化效果的架構,並填入所有必要屬性。其中包含 create 函式和 updateAsync 函式,您可以在其中編寫視覺化程式碼:

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

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

  }
})

這段程式碼是有效的 Looker 視覺化內容,但尚未視覺化,因此會顯示為空白方塊。

背景介紹

請考慮使用 create 函式,其中包含兩個引數:element 和 config。

Looker 會提供 element,這是 Looker 要求您將圖表放入的 DOM 元素。Looker 會建立這個元素並調整為適當大小,您必須在其中放置內容。

create 函式可讓您執行元素的初始設定。在本例中,您要建立類似下列 HTML 結構的圖表:

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

您可以使用 JavaScript 將元素插入 DOM 元素,以符合這個結構。

以下範例顯示這個函式,並加入更多詳細資料:

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

},

這段程式碼會新增 CSS、建立 hello-world-vis 容器,並在其中新增 div。

程式碼也會將 this._textElement 指派給要算繪的容器。這樣一來,您就不必在圖表開始算繪時再次查詢。

create 函式是執行只需要一次的設定工作的便利位置。

算繪

本節說明如何擴充 updateAsync 方法,以便將資料視覺化。每當圖表必須顯示變更,或發生任何可能影響圖表顯示方式的其他事件 (例如圖表大小調整或設定選項變更) 時,系統就會呼叫這個方法。

在本範例中,您只需要找出第一個儲存格中的第一個維度。您可以使用 data 執行這項操作,這是資料集每列的陣列,而 queryResponse 則包含查詢的中繼資料,例如欄位名稱和類型。

您也可以使用名為 LookerCharts.Utils.htmlForCell 的輔助方法呼叫,在該儲存格中提供資料點的適當 HTML 表示法。這個方法會自動處理鑽取連結、格式和資料動作等元素:

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

這樣就完成自訂視覺化圖表正常運作所需的步驟。不過,請務必加入處理錯誤的方法。

處理錯誤

updateAsync 程式碼會擷取第一列資料,但如果查詢未傳回任何結果或不含任何維度,就可能發生錯誤。

如果沒有錯誤處理機制,瀏覽器控制台會顯示 JavaScript 錯誤,圖表無法轉譯時,可能會讓使用者感到困惑。

如果圖表在嘗試算繪時遇到問題,可以顯示自訂錯誤訊息。Looker 會在圖表物件中加入兩個函式:addError 和 clearErrors。您可以使用這些函式,向所有使用者顯示合理的錯誤訊息。

由於這些函式會新增至視覺化物件,因此可透過 this 物件,從 updateAsync 函式的環境取得。

您可以修改 updateAsync 方法的開頭,偵測錯誤情況、通知使用者問題,然後結束,而不是嘗試算繪:

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

如果使用者建立的查詢只包含測量指標,就會看到類似下方的錯誤訊息:

非同步顯示和匯出 PDF

在上述「Hello World」範例中,系統會在 DOM 更新後立即呼叫 done() 函式。由於設定 innerHTML 是同步作業,因此這個方法很合適。

不過,如果您使用 D3.js、Chart.js 或 React 等圖表程式庫,算繪作業可能會是非同步。如果在指令碼底部呼叫 done(),Looker 可能會在圖表繪製完成前,擷取 PDF 或 PNG 匯出作業的螢幕截圖,導致圖塊空白。

Looker 匯出資訊主頁時,會使用無頭瀏覽器,並依賴 done() 回呼,判斷何時可以安全擷取螢幕截圖。

為確保圖表能正確匯出,您必須將 done() 回呼繫結至程式庫的完成事件,並使用 details.print 旗標在匯出期間停用動畫。

以下範例說明如何使用 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();
        });
    }
  }

如果您使用 React,請務必將 done 回呼做為第三個引數傳遞至轉譯函式,這樣 Looker 就會等待 React 掛接元件:

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

設定

您可以允許使用者自訂圖表的某些部分。

除了視覺化物件的其他屬性,您還可以使用名為 options 的屬性。

您可以使用這個屬性指定圖表所需的選項類型:

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

這個範例會建立 font_size 選項,以圓形按鈕的形式顯示,讓使用者選擇「小」和「大」字型大小。

您必須指定 options 屬性,才能將選項新增至圖表挑選器。

如要在程式碼中使用這個選項,請回想一下,updateAsync 方法中有 config 參數。這項參數包含下列所選選項:

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

config 物件大致如下:

{font_size: "large"}

更新圖表時,您可以檢查這個物件並相應回覆。 在更新方法結尾新增下列檢查,實作字型大小變更:

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

您也應更新在 create 方法中新增的 <style> 標記,定義 hello-world-text-small 和 hello-world-text-large CSS 類別:

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

由於設定變更時會呼叫 updateAsync 函式,且 Looker 會自動儲存設定,因此您只需執行這項操作,即可回應設定。

後續步驟

如要查看這個「Hello World」圖表的完整原始碼,請前往 Looker 開放原始碼 GitHub 存放區。

如要進一步瞭解其他功能,請參閱 Visualization API 參考資料。