Udostępnij za pośrednictwem


Interfejs API formatowania obiektów (wersja zapoznawcza)

formatowanie obiektu on-object umożliwia użytkownikom szybkie i łatwe modyfikowanie formatu wizualizacji przez bezpośrednie wybranie elementów, które mają zostać zmodyfikowane. Po wybraniu elementu okienko formatowania automatycznie przechodzi i rozwija określone ustawienie formatowania dla wybranego elementu. Aby uzyskać więcej informacji na temat formatowania obiektów, zobacz formatowanie obiektów w programie Power BI Desktop.

Aby dodać te funkcje do wizualizacji, każda wizualizacja musi podać opcję stylu podwybierz i skrót dla każdego regionu, który można wybrać.

Nuta

  • Wizualizacje, które obsługują formatowanie obiektów, muszą implementować getFormattingModel API, który jest dostępny z interfejsu API w wersji 5.1.
  • Jeśli używasz modelu powerbi-visuals-utils-formattingmodel, użyj co najmniej wersji 6.0.0.

Tworzenie środowiska obiektu lokalnego

Użyj usługi podwybierz, gdy użytkownik wybierze element z możliwością wyboru podrzędnego, aby wysłać usługę Power BI jako podwybór. Podaj style i skróty podwybierz przy użyciu interfejsu API podwybierz . Pomocnik podwybierz może służyć do uproszczenia procesu.

Tryb formatowania

Tryb formatowania to nowy tryb, w którym użytkownik może włączyć i wyłączyć formatowanie onObject w trybie tworzenia. Wizualizacja zostanie zaktualizowana o stan trybu formatowania w opcjach aktualizacji. Opcje aktualizacji obejmują również aktualnie wybrane podwybierz jako CustomVisualSubSelection.

Jak zaimplementować interfejs API formatowania obiektów

Plik możliwości

W pliku capabilites.json dodaj następujące właściwości, aby zadeklarować, że wizualizacja obsługuje formatowanie obiektu lokalnego:

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

Interfejs IVisual

Wizualizacja musi zaimplementować interfejs VisualOnObjectFormatting w ramach interfejsu IVisual.

VisualOnObjectFormatting zawiera trzy metody:

getSubSelectionStyles

Każda wizualizacja jest wymagana do zaimplementowania metody getSubSelectionStyles, która jest wywoływana, gdy podwybierze element jest wybierany. Metoda getSubSelectionStyles jest dostarczana z bieżącymi elementami wybranymi jako tablica CustomVisualSubSelection i oczekuje się, że zwróci obiekt SubSelectionStyles lub undefined.

Istnieją trzy kategorie stylów podwybierz, które obejmują większość scenariuszy:

  • Tekst
  • Tekst liczbowy
  • Kształt

Każdy obiekt SubSelectionStyles zapewnia użytkownikowi inne środowisko modyfikowania stylu elementu.

getSubSelectionShortcuts

Aby zapewnić więcej opcji dla użytkownika, wizualizacja musi zaimplementować metodę getSubSelectionShortcuts. Ta metoda zwraca VisualSubSelectionShortcuts lub undefined. Ponadto w przypadku podania SubSelectionShortcuts należy również podać VisualNavigateSubSelectionShortcut, aby po wybraniu przez użytkownika elementu i otwarciu okienka formatowania okienko automatycznie przewijało się do odpowiedniej karty.

Istnieje kilka skrótów do podwybierz, aby zmodyfikować stan wizualizacji. Każdy z nich definiuje element menu w menu kontekstowym z odpowiednią etykietą.

Sub-Selection menu uściślania: menu uściślania obiektu on-object udostępnia metodę wyboru żądanego podwyboru, gdy nie jest jasne, który element wizualizacji jest wybierany. Dzieje się tak często, gdy użytkownik podwybierze tło wizualizacji. Aby niejednoznaczne menu przedstawiało więcej wyborów podsieciowych, wizualizacja musi dostarczyć wszystkie wybory podsieci za pośrednictwem metody getSubSelectables.

getSubSelectables

