Partilhar via


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

Captura de tela que mostra o visual com seleções.

Para exibir dados fatiados, preencha as cestas de dados do visual da seguinte maneira:

Captura de tela que mostra as cestas de dados do visual.

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