Dodawanie interakcyjności do wizualizacji według wybranych wizualizacji usługi Power BI

Usługa Power BI udostępnia dwa sposoby interakcji z wizualizacjami — wybieranie i filtrowanie. W poniższym przykładzie pokazano, jak wybrać element z jednej wizualizacji i powiadomić inne wizualizacje w raporcie o nowym stanie wyboru.

Interfejs odpowiada Selection obiektowi:

export interface ISelectionId {
    equals(other: ISelectionId): boolean;
    includes(other: ISelectionId, ignoreHighlight?: boolean): boolean;
    getKey(): string;
    getSelector(): Selector;
    getSelectorsByColumn(): SelectorsByColumn;
    hasIdentity(): boolean;
}

Wybieranie punktów danych za pomocą menedżera wyboru

Obiekt hosta wizualizacji udostępnia metodę tworzenia wystąpienia menedżera wyboru. Menedżer wyboru ma odpowiednią metodę dla każdej z następujących akcji:

  • Wybierz pozycję
  • Wyczyść zaznaczenie
  • Pokaż menu kontekstowe
  • Przechowywanie bieżących wyborów
  • Sprawdzanie stanu zaznaczenia

Tworzenie wystąpienia menedżera wyboru

Aby użyć menedżera wyboru, utwórz wystąpienie menedżera wyboru. Zazwyczaj wizualizacje tworzą wystąpienie menedżera wyboru w constructor sekcji obiektu wizualizacji.

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();
    }
    // ...
}

Tworzenie wystąpienia konstruktora wyboru

Po utworzeniu wystąpienia menedżera wyboru należy utworzyć selections dla każdego punktu danych wizualizacji. Metoda obiektu createSelectionIdBuilder hosta wizualizacji generuje wybór dla każdego punktu danych. Ta metoda zwraca wystąpienie obiektu z interfejsem 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;
}

Ten obiekt ma odpowiednie metody tworzenia selections dla różnych typów mapowań widoku danych.

Uwaga

Metody withTable i withMatrixNode zostały wprowadzone w interfejsie API 2.5.0 wizualizacji usługi Power BI. Jeśli musisz użyć opcji dla mapowań widoku danych tabeli lub macierzy, zaktualizuj do interfejsu API w wersji 2.5.0 lub nowszej.

Tworzenie wyborów dla mapowania widoku danych kategorii

Sprawdźmy, w jaki sposób wybory reprezentują mapowanie widoku danych kategorii dla przykładowego modelu semantycznego:

Producent Type Wartość
Chrysler Samochód krajowy 28883
Chrysler Ciężarówka krajowa 117131
Chrysler Samochód importowy 0
Chrysler Importowanie ciężarówki 6362
Ford Samochód krajowy 50032
Ford Ciężarówka krajowa 122446
Ford Samochód importowy 0
Ford Importowanie ciężarówki 0
GM Samochód krajowy 65426
GM Ciężarówka krajowa 138122
GM Samochód importowy 197
GM Importowanie ciężarówki 0
Honda Samochód krajowy 51450
Honda Ciężarówka krajowa 46115
Honda Samochód importowy 2932
Honda Importowanie ciężarówki 0
Nissan Samochód krajowy 51476
Nissan Ciężarówka krajowa 47343
Nissan Samochód importowy 5485
Nissan Importowanie ciężarówki 1430
Toyota Samochód krajowy 55643
Toyota Ciężarówka krajowa 61227
Toyota Samochód importowy 20799
Toyota Importowanie ciężarówki 23614

Wizualizacja używa następującego mapowania widoku danych:

{
    "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"
                                }
                            }
                        ]
                    }
                }
            }
        }
    ]
}

W poprzednim przykładzie Manufacturer parametr ma wartość columns i Type ma wartość rows. Seria jest tworzona przez grupowanie wartości według rows (Type).

Wizualizacja powinna mieć możliwość fragmentowania danych według Manufacturer lub Type.

