Tutorial: Develop a Power BI circle card visual

In this tutorial, you develop a Power BI visual named circle card that displays a formatted measure value inside a circle. The circle card visual supports customization of fill color and outline thickness.

In this tutorial, you learn how to:

  • Create a development project for your visual.
  • Develop your visual with D3 visual elements.
  • Configure your visual to process data.
  • Configure your visual to adapt to size changes.
  • Configure adaptive color and border settings for your visual.

Note

For the full source code of this visual, see circle card Power BI visual.

Prerequisites

Before you start developing your Power BI visual, verify that you have everything listed in this section.

Create a development project

In this section, you create a project for the circle card visual.

Note

In this tutorial, Visual Studio Code (VS Code) is used for developing the Power BI visual.

  1. Open a new terminal in VS Code and navigate to the folder you want to create your project in.

  2. Enter the following command in the PowerShell terminal:

    pbiviz new CircleCard
    
  3. Open the CircleCard folder in the VS Code explorer. (File > Open Folder).

    Screenshot of VS Code window opened to the circle card folder.

    For a detailed explanation of the function of each of these files, see Power BI visual project structure.

  4. Check the terminal window and confirm that you're in the circleCard directory. Install the Power BI visual tools dependencies.

    npm install
    

    Tip

    To see which dependencies have been installed in your visual, check the package.json file.

  5. Start the circle card visual.

    pbiviz start
    

    Your visual is now running while being hosted on your computer.

    Important

    Don't close the PowerShell window until the end of the tutorial. To stop the visual from running, enter Ctrl+C and if prompted to terminate the batch job, enter Y and then Enter.

View the visual in the Power BI service

To test the visual in Power BI service, we'll use the US Sales Analysis report. You can download this report and upload it to Power BI service.

You can also use your own report to test the visual.

Note

Before you continue, verify that you enabled the visuals developer settings.

  1. Sign in to PowerBI.com and open the US Sales Analysis report.

  2. Select Edit.

    Screenshot of the edit option in Power B I service.

  3. Create a new page for testing, by clicking on the New page button at the bottom of the Power BI service interface.

    Screenshot of the new page button in Power B I service.

  4. From the Visualizations pane, select the Developer Visual.

    Screenshot of the developer visual in the visualizations pane.

    This visual represents the custom visual that you're running on your computer. It's only available when the custom visual debugging setting is enabled.

  5. Verify that a visual was added to the report canvas.

    Screenshot of the new visual added to the report.

    This is a simple visual that displays the number of times its update method has been called. At this stage, the visual does not retrieve any data.

    Note

    If the visual displays a connection error message, open a new tab in your browser, navigate to https://localhost:8080/assets, and authorize your browser to use this address.

    Screenshot of the new visual displaying a connection error.

  6. While the new visual is selected, go to the Data pane, expand Sales, and select Quantity.

    Screenshot of the Power B I service quantity field in the sales table in the U S sales analysis report.

  7. To test how the visual is responding, resize it and notice that the Update count value increments every time you resize the visual.

    Screenshot of the new visual displaying a different update count number, after being resized.

Add visual elements and text

In this section you learn how to turn your visual into a circle, and make it display text.

Modify the visuals file

Set up the visual.ts file.

Tip

