Поделиться через


API форматирования в объекте (предварительная версия)

форматирование в объекте позволяет пользователям быстро и легко изменять формат визуальных элементов путем прямого выбора элементов, которые они хотят изменить. При выборе элемента область форматирования автоматически перемещается и расширяет определенный параметр форматирования для выбранного элемента. Дополнительные сведения о форматировании в объекте см. в форматировании объекта в Power BI Desktop.

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

Заметка

  • Визуальные элементы, поддерживающие форматирование объектов, должны реализовать API getFormattingModel, который доступен из API версии 5.1.
  • Если вы используете powerbi-visuals-utils-formattingmodel, используйте по крайней мере версию 6.0.0.

Создание интерфейса в объекте

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

Режим форматирования

Режим форматирования — это новый режим, в котором пользователь может включить и отключить форматирование onObject в режиме разработки. Визуальный элемент обновляется с состоянием режима форматирования в параметрах обновления. Параметры обновления также включают в себя выбранный в данный момент вложенный выбор как CustomVisualSubSelection.

Реализация API форматирования в объекте

Файл возможностей

В файле capabilites.json добавьте следующие свойства, чтобы объявить, что визуальный элемент поддерживает форматирование в объекте:

{
  "supportsOnObjectFormatting": true,
  "enablePointerEventsFormatMode": true,
}

Интерфейс IVisual

Визуальный элемент должен реализовать интерфейс VisualOnObjectFormatting в составе интерфейса IVisual.

VisualOnObjectFormatting содержит три метода:

getSubSelectionStyles

Каждый визуальный элемент требуется для реализации метода getSubSelectionStyles, который вызывается при выборе вложенного элемента. Метод getSubSelectionStyles предоставляется текущими вложенными элементами в виде массива CustomVisualSubSelection и, как ожидается, возвращает объект SubSelectionStyles или undefined.

Существует три категории стилей вложенных выборов, охватывающих большинство сценариев:

  • СМС
  • Числовый текст
  • Форма

Каждый SubSelectionStyles объект предоставляет разные возможности для пользователя для изменения стиля элемента.

getSubSelectionShortcuts

Чтобы предоставить пользователю дополнительные возможности, визуальный элемент должен реализовать метод getSubSelectionShortcuts. Этот метод возвращает VisualSubSelectionShortcuts или undefined. Кроме того, если предоставляются SubSelectionShortcuts, необходимо также указать VisualNavigateSubSelectionShortcut, чтобы, когда пользователь подбирает элемент и область форматирования открывается, панель автоматически прокручивается до соответствующей карточки.

Существует несколько сочетаний клавиш для изменения визуального состояния. Каждый определяет элемент меню в контекстном меню с соответствующей меткой.

Sub-Selection меню disambiguation: меню "Дисамбигация в объекте" предоставляет метод для пользователей, чтобы выбрать нужный вложенный выбор, если не ясно, какой визуальный элемент выбирается. Это часто происходит, когда пользователь подбирает фон визуального элемента. Чтобы неявное меню было представлено больше вложенных выборов, визуальный элемент должен предоставить все вложенные выборы с помощью метода getSubSelectables.

getSubSelectables

Чтобы предоставить вложенные выборы в меню диамбигуации, визуальный элемент должен реализовать метод getSubSelectables. Этот метод предоставляет необязательный аргумент filterType типа SubSelectionStylesType и возвращает массив CustomVisualSubSelection или undefined. Если HTMLSubSelectionHelper используется для создания подселектора, метод HTMLSubSelectionHelper.getSubSelectables() можно использовать для сбора вложенных элементов из DOM.

Sub-Selection прямое редактирование текста: с форматированием в объекте можно дважды щелкнуть текст выбранного дочернего элемента, чтобы напрямую изменить его. Чтобы предоставить возможность прямого редактирования, необходимо предоставить RectangleSubSelectionOutline с соответствующим свойством cVDirectEdit, заполненным объектом SubSelectableDirectEdit. Структура может быть предоставлена как настраиваемая структура или, если вы используете HTMLSubSelectionHelper можно использовать атрибут SubSelectableDirectEdit. (См. атрибуты, предоставляемые HTMLSubSelectionHelper)

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

Интерфейс FormattingId

Следующий интерфейс используется для ссылки на сочетания клавиш и стили subSelection.

