Fremhæv datapunkter i Power BI-visualiseringer
I denne artikel beskrives det, hvordan du fremhæver data i Power BI-visualiseringer.
Når et element er valgt, filtreres matrixen values
dataView
i objektet som standard, så den kun viser de valgte værdier. Når matrixen values
filtreres, viser alle andre visualiseringer på siden kun de valgte data.
Hvis du angiver egenskaben supportsHighlight
i filen capabilities.json
til true
, resulterer den i den fulde ufiltrerede values
matrix sammen med en highlights
matrix. Matrixen highlights
har samme længde som værdimatrixen, og alle ikke-markerede værdier er angivet til null
. Når denne egenskab er aktiveret, fremhæves de relevante data i visualiseringen ved at sammenligne matrixen values
med matrixen highlights
.
Bemærk i eksemplet, at:
- Uden understøttelse af fremhævning er markeringen den eneste værdi i matrixen
values
og den eneste søjle, der vises i datavisningen. - Med understøttelse af fremhævning er alle værdier i matrixen
values
. Matrixenhighlights
indeholder ennull
værdi for elementer, der ikke er fremhævet. Alle søjler vises i datavisningen, og den fremhævede søjle har en anden farve.
Der kan også være flere markeringer og delvise fremhævninger. De fremhævede værdier vises i datavisningen.
Bemærk
Tilknytning af tabeldatavisning understøtter ikke fremhævningsfunktioner.
Fremhæv datapunkter med tilknytning af kategoriske datavisninger
Føj "supportsHighlight": true
til filen for visualiseringer med tilknytning af capabilities.json
kategoriske datavisninger. Eksempler:
{
"dataRoles": [
{
"displayName": "Category",
"name": "category",
"kind": "Grouping"
},
{
"displayName": "Value",
"name": "value",
"kind": "Measure"
}
],
"dataViewMappings": [
{
"categorical": {
"categories": {
"for": {
"in": "category"
}
},
"values": {
"for": {
"in": "value"
}
}
}
}
],
"supportsHighlight": true
}
Når du har fjernet unødvendig kode, ser standardkildekoden for visualiseringen ud som i følgende eksempel:
"use strict";
// ... default imports list
import { FormattingSettingsService } from "powerbi-visuals-utils-formattingmodel";
import DataViewCategorical = powerbi.DataViewCategorical;
import DataViewCategoryColumn = powerbi.DataViewCategoryColumn;
import PrimitiveValue = powerbi.PrimitiveValue;
import DataViewValueColumn = powerbi.DataViewValueColumn;
import { VisualFormattingSettingsModel } from "./settings";
export class Visual implements IVisual {
private target: HTMLElement;
private formattingSettings: VisualFormattingSettingsModel;
private formattingSettingsService: FormattingSettingsService;
constructor(options: VisualConstructorOptions) {
console.log('Visual constructor', options);
this.formattingSettingsService = new FormattingSettingsService();
this.target = options.element;
this.host = options.host;
}
public update(options: VisualUpdateOptions) {
this.formattingSettings = this.formattingSettingsService.populateFormattingSettingsModel(VisualFormattingSettingsModel, options.dataViews);
console.log('Visual update', options);
}
// Returns properties pane formatting model content hierarchies, properties and latest formatting values, Then populate properties pane.
// This method is called once every time we open properties pane or when the user edit any format property.
public getFormattingModel(): powerbi.visuals.FormattingModel {
return this.formattingSettingsService.buildFormattingModel(this.formattingSettings);
}
}
Importér påkrævede grænseflader for at behandle data fra Power BI:
import DataViewCategorical = powerbi.DataViewCategorical;
import DataViewCategoryColumn = powerbi.DataViewCategoryColumn;
import PrimitiveValue = powerbi.PrimitiveValue;
import DataViewValueColumn = powerbi.DataViewValueColumn;
Opret rodelementet div
for kategoriværdier:
export class Visual implements IVisual {
private target: HTMLElement;
private formattingSettings: VisualFormattingSettingsModel;
private formattingSettingsService: FormattingSettingsService;
private div: HTMLDivElement; // new property
constructor(options: VisualConstructorOptions) {
console.log('Visual constructor', options);
this.formattingSettingsService = new FormattingSettingsService();
this.target = options.element;
this.host = options.host;
// create div element
this.div = document.createElement("div");
this.div.classList.add("vertical");
this.target.appendChild(this.div);
}
// ...
}
Ryd indholdet af div-elementerne, før du gengiver nye data:
// ...
public update(options: VisualUpdateOptions) {
this.formattingSettings = this.formattingSettingsService.populateFormattingSettingsModel(VisualFormattingSettingsModel, options.dataViews);
console.log('Visual update', options);
while (this.div.firstChild) {
this.div.removeChild(this.div.firstChild);
}
// ...
}
Hent kategorierne og målingsværdierne fra objektet dataView
:
public update(options: VisualUpdateOptions) {
this.formattingSettings = this.formattingSettingsService.populateFormattingSettingsModel(VisualFormattingSettingsModel, options.dataViews);
console.log('Visual update', options);
while (this.div.firstChild) {
this.div.removeChild(this.div.firstChild);
}
const dataView: DataView = options.dataViews[0];
const categoricalDataView: DataViewCategorical = dataView.categorical;
const categories: DataViewCategoryColumn = categoricalDataView.categories[0];
const categoryValues = categories.values;
const measures: DataViewValueColumn = categoricalDataView.values[0];
const measureValues = measures.values;
const measureHighlights = measures.highlights;
// ...
}
Hvor categoryValues
er en matrix af kategoriværdier, measureValues
er en matrix af målinger og measureHighlights
er de fremhævede dele af værdier.
Bemærk
Hvis værdierne for measureHighlights
egenskaben er mindre end værdierne for categoryValues
egenskaben, er værdien delvist fremhævet.
Optæl matrixen, categoryValues
og hent tilsvarende værdier og fremhævninger:
// ...
const measureHighlights = measures.highlights;
categoryValues.forEach((category: PrimitiveValue, index: number) => {
const measureValue = measureValues[index];
const measureHighlight = measureHighlights && measureHighlights[index] ? measureHighlights[index] : null;
console.log(category, measureValue, measureHighlight);
});
Opret div
elementer p
for at få vist og visualisere værdier for datavisning i visualiseringens DOM:
categoryValues.forEach((category: PrimitiveValue, index: number) => {
const measureValue = measureValues[index];
const measureHighlight = measureHighlights && measureHighlights[index] ? measureHighlights[index] : null;
console.log(category, measureValue, measureHighlight);
// div element. it contains elements to display values and visualize value as progress bar
let div = document.createElement("div");
div.classList.add("horizontal");
this.div.appendChild(div);
// div element to visualize value of measure
let barValue = document.createElement("div");
barValue.style.width = +measureValue * 10 + "px";
barValue.style.display = "flex";
barValue.classList.add("value");
// element to display category value
let bp = document.createElement("p");
bp.innerText = category.toString();
// div element to visualize highlight of measure
let barHighlight = document.createElement("div");
barHighlight.classList.add("highlight")
barHighlight.style.backgroundColor = "blue";
barHighlight.style.width = +measureHighlight * 10 + "px";
// element to display highlighted value of measure
let p = document.createElement("p");
p.innerText = `${measureHighlight}/${measureValue}`;
barHighlight.appendChild(bp);
div.appendChild(barValue);
barValue.appendChild(barHighlight);
div.appendChild(p);
});
Anvend de påkrævede typografier for elementer, der skal bruges flexbox
, og definer farver for div-elementer:
div.vertical {
display: flex;
flex-direction: column;
}
div.horizontal {
display: flex;
flex-direction: row;
}
div.highlight {
background-color: blue
}
div.value {
background-color: red;
display: flex;
}
Følgende visning af visualiseringen er resultatet:
Fremhæv datapunkter med tilknytning af matrixdatavisning
Føj "supportsHighlight": true
til filen for visualiseringer med tilknytning af capabilities.json
matrixdatavisning. Eksempler:
{
"dataRoles": [
{
"displayName": "Columns",
"name": "columns",
"kind": "Grouping"
},
{
"displayName": "Rows",
"name": "rows",
"kind": "Grouping"
},
{
"displayName": "Value",
"name": "value",
"kind": "Measure"
}
],
"dataViewMappings": [
{
"matrix": {
"columns": {
"for": {
"in": "columns"
}
},
"rows": {
"for": {
"in": "rows"
}
},
"values": {
"for": {
"in": "value"
}
}
}
}
],
"supportsHighlight": true
}
De eksempeldata, der skal oprettes et hierarki for tilknytning af matrixdatavisning:
Række1 | Række2 | Række3 | Kolonne1 | Kolonne2 | Column3 | Værdier |
---|---|---|---|---|---|---|
R1 | R11 | R111 | C1 | C11 | C111 | 0 |
R1 | R11 | R112 | C1 | C11 | C112 | 2 |
R1 | R11 | R113 | C1 | C11 | C113 | 3 |
R1 | R12 | R121 | C1 | C12 | C121 | 4 |
R1 | R12 | R122 | C1 | C12 | C122 | 5 |
R1 | R12 | R123 | C1 | C12 | C123 | 6 |
R1 | R13 | R131 | C1 | C13 | C131 | 7 |
R1 | R13 | R132 | C1 | C13 | C132 | 8 |
R1 | R13 | R133 | C1 | C13 | C133 | 9 |
R2 | R21 | R211 | C2 | C21 | C211 | 10 |
R2 | R21 | R212 | C2 | C21 | C212 | 11 |
R2 | R21 | R213 | C2 | C21 | C213 | 12 |
R2 | R22 | R221 | C2 | C22 | C221 | 13 |
R2 | R22 | R222 | C2 | C22 | C222 | 14 |
R2 | R22 | R223 | C2 | C22 | C223 | 16 |
R2 | R23 | R231 | C2 | C23 | C231 | 17 |
R2 | R23 | R232 | C2 | C23 | C232 | 18 |
R2 | R23 | R233 | C2 | C23 | C233 | 19 |
Opret standardprojektet for visualiseringen, og anvend eksemplet på capabilities.json
filen.
Når du har fjernet den unødvendige kode, ser standardkildekoden for visualiseringen ud som i følgende eksempel:
"use strict";
// ... default imports
import { FormattingSettingsService } from "powerbi-visuals-utils-formattingmodel";
import { VisualFormattingSettingsModel } from "./settings";
export class Visual implements IVisual {
private target: HTMLElement;
private formattingSettings: VisualFormattingSettingsModel;
private formattingSettingsService: FormattingSettingsService;
constructor(options: VisualConstructorOptions) {
console.log('Visual constructor', options);
this.formattingSettingsService = new FormattingSettingsService();
this.target = options.element;
this.host = options.host;
}
public update(options: VisualUpdateOptions) {
this.formattingSettings = this.formattingSettingsService.populateFormattingSettingsModel(VisualFormattingSettingsModel, options.dataViews);
console.log('Visual update', options);
}
/**
* Returns properties pane formatting model content hierarchies, properties and latest formatting values, Then populate properties pane.
* This method is called once every time we open properties pane or when the user edit any format property.
*/
public getFormattingModel(): powerbi.visuals.FormattingModel {
return this.formattingSettingsService.buildFormattingModel(this.formattingSettings);
}
}
Importér de nødvendige grænseflader for at behandle data fra Power BI:
import DataViewMatrix = powerbi.DataViewMatrix;
import DataViewMatrixNode = powerbi.DataViewMatrixNode;
import DataViewHierarchyLevel = powerbi.DataViewHierarchyLevel;
Opret to div
elementer til visualiseringslayoutet:
constructor(options: VisualConstructorOptions) {
// ...
this.rowsDiv = document.createElement("div");
this.target.appendChild(this.rowsDiv);
this.colsDiv = document.createElement("div");
this.target.appendChild(this.colsDiv);
this.target.style.overflowY = "auto";
}
Kontrollér dataene i update
metoden for at sikre, at visualiseringen henter data:
public update(options: VisualUpdateOptions) {
this.formattingSettings = this.formattingSettingsService.populateFormattingSettingsModel(VisualFormattingSettingsModel, options.dataViews);
console.log('Visual update', options);
const dataView: DataView = options.dataViews[0];
const matrixDataView: DataViewMatrix = dataView.matrix;
if (!matrixDataView ||
!matrixDataView.columns ||
!matrixDataView.rows ) {
return
}
// ...
}
Ryd indholdet af elementerne, div
før du gengiver nye data:
public update(options: VisualUpdateOptions) {
// ...
// remove old elements
// to better performance use D3js pattern:
// https://d3js.org/#enter-exit
while (this.rowsDiv.firstChild) {
this.rowsDiv.removeChild(this.rowsDiv.firstChild);
}
const prow = document.createElement("p");
prow.innerText = "Rows";
this.rowsDiv.appendChild(prow);
while (this.colsDiv.firstChild) {
this.colsDiv.removeChild(this.colsDiv.firstChild);
}
const pcol = document.createElement("p");
pcol.innerText = "Columns";
this.colsDiv.appendChild(pcol);
// ...
}
Opret funktionen treeWalker
for at gennemgå matrixdatastrukturen:
public update(options: VisualUpdateOptions) {
// ...
const treeWalker = (matrixNode: DataViewMatrixNode, index: number, levels: DataViewHierarchyLevel[], div: HTMLDivElement) => {
}
// ...
}
Hvor matrixNode
er den aktuelle node, levels
er metadatakolonner på dette hierarkiniveau – div
overordnet element for underordnede HTML-elementer.
treeWalker
er den rekursive funktion, skal oprette div
-elementet og p
for tekst som header og kalde funktionen for underordnede elementer i noden:
public update(options: VisualUpdateOptions) {
// ...
const treeWalker = (matrixNode: DataViewMatrixNode, index: number, levels: DataViewHierarchyLevel[], div: HTMLDivElement) => {
// ...
if (matrixNode.children) {
const childDiv = document.createElement("div");
childDiv.classList.add("vertical");
div.appendChild(childDiv);
const p = document.createElement("p");
const level = levels[matrixNode.level]; // get current level column metadata from current node
p.innerText = level.sources[level.sources.length - 1].displayName; // get column name from metadata
childDiv.appendChild(p); // add paragraph element to div element
matrixNode.children.forEach((node, index) => treeWalker(node, levels, childDiv, ++levelIndex));
}
}
// ...
}
Kald funktionen for rodelementer i kolonnen og rækken i matrixens datavisningsstruktur:
public update(options: VisualUpdateOptions) {
// ...
const treeWalker = (matrixNode: DataViewMatrixNode, index: number, levels: DataViewHierarchyLevel[], div: HTMLDivElement) => {
// ...
}
// ...
// remove old elements
// ...
// ...
const rowRoot: DataViewMatrixNode = matrixDataView.rows.root;
rowRoot.children.forEach((node) => treeWalker(node, matrixDataView.rows.levels, this.rowsDiv));
const colRoot = matrixDataView.columns.root;
colRoot.children.forEach((node) => treeWalker(node, matrixDataView.columns.levels, this.colsDiv));
}
Generér selectionID for noder og opret knapper for at få vist noder:
public update(options: VisualUpdateOptions) {
// ...
const treeWalker = (matrixNode: DataViewMatrixNode, index: number, levels: DataViewHierarchyLevel[], div: HTMLDivElement) => {
const selectionID: ISelectionID = this.host.createSelectionIdBuilder()
.withMatrixNode(matrixNode, levels)
.createSelectionId();
let nodeBlock = document.createElement("button");
nodeBlock.innerText = matrixNode.value.toString();
nodeBlock.addEventListener("click", (event) => {
// call select method in the selection manager
this.selectionManager.select(selectionID);
});
nodeBlock.addEventListener("contextmenu", (event) => {
// call showContextMenu method to display context menu on the visual
this.selectionManager.showContextMenu(selectionID, {
x: event.clientX,
y: event.clientY
});
event.preventDefault();
});
// ...
}
// ...
}
Det primære trin i fremhævningen er at oprette en anden matrix af værdier.
Objektet for terminalnoden har to egenskaber for værdimatrixen, værdi og fremhævning:
JSON.stringify(options.dataViews[0].matrix.rows.root.children[0].children[0].children[0], null, " ");
{
"level": 2,
"levelValues": [
{
"value": "R233",
"levelSourceIndex": 0
}
],
"value": "R233",
"identity": {
"identityIndex": 2
},
"values": {
"0": {
"value": null,
"highlight": null
},
"1": {
"value": 19,
"highlight": 19
}
}
}
Hvor value
repræsenterer værdien af noden uden at anvende en markering fra den anden visualisering, angiver, highlight
hvilken del af dataene der blev fremhævet.
Bemærk
Hvis værdien af highlight
er mindre end værdien af value
, value
blev den delvist fremhævet.
Tilføj kode for at behandle matrixen values
for noden, hvis den vises:
public update(options: VisualUpdateOptions) {
// ...
const treeWalker = (matrixNode: DataViewMatrixNode, index: number, levels: DataViewHierarchyLevel[], div: HTMLDivElement) => {
// ...
if (matrixNode.values) {
const sumOfValues = Object.keys(matrixNode.values) // get key property of object (value are 0 to N)
.map(key => +matrixNode.values[key].value) // convert key property to number
.reduce((prev, curr) => prev + curr) // sum of values
let sumOfHighlights = sumOfValues;
sumOfHighlights = Object.keys(matrixNode.values) // get key property of object (value are 0 to N)
.map(key => matrixNode.values[key].highlight ? +matrixNode.values[key].highlight : null ) // convert key property to number if it exists
.reduce((prev, curr) => curr ? prev + curr : null) // convert key property to number
// create div container for value and highlighted value
const vals = document.createElement("div");
vals.classList.add("vertical")
vals.classList.replace("vertical", "horizontal");
// create paragraph element for label
const highlighted = document.createElement("p");
// Display complete value and highlighted value
highlighted.innerText = `${sumOfHighlights}/${sumOfValues}`;
// create div container for value
const valueDiv = document.createElement("div");
valueDiv.style.width = sumOfValues * 10 + "px";
valueDiv.classList.add("value");
// create div container for highlighted values
const highlightsDiv = document.createElement("div");
highlightsDiv.style.width = sumOfHighlights * 10 + "px";
highlightsDiv.classList.add("highlight");
valueDiv.appendChild(highlightsDiv);
// append button and paragraph to div containers to parent div
vals.appendChild(nodeBlock);
vals.appendChild(valueDiv);
vals.appendChild(highlighted);
div.appendChild(vals);
} else {
div.appendChild(nodeBlock);
}
if (matrixNode.children) {
// ...
}
}
// ...
}
Resultatet er en visualisering med knapper og værdier, f.eks highlighted value/default value
. .