Earn the coveted Fabric Analytics Engineer certification. 100% off your exam for a limited time only!
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
User | Count |
---|---|
17 | |
11 | |
5 | |
4 | |
3 |