interface FormattingId {
            objectName: string;
            propertyName: string;
            selector?: powerbi.data.Selector;
        }
  • objectName: имя объекта, объявленное в capabilities.json.
  • propertyName: имя свойства объекта, объявленного в capabilities.json.
  • селектор: если в точке данных есть идентификатор selectionId, используйте selectionId.getSelector(), этот селектор должен совпадать с указанным для среза модели форматирования.

Примеры

В этом примере мы создадим пользовательский визуальный элемент с двумя объектами, colorSelector и directEdit. Мы используем HTMLSubSelectionHelper из onobjectFormatting utils, чтобы обрабатывать большую часть задания subSelection. Дополнительные сведения см. в .

Во-первых, мы создадим карточки для области форматирования и предоставляем подселекцияShortcuts и стили для каждого подзабираемого.

Определение объектов

Определите объекты и объявите, что визуальный элемент поддерживает форматирование OnObject в capabilities.json:

"objects": {
      "directEdit": {
      "properties": {
        "show": {
          "displayName": "Show",
          "type": {
            "bool": true
          }
        },
        "textProperty": {
          "displayName": "Text",
          "type": {
            "text": true
          }
        },
        "fontFamily": {
          "type": {
            "formatting": {
              "fontFamily": true
            }
          }
        },
        "fontSize": {
          "type": {
            "formatting": {
              "fontSize": true
            }
          }
        },
        "bold": {
          "type": {
            "bool": true
          }
        },
        "italic": {
          "type": {
            "bool": true
          }
        },
        "underline": {
          "type": {
            "bool": true
          }
        },
        "fontColor": {
          "displayName": "Font Color",
          "type": {
            "fill": {
              "solid": {
                "color": true
              }
            }
          }
        },
        "background": {
          "displayName": "Background",
          "type": {
            "fill": {
              "solid": {
                "color": true
              }
            }
          }
        },
        "position": {
          "displayName": "Position",
          "type": {
            "enumeration": [
              { "displayName": "Left", "value": "Left" }, { "displayName": "Right", "value": "Right" }
            ]
          }
        }
      }
    },
    "colorSelector": {
      "displayName": "Data Colors",
      "properties": {
        "fill": {
          "displayName": "Color",
          "type": {
            "fill": {
              "solid": {
                "color": true
              }
            }
          }
        }
      }
    },
   },
  "supportsOnObjectFormatting": true,
  "enablePointerEventsFormatMode": true,

Создание карт форматирования

Создайте карточки форматирования с помощью форматирования.

Параметры карточки селектора цвета

class ColorSelectorCardSettings extends Card {
    name: string = "colorSelector";
    displayName: string = "Data Colors";
    slices = [];
}

Добавьте метод в форматtingSetting, чтобы мы могли динамически заполнять срезы для объекта colorSelector (наши точки данных).

populateColorSelector(dataPoints: BarChartDataPoint[]) {
        let slices: formattingSettings.ColorPicker[] = this.colorSelector.slices;
        if (dataPoints) {
            dataPoints.forEach(dataPoint => {
                slices.push(new formattingSettings.ColorPicker({
                    name: "fill",
                    displayName: dataPoint.category,
                    value: { value: dataPoint.color },
                    selector: dataPoint.selectionId.getSelector(),
                }));
            });
        }
    }

Мы передаем селектор определенной точки данных в поле селектора. Этот селектор используется при реализации API получения объекта OnObject.

Параметры карточки прямого редактирования

class DirectEditSettings extends Card {
    displayName = 'Direct Edit';
    name = 'directEdit';
    private minFontSize: number = 8;
    private defaultFontSize: number = 11;
    show = new formattingSettings.ToggleSwitch({
        name: "show",
        displayName: undefined,
        value: true,
    });
    topLevelSlice = this.show;
    textProperty = new formattingSettings.TextInput({
        displayName: "Text Property",
        name: "textProperty",
        value: "What is your quest?",
        placeholder: ""
    });
    position = new formattingSettings.ItemDropdown({
        name: 'position',
        items: [{ displayName: 'Left', value: 'Left' }, { displayName: 'Right', value: 'Right' }],
        value: { displayName: 'Right', value: 'Right' }
    });
    font = new formattingSettings.FontControl({
        name: "font",
        displayName: 'Font',
        fontFamily: new formattingSettings.FontPicker({
            name: "fontFamily",
            displayName: "Font Family",
            value: "Segoe UI, wf_segoe-ui_normal, helvetica, arial, sans-serif"
        }),
        fontSize: new formattingSettings.NumUpDown({
            name: "fontSize",
            displayName: "Font Size",
            value: this.defaultFontSize,
            options: {
                minValue: {
                    type: powerbi.visuals.ValidatorType.Min,
                    value: this.minFontSize,
                }
            }
        }),
        bold: new formattingSettings.ToggleSwitch({
            name: 'bold',
            displayName: "Font Size",
            value: true
        }),
        italic: new formattingSettings.ToggleSwitch({
            name: 'italic',
            displayName: "Font Size",
            value: true
        }),
        underline: new formattingSettings.ToggleSwitch({
            name: 'underline',
            displayName: "Font Size",
            value: true
        })
    });
    fontColor = new formattingSettings.ColorPicker({
        name: "fontColor",
        displayName: "Color",
        value: { value: "#000000" }
    });
    background = new formattingSettings.ColorPicker({
        name: "background",
        displayName: "Color",
        value: { value: "#FFFFFF" }
    });
    slices = [this.show, this.textProperty, this.font, this.fontColor, this.background, this.position];
}