Jeśli na przykład użytkownik wybierze Chrysler wartość Manufacturer, inne wizualizacje powinny wyświetlić następujące dane:

Producent Type Wartość
Chrysler Samochód krajowy 28883
Chrysler Ciężarówka krajowa 117131
Chrysler Samochód importowy 0
Chrysler Importowanie ciężarówki 6362

Gdy użytkownik wybierze Import Car pozycję Type (wybiera dane według serii), inne wizualizacje powinny wyświetlać następujące dane:

Producent Type Wartość
Chrysler Samochód importowy 0
Ford Samochód importowy 0
GM Samochód importowy 197
Honda Samochód importowy 2932
Nissan Samochód importowy 5485
Toyota Samochód importowy 20799

Screenshot that shows the visual with selections.

Aby wyświetlić wycinek danych, wypełnij koszyki danych wizualizacji w następujący sposób:

Screenshot that shows visual's data baskets.

W poprzednim przykładzie Manufacturer jest kategoria (kolumny), Type jest serią (wierszami) i Sales jest Values dla serii.

Uwaga

Values są wymagane do wyświetlania serii, ponieważ zgodnie z mapowaniem Values widoku danych są grupowane według Rows danych.

Tworzenie wyborów dla kategorii

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

W poprzednim przykładowym kodzie iterujemy wszystkie kategorie. W każdej iteracji wywołujemy createSelectionIdBuilder metodę tworzenia kolejnego wyboru dla każdej kategorii przez wywołanie withCategory metody konstruktora wyboru. Metoda createSelectionId jest używana jako ostateczna metoda, aby zwrócić wygenerowany selection obiekt.

W metodzie withCategory przekazujemy kolumnę category, w przykładzie , jej Manufactureri indeks elementu category.

Tworzenie wyborów dla serii

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

Tworzenie wyborów dla mapowania widoku danych tabeli

W poniższym przykładzie przedstawiono mapowanie widoku danych tabeli:

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

Aby utworzyć wybór dla każdego wiersza mapowania widoku danych tabeli, wywołaj metodę withTable konstruktora wyboru.

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

Kod wizualizacji iteruje wiersze tabeli, a każdy wiersz wywołuje metodę withTable tabeli. withTable Parametry metody to table obiekt i indeks wiersza tabeli.

Tworzenie wyborów dla mapowania widoku danych macierzy

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

W przykładzie nodeWalker cyklicznie wywołuje każdy węzeł i węzeł podrzędny.

nodeWalker tworzy nodeSelection obiekt w każdym wywołaniu. Każda z nich nodeSelection reprezentuje selection odpowiednie węzły.

Wybieranie punktów danych w celu wycinka innych wizualizacji

W tym przykładzie utworzyliśmy procedurę obsługi kliknięć dla elementów przycisku. Procedura obsługi wywołuje metodę select menedżera wyboru i przekazuje obiekt zaznaczenia.

button.addEventListener("click", () => {
    // handle click event to apply correspond selection
    this.selectionManager.select(categorySelectionId);
});

Interfejs select metody:

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

Metoda select może akceptować tablicę wyborów. Dzięki temu wizualizacja może jednocześnie wybrać kilka punktów danych. Drugi parametr , multiSelectjest odpowiedzialny za wybór wielokrotny. Jeśli multiSelect wartość ma wartość true, usługa Power BI nie wyczyści poprzedniego stanu zaznaczenia, gdy zastosuje bieżące zaznaczenie. Jeśli wartość ma wartość false, poprzednie zaznaczenie zostanie zastąpione.

Typowym przykładem użycia multiSelect jest obsługa stanu przycisku Ctrl na zdarzeniu kliknięcia. Po naciśnięciu klawisza Ctrl w dół można wybrać więcej niż jeden obiekt.

button.addEventListener("click", (mouseEvent) => {
    const multiSelect = (mouseEvent as MouseEvent).ctrlKey;
    this.selectionManager.select(seriesSelectionId, multiSelect);
});