title | description | author | ms.author | ms.reviewer | ms.service | ms.subservice | ms.topic | ms.date |
---|---|---|---|---|---|---|---|---|
Create a React-based visual for Power . |
This tutorial shows how to create a Power BI visual using React. It displays a value in a circle. Adaptive size and settings allow you to customize it. |
mberdugo |
monaberdugo |
sranins |
powerbi |
powerbi-custom-visuals |
tutorial |
10/12/2022 |
[!INCLUDEPower B I visuals tutorials overview]
In this tutorial, you develop a Power BI visual using React. The visual displays a formatted measure value inside a circle. The visual has adaptive size and allows you to customize its settings.
In this tutorial, you learn how to:
[!div class="checklist"]
- Create a development project for your visual.
- Develop your visual using React.
- 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 React circle card Power BI visual.
[!INCLUDEPower B I tutorials prerequisites]
In this section, you create a project for the React circle card visual.
-
Open PowerShell and navigate to the folder you want to create your project in.
-
Enter the following command:
pbiviz new ReactCircleCard
-
Navigate to the project's folder.
cd ReactCircleCard
-
Start the React circle card visual. Your visual is now running while being hosted on your computer.
pbiviz start
[!IMPORTANT] To stop the visual from running, in PowerShell enter Ctrl+C and if prompted to terminate the batch job, enter Y, and press Enter.
[!INCLUDEView the Power BI visual in Power BI service]
In this section, you learn how to set up React for your Power BI visual project.
Open PowerShell and stop the visual from running by entering Ctrl+C. If prompted to terminate the batch job, enter Y, and press Enter.
To install the required React dependencies, open PowerShell in your ReactCircleCard folder, and run the following command:
npm i react react-dom
To install type definitions for React, open PowerShell in your reactCircleCard folder and run the following command:
npm i @types/react @types/react-dom
Follow these steps to create a React component class.
-
Open VS Code and navigate to the reactCircleCard folder.
-
Create a new file by selecting File > New File.
-
Copy the following code into the new file.
import * as React from "react"; export class ReactCircleCard extends React.Component<{}>{ render(){ return ( <div className="circleCard"> Hello, React! </div> ) } } export default ReactCircleCard;
-
Select Save As and navigate to the src folder.
-
Save the file as follows:
- In the File name field, enter component.
- From the Save as type drop-down menu, select TypeScript React.
Replace the code in the visual.ts file with code that enables using React.
-
In the src folder, open visual.ts and replace the code in the file with the following code:
"use strict"; import powerbi from "powerbi-visuals-api"; import DataView = powerbi.DataView; import VisualConstructorOptions = powerbi.extensibility.visual.VisualConstructorOptions; import VisualUpdateOptions = powerbi.extensibility.visual.VisualUpdateOptions; import IVisual = powerbi.extensibility.visual.IVisual; // Import React dependencies and the added component import * as React from "react"; import * as ReactDOM from "react-dom"; import ReactCircleCard from "./component"; import "./../style/visual.less"; export class Visual implements IVisual { constructor(options: VisualConstructorOptions) { } public update(options: VisualUpdateOptions) { } }
[!NOTE] As default Power BI TypeScript settings don't recognize React tsx files, VS Code highlights
component
as an error. -
To render the component, add the target HTML element to visual.ts. This element is
HTMLElement
inVisualConstructorOptions
, which is passed into the constructor.-
In the src folder, open visual.ts.
-
Add the following code to the
Visual
class:
private target: HTMLElement; private reactRoot: React.ComponentElement<any, any>;
- Add the following lines to the
VisualConstructorOptions
constructor:
this.reactRoot = React.createElement(ReactCircleCard, {}); this.target = options.element; ReactDOM.render(this.reactRoot, this.target);
Your visual.ts file should now look like this:
"use strict"; import powerbi from "powerbi-visuals-api"; import DataView = powerbi.DataView; import VisualConstructorOptions = powerbi.extensibility.visual.VisualConstructorOptions; import VisualUpdateOptions = powerbi.extensibility.visual.VisualUpdateOptions; import IVisual = powerbi.extensibility.visual.IVisual; import * as React from "react"; import * as ReactDOM from "react-dom"; import ReactCircleCard from "./component"; import "./../style/visual.less"; export class Visual implements IVisual { private target: HTMLElement; private reactRoot: React.ComponentElement<any, any>; constructor(options: VisualConstructorOptions) { this.reactRoot = React.createElement(ReactCircleCard, {}); this.target = options.element; ReactDOM.render(this.reactRoot, this.target); } public update(options: VisualUpdateOptions) { } }
-
-
Save visual.ts.
Edit the tsconfig.json to work with React.
-
In the reactCircleCard folder, open tsconfig.json and add two lines to the beginning of the
compilerOptions
item."jsx": "react", "types": ["react", "react-dom"],
Your tsconfig.json file should now look like this, and the
component
error in visual.ts should be gone.{ "compilerOptions": { "jsx": "react", "types": ["react", "react-dom"], "allowJs": false, "emitDecoratorMetadata": true, "experimentalDecorators": true, "target": "es6", "sourceMap": true, "outDir": "./.tmp/build/", "moduleResolution": "node", "declaration": true, "lib": [ "es2015", "dom" ] }, "files": [ "./src/visual.ts" ] }
-
Save tsconfig.json.
Open PowerShell in the CircleCardVisual folder, and run your project:
pbiviz start
When you add a new Developer Visual to your report in the Power BI service, it looks like this:
Configure your visual's capabilities file so that only one data field can be submitted to the visual's Measure data field.
-
In VS Code, from the reactCircleCard folder, open capabilities.json.
-
The
ReactCircleCard
displays a single value,Measure Data
. Remove theCategory Data
object fromdataRoles
.After removing the
Category Data
object, thedataRoles
key looks like this:"dataRoles": [ { "displayName": "Measure Data", "name": "measure", "kind": "Measure" } ],
-
Remove all the content of the
objects
key (you'll fill it in later).After you remove its content, the
objects
key looks like this:"objects": {},
-
Replace the
dataViewMappings
property with the following code.max: 1
inmeasure
specifies that only one data field can be submitted to the visual's Measure data field."dataViewMappings": [ { "conditions": [ { "measure": { "max": 1 } } ], "single": { "role": "measure" } } ]
-
Save the changes you made to capabilities.json.
-
Verify that
pbiviz start
is running and in Power BI service, refresh your React Circle Card visual. The Measure data field can accept only one data field, as specified bymax: 1
.
In this section, you turn the visual's shape into a circle. Use the visual.less file to control the style of your visual.
-
From the style folder, open visual.less.
-
Replace the content of visual.less with the following code.
.circleCard { position: relative; box-sizing: border-box; border: 1px solid #000; border-radius: 50%; width: 200px; height: 200px; } p { text-align: center; line-height: 30px; font-size: 20px; font-weight: bold; position: relative; top: -30px; margin: 50% 0 0 0; }
-
Save visual.less.
In this section you configure the visual to receive data from Power BI, and send updates to the instances in the component.tsx file.
You can render data using React. The component can display data from its own state.
-
In VS Code, from the reactCircleCard folder, open component.tsx.
-
Replace the content of component.tsx with the following code.
import * as React from "react"; export interface State { textLabel: string, textValue: string } export const initialState: State = { textLabel: "", textValue: "" } export class ReactCircleCard extends React.Component<{}, State>{ constructor(props: any){ super(props); this.state = initialState; } render(){ const { textLabel, textValue } = this.state; return ( <div className="circleCard"> <p> {textLabel} <br/> <em>{textValue}</em> </p> </div> ) } }
-
Save component.tsx.
Visuals receive data as an argument of the update
method. In this section, you update this method to receive data.
The following code selects textLabel
and textValue
from DataView
, and if the data exists, updates the component state.
-
In VS Code, from the src folder, open visual.ts.
-
Replace the line
import ReactCircleCard from "./component";
with the following code:import { ReactCircleCard, initialState } from "./component";
-
Add the following code to the
update
method.if(options.dataViews && options.dataViews[0]){ const dataView: DataView = options.dataViews[0]; ReactCircleCard.update({ textLabel: dataView.metadata.columns[0].displayName, textValue: dataView.single.value.toString() }); } else { this.clear(); }
-
Create a
clear
method by adding the following code below theupdate
method.private clear() { ReactCircleCard.update(initialState); }
-
Save visual.ts
In this section, you update the visual to send updates to instances in the component file.
-
In VS Code, from the src folder, open component.tsx.
-
Add the following code to the
ReactCircleCard
class:private static updateCallback: (data: object) => void = null; public static update(newState: State) { if(typeof ReactCircleCard.updateCallback === 'function'){ ReactCircleCard.updateCallback(newState); } } public state: State = initialState; public componentWillMount() { ReactCircleCard.updateCallback = (newState: State): void => { this.setState(newState); }; } public componentWillUnmount() { ReactCircleCard.updateCallback = null; }
-
Save component.tsx.
Test your React Circle Card visual to view the changes you made.
-
Verify that
pbiviz start
is running, and in the Power BI service, refresh your React Circle Card visual. -
Add Sales to the visual's Measure data field.
Currently, your visual has fixed width and height. To make the visual resizable you need to define the size
variable in both the visual.ts and component.tsx files. In this section, you make the visual resizable.
After you complete the steps outlined in this section, the circle diameter in your visual will correspond to the minimal width or height size, and you'll be able to resize it in Power BI service.
Get the current size of the visual viewport from the options
object.
-
In VS Code, from the src folder, open visual.ts.
-
Insert this code to import the
IViewport
interface.import IViewport = powerbi.IViewport;
-
Add the
viewport
property to thevisual
class.private viewport: IViewport;
-
In the
update
method, beforeReactCircleCard.update
, add the following code.this.viewport = options.viewport; const { width, height } = this.viewport; const size = Math.min(width, height);
-
In the
update
method, inReactCircleCard.update
, addsize
.size,
-
Save visual.ts.
-
In VS Code, from the src folder, open component.tsx.
-
Add the following code to
export interface State
.size: number
-
Add the following code to
export const initialState: State
.size: 200
-
In the
render
method, make the following changes to the code:-
Add
size
toconst { textLabel, textValue, size } = this.state;
. This declaration should now look like this:const { textLabel, textValue, size } = this.state;
-
Add the following code above
return
.const style: React.CSSProperties = { width: size, height: size };
-
Replace the first return line
<div className="circleCard">
with:<div className="circleCard" style={style}>
-
-
Save component.tsx.
-
In VS Code, from the style folder, open visual.less.
-
In
.circleCard
, replacewidth
andheight
withmin-width
andmin-height
.min-width: 200px; min-height: 200px;
-
Save visual.less.
In this section, you add the ability to customize your visual, allowing users to make changes to its color and border thickness.
Add the color and border thickness to the object
property in capabilities.json.
-
In VS Code, from the reactCircleCard folder, open capabilities.json.
-
Add the following settings to the
objects
property."circle": { "properties": { "circleColor": { "type": { "fill": { "solid": { "color": true } } } }, "circleThickness": { "type": { "numeric": true } } } }
-
Save capabilities.json.
Add the Circle
formatting settings to settings.ts. For more information how to build formatting model settings, see formatting utils.
-
In VS Code, from the src folder, open settings.ts.
-
Replace the code in settings.ts with the following code:
"use strict"; import { formattingSettings } from "powerbi-visuals-utils-formattingmodel"; import FormattingSettingsCard = formattingSettings.SimpleCard; import FormattingSettingsSlice = formattingSettings.Slice; import FormattingSettingsModel = formattingSettings.Model; /** * Circle Formatting Card */ class CircleCardSettings extends FormattingSettingsCard { circleColor = new formattingSettings.ColorPicker({ name: "circleColor", // circle color name should match circle color property name in capabilities.json displayName: "Color", description: "The fill color of the circle.", show: true, value: { value: "white" } }); circleThickness = new formattingSettings.NumUpDown({ name: "circleThickness", // circle thickness name should match circle color property name in capabilities.json displayName: "Thickness", description: "The circle thickness.", show: true, value: 2 }); name: string = "circle"; // circle card name should match circle object name in capabilities.json displayName: string = "Circle"; show: boolean = true; slices: Array<FormattingSettingsSlice> = [this.circleColor, this.circleThickness]; } /** * visual settings model class * */ export class VisualFormattingSettingsModel extends FormattingSettingsModel { // Create formatting settings model circle formatting card circleCard = new CircleCardSettings(); cards = [this.circleCard]; }
-
Save settings.ts.
Add the getFormattingModel
method used to apply visual settings and required imports to the visual.ts file.
-
In VS Code, from the src folder, open visual.ts.
-
Add these
import
statements at the top of visual.ts.import { FormattingSettingsService } from "powerbi-visuals-utils-formattingmodel"; import { VisualFormattingSettingsModel } from "./settings";
-
Add the following declaration to Visual.
private formattingSettings: VisualFormattingSettingsModel; private formattingSettingsService: FormattingSettingsService;
-
Add the
getFormattingModel
method to Visual.public getFormattingModel(): powerbi.visuals.FormattingModel { return this.formattingSettingsService.buildFormattingModel(this.formattingSettings); }
-
In the
Visual
class, add the following code line toconstructor
to initializeformattingSettingsService
this.formattingSettingsService = new FormattingSettingsService();
-
In the
Visual
class, add the following code toupdate
to update the visual formatting settings to the latest formatting properties values.-
Add this code to the if statement after
const size = Math.min(width, height);
.this.formattingSettings = this.formattingSettingsService.populateFormattingSettingsModel(VisualFormattingSettingsModel, options.dataViews[0]); const circleSettings = this.formattingSettings.circleCard;
-
Add this code to
ReactCircleCard.update
aftersize
:borderWidth: circleSettings.circleThickness.value, background: circleSettings.circleColor.value.value, }
-
-
Save visual.ts.
Edit the component file so that it can render the changes to the visual's color and border thickness.
-
In VS Code, from the src folder, open component.tsx.
-
Add these values to
State
:background?: string, borderWidth?: number
-
In the
render
method, replace the following code lines:-
const { textLabel, textValue, size } = this.state;
with:const { textLabel, textValue, size, background, borderWidth } = this.state;
-
const style: React.CSSProperties = { width: size, height: size };
with:const style: React.CSSProperties = { width: size, height: size, background, borderWidth };
-
-
Save component.tsx.
Experiment with the visual's color and border thickness, which you can now control.
-
Verify that
pbiviz start
is running, and in the Power BI service, refresh your React Circle Card visual. -
Select the Format tab and expand Circle.
-
Adjust the visual's Color and Thickness settings, and review their effect on the visual.