Использование вспомогательных атрибутов вложенного выбора

Добавьте атрибуты HTMLSubSelectionHelper в объекты. Чтобы узнать, какие атрибуты предоставляют HTMLSubSelectionHelper, проверьте документацию по объекту.

  • Для атрибута directEdit:

    import {
       HtmlSubSelectableClass, HtmlSubSelectionHelper, SubSelectableDirectEdit as SubSelectableDirectEditAttr,
       SubSelectableDisplayNameAttribute, SubSelectableObjectNameAttribute, SubSelectableTypeAttribute 
    } from 'powerbi-visuals-utils-onobjectutils';
    
    const DirectEdit: powerbi.visuals.SubSelectableDirectEdit = {
        reference: {
            objectName: 'directEdit',
            propertyName: 'textProperty'
        },
        style: SubSelectableDirectEditStyle.Outline,
    };
    private visualDirectEditSubSelection = JSON.stringify(DirectEdit);
    
    this.directEditElement
                .classed('direct-edit', true)
                .classed('hidden', !this.formattingSettings.directEditSettings.show.value)
                .classed(HtmlSubSelectableClass, options.formatMode && this.formattingSettings.directEditSettings.show.value)
                .attr(SubSelectableObjectNameAttribute, 'directEdit')
                .attr(SubSelectableDisplayNameAttribute, 'Direct Edit')
                .attr(SubSelectableDirectEditAttr, this.visualDirectEditSubSelection)
    

    HTMLSubSelectionHelper использует атрибут SubSelectableDirectEditAttr для предоставления ссылки directEdit структуры directEdit, поэтому прямое изменение начинается, когда пользователь дважды щелкает элемент.

    снимок экрана, показывающий, как работает вспомогательный элемент вложенного выбора.

  • Для цветаSelector:

    barSelectionMerged
              .attr(SubSelectableObjectNameAttribute, 'colorSelector')
              .attr(SubSelectableDisplayNameAttribute, (dataPoint: BarChartDataPoint) => this.formattingSettings.colorSelector.slices[dataPoint.index].displayName)
              .attr(SubSelectableTypeAttribute, powerbi.visuals.SubSelectionStylesType.Shape)
              .classed(HtmlSubSelectableClass, options.formatMode)
    
    

Определение ссылок

Определите следующий интерфейс, чтобы упростить примеры:

Заметка

Предоставленный cardUid должен совпадать с указанным для API getFormattingModel. Например, если вы используете powerbi-visuals-utils-formattingmodel, укажите cardUid как карточки Visual-cardName, где имя карточки — это имя, назначенное этой карточке в параметрах модели форматирования. В противном случае укажите его как Visual-cardUid, назначенный этой карте.

interface References {
    cardUid?: string;
    groupUid?: string;
    fill?: FormattingId;
    font?: FormattingId;
    fontColor?: FormattingId;
    show?: FormattingId;
    fontFamily?: FormattingId;
    bold?: FormattingId;
    italic?: FormattingId;
    underline?: FormattingId;
    fontSize?: FormattingId;
    position?: FormattingId;
    textProperty?: FormattingId;
}

В этом примере создайте перечисление для имен объектов:

const enum BarChartObjectNames {
    ColorSelector = 'colorSelector',
    DirectEdit = 'directEdit'
}
  • Ссылки на объект directEdit:
const directEditReferences: References = {
    cardUid: 'Visual-directEdit-card',
    groupUid: 'directEdit-group',
    fontFamily: {
        objectName: BarChartObjectNames.DirectEdit,
        propertyName: 'fontFamily'
    },
    bold: {
        objectName: BarChartObjectNames.DirectEdit,
        propertyName: 'bold'
    },
    italic: {
        objectName: BarChartObjectNames.DirectEdit,
        propertyName: 'italic'
    },
    underline: {
        objectName: BarChartObjectNames.DirectEdit,
        propertyName: 'underline'
    },
    fontSize: {
        objectName: BarChartObjectNames.DirectEdit,
        propertyName: 'fontSize'
    },
    fontColor: {
        objectName: BarChartObjectNames.DirectEdit,
        propertyName: 'fontColor'
    },
    show: {
        objectName: BarChartObjectNames.DirectEdit,
        propertyName: 'show'
    },
    position: {
        objectName: BarChartObjectNames.DirectEdit,
        propertyName: 'position'
    },
    textProperty: {
        objectName: BarChartObjectNames.DirectEdit,
        propertyName: 'textProperty'
    }
};
  • Для colorSelector:
const colorSelectorReferences: References = {
    cardUid: 'Visual-colorSelector-card',
    groupUid: 'colorSelector-group',
    fill: {
        objectName: BarChartObjectNames.ColorSelector,
        propertyName: 'fill'
    }
};

Реализация API

Теперь давайте реализуем API get для форматирования onObject и предоставьте их в visualOnObjectFormatting:

  1. В коде конструктора укажите методы получения в visualOnObjectFormatting:

    public visualOnObjectFormatting: powerbi.extensibility.visual.VisualOnObjectFormatting;
    constructor(options: VisualConstructorOptions) {
            this.subSelectionHelper = HtmlSubSelectionHelper.createHtmlSubselectionHelper({
                     hostElement: options.element,
                     subSelectionService: options.host.subSelectionService,
                     selectionIdCallback: (e) => this.selectionIdCallback(e),
                });
    
     this.visualOnObjectFormatting = {
                    getSubSelectionStyles: (subSelections) => this.getSubSelectionStyles(subSelections),
                    getSubSelectionShortcuts: (subSelections, filter) => this.getSubSelectionShortcuts(subSelections, filter),
                    getSubSelectables: (filter) => this. getSubSelectables(filter)
                }
       }
    
    private getSubSelectionStyles(subSelections: CustomVisualSubSelection[]): powerbi.visuals.SubSelectionStyles | undefined {
            const visualObject = subSelections[0]?.customVisualObjects[0];
            if (visualObject) {
                switch (visualObject.objectName) {
                    case BarChartObjectNames.ColorSelector:
                        return this.getColorSelectorStyles(subSelections);
                     case BarChartObjectNames.DirectEdit:
                        return this.getDirectEditStyles();
                }
            }
        }
    
    private getSubSelectionShortcuts(subSelections: CustomVisualSubSelection[], filter: SubSelectionShortcutsKey | undefined):    VisualSubSelectionShortcuts | undefined {
            const visualObject = subSelections[0]?.  customVisualObjects[0];
            if (visualObject) {
                switch (visualObject.objectName) {
                    case BarChartObjectNames.ColorSelector:
                        return this.getColorSelectorShortcuts(subSelections);
                    case BarChartObjectNames.DirectEdit:
                        return this.getDirectEditShortcuts();
                }
            }
        }
    
  2. Реализуйте сочетания клавиш getSubSelection и стиль для цветаSelector:

    private getColorSelectorShortcuts(subSelections:  CustomVisualSubSelection[]): VisualSubSelectionShortcuts   {
            const selector = subSelections[0].customVisualObjects[0].selectionId?.getSelector();
            return [
                {
                    type: VisualShortcutType.Reset,
                    relatedResetFormattingIds: [{
                        ...colorSelectorReferences.fill,
                        selector
                    }],
                },
                {
                    type: VisualShortcutType.Navigate,
                    destinationInfo: { cardUid: colorSelectorReferences.cardUid },
                    label: 'Color'
                }
            ];
        }
    

    Приведенный выше ярлык возвращает соответствующий пункт меню в контекстном меню и добавляет следующие функции:

    • VisualShortcutType.Navigate: когда пользователь выбирает одну из полос (точка данных), а область форматирования открыта, область форматирования прокручивается до карточки селектора цветов и открывает ее.
    • VisualShortcutType.Reset: добавляет ярлык сброса в контекстное меню. Он включен, если цвет заливки был изменен.
    private getColorSelectorStyles(subSelections: CustomVisualSubSelection[]): SubSelectionStyles {
            const selector = subSelections[0].customVisualObjects[0].selectionId?.getSelector();
            return {
                type: SubSelectionStylesType.Shape,
                fill: {
                    label: 'Fill',
                    reference: {
                        ...colorSelectorReferences.fill,
                     selector
                    },
                },
            };
        }
    

