Tutorial: Erstellen eines Balkendiagramms

In diesem Tutorial erfahren Sie, wie Sie ein visuelles PowerBI-Element entwickeln, das Daten in Form eines einfachen Balkendiagramms anzeigt. Dieses visuelles Element unterstützt nur ein Minimum an Anpassung. Auf anderen Seiten dieser Dokumentation wird erläutert, wie Sie weitere Anpassungen wie Kontextmenüs, Tooltipps und vieles mehr hinzufügen.

In diesem Tutorial lernen Sie, wie die folgenden Aufgaben ausgeführt werden:

  • Definieren der Funktionen Ihres visuellen Elements
  • Verstehen des Quellcodes, der zum Erstellen eines visuellen Elements verwendet wird
  • Rendern des visuellen Elements
  • Hinzufügen von Objekten zum Eigenschaftsbereich
  • Packen des Visuals

Erstellen Ihrer Umgebung

Vergewissern Sie sich, bevor Sie mit der Entwicklung eines Power BI-Visuals beginnen, dass alle in diesem Abschnitt aufgeführten Anforderungen erfüllt sind.

Hinweis

Wenn die D3-JavaScript-Bibliothek nicht im Rahmen Ihres Setups installiert wurde, installieren Sie sie jetzt. Führen Sie in PowerShell Folgendes aus:npm i d3@latest --save

Das Erstellen eines visuellen Balkendiagrammelements umfasst die folgenden Schritte:

  1. Neues Projekt erstellen
  2. Definieren der Datei mit den Funktionencapabilities.json
  3. Erstellen der Visual-API
  4. Verpacken Ihres visuellen Elements – pbiviz.json

Erstellen eines neuen Projekts