Aby udostępnić wybory podrzędne do menu uściślania, wizualizacja musi zaimplementować metodę getSubSelectables. Ta metoda jest udostępniana opcjonalny argument filterType typu SubSelectionStylesType i zwraca tablicę CustomVisualSubSelection lub undefined. Jeśli HTMLSubSelectionHelper jest używany do tworzenia podwybór, HTMLSubSelectionHelper.getSubSelectables() metody można użyć do zbierania elementów podrzędnych z modelu DOM.

Sub-Selection bezpośrednie edytowanie tekstu: za pomocą formatowania On-Object, możesz kliknąć dwukrotnie tekst elementu wybieranego podselektowego, aby bezpośrednio go edytować. Aby zapewnić możliwość edycji bezpośredniej, należy podać RectangleSubSelectionOutline z odpowiednią właściwością cVDirectEdit wypełniona obiektem SubSelectableDirectEdit. Konspekt można podać jako konspekt niestandardowy lub, jeśli używasz HTMLSubSelectionHelper możesz użyć atrybutu SubSelectableDirectEdit. (Zobacz atrybuty udostępniane przez element HTMLSubSelectionHelper)

Dodawanie bezpośredniej edycji dla określonego punktu danych (przy użyciu selektorów) nie jest jeszcze obsługiwane.

FormattingId, interfejs

Poniższy interfejs służy do odwołowania się do skrótów i stylów subSelection.

interface FormattingId {
            objectName: string;
            propertyName: string;
            selector?: powerbi.data.Selector;
        }
  • objectName: nazwa obiektu zadeklarowana w capabilities.json.
  • propertyName: nazwa właściwości obiektu zadeklarowana w capabilities.json.
  • selektor: jeśli punkt danych ma identyfikator selectionId, użyj selectionId.getSelector(), ten selektor musi być taki sam, jak w przypadku wycinka modelu formatowania.

Przykłady

W tym przykładzie utworzymy wizualizację niestandardową zawierającą dwa obiekty, colorSelector i directEdit. Używamy HTMLSubSelectionHelper z narzędzia onobjectFormatting do obsługi większości zadań podrzędnychWybierania. Aby uzyskać więcej informacji, zobacz on-object utils.

Najpierw tworzymy karty dla okienka formatowania i udostępniamy subSelectionShortcuts i style dla każdego podwybór.

Definiowanie obiektów

Zdefiniuj obiekty i zadeklaruj, że wizualizacja obsługuje formatowanie OnObject w 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,

Tworzenie kart formatowania

Skompiluj karty formatowania przy użyciu narzędzi formatowaniaModel.

Ustawienia karty selektora kolorów

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

Dodaj metodę do formatowaniaUstawienia, aby umożliwić dynamiczne wypełnianie wycinków dla obiektu colorSelector (naszych punktów danych).

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

Przekazujemy selektor określonego punktu danych w polu selektora. Ten selektor jest używany podczas implementowania interfejsów API pobierania obiektu OnObject.

Ustawienia karty edycji bezpośredniej

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

Używanie atrybutów pomocnika podwybierz

Dodaj atrybuty HTMLSubSelectionHelper do naszych obiektów. Aby sprawdzić, które atrybuty zapewniają atrybuty elementu HTMLSubSelectionHelper, zapoznaj się z dokumentacją narzędzia obiektów .

  • Dla atrybutu 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 używa atrybutu SubSelectableDirectEditAttr, aby podać odwołanie directEdit do konspektu directEdit, więc bezpośrednia edycja rozpoczyna się po dwukrotnym kliknięciu elementu przez użytkownika.

    Zrzut ekranu przedstawiający sposób działania pomocnika podwybierz.

  • Dla elementu colorSelector:

    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)
    
    

Definiowanie odwołań

Zdefiniuj następujący interfejs, aby uprościć przykłady:

Nuta

Podany cardUid powinien być taki sam jak podany dla interfejsu API getFormattingModel. Jeśli na przykład używasz modelu formatowania powerbi-visuals-utils, podaj cardUid jako visual-cardName-card, gdzie cardName jest nazwą przypisaną do tej karty w ustawieniach modelu formatowania. W przeciwnym razie podaj go jako identyfikator Visual-cardUid przypisany do tej karty.

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

W tym przykładzie utwórz wyliczenie dla nazw obiektów:

const enum BarChartObjectNames {
    ColorSelector = 'colorSelector',
    DirectEdit = 'directEdit'
}
  • Odwołania do obiektu 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'
    }
};
  • Dla colorSelector:
const colorSelectorReferences: References = {
    cardUid: 'Visual-colorSelector-card',
    groupUid: 'colorSelector-group',
    fill: {
        objectName: BarChartObjectNames.ColorSelector,
        propertyName: 'fill'
    }
};

Implementowanie interfejsów API

Teraz zaimplementujmy interfejsy API pobierania dla formatowania onObject i podajmy je w obiekcie visualOnObjectFormatting:

  1. W kodzie konstruktora podaj metody get w obiekcie 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. Zaimplementuj skróty getSubSelection i styl dla elementu colorSelector:

    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'
                }
            ];
        }
    

    Powyższy skrót zwraca odpowiedni element menu w menu kontekstowym i dodaje następujące funkcje:

    • VisualShortcutType.Navigate: gdy użytkownik wybierze jeden z pasków (punkt danych), a okienko formatowania jest otwarte, okienko formatowania przewija kartę selektora kolorów i otwiera je
    • VisualShortcutType.Reset: dodaje skrót resetowania do menu kontekstowego. Jest on włączony, jeśli kolor wypełnienia został zmieniony.
    private getColorSelectorStyles(subSelections: CustomVisualSubSelection[]): SubSelectionStyles {
            const selector = subSelections[0].customVisualObjects[0].selectionId?.getSelector();
            return {
                type: SubSelectionStylesType.Shape,
                fill: {
                    label: 'Fill',
                    reference: {
                        ...colorSelectorReferences.fill,
                     selector
                    },
                },
            };
        }
    

Gdy użytkownik kliknie prawym przyciskiem myszy pasek, zostanie wyświetlone następujące polecenie:

Zrzut ekranu przedstawiający interfejs użytkownika, gdy użytkownik kliknie prawym przyciskiem myszy pasek.

Podczas zmieniania koloru:

Zrzut ekranu przedstawiający zmianę koloru.

Skróty podsekcji

Aby zaimplementować skróty i style subSelection dla elementu 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'
            }
        ];
    }

Ten skrót dodaje odpowiedni element menu w menu kontekstowym i dodaje następujące funkcje:

  • VisualShortcutType.Reset: dodaje reset do domyślnego elementu w menu kontekstowym, gdy jedna z właściwości podanych w relatedResetFormattingIds zmienia tablicę.
  • VisualShortcutType.Toggle: dodaje opcje Usuwania do menu kontekstowego. Po kliknięciu przełącznik directEdit karty jest wyłączony.
  • VisualShortcutType.Picker: dodaje opcję w menu kontekstowym, aby wybrać między prawą i lewą, ponieważ dodaliśmy wycinek pozycji na karcie formatowania dla directEdit.
  • VisualShortcutType.Navigate: po otwarciu okienka formatowania użytkownik wybiera element directEdit, okienko formatowania przewija i otwiera kartę 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'
            }
        }
    }

Udostępniliśmy odpowiednie właściwości, gdy dodaliśmy je w formacieSettings.

Na poniższej ilustracji przedstawiono wygląd interfejsu użytkownika po kliknięciu prawym przyciskiem myszy elementu directEdit:

Zrzut ekranu przedstawiający interfejs edycji bezpośredniej.

Lokalizacji

Wizualizacja powinna obsługiwać lokalizację i udostępniać zlokalizowane ciągi.

Zasoby usługi GitHub

  • Wszystkie interfejsy formatowania obiektów można znaleźć w pliku (link do udostępnienia po wydaniu interfejsu API) w on-object-formatting-api.d.ts
  • Zalecamy użycie narzędzia [on object utils], które obejmują element [HTMLSubSelectionHelper](link do udostępnienia po wydaniu interfejsu API)
  • Przykład wizualizacji niestandardowej SampleBarChart korzystających z interfejsu API w wersji 5.8.0 i implementuje obsługę formatowania obiektów przy użyciu narzędzi obiektów w witrynie (link do udostępnienia po wydaniu interfejsu API)