Добавление интерактивности в визуальные элементы путем выбора визуальных элементов 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;
}
Выбор точек данных с помощью диспетчера выбора
Объект визуального узла предоставляет метод для создания экземпляра диспетчера выбора. Диспетчер выбора имеет соответствующий метод для каждого из следующих действий:
- Выбрать
- Очистка выделенного фрагмента
- Показать контекстное меню
- Сохранение текущих выделенных фрагментов
- Проверка состояния выделения
Создание экземпляра диспетчера выбора
Чтобы использовать диспетчер выбора, создайте экземпляр диспетчера выбора. Как правило, визуальные элементы создают экземпляр диспетчера 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"
}
}
]
}
}
}
}
]
}
В предыдущем примере имеет значение columns
, Manufacturer
а Type
— .rows
Ряд создается путем группировки значений по rows
(Type
).
Визуальный элемент должен иметь возможность срезать данные с помощью Manufacturer
или Type
.
Например, если пользователь выбирает Chrysler
по Manufacturer
, другие визуальные элементы должны отображать следующие данные:
Производитель | Тип | Значение |
---|---|---|
Chrysler | Отечественные автомобили | 28883 |
Chrysler | Отечественные грузовики | 117131 |
Chrysler | Импортные автомобили | 0 |
Chrysler | Импортные грузовики | 6362 |
Когда пользователь выбирает Import Car
по Type
(выбирает данные по рядам), другие визуальные элементы должны отображать следующие данные:
Производитель | Тип | Значение |
---|---|---|
Chrysler | Импортные автомобили | 0 |
Ford | Импортные автомобили | 0 |
GM | Импортные автомобили | 197 |
Honda | Импортные автомобили | 2932 |
Nissan | Импортные автомобили | 5485 |
Toyota | Импортные автомобили | 20799 |
Чтобы отобразить срезанные данные, заполните корзины данных визуального элемента следующим образом:
В предыдущем примере 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
метод table. Параметрами 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
рекурсивно вызывает каждый узел и дочерний узел.
nodeWalker
создает nodeSelection
объект при каждом вызове. Каждый 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);
});