Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate SampleBarChart to new Formatting Model Pane #102

Open
wants to merge 39 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
45f286c
Migrate SampleBarChart to new Formatting Model Pane
Jul 5, 2022
87a6623
Add topLevelToggle boolean
Jul 5, 2022
fa20f56
Update barChart formatting settings model
Aug 2, 2022
6937e3d
Modify formatting settings to use formatting model utils service & Ad…
Aug 15, 2022
3c7df9c
Merge pull request #104 from microsoft/dev/sdabbah/Modify-UseFormatti…
ShereinDabbah Sep 4, 2022
d275cb2
Delete Localization strings - it didnt exist before
Sep 25, 2022
dc1c493
Update visuals-api version to 5.1.0
Oct 19, 2022
54b69e1
Update visuals-api version to 5.1.0
Oct 19, 2022
b3e1617
Fix npm run lint errors
Oct 19, 2022
e68e994
Additional version change and Add changelog
Oct 20, 2022
60f12d8
Description and comments modifications
Oct 23, 2022
d8c4359
Update package-lock
Oct 23, 2022
8887dc7
Change version to 5.0.0
Oct 23, 2022
769f106
Update sample bar chart docs
Oct 23, 2022
05ac876
add d3-selection v1 dependency
Oct 25, 2022
41a6f86
Merge branch 'main' into dev/sdabbah/formattingmodel-interfaces
ShereinDabbah Dec 27, 2022
890a500
Adding typescript dependency
Dec 27, 2022
919bffb
Add topLevelToggle boolean
Jul 5, 2022
cee76c3
Update barChart formatting settings model
Aug 2, 2022
d746aba
Modify formatting settings to use formatting model utils service & Ad…
Aug 15, 2022
82dacfa
Delete Localization strings - it didnt exist before
Sep 25, 2022
b579279
Update visuals-api version to 5.1.0
Oct 19, 2022
972f43e
Update visuals-api version to 5.1.0
Oct 19, 2022
2a13c9f
Fix npm run lint errors
Oct 19, 2022
9d7b86e
Additional version change and Add changelog
Oct 20, 2022
f08668f
Description and comments modifications
Oct 23, 2022
f65a625
Update package-lock
Oct 23, 2022
ee57175
Change version to 5.0.0
Oct 23, 2022
4bb51f0
Update sample bar chart docs
Oct 23, 2022
58d2199
add d3-selection v1 dependency
Oct 25, 2022
ed40f1d
Microsoft mandatory file
microsoft-github-policy-service[bot] Sep 22, 2022
77ce691
Adding typescript dependency
Dec 27, 2022
03de612
Merge branch 'dev/sdabbah/formattingmodel-interfaces' of https://gith…
Feb 20, 2023
685eb12
Merge branch 'dev/sdabbah/formattingmodel-interfaces' of https://gith…
Feb 20, 2023
1dd833d
Merge branch 'dev/sdabbah/formattingmodel-interfaces' of https://gith…
Feb 20, 2023
2dd5342
Revert "Adding typescript dependency"
Feb 22, 2023
407d681
Add topLevelToggle boolean
Jul 5, 2022
93f23dd
Update barChart formatting settings model
Aug 2, 2022
7fd3c5b
Revert "Update barChart formatting settings model"
Mar 30, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

This page contains information about changes to the 'Sample bar chart' Power BI visual.

ShereinDabbah marked this conversation as resolved.
Show resolved Hide resolved
## 5.0.0

* Migrate to API version 5.1.0
* Update powerbi-visuals-api to 5.1.x
* Added powerbi-visuals-utils-formattingmodel 5.0.x
* Replace enumerateObjectInstances by getFormattingModel API
* Build new formatting pane settings

## 3.2.0

