Skip to content

Commit ac2dbaf

Browse files
shafeeqzShafeeq
andauthored
Adding OnObject Formatting (#125)
* Add on object formatting support * Update Bar chart to use formattingId * Update barChartSettingsModel.ts * Update capabilities.json * Update package.json * use onobjectutils package * comments * lint fixes and comments * iupdate tutorials * update onobject tutorial --------- Co-authored-by: Shafeeq <shafeeqazzam@microsoft.com>
1 parent 4d39741 commit ac2dbaf

21 files changed

Lines changed: 2154 additions & 1401 deletions

Tutorial/ColorPalette.md

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,48 @@ interface BarChartDataPoint {
2626
`colorPalette` is a service that manages the colors used on your visual. An instance of it is available on `IVisualHost`.
2727

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

3232
```typescript
33-
let colorPalette: IColorPalette = host.colorPalette; // host: IVisualHost
34-
for (let i = 0, len = Math.max(category.values.length, dataValue.values.length); i < len; i++) {
35-
barChartDataPoints.push({
36-
category: category.values[i],
37-
value: dataValue.values[i],
38-
color: colorPalette.getColor(category.values[i]).value,
39-
});
33+
34+
function createSelectorDataPoints(options: VisualUpdateOptions, host: IVisualHost): BarChartDataPoint[] {
35+
let barChartDataPoints: BarChartDataPoint[] = []
36+
const dataViews = options.dataViews;
37+
if (!dataViews
38+
|| !dataViews[0]
39+
|| !dataViews[0].categorical
40+
|| !dataViews[0].categorical.categories
41+
|| !dataViews[0].categorical.categories[0].source
42+
|| !dataViews[0].categorical.values
43+
) {
44+
return barChartDataPoints;
45+
}
46+
47+
const categorical = dataViews[0].categorical;
48+
const category = categorical.categories[0];
49+
const dataValue = categorical.values[0];
50+
51+
const colorPalette: ISandboxExtendedColorPalette = host.colorPalette;
52+
const strokeColor: string = getColumnStrokeColor(colorPalette);
53+
const strokeWidth: number = getColumnStrokeWidth(colorPalette.isHighContrast);
54+
55+
for (let i = 0, len = Math.max(category.values.length, dataValue.values.length); i < len; i++) {
56+
const color: string = getColumnColorByIndex(category, i, colorPalette);
57+
58+
const selectionId: ISelectionId = host.createSelectionIdBuilder()
59+
.withCategory(category, i)
60+
.createSelectionId();
61+
62+
barChartDataPoints.push({
63+
color,
64+
strokeColor,
65+
strokeWidth,
66+
selectionId,
67+
value: dataValue.values[i],
68+
category: `${category.values[i]}`,
69+
});
70+
}
71+
return barChartDataPoints;
4072
}
41-
```
73+
```

Tutorial/ConditionalFormatting.md

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
# Adding conditional formatting to your Visual
2-
[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.
3-
4-
See [commit](https://github.com/microsoft/powerbi-visuals-api/commit/8fe88399c5ba82feeec4541ce5bf8e02a3ecd15a) for what was added at this step.
2+
[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.
3+
For more info on conditional formatting click [here](https://learn.microsoft.com/en-us/power-bi/developer/visuals/conditional-format?tabs=getFormattingModel)
54

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

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

15-
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.
14+
Define `instanceKind` property of required formatting property `descriptor` with the appropriate value.
1615
Use `VisualEnumerationInstanceKinds` enum to declare the type of the desired format (constant, rule or both).
1716

1817
```typescript
1918
// List your conditional formatting properties
20-
propertyInstanceKind: {
21-
fill: VisualEnumerationInstanceKinds.ConstantOrRule
22-
}
19+
instanceKind: powerbi.VisualEnumerationInstanceKinds.ConstantOrRule
2320
```
2421
![](images/ConditionalFormattingEntry.png)
2522

2623
## Define how conditional formatting behaves
2724
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).
2825

29-
In `enumerateObjectInstances`, make the following changes to the objects you want to apply conditional formatting to:
26+
In `BarChartFormattingSettingsModel`, make the following changes to the formatting properties you want to apply conditional formatting to:
3027

31-
* 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.
28+
* 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.
3229

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

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

4441
![](images/CondFormatSupport.png)

Tutorial/DataBinding.md

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -57,26 +57,25 @@ Use the internal `name` defined in your dataRoles to reference each field.
5757

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

60-
## Defining and Using `visualTransform`
60+
## Defining and Using `createSelectorDataPoints`
6161
DataView is the structure that PowerBI provides to your visual and it contains the queried data to be visualized.
6262
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.
6363

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

6767
```typescript
6868
/**
69-
* Function that converts queried data into a view model that will be used by the visual
69+
* Function that converts queried data into bar chart data points that will be used by the visual
7070
*
7171
* @function
7272
* @param {VisualUpdateOptions} options - Contains references to the size of the container
7373
* and the dataView which contains all the data
7474
* the visual had queried.
7575
* @param {IVisualHost} host - Contains references to the host which contains services
7676
*/
77-
function visualTransform(options: VisualUpdateOptions, host: IVisualHost): BarChartViewModel {
78-
/*Convert dataView to your viewModel*/
77+
function createSelectorDataPoints(options: VisualUpdateOptions, host: IVisualHost): BarChartDataPoint[] {
78+
/*Convert dataView to bar chart data points*/
7979
}
8080

81-
```
82-
See [commit](https://github.com/Microsoft/PowerBI-visuals-sampleBarChart/commit/3c6e8186436b63bf0cf97d2cdd5dde8aa8d08709) for what was added to visualTransform
81+
```

Tutorial/DataBoundObjects.md

Lines changed: 45 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,13 @@ See [commit](https://github.com/Microsoft/PowerBI-visuals-sampleBarChart/commit/
99
## Define Object in Capabilities
1010
Similar to static objects, we will define another object in the capabilities
1111
`colorSelector` is the internal name that will be referenced in the `dataView`.
12-
`displayName` is the name that will be shown on the property pane.
1312

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

1615
```typescript
1716
"colorSelector": {
18-
"displayName": "Data Colors",
1917
"properties": {
2018
"fill": {
21-
"displayName": "Color",
2219
"type": {
2320
"fill": {
2421
"solid": {
@@ -69,74 +66,65 @@ export function getCategoricalObjectValue<T>(category: DataViewCategoryColumn, i
6966
See [objectEnumerationUtility.ts](https://github.com/Microsoft/PowerBI-visuals-sampleBarChart/blob/master/src/objectEnumerationUtility.ts) for source code.
7067

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

7471
```typescript
72+
const strokeWidth: number = getColumnStrokeWidth(colorPalette.isHighContrast);
73+
7574
for (let i = 0, len = Math.max(category.values.length, dataValue.values.length); i < len; i++) {
76-
let defaultColor: Fill = {
77-
solid: {
78-
color: colorPalette.getColor(category.values[i]).value
79-
}
80-
}
75+
const color: string = getColumnColorByIndex(category, i, colorPalette);
76+
77+
const selectionId: ISelectionId = host.createSelectionIdBuilder()
78+
.withCategory(category, i)
79+
.createSelectionId();
8180

8281
barChartDataPoints.push({
83-
category: category.values[i],
82+
color,
83+
strokeColor,
84+
strokeWidth,
85+
selectionId,
8486
value: dataValue.values[i],
85-
color: getCategoricalObjectValue<Fill>(category, i, 'colorSelector', 'fill', defaultColor).solid.color,
86-
selectionId: host.createSelectionIdBuilder()
87-
.withCategory(category, i)
88-
.createSelectionId()
87+
category: `${category.values[i]}`,
8988
});
9089
}
9190
```
9291

93-
## Populate Property Pane with `enumerateObjectInstances`
94-
`enumerateObjectInstances` is used to populate the property pane with objects.
92+
## Populate Property Pane with `getFormattingModel`
93+
`getFormattingModel` is used to populate the property pane with objects.
94+
For more information [here](https://learn.microsoft.com/en-us/power-bi/developer/visuals/format-pane)
95+
9596
For this instance, we would like a color picker per category we have. Each category be rendered on the property pane.
97+
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.
9698

97-
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.
99+
Selection is required to associate the color with a data point.
100+
In visual class:
101+
```typescript
102+
public update(options: VisualUpdateOptions) {
103+
this.formattingSettings = this.formattingSettingsService.populateFormattingSettingsModel(BarChartSettingsModel, options.dataViews);
104+
this.barDataPoints = createSelectorDataPoints(options, this.host);
105+
this.formattingSettings.populateColorSelector(this.barDataPoints);
98106

99-
Selection is required to associate the color with a datapoint.
107+
// ...
108+
}
109+
```
100110

111+
In formatting settings model:
101112
```typescript
102-
/**
103-
* Enumerates through the objects defined in the capabilities and adds the properties to the format pane
104-
*
105-
* @function
106-
* @param {EnumerateVisualObjectInstancesOptions} options - Map of defined objects
113+
/**
114+
* populate colorSelector object categories formatting properties
115+
* @param dataPoints
107116
*/
108-
public enumerateObjectInstances(options: EnumerateVisualObjectInstancesOptions): VisualObjectInstanceEnumeration {
109-
let objectName = options.objectName;
110-
let objectEnumeration: VisualObjectInstance[] = [];
111-
112-
switch(objectName) {
113-
case 'enableAxis':
114-
objectEnumeration.push({
115-
objectName: objectName,
116-
properties: {
117-
show: this.barChartSettings.enableAxis.show,
118-
},
119-
selector: null
117+
populateColorSelector(dataPoints: BarChartDataPoint[]) {
118+
const slices: formattingSettings.ColorPicker[] = this.colorSelector.slices;
119+
if (dataPoints) {
120+
dataPoints.forEach(dataPoint => {
121+
slices.push(new formattingSettings.ColorPicker({
122+
name: "fill",
123+
displayName: dataPoint.category,
124+
value: { value: dataPoint.color },
125+
selector: dataPoint.selectionId.getSelector(),
126+
}));
120127
});
121-
break;
122-
case 'colorSelector':
123-
for(let barDataPoint of this.barDataPoints) {
124-
objectEnumeration.push({
125-
objectName: objectName,
126-
displayName: barDataPoint.category,
127-
properties: {
128-
fill: {
129-
solid: {
130-
color: barDataPoint.color
131-
}
132-
}
133-
},
134-
selector: barDataPoint.selectionId.getSelector()
135-
});
136-
}
137-
break;
138-
};
139-
140-
return objectEnumeration;
141-
}
142-
```
128+
}
129+
}
130+
```

Tutorial/ExtensibilityUtils.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ PowerBI provides several tools that help to cover the main needs to build your o
99
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.
1010
6. [FormattingUtils](https://www.npmjs.com/package/powerbi-visuals-utils-formattingutils) are interfaces for creating PowerBI custom visuals.
1111
7. [SVGUtils](https://www.npmjs.com/package/powerbi-visuals-utils-svgutils) is a tool for SVG manipulations for PowerBI custom visuals.
12+
8. [FormattingModelUtils](https://github.com/microsoft/powerbi-visuals-utils-formattingmodel) is a set of classes, interfaces and method help building format pane easily.
13+
9. [OnObjectUtils](https://github.com/microsoft/powerbi-visuals-utils-onobjectutils) provides an easy way for your Power BI custom visual to emit subselections to Power BI, get and render outlines.
1214

1315
### How to install
1416
To install the package you should run the following command in the directory with your current custom visual:
@@ -47,4 +49,4 @@ After that user can use all available module methods
4749
.call(xAxis);
4850
```
4951

50-
To get more information about SVGItils package, please check the following [documentation](https://github.com/Microsoft/powerbi-visuals-utils-svgutils/)
52+
To get more information about SVGItils package, please check the following [documentation](https://github.com/Microsoft/powerbi-visuals-utils-svgutils/)

Tutorial/ExternalLibraries.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,4 @@ Add the library to your `tsconfig.json` file.
4040
}
4141
```
4242

43-
Refer to [this](Typings.md) if you'd like to add typings for your JS file to get intellisense and compile time safety on them.
43+
Refer to [this](Typings.md) if you'd like to add typings for your JS file to get intellisense and compile time safety on them.

Tutorial/HighContrastSupport.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ In Sample Bar Chart, for example, all bars are drawn with 2 pixels thick foregro
6565
![Sample Bar Chart using *Dark #2* color theme](images/HC_sampleBarChart_dark2.png)
6666
![Sample Bar Chart using *White* color theme](images/HC_sampleBarChart_white.png)
6767
68-
Here is one place in the `visualTransform` function that was changed to support high-contrast, it is called as part of rendering during `update`:
68+
Here is one place in the `createSelectorDataPoints` function that was changed to support high-contrast, it is called as part of rendering during `update`:
6969
7070
**before**
7171
```typescript
@@ -89,6 +89,11 @@ Here is one place in the `visualTransform` function that was changed to support
8989
9090
**after**
9191
```typescript
92+
93+
const colorPalette: ISandboxExtendedColorPalette = host.colorPalette;
94+
const strokeColor: string = getColumnStrokeColor(colorPalette);
95+
const strokeWidth: number = getColumnStrokeWidth(colorPalette.isHighContrast);
96+
9297
for (let i = 0, len = Math.max(category.values.length, dataValue.values.length); i < len; i++) {
9398
const color: string = getColumnColorByIndex(category, i, colorPalette);
9499

@@ -125,9 +130,4 @@ Here is one place in the `visualTransform` function that was changed to support
125130

126131
return getCategoricalObjectValue<Fill>(category, index, 'colorSelector', 'fill', defaultColor).solid.color;
127132
}
128-
```
129-
130-
131-
132-
133-
133+
```

0 commit comments

Comments
 (0)