Find everything you need to get certified on Fabric—skills challenges, live sessions, exam prep, role guidance, and more.
Get startedGrow your Fabric skills and prepare for the DP-600 certification exam by completing the latest Microsoft Fabric challenge.
Hi,
I am trying to implement highlighting in a custom visual I am developing. This visual is using the Matrix dataViewMapping.
I am able to use selections in my Visual and when enabling visual interactions I can select the highlight options in my visual (see image)
But when I now select a value in another visual the selected point is not highlighted in my visual, which it should so if highlighting would work.
Because I am not sure what I am missing, I will add as much as information to this post. So it might get a bit long 🙂
I hope someone can help me to get this to work.
Thanks in advance!
Paul.
Below you will find the information:
The dataViewMappings-part of my capabilities.json:
"dataRoles": [
{
"name": "category",
"kind": "Grouping",
"displayName": "Category"
},
{
"name": "value",
"kind": "GroupingOrMeasure",
"displayName": "Value"
}
],
"dataViewMappings": [
{
"conditions": [
{
"value": {
"max": 1
},
"category": {
"max": 1
}
}
],
"matrix": {
"rows": {
"for": {
"in": "category"
}
},
"values": {
"select": [
{
"for": {
"in": "value"
}
}
]
}
}
}
],
"supportsHighlight": true,
I am using the GroupingOrMeasure-kind for 'value' so I can select Don't summarize for the measures that are selected for this value.
My dataViewModel looks like this:
export interface StripPlotViewModel {
dataView: DataView;
settings: StripPlotSettings;
dataPoints: StripPlotPoint[];
hasHighlights: boolean;
isCategoryFilled: boolean;
isValueFilled: boolean;
}
The StripPlotPoint-interface :
export interface StripPlotPoint extends SelectableDataPoint {
category: PrimitiveValue;
value: PrimitiveValue;
opacity: number;
highlight?: boolean;
hasHighlights: boolean;
}
I am using a seperate file to define my behavior:
import * as d3 from "d3";
type Selection<T1, T2 = T1> = d3.Selection<any, T1, any, T2>;
import { interactivityBaseService as interactivityService } from "powerbi-visuals-utils-interactivityutils";
import IInteractiveBehavior = interactivityService.IInteractiveBehavior;
import IInteractivityService = interactivityService.IInteractivityService;
import ISelectionHandler = interactivityService.ISelectionHandler;
import { StripPlotPoint } from "./dataInterfaces";
import { IBehaviorOptions } from "powerbi-visuals-utils-interactivityutils/lib/interactivityBaseService";
import { StripPlotSettings } from "./settings";
export const DimmedOpacity: number = 0.2;
export const DefaultOpacity: number = 1.0;
const getEvent = () => d3.event;
export function getFillOpacity(
selected: boolean,
highlight: boolean,
hasSelection: boolean,
hasPartialHighlights: boolean
): number {
if ((hasPartialHighlights && !highlight) || (hasSelection && !selected)) {
return DimmedOpacity;
}
return DefaultOpacity;
}
export interface BehaviorOptions extends IBehaviorOptions<StripPlotPoint> {
clearCatcher: Selection<any>;
pointSelection: Selection<StripPlotPoint>;
interactivityService: IInteractivityService<StripPlotPoint>;
settings: StripPlotSettings;
}
export class Behavior implements IInteractiveBehavior {
private options: BehaviorOptions;
public bindEvents(options: BehaviorOptions, selectionHandler: ISelectionHandler) {
this.options = options;
let clearCatcher = options.clearCatcher;
options.pointSelection.on("click", (dataPoint: StripPlotPoint) => {
const event: MouseEvent = d3.event;
console.log("clicked: ");
console.log(event);
selectionHandler.handleSelection(dataPoint, event.ctrlKey || event.metaKey);
event.stopPropagation();
});
clearCatcher.on("click", () => {
selectionHandler.handleClearSelection();
});
}
public renderSelection(hasSelection: boolean) {
const {
pointSelection,
interactivityService,
} = this.options;
const hasHighlights: boolean = interactivityService.hasSelection();
pointSelection.style("opacity", (dataPoint: StripPlotPoint) => {
return getFillOpacity(
dataPoint.selected,
dataPoint.highlight,
!dataPoint.highlight && hasSelection,
!dataPoint.selected && hasHighlights,
);
});
}
}
During the update of the Visual I am converting the dataView to my dataViewModel and adding the selectionIds:
let dataPoints: StripPlotPoint[] = [];
for (let n = 0; n < dataView.matrix.rows.root.children.length; n++) {
const selector: ISelectionId = host.createSelectionIdBuilder()
.withMatrixNode(dataView.matrix.rows.root.children[n],dataView.matrix.rows.levels )
.createSelectionId();
let dataPoint: StripPlotPoint = {
category: dataView.matrix.rows.root.children[n].levelValues[categoryIndex].value,
value: dataView.matrix.rows.root.children[n].levelValues[valueIndex].value,
selected: false,
highlight: false,
identity: selector,
opacity: 1,
hasHighlights: false
}
dataPoints.push(dataPoint)
}
When checking the datapoints I can see that there are values added for the identity (see screenshot of my console.log)
In the development-visual the data the dataview looks like (i removed a lot of children to limit the size)
[
{
"metadata":{
"columns":[
{
"roles":{"category":true},
"type":{"underlyingType":1,"category":{},"primitiveType":1,"extendedType":1,"categoryString":{},"text":true,"numeric":false,"integer":false,"bool":false,"dateTime":false,"duration":false,"binary":false,"none":false},
"displayName":"gender",
"queryName":"strip-plot-test.gender",
"expr":{"_kind":2,"source":{"_kind":0,"entity":"strip-plot-test","variable":"s","kind":0},"ref":"gender","kind":2},
"rolesIndex":{"category":[0]},
"index":0,
"identityExprs":[{"_kind":2,"source":{"_kind":0,"entity":"strip-plot-test","kind":0},"ref":"gender","kind":2}]
},{
"roles":{"value":true},
"type":{"underlyingType":259,"category":{},"primitiveType":3,"extendedType":259,"categoryString":{},"text":false,"numeric":true,"integer":false,"bool":false,"dateTime":false,"duration":false,"binary":false,"none":false},
"displayName":"height",
"queryName":"strip-plot-test.height",
"expr":{"_kind":2,"source":{"_kind":0,"entity":"strip-plot-test","variable":"s","kind":0},"ref":"height","kind":2},
"rolesIndex":{"value":[0]},
"index":1,
"identityExprs":[{"_kind":2,"source":{"_kind":0,"entity":"strip-plot-test","kind":0},"ref":"height","kind":2}]}],
"objects":{
"chart":{"dataPointShape":"bar","showGridLines":true},
"yAxis":{"textSize":19},
"triangle":{"strokeWidth":0,"size":12},
"license":{"show":true},
"bar":{"strokeWidth":8,"size":9,"percentile":72}
},
"dataReduction":{
"matrix":{"rows":{}}
}
},
"matrix":{
"rows":{
"levels":[
{
"sources":[
{
"roles":{"category":true},
"type":{"underlyingType":1,"category":{},"primitiveType":1,"extendedType":1,"categoryString":{},"text":true,"numeric":false,"integer":false,"bool":false,"dateTime":false,"duration":false,"binary":false,"none":false},
"displayName":"gender",
"queryName":"strip-plot-test.gender",
"expr":{"_kind":2,"source":{"_kind":0,"entity":"strip-plot-test","variable":"s","kind":0},"ref":"gender","kind":2},
"rolesIndex":{"category":[0]},
"index":0,
"identityExprs":[{"_kind":2,"source":{"_kind":0,"entity":"strip-plot-test","kind":0},"ref":"gender","kind":2}]
},
{
"roles":{"value":true},
"type":{"underlyingType":259,"category":{},"primitiveType":3,"extendedType":259,"categoryString":{},"text":false,"numeric":true,"integer":false,"bool":false,"dateTime":false,"duration":false,"binary":false,"none":false},
"displayName":"height",
"queryName":"strip-plot-test.height",
"expr":{"_kind":2,"source":{"_kind":0,"entity":"strip-plot-test","variable":"s","kind":0},"ref":"height","kind":2},
"rolesIndex":{"value":[0]},
"index":1,
"identityExprs":[{"_kind":2,"source":{"_kind":0,"entity":"strip-plot-test","kind":0},"ref":"height","kind":2}]
}
]
}
],
"root":{
"children":[
{
"levelValues":[
{
"levelSourceIndex":0,
"value":"female"
},
{
"levelSourceIndex":1,
"value":57.50321861
}
],
"value":57.50321861,
"levelSourceIndex":1,
"level":0,
"identity":{
"kind":1,
"_expr":{"_kind":8,"left":{"_kind":13,"comparison":0,"left":{"_kind":2,"source":{"_kind":0,"entity":"strip-plot-test","kind":0},"ref":"gender","kind":2},"right":{"_kind":17,"type":{"underlyingType":1,"category":{},"primitiveType":1,"extendedType":1,"categoryString":{},"text":true,"numeric":false,"integer":false,"bool":false,"dateTime":false,"duration":false,"binary":false,"none":false},"value":"female","typeEncodedValue":"'female'","valueEncoded":"'female'","kind":17},"kind":13},"right":{"_kind":13,"comparison":0,"left":{"_kind":2,"source":{"_kind":0,"entity":"strip-plot-test","kind":0},"ref":"height","kind":2},"right":{"_kind":17,"type":{"underlyingType":259,"category":{},"primitiveType":3,"extendedType":259,"categoryString":{},"text":false,"numeric":true,"integer":false,"bool":false,"dateTime":false,"duration":false,"binary":false,"none":false},"value":57.50321861,"typeEncodedValue":"57.50321861D","valueEncoded":"57.50321861D","kind":17},"kind":13},"kind":8},
"_key":{"factoryMethod":{},"value":"{\"and\":{\"l\":{\"comp\":{\"k\":0,\"l\":{\"col\":{\"s\":{\"e\":\"strip-plot-test\"},\"r\":\"gender\"}},\"r\":{\"const\":{\"t\":1,\"v\":\"female\"}}}},\"r\":{\"comp\":{\"k\":0,\"l\":{\"col\":{\"s\":{\"e\":\"strip-plot-test\"},\"r\":\"height\"}},\"r\":{\"const\":{\"t\":3,\"v\":57.50321861}}}}}}"},
"expr":{"_kind":8,"left":{"_kind":13,"comparison":0,"left":{"_kind":2,"source":{"_kind":0,"entity":"strip-plot-test","kind":0},"ref":"gender","kind":2},"right":{"_kind":17,"type":{"underlyingType":1,"category":{},"primitiveType":1,"extendedType":1,"categoryString":{},"text":true,"numeric":false,"integer":false,"bool":false,"dateTime":false,"duration":false,"binary":false,"none":false},"value":"female","typeEncodedValue":"'female'","valueEncoded":"'female'","kind":17},"kind":13},"right":{"_kind":13,"comparison":0,"left":{"_kind":2,"source":{"_kind":0,"entity":"strip-plot-test","kind":0},"ref":"height","kind":2},"right":{"_kind":17,"type":{"underlyingType":259,"category":{},"primitiveType":3,"extendedType":259,"categoryString":{},"text":false,"numeric":true,"integer":false,"bool":false,"dateTime":false,"duration":false,"binary":false,"none":false},"value":57.50321861,"typeEncodedValue":"57.50321861D","valueEncoded":"57.50321861D","kind":17},"kind":13},"kind":8},"key":"{\"and\":{\"l\":{\"comp\":{\"k\":0,\"l\":{\"col\":{\"s\":{\"e\":\"strip-plot-test\"},\"r\":\"gender\"}},\"r\":{\"const\":{\"t\":1,\"v\":\"female\"}}}},\"r\":{\"comp\":{\"k\":0,\"l\":{\"col\":{\"s\":{\"e\":\"strip-plot-test\"},\"r\":\"height\"}},\"r\":{\"const\":{\"t\":3,\"v\":57.50321861}}}}}}"}
},
{
"levelValues":[
{
"levelSourceIndex":0,
"value":"female"
},
{
"levelSourceIndex":1,
"value":57.97290083
}
]
},...
]
},
"columns":{
"levels":[],
"root":{
"children":[]
}
},
"valueSources":[]
},
"categorical":{},
"table":{},
"tree":{},
"single":{}
}
]
Solved! Go to Solution.
Hi All,
It looks like this only works when you are not selecting Don't Summarize for the GroupingOrMeasure-datafield.
When you select an aggregation (it will behave like a measure) then the highlights do appear.
Unfortunately this is not going to work for this visual because of the granularity of the values. I need all values and not the aggregates. So the hightlighting will work for the matrix-dataViewMapping when you select an aggregation for the measure
Regards
Paul
Hi All,
It looks like this only works when you are not selecting Don't Summarize for the GroupingOrMeasure-datafield.
When you select an aggregation (it will behave like a measure) then the highlights do appear.
Unfortunately this is not going to work for this visual because of the granularity of the values. I need all values and not the aggregates. So the hightlighting will work for the matrix-dataViewMapping when you select an aggregation for the measure
Regards
Paul
Ask questions in Eventhouse and KQL, Eventstream, and Reflex.
Check out the May 2024 Power BI update to learn about new features.
User | Count |
---|---|
15 | |
4 | |
3 | |
3 | |
2 |