Adicionar interatividade ao visual por seleções visuais do Power BI
O Power BI fornece duas maneiras de interagir com elementos visuais: selecionando e filtrando. O exemplo a seguir demonstra como selecionar um item de um visual e notificar os outros visuais no relatório sobre o novo estado de seleção.
A interface corresponde a um Selection
objeto:
export interface ISelectionId {
equals(other: ISelectionId): boolean;
includes(other: ISelectionId, ignoreHighlight?: boolean): boolean;
getKey(): string;
getSelector(): Selector;
getSelectorsByColumn(): SelectorsByColumn;
hasIdentity(): boolean;
}
Usar o gerenciador de seleção para selecionar pontos de dados
O objeto host visual fornece um método para criar uma instância do gerenciador de seleção. O gestor da seleção tem um método correspondente para cada uma das seguintes ações:
- Selecione
- Limpar a seleção
- Mostrar o menu de contexto
- Armazenar as seleções atuais
- Verificar o estado de seleção
Criar uma instância do gestor de seleção
Para utilizar o gestor de seleção, crie a instância de um gestor de seleção. Normalmente, os elementos visuais criam uma instância do gerenciador de seleção na constructor
seção do objeto visual.
export class Visual implements IVisual {
private target: HTMLElement;
private host: IVisualHost;
private selectionManager: ISelectionManager;
// ...
constructor(options: VisualConstructorOptions) {
this.host = options.host;
// ...
this.selectionManager = this.host.createSelectionManager();
}
// ...
}
Criar uma instância do construtor de seleção
Quando a instância do gerenciador de seleção é criada, você precisa criar selections
para cada ponto de dados do visual. O método do objeto host visual gera uma seleção para cada ponto de createSelectionIdBuilder
dados. Este método retorna uma instância do objeto com interface powerbi.visuals.ISelectionIdBuilder
:
export interface ISelectionIdBuilder {
withCategory(categoryColumn: DataViewCategoryColumn, index: number): this;
withSeries(seriesColumn: DataViewValueColumns, valueColumn: DataViewValueColumn | DataViewValueColumnGroup): this;
withMeasure(measureId: string): this;
withMatrixNode(matrixNode: DataViewMatrixNode, levels: DataViewHierarchyLevel[]): this;
withTable(table: DataViewTable, rowIndex: number): this;
createSelectionId(): ISelectionId;
}
Este objeto tem métodos correspondentes para criar selections
para diferentes tipos de mapeamentos de exibição de dados.
Nota
Os métodos withTable
e withMatrixNode
foram introduzidos na API 2.5.0 dos visuais do Power BI.
Se você precisar usar seleções para mapeamentos de exibição de dados de tabela ou matriz, atualize para a API versão 2.5.0 ou superior.
Criar seleções para mapeamento de exibição de dados categórica
Vamos analisar como as seleções representam o mapeamento de exibição de dados categóricos para um modelo semântico de exemplo:
Fabricante | Type | valor |
---|---|---|
Chrysler | Carro Doméstico | 28883 |
Chrysler | Camião Doméstico | 117131 |
Chrysler | Carro de importação | 0 |
Chrysler | Caminhão de Importação | 6362 |
Ford | Carro Doméstico | 50032 |
Ford | Camião Doméstico | 122446 |
Ford | Carro de importação | 0 |
Ford | Caminhão de Importação | 0 |
GM | Carro Doméstico | 65426 |
GM | Camião Doméstico | 138122 |
GM | Carro de importação | 197 |
GM | Caminhão de Importação | 0 |
Honda | Carro Doméstico | 51450 |
Honda | Camião Doméstico | 46115 |
Honda | Carro de importação | 2932 |
Honda | Caminhão de Importação | 0 |
Nissan | Carro Doméstico | 51476 |
Nissan | Camião Doméstico | 47343 |
Nissan | Carro de importação | 5485 |
Nissan | Caminhão de Importação | 1430 |
Toyota | Carro Doméstico | 55643 |
Toyota | Camião Doméstico | 61227 |
Toyota | Carro de importação | 20799 |
Toyota | Caminhão de Importação | 23614 |
O visual usa o seguinte mapeamento de exibição de dados:
{
"dataRoles": [
{
"displayName": "Columns",
"name": "columns",
"kind": "Grouping"
},
{
"displayName": "Rows",
"name": "rows",
"kind": "Grouping"
},
{
"displayName": "Values",
"name": "values",
"kind": "Measure"
}
],
"dataViewMappings": [
{
"categorical": {
"categories": {
"for": {
"in": "columns"
}
},
"values": {
"group": {
"by": "rows",
"select": [
{
"for": {
"in": "values"
}
}
]
}
}
}
}
]
}
No exemplo anterior, Manufacturer
é columns
e Type
é rows
. Uma série é criada agrupando valores por rows
(Type
).
O visual deve ser capaz de fatiar dados por Manufacturer
ou Type
.
Por exemplo, se um usuário selecionar Chrysler
por Manufacturer
, outros elementos visuais deverão mostrar os seguintes dados:
Fabricante | Type | valor |
---|---|---|
Chrysler | Carro Doméstico | 28883 |
Chrysler | Camião Doméstico | 117131 |
Chrysler | Carro de importação | 0 |
Chrysler | Caminhão de Importação | 6362 |
Quando o usuário seleciona Import Car
por Type
(seleciona dados por série), os outros elementos visuais devem mostrar os seguintes dados:
Fabricante | Type | valor |
---|---|---|
Chrysler | Carro de importação | 0 |
Ford | Carro de importação | 0 |
GM | Carro de importação | 197 |
Honda | Carro de importação | 2932 |
Nissan | Carro de importação | 5485 |
Toyota | Carro de importação | 20799 |
Para exibir dados fatiados, preencha as cestas de dados do visual da seguinte maneira:
No exemplo anterior, Manufacturer
é categoria (colunas), Type
é série (linhas) e Sales
é Values
para série.
Nota
Values
são necessários para exibir uma série porque, de acordo com o mapeamento da exibição de dados, Values
são agrupados por Rows
dados.
Criar seleções para categorias
// categories
const categories = dataView.categorical.categories;
// create label for 'Manufacturer' column
const p = document.createElement("p") as HTMLParagraphElement;
p.innerText = categories[0].source.displayName.toString();
this.target.appendChild(p);
// get count of category elements
const categoriesCount = categories[0].values.length;
// iterate all categories to generate selection and create button elements to use selections
for (let categoryIndex = 0; categoryIndex < categoriesCount; categoryIndex++) {
const categoryValue: powerbi.PrimitiveValue = categories[0].values[categoryIndex];
const categorySelectionId = this.host.createSelectionIdBuilder()
.withCategory(categories[0], categoryIndex) // we have only one category (only one `Manufacturer` column)
.createSelectionId();
this.dataPoints.push({
value: categoryValue,
selection: categorySelectionId
});
console.log(categorySelectionId);
// create button element to apply selection on click
const button = document.createElement("button") as HTMLButtonElement;
button.value = categoryValue.toString();
button.innerText = categoryValue.toString();
button.addEventListener("click", () => {
// handle click event to apply correspond selection
this.selectionManager.select(categorySelectionId);
});
this.target.appendChild(button);
}
No código de exemplo anterior, repetimos todas as categorias. Em cada iteração, chamamos createSelectionIdBuilder
para criar a próxima seleção para cada categoria chamando o withCategory
método do construtor de seleção. O createSelectionId
método é usado como um método final para retornar o objeto gerado selection
.
withCategory
No método, passamos a coluna de category
, na amostra, seu Manufacturer
, e o índice do elemento de categoria.
Criar seleções para séries
// get groupped values for series
const series: powerbi.DataViewValueColumnGroup[] = dataView.categorical.values.grouped();
// create label for 'Type' column
const p2 = document.createElement("p") as HTMLParagraphElement;
p2.innerText = dataView.categorical.values.source.displayName;
this.target.appendChild(p2);
// iterate all series to generate selection and create button elements to use selections
series.forEach( (ser: powerbi.DataViewValueColumnGroup) => {
// create selection id for series
const seriesSelectionId = this.host.createSelectionIdBuilder()
.withSeries(dataView.categorical.values, ser)
.createSelectionId();
this.dataPoints.push({
value: ser.name,
selection: seriesSelectionId
});
// create button element to apply selection on click
const button = document.createElement("button") as HTMLButtonElement;
button.value =ser.name.toString();
button.innerText = ser.name.toString();
button.addEventListener("click", () => {
// handle click event to apply correspond selection
this.selectionManager.select(seriesSelectionId);
});
this.target.appendChild(button);
});
Criar seleções para mapeamento de exibição de dados de tabela
O exemplo a seguir mostra o mapeamento da exibição de dados da tabela:
{
"dataRoles": [
{
"displayName": "Values",
"name": "values",
"kind": "GroupingOrMeasure"
}
],
"dataViewMappings": [
{
"table": {
"rows": {
"for": {
"in": "values"
}
}
}
}
]
}
Para criar uma seleção para cada linha de mapeamento de exibição de dados de tabela, chame o withTable
método do construtor de seleção.
public update(options: VisualUpdateOptions) {
const dataView = options.dataViews[0];
dataView.table.rows.forEach((row: DataViewTableRow, rowIndex: number) => {
this.target.appendChild(rowDiv);
const selection: ISelectionId = this.host.createSelectionIdBuilder()
.withTable(dataView.table, rowIndex)
.createSelectionId();
}
}
O código visual itera as linhas da tabela e cada linha chama o withTable
método table. Os parâmetros do withTable
método são o table
objeto e o índice da linha da tabela.
Criar seleções para mapeamento de exibição de dados de matriz
public update(options: VisualUpdateOptions) {
const host = this.host;
const rowLevels: powerbi.DataViewHierarchyLevel[] = dataView.matrix.rows.levels;
const columnLevels: powerbi.DataViewHierarchyLevel[] = dataView.matrix.rows.levels;
// iterate rows hierarchy
nodeWalker(dataView.matrix.rows.root, rowLevels);
// iterate columns hierarchy
nodeWalker(dataView.matrix.columns.root, columnLevels);
function nodeWalker(node: powerbi.DataViewMatrixNode, levels: powerbi.DataViewHierarchyLevel[]) {
const nodeSelection = host.createSelectionIdBuilder().withMatrixNode(node, levels);
if (node.children && node.children.length) {
node.children.forEach(child => {
nodeWalker(child, levels);
});
}
}
}
No exemplo, nodeWalker
chama recursivamente cada nó e nó filho.
nodeWalker
Cria um nodeSelection
objeto em cada chamada. Cada nodeSelection
um representa um selection
dos nós correspondentes.
Selecionar pontos de dados para fatiar outros elementos visuais
Neste exemplo, criamos um manipulador de clique para elementos button. O manipulador chama o select
método do gerenciador de seleção e passa o objeto de seleção.
button.addEventListener("click", () => {
// handle click event to apply correspond selection
this.selectionManager.select(categorySelectionId);
});
A interface do select
método:
interface ISelectionManager {
// ...
select(selectionId: ISelectionId | ISelectionId[], multiSelect?: boolean): IPromise<ISelectionId[]>;
// ...
}
O select
método pode aceitar uma matriz de seleções. Isso permite que seu visual tenha vários pontos de dados selecionados ao mesmo tempo. O segundo parâmetro, multiSelect
, é responsável por multi-seleções. Se multiSelect
for true, o Power BI não limpa o estado de seleção anterior quando aplica a seleção atual. Se o valor for false, a seleção anterior será substituída.
Um exemplo típico de uso multiSelect
é manipular o estado do botão Ctrl em um evento de clique. Quando o botão Ctrl é pressionado, você pode selecionar mais de um objeto.
button.addEventListener("click", (mouseEvent) => {
const multiSelect = (mouseEvent as MouseEvent).ctrlKey;
this.selectionManager.select(seriesSelectionId, multiSelect);
});