Когда пользователь щелкает правой кнопкой мыши панель, появляется следующее:

снимок экрана пользовательского интерфейса при щелчке правой кнопкой мыши пользователя на панели.

При изменении цвета:

снимок экрана: изменение цвета.

Сочетания клавиш подраздела

Чтобы реализовать сочетания клавиш и стили вложенных элементов для directEdit, выполните следующие действия:

private getDirectEditShortcuts(): VisualSubSelectionShortcuts {
        return [
            {
                type: VisualShortcutType.Reset,
                relatedResetFormattingIds: [
                    directEditReferences.bold,
                    directEditReferences.fontFamily,
                    directEditReferences.fontSize,
                    directEditReferences.italic,
                    directEditReferences.underline,
                    directEditReferences.fontColor,
                    directEditReferences.textProperty
                ]
            },
            {
                type: VisualShortcutType.Toggle,
                relatedToggledFormattingIds: [{
                    ...directEditReferences.show,
                }],
                ...directEditReferences.show,
                disabledLabel: 'Delete',
            },
            {
                type: VisualShortcutType.Picker,
                ...directEditReferences.position,
                label: 'Position'
            },
            {
                type: VisualShortcutType.Navigate,
                destinationInfo: { cardUid: directEditReferences.cardUid },
                label: 'Direct edit'
            }
        ];
    }

Этот ярлык добавляет соответствующий пункт меню в контекстное меню и добавляет следующие функции:

  • VisualShortcutType.Reset: добавляет сброс к элементу по умолчанию в контекстное меню, когда одно из свойств, предоставленных в связанном массивеResetFormattingIds.
  • VisualShortcutType.Toggle: добавляет параметры удаления в контекстное меню. При щелчке переключатель для directEdit карточка отключена.
  • VisualShortcutType.Picker: добавляет параметр в контекстное меню, чтобы выбрать между правым и левым, так как мы добавили срез позиции в карточке форматирования для directEdit.
  • VisualShortcutType.Navigate: когда область форматирования открыта, а пользователь выбирает элемент directEdit, область форматирования прокручивается и открывает карточку directEdit.
private getDirectEditStyles(): SubSelectionStyles {
        return {
            type: powerbi.visuals.SubSelectionStylesType.Text,
            fontFamily: {
                reference: {
                    ...directEditReferences.fontFamily
                },
                label: 'font family'
            },
            bold: {
                reference: {
                    ...directEditReferences.bold
                },
                label: 'bold'
            },
            italic: {
                reference: {
                    ...directEditReferences.italic
                },
                label: 'italic'
            },
            underline: {
                reference: {
                    ...directEditReferences.underline
                },
                label: 'underline'
            },
            fontSize: {
                reference: {
                    ...directEditReferences.fontSize
                },
                label: 'font size'
            },
            fontColor: {
                reference: {
                    ...directEditReferences.fontColor
                },
                label: 'font color'
            },
            background: {
                reference: {
                    objectName: 'directEdit',
                    propertyName: 'background'
                },
                label: 'background'
            }
        }
    }

Мы предоставили соответствующие свойства, как мы добавили их в форматированиеSettings.

На следующем рисунке показано, как выглядит пользовательский интерфейс при щелчке правой кнопкой мыши на элемент directEdit:

снимок экрана с интерфейсом прямого редактирования.

Локализация

Визуальный элемент должен обрабатывать локализацию и предоставлять локализованные строки.

Ресурсы GitHub

  • Все интерфейсы форматирования объектов можно найти в разделе (ссылка, предоставляемая после выпуска API) в on-object-formatting-api.d.ts
  • Рекомендуется использовать [on object utils], включающую [HTMLSubSelectionHelper](ссылку, которую необходимо предоставить после выпуска API).
  • Пример пользовательского визуального SampleBarChart, использующего API версии 5.8.0, и реализует поддержку форматирования объектов с помощью объекта utils at (ссылка, которую необходимо предоставить после выпуска API).