To improve readability, it's recommended that you format the document every time you copy code snippets into your project. Right-click anywhere in VS code, and select Format Document (or enter Alt+Shift+F).

  1. In VS Code, in the Explorer pane, expand the src folder, and select the file visual.ts.

    Screenshot of accessing the visual.ts file in V S code.

  2. Remove all the code under the MIT License comment.

    Important

    Notice the comments at the top of the visual.ts file. Permission to use the Power BI visual packages is granted free of charge under the terms of the Massachusetts Institute of Technology (MIT) License. As part of the agreement, you must leave the comments at the top of the file.

  3. Import the libraries and modules needed, and define the type selection for the d3 library:

    "use strict";
    
    import "./../style/visual.less";
    import powerbi from "powerbi-visuals-api";
    import VisualConstructorOptions = powerbi.extensibility.visual.VisualConstructorOptions;
    import VisualUpdateOptions = powerbi.extensibility.visual.VisualUpdateOptions;
    import IVisual = powerbi.extensibility.visual.IVisual;
    import DataView = powerbi.DataView;
    import IVisualHost = powerbi.extensibility.IVisualHost;
    import * as d3 from "d3";
    type Selection<T extends d3.BaseType> = d3.Selection<T, any, any, any>;
    

    Note

    If the D3 JavaScript library wasn't installed as part of your setup, install it now. From PowerShell, run npm i d3@latest --save

    Notice that among the items you imported are:

    • IVisualHost - A collection of properties and services used to interact with the visual host (Power BI).
    • D3 library - JavaScript library for creating data driven documents.
  4. Below the imports, create an empty visual class. The visual class implements the IVisual interface where all visuals begin:

    export class Visual implements IVisual {
    
    }
    

    For information about what goes into the visual class, see Visual API. In the next three steps, we define this class.

  5. Add class-level private methods at the beginning of the visual class:

    private host: IVisualHost;
    private svg: Selection<SVGElement>;
    private container: Selection<SVGElement>;
    private circle: Selection<SVGElement>;
    private textValue: Selection<SVGElement>;
    private textLabel: Selection<SVGElement>;
    

    Notice that some of these private methods use the Selection type.

  6. Define the circle and text elements in the constructor method. This method is called when the visual is instantiated. The D3 Scalable Vector Graphics (SVG) enable creating three shapes: a circle, and two text elements:

    constructor(options: VisualConstructorOptions) {
        this.svg = d3.select(options.element)
            .append('svg')
            .classed('circleCard', true);
        this.container = this.svg.append("g")
            .classed('container', true);
        this.circle = this.container.append("circle")
            .classed('circle', true);
        this.textValue = this.container.append("text")
            .classed("textValue", true);
        this.textLabel = this.container.append("text")
            .classed("textLabel", true);
    }
    
  7. Define the width and height in the update method. This method is called every time there's a change in the data or host environment, such as a new value or resizing.

    public update(options: VisualUpdateOptions) {
        let width: number = options.viewport.width;
        let height: number = options.viewport.height;
        this.svg.attr("width", width);
        this.svg.attr("height", height);
        let radius: number = Math.min(width, height) / 2.2;
        this.circle
            .style("fill", "white")
            .style("fill-opacity", 0.5)
            .style("stroke", "black")
            .style("stroke-width", 2)
            .attr("r", radius)
            .attr("cx", width / 2)
            .attr("cy", height / 2);
        let fontSizeValue: number = Math.min(width, height) / 5;
        this.textValue
            .text("Value")
            .attr("x", "50%")
            .attr("y", "50%")
            .attr("dy", "0.35em")
            .attr("text-anchor", "middle")
            .style("font-size", fontSizeValue + "px");
        let fontSizeLabel: number = fontSizeValue / 4;
        this.textLabel
            .text("Label")
            .attr("x", "50%")
            .attr("y", height / 2)
            .attr("dy", fontSizeValue / 1.2)
            .attr("text-anchor", "middle")
            .style("font-size", fontSizeLabel + "px");
    }
    
  8. Save the visual.ts file.

(Optional) Review the code in the visuals file

Verify that the final code in the visual.ts file looks like this:

/*
*  Power BI Visual CLI
*
*  Copyright (c) Microsoft Corporation
*  All rights reserved.
*  MIT License
*
*  Permission is hereby granted, free of charge, to any person obtaining a copy
*  of this software and associated documentation files (the ""Software""), to deal
*  in the Software without restriction, including without limitation the rights
*  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
*  copies of the Software, and to permit persons to whom the Software is
*  furnished to do so, subject to the following conditions:
*
*  The above copyright notice and this permission notice shall be included in
*  all copies or substantial portions of the Software.
*
*  THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
*  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
*  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
*  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
*  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
*  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
*  THE SOFTWARE.
*/
"use strict";

import "./../style/visual.less";
import powerbi from "powerbi-visuals-api";
import VisualConstructorOptions = powerbi.extensibility.visual.VisualConstructorOptions;
import VisualUpdateOptions = powerbi.extensibility.visual.VisualUpdateOptions;
import IVisual = powerbi.extensibility.visual.IVisual;
import DataView = powerbi.DataView;
import IVisualHost = powerbi.extensibility.IVisualHost;
import * as d3 from "d3";
type Selection<T extends d3.BaseType> = d3.Selection<T, any, any, any>;

export class Visual implements IVisual {
    private host: IVisualHost;
    private svg: Selection<SVGElement>;
    private container: Selection<SVGElement>;
    private circle: Selection<SVGElement>;
    private textValue: Selection<SVGElement>;
    private textLabel: Selection<SVGElement>;
    
    constructor(options: VisualConstructorOptions) {
        this.svg = d3.select(options.element)
            .append('svg')
            .classed('circleCard', true);
        this.container = this.svg.append("g")
            .classed('container', true);
        this.circle = this.container.append("circle")
            .classed('circle', true);
        this.textValue = this.container.append("text")
            .classed("textValue", true);
        this.textLabel = this.container.append("text")
            .classed("textLabel", true);
    }
    
    public update(options: VisualUpdateOptions) {
        let width: number = options.viewport.width;
        let height: number = options.viewport.height;
        this.svg.attr("width", width);
        this.svg.attr("height", height);
        let radius: number = Math.min(width, height) / 2.2;
        this.circle
            .style("fill", "white")
            .style("fill-opacity", 0.5)
            .style("stroke", "black")
            .style("stroke-width", 2)
            .attr("r", radius)
            .attr("cx", width / 2)
            .attr("cy", height / 2);
        let fontSizeValue: number = Math.min(width, height) / 5;
        this.textValue
            .text("Value")
            .attr("x", "50%")
            .attr("y", "50%")
            .attr("dy", "0.35em")
            .attr("text-anchor", "middle")
            .style("font-size", fontSizeValue + "px");
        let fontSizeLabel: number = fontSizeValue / 4;
        this.textLabel
            .text("Label")
            .attr("x", "50%")
            .attr("y", height / 2)
            .attr("dy", fontSizeValue / 1.2)
            .attr("text-anchor", "middle")
            .style("font-size", fontSizeLabel + "px");
    }
}