Dieses Tutorial soll Ihnen helfen zu verstehen, wie ein visuelles Element strukturiert und geschrieben wird. Sie können diese Anweisungen befolgen, um ein visuelles Balkencode-Element von Grund auf neu zu erstellen, oder Sie können das Quellcoderepository klonen und verwenden, um diesem Tutorial zu folgen, ohne Ihr eigenes visuelles Element zu erstellen.

  1. Öffnen Sie PowerShell, und navigieren Sie zu dem Ordner, in dem Sie das Projekt erstellen möchten.

  2. Geben Sie den folgenden Befehl ein:

    pbiviz new BarChart
    

    Sie sollten nun über einen Ordner namens BarChart verfügen, der die Dateien des visuellen Elements enthält.

  3. Öffnen Sie in VS Code die Datei [tsconfig.json] (visual-project-structure.md#tsconfigjson), und ändern Sie den Namen von „files“ in „src/barChart.ts“.

    "files": [
    "src/barChart.ts"
    ]
    

    Das „files“-Objekt in tsconfig.json verweist auf die Datei, in der die Main-Klasse des visuellen Elements gespeichert ist.

    Ihre endgültige tsconfig.js-Datei sollte so aussehen.

  4. Die Datei package.js enthält eine Liste der Projektabhängigkeiten. Ersetzen Sie Ihre package.json-Datei durch diese hier.

Sie sollten nun über einen neuen Ordner für Ihr visuelles Element mit den folgenden Dateien und Ordnern verfügen:

Screenshot showing the structure of visuals.

Eine ausführliche Erläuterung der Funktion jeder dieser Dateien finden Sie unter Struktur von Visualprojekten in Power BI.

Die beiden Dateien, auf die wir uns in diesem Tutorial konzentrieren, sind die Datei capabilities.json, die das visuelle Element für den Host beschreibt, und die Datei src/barchart.ts, die die API des visuellen Elements enthält.

Definieren von Funktionen

Die Datei capabilities.json ist der Ort, an dem wir Daten an den Host binden. Wir beschreiben die Art der akzeptierten Datenfelder und die Features, über die das visuelle Element verfügen sollte.

Screenshot showing how to bind data in the field bucket.

Definieren von Datenrollen

Variablen werden im Abschnitt dataRoles der Funktionsdatei definiert und gebunden. Unser Balkendiagramm soll zwei Arten von Variablen akzeptieren:

  • Kategoriedaten, die durch die verschiedenen Balken im Diagramm dargestellt werden
  • Numerische Daten oder gemessene Daten, die durch die Höhe der einzelnen Balken dargestellt werden

Vergewissern Sie sich in Visual Studio Code, dass in der Datei capabilities.json das folgende JSON-Fragment im Objekt mit der Bezeichnung „dataRoles“ vorhanden ist.

    "dataRoles": [
        {
            "displayName": "Category Data",
            "name": "category",
            "kind": "Grouping"
        },
        {
            "displayName": "Measure Data",
            "name": "measure",
            "kind": "Measure"
        }
    ],

Zuordnen der Daten

Fügen Sie als Nächstes Datenzuordnung hinzu, um dem Host mitzuteilen, was mit diesen Variablen zu tun ist:

Ersetzen Sie die Inhalte des Objekts „dataViewMappings“ durch folgenden Code:

"dataViewMappings": [
        {
            "conditions": [
                {
                    "category": {
                        "max": 1
                    },
                    "measure": {
                        "max": 1
                    }
                }
            ],
            "categorical": {
                "categories": {
                    "for": {
                        "in": "category"
                    }
                },
                "values": {
                    "select": [
                        {
                            "bind": {
                                "to": "measure"
                            }
                        }
                    ]
                }
            }
        }
    ],

Der obige Code erstellt „Bedingungen“, dass jedes Datenrollenobjekt stets nur ein Feld enthalten kann. Beachten Sie, dass wir den internen name der Datenrolle verwenden, um auf die einzelnen Felder zu verweisen.

Darüber hinaus legt sie außerdem die Zuordnung der Kategoriedaten fest, sodass jedes Feld der richtigen Variable zugeordnet ist.

Definieren von Objekten für den Eigenschaftsbereich

Der Abschnitt „objects“ der capabilities-Datei ist der Ort, an dem wir die anpassbaren Features definieren, die im Formatbereich angezeigt werden sollen. Diese Features wirken sich nicht auf den Inhalt des Diagramms aus, können jedoch das Aussehen und Verhalten ändern.

Weitere Informationen zu Objekten und ihrer Funktionsweise finden Sie unter Objekte.

Die folgenden Objekte sind optional: Fügen Sie sie hinzu, wenn Sie die optionalen Abschnitte dieses Tutorials zum Hinzufügen von Farben und zum Rendern der X-Achse durchgehen möchten.

Ersetzen Sie den Inhalt des Abschnitts „objects“ durch folgenden Code:

     "objects": {
        "enableAxis": {
            "properties": {
                "show": {
                    "type": {
                        "bool": true
                    }
                },
                "fill": {
                    "type": {
                        "fill": {
                            "solid": {
                                "color": true
                            }
                        }
                    }
                }
            }
        }
     },

Speichern Sie die Datei capabilities.json.

Ihre endgültige Datei capabilities sollte wie die in diesem Beispiel aussehen.

Visual-API

Alle visuellen Elemente beginnen mit einer Klasse, mit der die IVisual-Schnittstelle implementiert wird. Die Datei src/visual.ts ist die Standarddatei, die diese Klasse enthält.

In diesem Tutorial bezeichnen wir unsere IVisual-Datei als barChart.ts. Laden Sie die Datei herunter, und speichern Sie sie im Ordner /src, falls Sie dies noch nicht getan haben. In diesem Abschnitt gehen wir diese Datei im Detail durch und beschreiben die verschiedenen Abschnitte.

Importe

Im ersten Abschnitt der Datei werden die Module importiert, die für dieses Visual benötigt werden. Beachten Sie, dass wir über die visuellen Power BI-Module hinaus auch die d3-Bibliothek importieren.

Die folgenden Module werden in die Datei barChart.ts importiert:

import {
    scaleBand, scaleLinear
} from "d3-scale";
import {
    select as d3Select
} from "d3-selection";
import "./../style/visual.less";

import { axisBottom } from "d3-axis";

import powerbiVisualsApi from "powerbi-visuals-api";
import "regenerator-runtime/runtime";
import powerbi = powerbiVisualsApi;

type Selection<T1, T2 = T1> = d3.Selection<any, T1, any, T2>;

import DataViewCategoryColumn = powerbi.DataViewCategoryColumn;
import DataViewObjects = powerbi.DataViewObjects;
import Fill = powerbi.Fill;
import ISandboxExtendedColorPalette = powerbi.extensibility.ISandboxExtendedColorPalette;
import ISelectionId = powerbi.visuals.ISelectionId;
import IVisual = powerbi.extensibility.IVisual;
import IVisualHost = powerbi.extensibility.visual.IVisualHost;
import PrimitiveValue = powerbi.PrimitiveValue;
import VisualUpdateOptions = powerbi.extensibility.visual.VisualUpdateOptions;
import VisualConstructorOptions = powerbi.extensibility.visual.VisualConstructorOptions;

import { textMeasurementService } from "powerbi-visuals-utils-formattingutils";

import { dataViewWildcard } from "powerbi-visuals-utils-dataviewutils";
import { getCategoricalObjectValue, getValue } from "./objectEnumerationUtility";

Schnittstellen

Als Nächstes definieren wir die ViewModel-Schnittstellen. Die folgenden drei Schnittstellen werden verwendet, um unser visuelles Balkendiagrammelement zu beschreiben:

  • BarChartDataPoint
  • BarChartViewModel
  • BarChartSettings

Diese Schnittstellen werden in der folgenden Weise definiert:

/**
 * Interface for BarCharts viewmodel.
 *
 * @interface
 * @property {BarChartDataPoint[]} dataPoints - Set of data points the visual will render.
 * @property {number} dataMax                 - Maximum data value in the set of data points.
 */
interface BarChartViewModel {
    dataPoints: BarChartDataPoint[];
    dataMax: number;
    settings: BarChartSettings;
}

/**
 * Interface for BarChart data points.
 *
 * @interface
 * @property {number} value             - Data value for point.
 * @property {string} category          - Corresponding category of data value.
 * @property {string} color             - Color corresponding to data point.
 * @property {ISelectionId} selectionId - Id assigned to data point for cross filtering
 *                                        and visual interaction.
 */
interface BarChartDataPoint {
    value: PrimitiveValue;
    category: string;
    color: string;
    strokeColor: string;
    strokeWidth: number;
    selectionId: ISelectionId;
}

/**
 * Interface for BarChart settings.
 *
 * @interface
 * @property {{show:boolean}} enableAxis - Object property that allows axis to be enabled.
*/
interface BarChartSettings {
    enableAxis: {
        show: boolean;
        fill: string;
    };
}

let defaultSettings: BarChartSettings = {
    enableAxis: {
        show: false,
        fill: "#000000",
    }
};

Visuelle Transformation

Beachten Sie, dass jetzt, da die Datenstrukturen definiert sind, wir ihnen Daten mithilfe der visualTransform-Funktion zuweisen müssen. Diese Funktion empfängt Daten aus der Datenansicht und wandelt sie in ein Format um, das vom visuellen Element verwendet werden kann. In diesem Fall wird die oben beschriebene BarChartViewModel-Schnittstelle zurückgegeben.

DataView enthält die Daten, die visualisiert werden sollen. Diese Daten können in unterschiedlicher Form vorliegen, z. B. kategorisch oder tabellarisch. Zum Erstellen eines visuellen Kategorie-Elements wie einem Balkendiagramm verwenden Sie die Eigenschaft categorical (kategorisch) von DataView.

Diese Funktion wird immer dann aufgerufen, wenn das visuelle Element aktualisiert wird.

/**
 * Function that converts queried data into a viewmodel that will be used by the visual.
 *
 * @function
 * @param {VisualUpdateOptions} options - Contains references to the size of the container
 *                                        and the dataView which contains all the data
 *                                        the visual had queried.
 * @param {IVisualHost} host            - Contains references to the host which contains services
 */
function visualTransform(options: VisualUpdateOptions, host: IVisualHost): BarChartViewModel {
    let dataViews = options.dataViews;
    let viewModel: BarChartViewModel = {
        dataPoints: [],
        dataMax: 0,
        settings: <BarChartSettings>{}
    };

    if (!dataViews
        || !dataViews[0]
        || !dataViews[0].categorical
        || !dataViews[0].categorical.categories
        || !dataViews[0].categorical.categories[0].source
        || !dataViews[0].categorical.values
    ) {
        return viewModel;
    }

    let categorical = dataViews[0].categorical;
    let category = categorical.categories[0];
    let dataValue = categorical.values[0];

    let barChartDataPoints: BarChartDataPoint[] = [];
    let dataMax: number;

    let colorPalette: ISandboxExtendedColorPalette = host.colorPalette;
    let objects = dataViews[0].metadata.objects;

    const strokeColor: string = getColumnStrokeColor(colorPalette);

    let barChartSettings: BarChartSettings = {
        enableAxis: {
            show: getValue<boolean>(objects, 'enableAxis', 'show', defaultSettings.enableAxis.show),
            fill: getAxisTextFillColor(objects, colorPalette, defaultSettings.enableAxis.fill),
        }
    };

    const strokeWidth: number = getColumnStrokeWidth(colorPalette.isHighContrast);

    for (let i = 0, len = Math.max(category.values.length, dataValue.values.length); i < len; i++) {
        const color: string = getColumnColorByIndex(category, i, colorPalette);

        const selectionId: ISelectionId = host.createSelectionIdBuilder()
            .withCategory(category, i)
            .createSelectionId();

        barChartDataPoints.push({
            color,
            strokeColor,
            strokeWidth,
            selectionId,
            value: dataValue.values[i],
            category: `${category.values[i]}`,
        });
    }

    dataMax = <number>dataValue.maxLocal;

    return {
        dataPoints: barChartDataPoints,
        dataMax: dataMax,
        settings: barChartSettings,
    };
}

Hinweis

Die nächsten Funktionen in der Datei barChart.ts befassen sich mit Farbe und dem Erstellen der X-Achse. Diese sind optional und werden weiter unten in diesem Tutorial erörtert. Dieses Tutorial wird ab der Funktion IVisual fortgesetzt.

Rendern des visuellen Elements

Nachdem die Daten definiert wurden, rendern wir das visuelle Element mithilfe der BarChart-Klasse, die dieIVisual-Schnittstelle implementiert. Die IVisual-Schnittstelle ist auf der Seite Visual-API beschrieben. Sie enthält eine constructor-Methode, die das visuelle Element erstellt, und eine update-Methode, die bei jedem Neuladen des visuellen Elements aufgerufen wird. Vor dem Rendern des visuellen Elements müssen wir die Elemente der Klasse deklarieren:

export class BarChart implements IVisual {
    private svg: Selection<any>;
    private host: IVisualHost;
    private barContainer: Selection<SVGElement>;
    private xAxis: Selection<SVGElement>;
    private barDataPoints: BarChartDataPoint[];
    private barChartSettings: BarChartSettings;

    private barSelection: d3.Selection<d3.BaseType, any, d3.BaseType, any>;

    static Config = {
        xScalePadding: 0.1,
        solidOpacity: 1,
        transparentOpacity: 1,
        margins: {
            top: 0,
            right: 0,
            bottom: 25,
            left: 30,
        },
        xAxisFontMultiplier: 0.04,
    }
 }

Erstellen des Visuals

Die Konstruktorfunktion wird nur einmal aufgerufen, wenn das visuelle Element zum ersten Mal gerendert wird. Sie erstellt leere SVG-Container für das Balkendiagramm und die X-Achse. Beachten Sie, dass sie die d3-Bibliothek zum Rendern der SVGs verwendet.

/**
     * Creates instance of BarChart. This method is only called once.
     *
     * @constructor
     * @param {VisualConstructorOptions} options - Contains references to the element that will
     *                                             contain the visual and a reference to the host
     *                                             which contains services.
     */
    constructor(options: VisualConstructorOptions) {
        this.host = options.host;

        this.svg = d3Select(options.element)
            .append('svg')
            .classed('barChart', true);

        this.barContainer = this.svg
            .append('g')
            .classed('barContainer', true);

        this.xAxis = this.svg
            .append('g')
            .classed('xAxis', true);
    }

Aktualisieren des visuellen Elements

Die Aktualisierungsmethode wird jedes Mal aufgerufen, wenn sich die Größe des visuellen Elements oder einer seiner Werte ändert.

Skalierung

Wir müssen das visuelle Element skalieren, damit die Anzahl der Balken und aktuellen Werte in die definierten Breiten- und Höhengrenzen des visuellen Elements passt. Dies ähnelt der Aktualisierungsmethode im Kreiskartentutorial.

Zum Berechnen des Maßstabs verwenden wir die Methoden scaleLinear und scaleBand, die zuvor aus der d3-scale-Bibliothek importiert wurden.

Der Wert viewModel.datamax enthält den größten Wert aller aktuellen Datenpunkte. Dieser Wert wird verwendet, um die Höhe der Y-Achse zu bestimmen. Die Skalierung für die Breite der X-Achse wird durch die Anzahl der Kategorien bestimmt, die in der Schnittstelle barchartdatapoint an das visuelle Element gebunden sind.

In Fällen, in denen die X-Achse gerendert wird, verarbeitet dieses visuelle Element auch Wortumbrüche, falls auf der X-Achse nicht genügend Platz zum Schreiben des gesamten Namens vorhanden ist.

Weitere Aktualisierungsfeatures

Neben der Skalierung verarbeitet diese Aktualisierungsmethode auch Auswahlen und Farben. Diese Features sind optional und werden später erläutert:

   /**
     * Updates the state of the visual. Every sequential databinding and resize will call update.
     *
     * @function
     * @param {VisualUpdateOptions} options - Contains references to the size of the container
     *                                        and the dataView which contains all the data
     *                                        the visual had queried.
     */
    public update(options: VisualUpdateOptions) {
        let viewModel: BarChartViewModel = visualTransform(options, this.host);
        let settings = this.barChartSettings = viewModel.settings;
        this.barDataPoints = viewModel.dataPoints;

        let width = options.viewport.width;
        let height = options.viewport.height;

        this.svg
            .attr("width", width)
            .attr("height", height);

        if (settings.enableAxis.show) {
            let margins = BarChart.Config.margins;
            height -= margins.bottom;
        }

        this.xAxis
            .style("font-size", Math.min(height, width) * BarChart.Config.xAxisFontMultiplier)
            .style("fill", settings.enableAxis.fill);

        let yScale = scaleLinear()
            .domain([0, viewModel.dataMax])
            .range([height, 0]);

        let xScale = scaleBand()
            .domain(viewModel.dataPoints.map(d => d.category))
            .rangeRound([0, width])
            .padding(0.2);

        let xAxis = axisBottom(xScale);

        const colorObjects = options.dataViews[0] ? options.dataViews[0].metadata.objects : null;
        this.xAxis.attr('transform', 'translate(0, ' + height + ')')
            .call(xAxis)
            .attr("color", getAxisTextFillColor(
                colorObjects,
                this.host.colorPalette,
                defaultSettings.enableAxis.fill
            ));

        const textNodes = this.xAxis.selectAll("text")
        BarChart.wordBreak(textNodes, xScale.bandwidth(), height);

        this.barSelection = this.barContainer
            .selectAll('.bar')
            .data(this.barDataPoints);

        const barSelectionMerged = this.barSelection
            .enter()
            .append('rect')
            .merge(<any>this.barSelection);

        barSelectionMerged.classed('bar', true);

        barSelectionMerged
            .attr("width", xScale.bandwidth())
            .attr("height", d => height - yScale(<number>d.value))
            .attr("y", d => yScale(<number>d.value))
            .attr("x", d => xScale(d.category))
            .style("fill", (dataPoint: BarChartDataPoint) => dataPoint.color)
            .style("stroke", (dataPoint: BarChartDataPoint) => dataPoint.strokeColor)
            .style("stroke-width", (dataPoint: BarChartDataPoint) => `${dataPoint.strokeWidth}px`);

        this.barSelection
            .exit()
            .remove();

    }

    private static wordBreak(
        textNodes: Selection<any, SVGElement>,
        allowedWidth: number,
        maxHeight: number
    ) {
        textNodes.each(function () {
            textMeasurementService.wordBreak(
                this,
                allowedWidth,
                maxHeight);
        });
    }

Auffüllen des Eigenschaftsbereichs

Die abschließende Methode in der Funktion IVisual ist getFormattingModel. Diese Methode erstellt und gibt ein modernes Formatbereichsformatmodellobjekt zurück, das alle Komponenten und Eigenschaften des Formatbereichs enthält. Anschließend wird das Objekt im Formatbereich platziert. In unserem Fall erstellen wir Formatkarten für enableAxis und colorSelector, einschließlich der Formatierungseigenschaften für show und fill, entsprechend den "Objekten" in der Datei capabilities.json .

Um ein Formatierungsmodell zu erstellen, sollte der Entwickler mit allen zugehörigen Komponenten vertraut sein. Überprüfen Sie die Komponenten des Formatbereichs im Formatbereich.

Um eine Farbauswahl für jede Kategorie im Bereich Eigenschaft hinzuzufügen, fügen Sie eine for-Schleife hinzu barDataPoints, und fügen Sie dem Formatierungsmodell eine neue Farbauswahlformateigenschaft hinzu.

    /** Gets the settings to display in the formatting pane */
    public getFormattingModel(): powerbi.visuals.FormattingModel {
        const enableAxisCard: powerbi.visuals.FormattingCard = {
            displayName: "Enable Axis",
            uid: "enableAxisCard_uid",
            topLevelToggle: {
                uid: "enableAxisCard_topLevelToggle_showToggleSwitch_uid",
                suppressDisplayName: true,
                control: {
                    type: powerbi.visuals.FormattingComponent.ToggleSwitch,
                    properties: {
                        descriptor: {
                            objectName: "enableAxis",
                            propertyName: "show"
                        },
                        value: this.barChartSettings.enableAxis.show
                    }
                }
            },
            groups: [{
                displayName: undefined,
                uid: "enableAxisCard_group1_uid",
                slices: [
                    {
                        uid: "enableAxisCard_group1_fill_uid",
                        displayName: "Color",
                        control: {
                            type: powerbi.visuals.FormattingComponent.ColorPicker,
                            properties: {
                                descriptor: {
                                    objectName: "enableAxis",
                                    propertyName: "fill"
                                },
                                value: { value: this.barChartSettings.enableAxis.fill }
                            }
                        }
                    }
                ],
            }],
            revertToDefaultDescriptors: [
                {
                    objectName: "enableAxis",
                    propertyName: "show"
                },
                {
                    objectName: "enableAxis",
                    propertyName: "fill"
                }
            ]
        };

        const colorSelectorCard: powerbi.visuals.FormattingCard = {
            displayName: "Data Colors",
            uid: "dataColorsCard_uid",
            groups: [{
                displayName: undefined,
                uid: "dataColorsCard_group_uid",

                slices: [],
            }]
        };

        if (this.barDataPoints) {
            let indx = 1;
            this.barDataPoints.forEach(dataPoint => {
                (colorSelectorCard.groups[0] as powerbi.visuals.FormattingGroup).slices.push(
                    {
                        uid: `dataColorsCard_group_colorSelector${indx}_uid`,
                        displayName: dataPoint.category,
                        control: {
                            type: powerbi.visuals.FormattingComponent.ColorPicker,
                            properties: {
                                descriptor: {
                                    objectName: "colorSelector",
                                    propertyName: "fill",
                                    selector: dataViewWildcard.createDataViewWildcardSelector(dataViewWildcard.DataViewWildcardMatchingOption.InstancesAndTotals),
                                    altConstantValueSelector: dataPoint.selectionId.getSelector(),
                                    instanceKind: powerbi.VisualEnumerationInstanceKinds.ConstantOrRule
                                },
                                value: { value: dataPoint.color }
                            }
                        }
                    });
            });

            colorSelectorCard.revertToDefaultDescriptors = [
                {
                    objectName: "colorSelector",
                    propertyName: "fill"
                }
            ]
        }
        return { cards: [enableAxisCard, colorSelectorCard] };
    } 

(Optional) Auffüllen des Eigenschaftenbereichs mithilfe der Formatierungsmodell-Utils

Auffüllen des Eigenschaftenbereichs mithilfe der getFormattingModel API im Repository für Utils des Formatierungsmodells

Den vollständigen Code eines Beispielbalkendiagramms mit Formatierungsmodellutils finden Sie im Balkendiagrammrepository.

Deklarieren Sie Formatierungseigenschaften und deren Werte in einer Formatierungseinstellungsklasse:

import powerbi from "powerbi-visuals-api";
import { dataViewWildcard } from "powerbi-visuals-utils-dataviewutils";
import { formattingSettings } from "powerbi-visuals-utils-formattingmodel";
import { BarChartDataPoint } from "./barChart";

import FormattingSettingsCard = formattingSettings.SimpleCard;
import FormattingSettingsSlice = formattingSettings.Slice;
import FormattingSettingsModel = formattingSettings.Model;

/**
 * Enable Axis Formatting Card
 */
class EnableAxisCardSettings extends FormattingSettingsCard {
    // Formatting property `show` toggle switch (formatting simple slice)
    show = new formattingSettings.ToggleSwitch({
        name: "show",
        displayName: undefined,
        value: false,
        topLevelToggle: true,
        show: true
    });

    // Formatting property `fill` color picker (formatting simple slice)
    fill = new formattingSettings.ColorPicker({
        name: "fill",
        displayName: "Color",
        value: { value: "#000000" },
        show: true
    });

    name: string = "enableAxis";
    displayName: string = "Enable Axis";
    show: boolean = true;
    slices: Array<FormattingSettingsSlice> = [this.show, this.fill];
}

/**
 * Color Selector Formatting Card
 */

class ColorSelectorCardSettings extends FormattingSettingsCard {
    name: string = "colorSelector";
    displayName: string = "Data Colors";

    // slices will be populated in barChart settings model `populateColorSelector` method
    slices: Array<FormattingSettingsSlice> = [];
}

/**
* BarChart settings model class
*
*/
export class BarChartSettingsModel extends FormattingSettingsModel {

    // Create formatting settings model formatting cards
    enableAxis = new EnableAxisCardSettings();
    colorSelector = new ColorSelectorCardSettings();
    cards = [this.enableAxis, this.colorSelector];

    /**
     * populate colorSelector object categories formatting properties
     * @param dataPoints 
     */
    populateColorSelector(dataPoints: BarChartDataPoint[]) {
        let slices = this.colorSelector.slices;
        if (dataPoints) {
            dataPoints.forEach(dataPoint => {
                slices.push(new formattingSettings.ColorPicker({
                    name: "fill",
                    displayName: dataPoint.category,
                    value: { value: dataPoint.color },
                    selector: dataViewWildcard.createDataViewWildcardSelector(dataViewWildcard.DataViewWildcardMatchingOption.InstancesAndTotals),
                    altConstantSelector: dataPoint.selectionId.getSelector(),
                    instanceKind: powerbi.VisualEnumerationInstanceKinds.ConstantOrRule
                }));
            });
        }
    }
}

Erstellen und erstellen Sie das Dienstmodell der Formatierungseinstellungen in der Konstruktormethode des visuellen Elements. Der Formatierungseinstellungsdienst empfängt die BarChart-Formateinstellungen und konvertiert sie in ein Formatmodel-Objekt, das in der getFormattingModel API zurückgegeben wird.

Um das Lokalisierungsfeature zu verwenden, fügen Sie den Lokalisierungs-Manager dem Formatierungseinstellungsdienst hinzu.

    import { FormattingSettingsService } from "powerbi-visuals-utils-formattingmodel";
    
    // ...
    // declare utils formatting settings service
    private formattingSettingsService: FormattingSettingsService;
    //...

    constructor(options: VisualConstructorOptions) {
        this.host = options.host;
        const localizationManager = this.host.createLocalizationManager();
        this.formattingSettingsService = new FormattingSettingsService(localizationManager);
        
        // Add here rest of your custom visual constructor code
    }

Aktualisieren Sie das Formatierungseinstellungsmodell mithilfe der Update-API. Rufen Sie die Update-API jedes Mal auf, wenn eine Formatierungseigenschaft im Eigenschaftenbereich geändert wird. Erstellen Sie Datenpunkte für Balkendiagrammselektoren, und füllen Sie sie im Formateinstellungsmodell auf:


    // declare formatting settings model for bar chart 
    private formattingSettings: BarChartSettingsModel;

    // ...

    public update(options: VisualUpdateOptions) {
        this.formattingSettings = this.formattingSettingsService.populateFormattingSettingsModel(BarChartSettingsModel, options.dataViews[0]);
        this.barDataPoints = createSelectorDataPoints(options, this.host);
        this.formattingSettings.populateColorSelector(this.barDataPoints);

        // Add the rest of your custom visual update API code here

    }

Schließlich ist die neue API getFormattingModel eine einfache Codezeile, die den Formatierungseinstellungsdienst und das aktuelle Formatierungseinstellungsmodell verwendet, das in der obigen Update-API erstellt wurde.

    public getFormattingModel(): powerbi.visuals.FormattingModel {
        return this.formattingSettingsService.buildFormattingModel(this.formattingSettings);
    }

(Optional) Rendern der X-Achse (statische Objekte)

Sie können dem Bereich Eigenschaften Objekte hinzufügen, um das Visual weiter anzupassen. Bei diesen Anpassungen kann es sich um Änderungen an der Benutzeroberfläche oder Änderungen in Bezug auf die abgefragten Daten handeln.

Sie können diese Objekte im Bereich Eigenschaft ein- oder ausschalten.

Screenshot of objects in the Property pane.

In diesem Beispiel wird eine X-Achse im Balkendiagramm als statisches Objekt gerendert.

Wir haben der capabilities-Datei und der barChartSettings-Schnittstelle bereits die Eigenschaft enableAxis hinzugefügt. Fügen Sie der Datei barChart.ts den folgenden Code vor der iVisual-Klasse hinzu, um die X-Achse zu zeichnen:

function getAxisTextFillColor(
    objects: DataViewObjects,
    colorPalette: ISandboxExtendedColorPalette,
    defaultColor: string
): string {
    if (colorPalette.isHighContrast) {
        return colorPalette.foreground.value;
    }

    return getValue<Fill>(
        objects,
        "enableAxis",
        "fill",
        {
            solid: {
                color: defaultColor,
            }
        },
    ).solid.color;
}

(Optional) Hinzufügen von Farbe (datengebundene Objekte)

Datengebundene Objekte ähneln statischen Objekten, behandeln aber üblicherweise die Datenauswahl. Beispielsweise können Sie datengebundene Objekte verwenden, um interaktiv die jedem Datenpunkt zugeordnete Farbe auszuwählen.

Screenshot of color selection on properties.

Wir haben das colorSelector-Objekt bereits in der capabilities-Datei definiert.

Jede Datenpunkt wird durch eine andere Farbe dargestellt. Wir nehmen Farbe in die BarChartDataPoint-Schnittstelle auf und weisen jedem Datenpunkt eine Standardfarbe zu, wenn er in IVisualHost definiert wird.

function getColumnColorByIndex(
    category: DataViewCategoryColumn,
    index: number,
    colorPalette: ISandboxExtendedColorPalette,
): string {
    if (colorPalette.isHighContrast) {
        return colorPalette.background.value;
    }

    const defaultColor: Fill = {
        solid: {
            color: colorPalette.getColor(`${category.values[index]}`).value,
        }
    };

    return getCategoricalObjectValue<Fill>(
        category,
        index,
        'colorSelector',
        'fill',
        defaultColor
    ).solid.color;
}

function getColumnStrokeColor(colorPalette: ISandboxExtendedColorPalette): string {
    return colorPalette.isHighContrast
        ? colorPalette.foreground.value
        : null;
}

function getColumnStrokeWidth(isHighContrast: boolean): number {
    return isHighContrast
        ? 2
        : 0;
}

Der colorPalette-Dienst in der visualTransform-Funktion verwaltet diese Farben. Da visualTransform jeden der Datenpunkte durchläuft, stellt sie den idealen Ort dar, um Kategorieobjekte wie Farbe zuzuweisen.

Ausführlichere Anweisungen zum Hinzufügen von Farbe zu Ihrem Balkendiagramm finden Sie unter Hinzufügen von Farben zu Ihrem visuellen Power BI-Element

Hinweis

Vergewissern Sie sich, dass Ihre endgültige barChart.ts-Datei wie dieser barChart.ts-Quellcode aussieht, oder laden Sie den barChart.ts-Quellcode herunter, und verwenden Sie ihn, um Ihre Datei zu ersetzen.

Hilfsprogramm zur Objektenumeration (optional)

Eigenschaftswerte von Objekten stehen als Metadaten in dataView zur Verfügung, es ist aber kein Dienst zum Abrufen dieser Eigenschaften vorhanden. ObjectEnumerationUtility ist ein optionaler Satz statischer Funktionen, die die dataView durchlaufen und Objektwerte abrufen. Erstellen Sie im Ordner src eine Datei mit dem Namen objectEnumerationUtility.ts, und kopieren Sie den folgenden Code hinein:

/**
 * Gets property value for a particular object.
 *
 * @function
 * @param {DataViewObjects} objects - Map of defined objects.
 * @param {string} objectName       - Name of desired object.
 * @param {string} propertyName     - Name of desired property.
 * @param {T} defaultValue          - Default value of desired property.
 */
export function getValue<T>(objects: DataViewObjects, objectName: string, propertyName: string, defaultValue: T ): T {
    if(objects) {
        let object = objects[objectName];
        if(object) {
            let property: <T>T = object[propertyName];
            if(property !== undefined) {
                return property;
            }
        }
    }
    return defaultValue;
}

/**
 * Gets property value for a particular object in a category.
 *
 * @function
 * @param {DataViewCategoryColumn} category - List of category objects.
 * @param {number} index                    - Index of category object.
 * @param {string} objectName               - Name of desired object.
 * @param {string} propertyName             - Name of desired property.
 * @param {T} defaultValue                  - Default value of desired property.
 */
export function getCategoricalObjectValue<T>(category: DataViewCategoryColumn, index: number, objectName: string, propertyName: string, defaultValue: T): T {
    let categoryObjects = category.objects;

    if (categoryObjects) {
        let categoryObject: DataViewObject = categoryObjects[index];
        if (categoryObject) {
            let object = categoryObject[objectName];
            if (object) {
                let property: T = <T>object[propertyName];
                if (property !== undefined) {
                    return property;
                }
            }
        }
    }
    return defaultValue;
}

Die Funktion getCategoricalObjectValue stellt eine bequeme Möglichkeit für den Zugriff auf Eigenschaften anhand ihres Kategorieindex dar. Sie müssen einen objectName- und einen propertyName-Wert angeben, der dem Objekt und der Eigenschaft in capabilities.json entspricht.

Den Quellcode finden Sie unter objectEnumerationUtility.ts.

Testen des visuellen Elements

Führen Sie das visuelle Element auf dem Power BI-Server aus, um zu sehen, wie es funktioniert:

  1. Navigieren Sie in PowerShell zum Ordner des Projekts, und starten Sie die Entwicklungs-App.

    pbiviz start
    

    Ihr Visual wird nun ausgeführt und auf Ihrem Computer gehostet.

    Wichtig

    Schließen Sie das PowerShell-Fenster erst nach dem Ende des Tutorials. Wenn Sie die Ausführung des visuellen Elements beenden möchten, geben Sie STRG+C ein. Wenn Sie aufgefordert werden, den Batchauftrag zu beenden, geben Sie Y ein, und drücken Sie die EINGABETASTE.

  2. Zeigen Sie das visuelle Element in Power BI an, indem Sie im Bereich Visualisierung das visuelle Element „Entwickler“ auswählen.

    Screenshot of developer visual.

  3. Hinzufügen von Daten zum visuellen Element

    Screenshot of data bound to field bucket.

  4. Ziehen Sie an den Kanten des visuellen Elements, um seine Größe zu ändern, und achten Sie darauf, wie sich der Maßstab anpasst.

  5. Schalten Sie die X-Achse ein und aus.

    Screenshot of X-Axis on property pane.

  6. Ändern Sie die Farben der verschiedenen Kategorien.

Hinzufügen weiterer Features

Sie können Ihr visuelles Element weiter anpassen, indem Sie weitere Features hinzufügen. Sie können Features hinzufügen, um die Funktionalität des visuellen Elements zu steigern, sein Aussehen und Verhalten zu verbessern oder dem Benutzer mehr Kontrolle über seine Darstellung zu geben. Beispielsweise können Sie folgende Aktionen ausführen:

Packen des Visuals

Damit Sie Ihr visuelles Element in Power BI Desktop laden oder über den Power BI-Visualkatalog mit anderen Benutzern teilen können, müssen Sie ein Paket erstellen.

Befolgen Sie die Anweisungen unter Packen eines Power BI Visuals, um das visuelle Element für das Teilen vorzubereiten.

Hinweis

Den vollständigen Quellcode eines Balkendiagramms mit weiteren Features, einschließlich tool-tips und einem Kontextmenü, finden Sie unter Beispiel-Balkendiagramm für Power BI-Visuals.

Nächste Schritte