本教學課程適用於經驗豐富的 JavaScript 開發人員,並假設您對功能式程式設計技巧略知一二。
在本例中,我們先查詢某些品牌的假設季度銷售資訊。首先,我們會篩選特定品牌的查詢,然後依銷售季度樞紐轉換結果。請參閱下表範例。
接著,我們會使用視覺化元件建立自訂視覺化圖表,顯示每個品牌的產品在過去一個季度的趨勢。結果會是一種新型態的視覺化資料,由一系列微型圖組成,並嵌入表格中,如下圖所示:
除了說明如何建立自訂圖表,這個範例也說明瞭在 React 應用程式中使用 Looker API 的最佳做法。
如要使用 Looker 元件建立自訂圖表,請確認設定符合規定,然後執行下列步驟:
如果自訂圖表是用於嵌入式應用程式或擴充功能,建議使用圖表元件來建立自訂圖表。如要讓自訂圖表可供 Looker 使用者在 Looker 執行個體中使用,請按照
visualization
說明文件中的操作說明進行。如要開發自訂視覺化報表並上傳至 Looker Marketplace,請按照「為 Looker Marketplace 開發自訂視覺化報表」說明文件中的操作說明進行。
需求條件
開始前,請先準備以下幾項元素:
- 您必須具備 Looker 執行個體的存取權。
- 無論您是使用擴充功能架構還是自有的獨立 React 應用程式,都必須透過 Looker API 進行驗證,並存取 Looker SDK 物件。詳情請參閱 Looker API 驗證或擴充功能架構。
- 請確認您已安裝 Looker 圖表可視化元件 NPM 套件,以及
@looker/components-data
NPM 套件。如要瞭解如何安裝及使用圖像化元件套件,請參閱 GitHub 和 NPM 中的 README 文件。
步驟 1:在探索中建立查詢並複製查詢 ID
在本例中,我們使用假設的季度銷售資訊,針對我們追蹤的品牌進行長期追蹤。
我們會轉換這項資料,因為轉換是 Looker 內建的查詢結果分組方式。在探索資料中,我們可以執行查詢,並使用 Looker 的原生可視化類型建立資料圖表。這張圖表提供許多資訊,但要一眼看出各品牌產品的趨勢,難度不低:
接下來,請從「探索」的網址列複製 qid
值。在本例中,qid
值為 Uijcav7pCA4MZY2MompsPZ
,但這個值僅適用於我們的測試例項;您的值會有所不同。
步驟 2:將資料傳遞至自訂圖表元件
首先,將從 Explore 網址取得的 qid
值傳遞至 Query
元件,並將已驗證的 SDK 物件傳遞至 DataProvider
。
import React, { useContext } from 'react'
import { ExtensionContext } from '@looker/extension-sdk-react'
import { DataProvider } from '@looker/components-data'
import { Query } from '@looker/visualizations'
export const MyReactApp = () => {
const { core40SDK } = useContext(ExtensionContext)
return (
<DataProvider sdk={core40SDK}>
<Query query='Uijcav7pCA4MZY2MompsPZ'></Query>
</DataProvider>
)
}
接下來,我們將建立名為 CustomVis
的自訂元件,而非透過 Visualization
元件算繪原生 Looker 圖表。
Query
元件可接受任何 React 元素做為子項,並只會將 config
、data
、fields
和 totals
值傳遞為屬性,以轉譯您自己的視覺化元件。我們會將 CustomVis
算繪為 Query
的子項,因此可以接收所有相關資料做為屬性。
import React, { useContext } from 'react'
import { ExtensionContext } from '@looker/extension-sdk-react'
import { DataProvider } from '@looker/components-data'
import { Query } from '@looker/visualizations'
import { CustomVis } from '../path/to/MyCustomVis'
export const MyReactApp = () => {
const { core40SDK } = useContext(ExtensionContext)
return (
<DataProvider sdk={core40SDK}>
<Query query='Uijcav7pCA4MZY2MompsPZ'>
<CustomVis />
</Query>
</DataProvider>
)
}
步驟 3:建構 CustomVis
元件
接下來,我們來建構 CustomVis
元件。從 Query
元件繼承的屬性包括 config
、fields
、data
、pivots
和 totals
:
config
會說明資料應如何在圖表中顯示,例如 Sparkline 中線條的粗細,或散布圖中點的大小和形狀。fields
會儲存查詢傳回的評量和維度值相關的其他中繼資料,例如值的格式設定或各軸的標籤。data
是查詢傳回的鍵/值回應。pivots
會說明用於樞紐查詢的維度。totals
會參照 Looker 的列總和,用於以表格為基礎的圖表。
我們可以插入 Table
元件,將這些未經修改的屬性傳遞至表格資料視覺化。
import React from 'react'
import { Table } from '@looker/visualizations'
export const CustomVis = ({ config, fields, data, pivots }) => {
return <Table config={config} data={data} fields={fields} pivots={pivots} />
}
這可讓我們瞭解直接從 SDK 傳回的資料。在轉譯的回應中,每個品牌都有一列,結果則按季度分組或樞紐。
步驟 4:轉換標準化資料
為了將這個樞紐資料轉換為以巢狀微型圖呈現的資料,我們會將所有評估值隔離,並傳遞至子圖表。在下方圖表中,我們會以醒目方式顯示單一資料列的相關資料,以便說明我們將如何折疊資料,並透過子項圖表呈現:
我們會為此建立自訂轉換。以下是這個情境的具體範例,您需要據此剖析自己的資料。
import React from 'react'
import { Table, Sparkline } from '@looker/visualizations'
// we assign this value to a constant to ensure that fields and data
// objects remain in sync.
const NESTED_DATA_KEY = 'orderCount'
const nestSparklines = (data) => {
return data.reduce((acc, d) => {
// the first entry is the dimension (brand name), and the rest of the rows are the
// quarterly sales information we want to pass to the Sparkline.
const [parentDimension, ...measurePairs] = Object.entries(d)
// `nonPivotedData` represents a single data row.
// e.g. [{entry: 1, orderCount: 10}, {entry: 2, orderCount: 15}, ...etc]
const nonPivotedData: SDKRecord[] = measurePairs.map(([_, value], i) => {
return { entry: i, [NESTED_DATA_KEY]: value }
})
// now for each row in the table we render a Sparkline using the `nonPivotedData`
// that we built.
// E.G. [{products.brand: 'adidas', orderCount: <Sparkline />}]
return [
...acc,
{
[parentDimension[0]]: parentDimension[1],
[NESTED_DATA_KEY]: () => (
<Sparkline
height={75}
data={nonPivotedData}
fields={{
measures: [{ name: NESTED_DATA_KEY }],
dimensions: [],
}}
/>
),
},
]
}, [])
}
建立函式的步驟如下:
- 對資料集進行縮減,從每個資料列的季度訂單資料中分離出品牌名稱。
- 更新每個資料列,納入維度和可代表表格中每個資料列值的呈現 React 元件。
步驟 5:將轉換後的資料插入 CustomVis
現在,請使用新的函式轉換資料,並將輸出結果指派給名為 nestedData
的新變數:
export const CustomVis =({
fields,
data,
config,
pivots,
}) => {
const nestedData = nestSparklines(data)
return (
<Table
fields={{
measures: [{ name: NESTED_DATA_KEY, label: 'Orders Count By Quarter' }],
dimensions: fields.dimensions,
pivots: [],
}}
config={config}
data={nestedData}
pivots={pivots}
/>
)
}
步驟 6:產生自訂圖表
插入轉換後的資料並設定圖表後,視覺化效果會如下所示,表格中會顯示每列的個別微型圖表:
完整的轉譯這項示意圖所需程式碼如下:
import React, { useContext } from 'react'
import { ExtensionContext } from '@looker/extension-sdk-react'
import { DataProvider } from '@looker/components-data'
import { Query, Sparkline, Table } from '@looker/visualizations'
// we assign this value to a constant to ensure that fields and data
// objects remain in sync.
const NESTED_DATA_KEY = 'orderCount'
const ROW_HEIGHT = 75
const nestSparklines = data => {
return data.reduce((acc, d) => {
// the first entry is the dimension (brand name), and the rest of the rows are the
// quarterly sales information we want to pass to the Sparkline.
const [parentDimension, ...measurePairs] = Object.entries(d)
// `nonPivotedData` represents a single data row.
// e.g. [{entry: 1, orderCount: 10}, {entry: 2, orderCount: 15}, ...etc]
const nonPivotedData = measurePairs.map(([_, value], i) => {
return { entry: i, [NESTED_DATA_KEY]: value }
})
// now for each row in the table we render a Sparkline using the `nonPivotedData`
// that we built.
// E.G. [{products.brand: 'adidas', orderCount: <Sparkline />}]
return [
...acc,
{
[parentDimension[0]]: parentDimension[1],
[NESTED_DATA_KEY]: () => (
<Sparkline
height={ROW_HEIGHT}
data={nonPivotedData}
fields={{
measures: [{ name: NESTED_DATA_KEY }],
dimensions: [],
}}
/>
),
},
]
}, [])
}
const CustomVis = ({ fields, data, pivots, config }) => {
const nestedData = nestSparklines(data)
return (
<Table
config={config}
height={500}
fields={{
measures: [{ name: NESTED_DATA_KEY, label: 'Orders Count By Quarter' }],
dimensions: fields.dimensions,
pivots: [],
}}
data={nestedData}
pivots={pivots}
defaultRowHeight={ROW_HEIGHT}
/>
)
}
export const MyReactApp = () => {
const { core40SDK } = useContext(ExtensionContext)
return (
<DataProvider sdk={core40SDK}>
<Query query='Uijcav7pCA4MZY2MompsPZ'>
<CustomVis />
</Query>
</DataProvider>
)
}