Добавление интерактивности в визуальные элементы путем выбора визуальных элементов Power BI

Power BI предоставляет два способа взаимодействия с визуальными элементами: выбор и фильтрация. В следующем примере показано, как выбрать элемент из одного визуального элемента и уведомить другие визуальные элементы в отчете о новом состоянии выделения.

Интерфейс соответствует объекту Selection :

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

Использование SelectionManager для выбора точек данных

Объект визуального узла предоставляет метод создания экземпляра диспетчера выбора. Диспетчер выбора имеет соответствующий метод для каждого из следующих действий:

  • Выбрать
  • Очистка выделенного фрагмента
  • Показать контекстное меню
  • Сохранение текущих выделенных элементов
  • Проверка состояния выбора

Создание экземпляра диспетчера выбора

Чтобы использовать диспетчер выбора, создайте экземпляр диспетчера выбора. Как правило, визуальные элементы создают экземпляр диспетчера выбора в constructor разделе визуального объекта.

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

Создание экземпляра конструктора выбора

При создании экземпляра диспетчера выбора необходимо создать selections для каждой точки данных визуального элемента. Метод визуального createSelectionIdBuilder узла создает выбор для каждой точки данных. Этот метод возвращает экземпляр объекта с интерфейсом 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;
}

Этот объект имеет соответствующие методы для создания selections для различных типов сопоставлений представлений данных.

Примечание

Методы withTable и withMatrixNode появились в API 2.5.0 визуальных элементов Power BI. Если необходимо использовать выделения для сопоставления табличных или матричных представлений данных, следует обновить API до версии 2.5.0 или более поздней.

Создание выбора для сопоставления представления данных о категориях

Давайте рассмотрим, как выборки представляют сопоставление представлений категориальных данных для примера набора данных:

Производитель Тип Значение
Chrysler Отечественные автомобили 28883
Chrysler Отечественные грузовики 117131
Chrysler Импортные автомобили 0
Chrysler Импортные грузовики 6362
Ford Отечественные автомобили 50032
Ford Отечественные грузовики 122446
Ford Импортные автомобили 0
Ford Импортные грузовики 0
GM Отечественные автомобили 65426
GM Отечественные грузовики 138122
GM Импортные автомобили 197
GM Импортные грузовики 0
Honda Отечественные автомобили 51450
Honda Отечественные грузовики 46115
Honda Импортные автомобили 2932
Honda Импортные грузовики 0
Nissan Отечественные автомобили 51476
Nissan Отечественные грузовики 47343
Nissan Импортные автомобили 5485
Nissan Импортные грузовики 1430
Toyota Отечественные автомобили 55643
Toyota Отечественные грузовики 61227
Toyota Импортные автомобили 20799
Toyota Импортные грузовики 23614

Визуальный элемент использует следующее сопоставление представления данных:

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

В предыдущем примере Manufacturer используется и Type имеет значение columnsrows. Ряд создается путем группировки значений по rows (Type).

Визуальный элемент должен иметь возможность срезать данные по Manufacturer или Type.

Например, если пользователь выбирает ChryslerManufacturer, другие визуальные элементы должны отображать следующие данные:

Производитель Тип Значение
Chrysler Отечественные автомобили 28883
Chrysler Отечественные грузовики 117131
Chrysler Импортные автомобили 0
Chrysler Импортные грузовики 6362

При выборе Import Car пользователем Type (выбирает данные по рядам), другие визуальные элементы должны отображать следующие данные:

Производитель Тип Значение
Chrysler Импортные автомобили 0
Ford Импортные автомобили 0
GM Импортные автомобили 197
Honda Импортные автомобили 2932
Nissan Импортные автомобили 5485
Toyota Импортные автомобили 20799

The visual with selections for categories and series

Чтобы отобразить срезные данные, заполните корзины данных визуального элемента следующим образом:

Data baskets of the visual with selections

В приведенном выше примере Manufacturer как категория (столбцы), Type как ряд (строки) и Sales как Values для ряда.

Примечание

Values требуется для отображения ряда, Values так как в соответствии с сопоставлением представления данных группируются по Rows данным.

Создание выделенных элементов для категорий

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

В предыдущем примере кода выполняется итерацию по всем категориям. В каждой итерации мы вызываем createSelectionIdBuilder создание следующего выбора для каждой категории путем вызова withCategory метода построителя выбора. Метод createSelectionId используется в качестве завершающего метода для возврата созданного объекта selection.

В withCategory методе мы передаваем столбец category, в примере его Manufacturer и индекс элемента category.

Создание элементов выбора для ряда

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

Создание элементов выбора для сопоставления представления табличных данных

Пример сопоставления представления данных таблицы:

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

Чтобы создать выбор для каждой строки сопоставления представления данных таблицы, вызовите withTable метод построителя выбора.

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

Код визуального элемента выполняет перебор строк таблицы, и каждая строка вызывает метод withTable таблицы. Параметры метода withTable — это объект table и индекс строки таблицы.

Создание элементов выбора для сопоставления представления матричных данных

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

В примере nodeWalker рекурсивно вызывает каждый узел и дочерний узел.

nodeWalkernodeSelection создает объект для каждого вызова. Каждый nodeSelection представляет selection собой соответствующие узлы.

Выбор точек данных для сегментации других визуальных элементов

В этом примере мы создали обработчик нажатия для элементов кнопки. Обработчик вызывает select метод диспетчера выделения и передает объект выделения.

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

Интерфейс select метода:

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

Метод select может принимать массив выделенных фрагментов. Это позволяет визуальному элементу одновременно выбрать несколько точек данных. Второй параметр, multiSelectотвечает за выбор нескольких элементов. Если multiSelect задано значение true, Power BI не очищает предыдущее состояние выделения при применении текущего выделения. Если значение равно false, предыдущий выделенный фрагмент будет перезаписан.

Типичный пример использования multiSelect — обработка состояния кнопки CTRL для события нажатия. Удерживая нажатой клавишу CTRL, можно выбрать несколько объектов.

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

Дальнейшие действия