* Added *modern tooltip* feature
Expand Down
50 changes: 41 additions & 9 deletions Tutorial/ColorPalette.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,48 @@ interface BarChartDataPoint {
`colorPalette` is a service that manages the colors used on your visual. An instance of it is available on `IVisualHost`.

## Assigning Color to Data Points
We defined `visualTransform` as a construct to convert `dataView` to a view model Bar Chart can use.
Since we iterate through the data points in `visualTransform` it is also the ideal place to assign colors.
We defined `createSelectorDataPoints` as a construct to convert options `dataView` to Bar Chart data points that will be used in visual view.
Since we iterate through the data points in `createSelectorDataPoints` it is also the ideal place to assign colors.

```typescript
let colorPalette: IColorPalette = host.colorPalette; // host: IVisualHost
for (let i = 0, len = Math.max(category.values.length, dataValue.values.length); i < len; i++) {
barChartDataPoints.push({
category: category.values[i],
value: dataValue.values[i],
color: colorPalette.getColor(category.values[i]).value,
});

function createSelectorDataPoints(options: VisualUpdateOptions, host: IVisualHost): BarChartDataPoint[] {
let barChartDataPoints: BarChartDataPoint[] = []
const dataViews = options.dataViews;
if (!dataViews
|| !dataViews[0]
|| !dataViews[0].categorical
|| !dataViews[0].categorical.categories
|| !dataViews[0].categorical.categories[0].source
|| !dataViews[0].categorical.values
) {
return barChartDataPoints;
}

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

const colorPalette: ISandboxExtendedColorPalette = host.colorPalette;
const strokeColor: string = getColumnStrokeColor(colorPalette);
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]}`,
});
}
return barChartDataPoints;
}
```
19 changes: 8 additions & 11 deletions Tutorial/ConditionalFormatting.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# Adding conditional formatting to your Visual
[Conditional formatting](https://docs.microsoft.com/en-us/power-bi/visuals/service-tips-and-tricks-for-color-formatting#conditional-formatting-for-visualizations) of custom properties is supported by updating `VisualObjectInstance` object's properties as enumerated under `enumerateObjectInstances` method.

See [commit](https://github.com/microsoft/powerbi-visuals-api/commit/8fe88399c5ba82feeec4541ce5bf8e02a3ecd15a) for what was added at this step.
[Conditional formatting](https://docs.microsoft.com/en-us/power-bi/visuals/service-tips-and-tricks-for-color-formatting#conditional-formatting-for-visualizations) of custom formatting properties is supported by setting formatting property `instanceKind` in `getFormattingModel` method.
For more info on conditional formatting click [here](https://learn.microsoft.com/en-us/power-bi/developer/visuals/conditional-format?tabs=getFormattingModel)

Conditional formatting can only be applied to the following property types:
* Color
Expand All @@ -10,25 +9,23 @@ Conditional formatting can only be applied to the following property types:
* Web URL

## Add a conditional color formatting entry in the format pane
To add the conditional color formatting button in the format pane for the desired object, under the `enumerateObjectInstances` method, make the following change:
To add the conditional color formatting button in the format pane for the desired object, under the `getFormattingModel` method, make the following change:

Via `propertyInstanceKind` property of enumerated `VisualObjectInstance`, list all the properties that you'd like to have the conditional formatting entry applied to in the format pane.
Define `instanceKind` property of required formatting property `descriptor` with the appropriate value.
Use `VisualEnumerationInstanceKinds` enum to declare the type of the desired format (constant, rule or both).

```typescript
// List your conditional formatting properties
propertyInstanceKind: {
fill: VisualEnumerationInstanceKinds.ConstantOrRule
}
instanceKind: powerbi.VisualEnumerationInstanceKinds.ConstantOrRule
```
![](images/ConditionalFormattingEntry.png)

## Define how conditional formatting behaves
Using `createDataViewWildcardSelector` declared under `powerbi-visuals-utils-dataviewutils`, specify whether conditional formatting will be applied to instances, totals, or both. For more information, see [DataViewWildcard](https://docs.microsoft.com/en-us/power-bi/developer/visuals/utils-dataview#dataviewwildcard).

In `enumerateObjectInstances`, make the following changes to the objects you want to apply conditional formatting to:
In `BarChartFormattingSettingsModel`, make the following changes to the formatting properties you want to apply conditional formatting to:

* Replace the `VisualObjectInstance`'s `selector` value with a `dataViewWildcard.createDataViewWildcardSelector()` call. Specify the desired option from `DataViewWildcardMatchingOption` enum to define whether conditional formatting is applied to instances, totals, or both.
* Replace the formatting property `descriptor`'s `selector` value with a `dataViewWildcard.createDataViewWildcardSelector()` call. Specify the desired option from `DataViewWildcardMatchingOption` enum to define whether conditional formatting is applied to instances, totals, or both.

* Add the `altConstantValueSelector` property having the value previously defined for the `selector` property.

Expand All @@ -39,6 +36,6 @@ selector: dataViewWildcard.createDataViewWildcardSelector(dataViewWildcard.DataV
// Add this property with the value previously defined for the selector property
altConstantValueSelector: barDataPoint.selectionId.getSelector()
```
See [commit](https://github.com/Microsoft/PowerBI-visuals-sampleBarChart/commit/956923b641bb1eacb613bf55a91f77725bc42431) for how conditional formatting was applied to sample bar chart.
See [commit](https://github.com/Microsoft/PowerBI-visuals-sampleBarChart) for how conditional formatting was applied to sample bar chart.

![](images/CondFormatSupport.png)
13 changes: 6 additions & 7 deletions Tutorial/DataBinding.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,26 +57,25 @@ Use the internal `name` defined in your dataRoles to reference each field.

For more information, see the section about [Data View Mapping](https://github.com/Microsoft/PowerBI-visuals/blob/master/Capabilities/DataViewMappings.md).

## Defining and Using `visualTransform`
## Defining and Using `createSelectorDataPoints`
DataView is the structure that PowerBI provides to your visual and it contains the queried data to be visualized.
However, DataView provides your data in different forms such as categorical and table forms. In this instance we're building a categorical visual and we will only need the use the categorical property on the DataView.

Defining visualTransform will allow you to convert DataView into a view model your visual will use.
Defining `createSelectorDataPoints` will allow you to convert options dataView into bar chart data points your visual will use.
IVisualHost is required because when defining individual data points, you will want to assign colors and selection to them.

```typescript
/**
* Function that converts queried data into a view model that will be used by the visual
* Function that converts queried data into bar chart data points 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 {
/*Convert dataView to your viewModel*/
function createSelectorDataPoints(options: VisualUpdateOptions, host: IVisualHost): BarChartDataPoint[] {
/*Convert dataView to bar chart data points*/
}

```
See [commit](https://github.com/Microsoft/PowerBI-visuals-sampleBarChart/commit/3c6e8186436b63bf0cf97d2cdd5dde8aa8d08709) for what was added to visualTransform
```
102 changes: 46 additions & 56 deletions Tutorial/DataBoundObjects.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,13 @@ See [commit](https://github.com/Microsoft/PowerBI-visuals-sampleBarChart/commit/
## Define Object in Capabilities
Similar to static objects, we will define another object in the capabilities
`colorSelector` is the internal name that will be referenced in the `dataView`.
`displayName` is the name that will be shown on the property pane.

`fill` is a `StructuralObjectValue` and is not associated with a primitive type.

```typescript
"colorSelector": {
"displayName": "Data Colors",
"properties": {
"fill": {
"displayName": "Color",
"type": {
"fill": {
"solid": {
Expand Down Expand Up @@ -69,74 +66,67 @@ export function getCategoricalObjectValue<T>(category: DataViewCategoryColumn, i
See [objectEnumerationUtility.ts](https://github.com/Microsoft/PowerBI-visuals-sampleBarChart/blob/master/src/objectEnumerationUtility.ts) for source code.

## Defining Default Color and Retrieving Categorical Object from DataView
Each color is now associated with each category inside `dataView`. We will set each data point to its cooresponding color.
Each color is now associated with each category inside options dataView. We will set each data point to its corresponding color.

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

for (let i = 0, len = Math.max(category.values.length, dataValue.values.length); i < len; i++) {
let defaultColor: Fill = {
solid: {
color: colorPalette.getColor(category.values[i]).value
}
}
const color: string = getColumnColorByIndex(category, i, colorPalette);

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

barChartDataPoints.push({
category: category.values[i],
color,
strokeColor,
strokeWidth,
selectionId,
value: dataValue.values[i],
color: getCategoricalObjectValue<Fill>(category, i, 'colorSelector', 'fill', defaultColor).solid.color,
selectionId: host.createSelectionIdBuilder()
.withCategory(category, i)
.createSelectionId()
category: `${category.values[i]}`,
});
}
```

## Populate Property Pane with `enumerateObjectInstances`
`enumerateObjectInstances` is used to populate the property pane with objects.
## Populate Property Pane with `getFormattingModel`
`getFormattingModel` is used to populate the property pane with objects.
For more information [here](https://learn.microsoft.com/en-us/power-bi/developer/visuals/format-pane)

For this instance, we would like a color picker per category we have. Each category be rendered on the property pane.
We will do this by adding a populate method `populateColorSelector` to create corresponding bar chart data points color selector in format pane after building the data points in `update` method. This `populateColorSelector` method iterate through each data point with the associated color.

We will do this by adding an additional case to the switch statement for `colorSelector` and iterate through each data point with the associated color.
Selection is required to associate the color with a data point.
In visual class:
```typescript
public update(options: VisualUpdateOptions) {
this.formattingSettings = this.formattingSettingsService.populateFormattingSettingsModel(BarChartSettingsModel, options.dataViews);
this.barDataPoints = createSelectorDataPoints(options, this.host);
this.formattingSettings.populateColorSelector(this.barDataPoints);

Selection is required to associate the color with a datapoint.
// ...
}
```

In formatting settings model:
```typescript
/**
* Enumerates through the objects defined in the capabilities and adds the properties to the format pane
*
* @function
* @param {EnumerateVisualObjectInstancesOptions} options - Map of defined objects
/**
* populate colorSelector object categories formatting properties
* @param dataPoints
*/
public enumerateObjectInstances(options: EnumerateVisualObjectInstancesOptions): VisualObjectInstanceEnumeration {
let objectName = options.objectName;
let objectEnumeration: VisualObjectInstance[] = [];

switch(objectName) {
case 'enableAxis':
objectEnumeration.push({
objectName: objectName,
properties: {
show: this.barChartSettings.enableAxis.show,
},
selector: null
});
break;
case 'colorSelector':
for(let barDataPoint of this.barDataPoints) {
objectEnumeration.push({
objectName: objectName,
displayName: barDataPoint.category,
properties: {
fill: {
solid: {
color: barDataPoint.color
}
}
},
selector: barDataPoint.selectionId.getSelector()
});
}
break;
};

return objectEnumeration;
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: powerbiVisualsApi.VisualEnumerationInstanceKinds.ConstantOrRule
}));
});
}
}
```
1 change: 1 addition & 0 deletions Tutorial/ExtensibilityUtils.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ PowerBI provides several tools that help to cover the main needs to build your o
5. [InteractivityUtils](https://www.npmjs.com/package/powerbi-visuals-utils-interactivityutils) is a set of functions and classes for implementation of cross-selection and cross-filtering for PowerBI custom visuals.
6. [FormattingUtils](https://www.npmjs.com/package/powerbi-visuals-utils-formattingutils) are interfaces for creating PowerBI custom visuals.
7. [SVGUtils](https://www.npmjs.com/package/powerbi-visuals-utils-svgutils) is a tool for SVG manipulations for PowerBI custom visuals.
8. [FormattingModelUtils](https://github.com/microsoft/powerbi-visuals-utils-formattingmodel) is a set of classes, interfaces and method help building format pane easily.

### How to install
To install the package you should run the following command in the directory with your current custom visual:
Expand Down
7 changes: 6 additions & 1 deletion Tutorial/HighContrastSupport.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ In Sample Bar Chart, for example, all bars are drawn with 2 pixels thick foregro
![Sample Bar Chart using *Dark #2* color theme](images/HC_sampleBarChart_dark2.png)
![Sample Bar Chart using *White* color theme](images/HC_sampleBarChart_white.png)

Here is one place in the `visualTransform` function that was changed to support high-contrast, it is called as part of rendering during `update`:
Here is one place in the `createSelectorDataPoints` function that was changed to support high-contrast, it is called as part of rendering during `update`:

**before**
```typescript
Expand All @@ -89,6 +89,11 @@ Here is one place in the `visualTransform` function that was changed to support

**after**
```typescript

const colorPalette: ISandboxExtendedColorPalette = host.colorPalette;
const strokeColor: string = getColumnStrokeColor(colorPalette);
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);

Expand Down
18 changes: 7 additions & 11 deletions Tutorial/LaunchURL.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
# Opening a URL in a new tab/window
Launch URL allows opening a new browser tab (or window), by delegating the actual work to Power BI.

See [commit](https://github.com/Microsoft/PowerBI-visuals-sampleBarChart/commit/2ecc5cf74b9bc6fbf5c03f84c3ab24841b489d4e) for what was added at this step.

Note: custom visuals are hosted in Power BI inside sandboxed iframes, this prevents opening a new browser tab (or window) in "the usual way", e.g. using `window.open('http://some.link.net','_blank')`.

## Usage
Use the `host.launchUrl()` API call, passing your destenation URL as a string argument:
Use the `host.launchUrl()` API call, passing your destination URL as a string argument:

```typescript
this.host.launchUrl('http://some.link.net');
Expand All @@ -18,7 +16,7 @@ this.host.launchUrl('http://some.link.net');

## Best practices
1. For most cases, it is best to only open a link as a response to a user's explicit action. Make it easy for the user to understand that clicking the link or button will result in opening a new tab. Triggering a `launchUrl()` call without a user's action, or as a side effect of a different action can be confusing or frustrating for the user.
2. If the link is not crucial for the proper functioning of the visual, it is recommanded to provide the report's author a way to disable and hide the link. This is especially relevant for special Power BI use-cases, such as embedding a report in a 3rd party application or publishing it to the web.
2. If the link is not crucial for the proper functioning of the visual, it is recommended to provide the report's author a way to disable and hide the link. This is especially relevant for special Power BI use-cases, such as embedding a report in a 3rd party application or publishing it to the web.
3. Avoid Triggering a `launchUrl()` call from inside a loop, the visual's `update` function, or any other frequently recurring code.

## Step by step example
Expand Down Expand Up @@ -51,11 +49,9 @@ A `showHelpLink` boolean static object was added to `capabilities.json` objects
"objects": {
//...
"generalView": {
"displayName": "General View",
"properties":
//...
"showHelpLink": {
"displayName": "Show Help Button",
"type": {
"bool": true
}
Expand All @@ -69,10 +65,10 @@ A `showHelpLink` boolean static object was added to `capabilities.json` objects

And, in the visual's `update` function, the following lines were added:
```typescript
if (settings.generalView.showHelpLink) {
this.helpLinkElement.classList.remove("hidden");
} else {
this.helpLinkElement.classList.add("hidden");
}
this.helpLinkElement
.classed("hidden", !this.formattingSettings.generalView.showHelpLink.value)
.style("border-color", this.formattingSettings.generalView.helpLinkColor)
.style("color", this.formattingSettings.generalView.helpLinkColor);
```

The `hidden` class is defined in visual.less to control the display of the element.
Loading