Modify the capabilities file

The circle card visual is a simple visual that doesn't create any objects in the Format pane. Therefore, you can safely remove the objects section of the file.

  1. Open your project in VS Code (File > Open Folder).

  2. Select the capabilities.json file.

    Screenshot of accessing the capabilities.json file in V S code.

  3. Remove the entire objects array.
    Don't leave any blank lines between dataRoles and dataViewMappings.

  4. Save the capabilities.json file.

Restart the circle card visual

Stop the visual from running and restart it.

  1. In the PowerShell window where you started the visual, enter Ctrl+C. If prompted to terminate the batch job, enter Y and then Enter.

  2. In PowerShell, start the visual again.

    pbiviz start
    

Test the visual with the added elements

Verify that the visual displays the newly added elements.

  1. In Power BI service, open the Power BI US Sales Analysis report. If you're using a different report to develop the circle card visual, navigate to that report.

  2. Drag a value into the Measure box and make sure that the visual is shaped as a circle.

    Screenshot of the circle card visual shaped as a circle.

    If the visual isn't displaying anything, from the Fields pane, drag the Quantity field into the developer visual.

  3. Resize the visual.

    Notice that the circle and text scale to fit the dimensions of the visual. The update method is called when you resize the visual, and as a result the visual elements get rescaled.

Enable auto reload

Use this setting to ensure that the visual is automatically reloaded each time you save project changes.

  1. Navigate to the Power BI US Sales Analysis report (or to the project that has your circle card visual).

  2. Select the circle card visual.

  3. In the floating toolbar, select Toggle Auto Reload.

    Screenshot of clicking the toggle auto reload option, in the circle card visual floating toolbar.

Get the visual to process data

In this section, you define data roles and data view mappings. You also modify the visual to display the name of the value it's displaying.

Configure the capabilities file

Modify the capabilities.json file to define the data role, objects, and data view mappings.

  • Define the data role

    Define the dataRoles array with a single data role of the type measure. This data role is called measure, and is displayed as Measure. It allows passing either a measure field, or a summed up field.

    1. Open the capabilities.json file in VS Code.

    2. Remove all the content inside the dataRoles array.

    3. Insert the following code to the dataRoles array.

      {
          "displayName": "Measure",
          "name": "measure",
          "kind": "Measure"
      }
      
    4. Save the capabilities.json file.

  • Define the data view mapping

    Define a field called measure in the dataViewMappings array. This field can be passed to the data role.

    1. Open the capabilities.json file in VS Code.

    2. Remove all the content inside the dataViewMappings array.

    3. Insert the following code to the dataViewMappings array.

      {
          "conditions": [
              { "measure": { "max": 1 } }
          ],
          "single": {
              "role": "measure"
          }
      }
      
    4. Save the capabilities.json file.

Confirm that your capabilities.json file looks like this:

{
    "dataRoles": [
        {
            "displayName": "Measure",
            "name": "measure",
            "kind": "Measure"
        }
    ],
    "dataViewMappings": [
        {
            "conditions": [
                { "measure": { "max": 1 } }
            ],
            "single": {
                "role": "measure"
            }
        }
    ],
    "privileges": []
}

(Optional) Review the capabilities file code changes

Verify that the circle card visual displays the measure field, and review the changes you made using the Show Dataview option.

  1. In Power BI service, open the Power BI US Sales Analysis report. If you're using a different report to develop the circle card visual, navigate to that report.

  2. Notice that the circle card visual can now be configured with a field titled Measure. You can drag and drop elements from the Data pane into the Measure field.

    Screenshot of the circle card measure filed, in the Power BI service visualization pane.

    Note

    The visual project does not yet include data binding logic.

  3. In the floating toolbar, select Show Dataview.

    Screenshot of the show dataview button, located in the circle card floating toolbar.

  4. Select the three dots to expand the display, and select single to view the value.

    Screenshot of the value figure as it's displayed in the circle card show dataview option.

  5. Expand metadata, then the columns array, and review the format and displayName values.

    Screenshot of the format and display name values as displayed in the circle card show dataview option.

  6. To toggle back to the visual, in the toolbar floating above the visual, select Show Dataview.

Configure the visual to consume data

So far, the visual renders, but doesn't display any data. In this section, you make changes to the visual.ts file, so that the circle card visual can consume data.

  1. Open the visual.ts file in VS Code.

  2. In the update method:

    • Add the following statement as the first statement. The statement assigns dataView to a variable for easy access, and declares the variable to reference the dataView object.

      let dataView: DataView = options.dataViews[0];
      
    • Replace .text("Value") with this line of code:

      .text(<string>dataView.single.value)
      
    • Replace .text("Label") with this line of code:

      .text(dataView.metadata.columns[0].displayName)
      
  3. Save the visual.ts file.

  4. Review the visual in the Power BI service.

The visual now displays the name and value of the selected data field.

Screenshot of a circle card visual displaying the quantity value.

You created a working Power BI visual. You can add formatting options to it, or you can package it as is for immediate use.