Compartilhar via


Adicione interatividade ao visual pelas seleções de visuais do Power BI

O Power BI fornece duas maneiras de interagir com visuais: selecionar e filtrar. 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 objeto Selection:

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 de host do visual fornece um método para criar uma instância do gerenciador de seleção. O gerenciador de seleção tem um método correspondente para cada uma das seguintes ações:

  • Selecionar
  • Desmarcar a seleção
  • Mostrar o menu de contexto
  • Armazenar as seleções atuais
  • Verificar o estado de seleção

Criar instância do gerenciador de seleção

Para usar o gerenciador de seleção, crie a instância do gerenciador de seleção. Geralmente, os visuais criam uma instância do gerenciador de seleção na seção constructor 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 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 createSelectionIdBuilder do objeto de host visual gera uma seleção para cada ponto de dados. Esse método retorna uma instância do objeto com a 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;
}

Esse objeto tem métodos correspondentes para criar selections para diferentes tipos de mapeamentos de exibição de dados.

Observação

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 versão da API 2.5.0 ou superior.

Criar seleções para o mapeamento da exibição de dados categóricos

Vamos examinar como as seleções representam o mapeamento categórico de exibição de dados para um modelo semântico de exemplo:

Fabricante Tipo Valor
Chrysler Carro nacional 28883
Chrysler Caminhonete nacional 117131
Chrysler Carro importado 0
Chrysler Caminhonete importada 6362
Ford Carro nacional 50032
Ford Caminhonete nacional 122446
Ford Carro importado 0
Ford Caminhonete importada 0
GM Carro nacional 65426
GM Caminhonete nacional 138122
GM Carro importado 197
GM Caminhonete importada 0
Honda Carro nacional 51450
Honda Caminhonete nacional 46115
Honda Carro importado 2932
Honda Caminhonete importada 0
Nissan Carro nacional 51476
Nissan Caminhonete nacional 47343
Nissan Carro importado 5485
Nissan Caminhonete importada 1430
Toyota Carro nacional 55643
Toyota Caminhonete nacional 61227
Toyota Carro importado 20799
Toyota Caminhonete importada 23614

O elemento 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 segmentar dados por Manufacturer ou Type.

Por exemplo, quando o usuário seleciona Chrysler por Manufacturer, outros elementos visuais devem mostrar os seguintes dados:

Fabricante Tipo Valor
Chrysler Carro nacional 28883
Chrysler Caminhonete nacional 117131
Chrysler Carro importado 0
Chrysler Caminhonete importada 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 Tipo Valor
Chrysler Carro importado 0
Ford Carro importado 0
GM Carro importado 197
Honda Carro importado 2932
Nissan Carro importado 5485
Toyota Carro importado 20799

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

Para exibir dados divididos, 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.

Observação

Os Values são necessários para exibir uma série porque, de acordo com o mapeamento de exibição de dados, os Values são agrupados por dados de Rows.

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, iteramos por todas as categorias. Em cada iteração, chamamos createSelectionIdBuilder para criar a próxima seleção para cada categoria chamando o método withCategory do construtor de seleção. O método createSelectionId é usado como um método final para retornar o objeto selection gerado.

No método withCategory, passamos a coluna de category, no exemplo, é Manufacturer e o índice do elemento da 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 o mapeamento da exibição de dados da tabela

O seguinte exemplo mostra o mapeamento de exibição de dados de tabela:

{
    "dataRoles": [
        {
            "displayName": "Values",
            "name": "values",
            "kind": "GroupingOrMeasure"
        }
    ],
    "dataViewMappings": [
        {
            "table": {
                "rows": {
                    "for": {
                        "in": "values"
                    }
                }
            }
        }
    ]
}

Para criar uma seleção para cada linha do mapeamento da visualização de dados da tabela, chame o método withTable do construtor da 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 do visual itera as linhas da tabela e cada linha chama o método de tabela withTable. Os parâmetros do método withTable são o objeto e table e o índice da linha da tabela.

Criar seleções para o mapeamento da exibição de dados da 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);
            });
        }
    }
}

Na amostra, nodeWalker chama recursivamente cada nó e cada nó filho.

O nodeWalker cria um objeto nodeSelection em cada chamada. Cada nodeSelection um representa um selection dos nós correspondentes.

Selecionar pontos de dados para segmentar outros visuais

Neste exemplo, criamos um manipulador de cliques para elementos de botão. O manipulador chama o método select 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 método select:

interface ISelectionManager {
    // ...
    select(selectionId: ISelectionId | ISelectionId[], multiSelect?: boolean): IPromise<ISelectionId[]>;
    // ...
}

O método select pode aceitar uma variedade de seleções. Isso permite que o visual tenha vários pontos de dados selecionados ao mesmo tempo. O segundo parâmetro, multiSelect, é responsável pela seleção múltipla. Se multiSelect for verdadeiro, o Power BI não limpará o estado de seleção anterior ao aplicar a seleção atual. Se o valor for falso, a seleção anterior será substituída.

Um exemplo típico do uso de multiSelect é lidar com 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);
});