Legg til neddrillingsstøtte
Når et visualobjekt har et hierarki, kan du tillate brukere å bruke funksjonen for neddrilling i Power BI for å vise flere detaljer.
Les mer om funksjonen for neddrilling av Power BI i drillmodus i Power Bi-tjeneste. Hvis du vil at visualobjektet skal kunne aktivere eller deaktivere drillefunksjonen dynamisk, kan du se Dynamisk neddrillingskontroll.
Aktiver neddrillingsstøtte i visualobjektet
Hvis du vil støtte neddrillingshandlinger i visualobjektet, legger du til et nytt felt capabilities.json
i navnet drill-down
. Dette feltet har én egenskap roles
kalt som inneholder navnet på dataroleen du vil aktivere neddrillingshandlinger på.
"drilldown": {
"roles": [
"category"
]
}
Merk
NeddrillingsdataRole må være av Grouping
typen.
max
i dataRole-betingelsene må angis til 1.
Når du legger til rollen i neddrillingsfeltet, kan brukere dra flere felt til datarollen.
Eksempel:
{
"dataRoles": [
{
"displayName": "Category",
"name": "category",
"kind": "Grouping"
},
{
"displayName": "Value",
"name": "value",
"kind": "Measure"
}
],
"drilldown": {
"roles": [
"category"
]
},
"dataViewMappings": [
{
"categorical": {
"categories": {
"for": {
"in": "category"
}
},
"values": {
"select": [
{
"bind": {
"to": "value"
}
}
]
}
}
}
]
}
Opprette et visualobjekt med ekstraheringsstøtte
Hvis du vil opprette et visualobjekt med neddrillingsstøtte, kjører du følgende kommando:
pbiviz new testDrillDown -t default
Hvis du vil opprette et standard eksempel på visualobjekt, bruker du eksemplet capabilities.json
ovenfor på det nyopprettede visualobjektet.
Opprett egenskapen for beholderen for div
å inneholde HTML-elementer i visualobjektet:
"use strict";
import "core-js/stable";
import "./../style/visual.less";
// imports
export class Visual implements IVisual {
// visual properties
// ...
private div: HTMLDivElement; // <== NEW PROPERTY
constructor(options: VisualConstructorOptions) {
// constructor body
// ...
}
public update(options: VisualUpdateOptions) {
// update method body
// ...
}
/**
* Returns properties pane formatting model content hierarchies, properties and latest formatting values, Then populate properties pane.
* This method is called once each time we open the properties pane or when the user edits any format property.
*/
public getFormattingModel(): powerbi.visuals.FormattingModel {
return this.formattingSettingsService.buildFormattingModel(this.formattingSettings);
}
}
Oppdater konstruktøren for visualobjektet:
export class Visual implements IVisual {
// visual properties
// ...
private div: HTMLDivElement;
constructor(options: VisualConstructorOptions) {
console.log('Visual constructor', options);
this.formattingSettingsService = new FormattingSettingsService();
this.target = options.element;
this.updateCount = 0;
if (document) {
const new_p: HTMLElement = document.createElement("p");
new_p.appendChild(document.createTextNode("Update count:"));
const new_em: HTMLElement = document.createElement("em");
this.textNode = document.createTextNode(this.updateCount.toString());
new_em.appendChild(this.textNode);
new_p.appendChild(new_em);
this.div = document.createElement("div"); // <== CREATE DIV ELEMENT
this.target.appendChild(new_p);
}
}
}
Hvis du vil opprette button
s, oppdaterer du visualobjektets update
metode:
export class Visual implements IVisual {
// ...
public update(options: VisualUpdateOptions) {
this.formattingSettings = this.formattingSettingsService.populateFormattingSettingsModel(VisualFormattingSettingsModel, options.dataViews);
console.log('Visual update', options);
const dataView: DataView = options.dataViews[0];
const categoricalDataView: DataViewCategorical = dataView.categorical;
// don't create elements if no data
if (!options.dataViews[0].categorical ||
!options.dataViews[0].categorical.categories) {
return
}
// to display current level of hierarchy
if (typeof this.textNode !== undefined) {
this.textNode.textContent = categoricalDataView.categories[categoricalDataView.categories.length - 1].source.displayName.toString();
}
// remove old elements
// for better performance use D3js pattern:
// https://d3js.org/#enter-exit
while (this.div.firstChild) {
this.div.removeChild(this.div.firstChild);
}
// create buttons for each category value
categoricalDataView.categories[categoricalDataView.categories.length - 1].values.forEach( (category: powerbi.PrimitiveValue, index: number) => {
let button = document.createElement("button");
button.innerText = category.toString();
this.div.appendChild(button);
})
}
// ...
Bruk enkle stiler i .\style\visual.less
:
button {
margin: 5px;
min-width: 50px;
min-height: 50px;
}
Klargjøre eksempeldata for testing av visualobjektet:
H1 | H2 | H3 | VERDIER |
---|---|---|---|
A | A1 | A11 | 1 |
A | A1 | A12 | 2 |
A | A2 | A21 | 3 |
A | A2 | A22 | 4 |
A | A3 | A31 | 5 |
A | A3 | A32 | 6 |
F | B1 | B11 | 7 |
F | B1 | B12 | 8 |
F | B2 | B21 | 9 |
F | B2 | B22 | 10 |
F | B3 | B31 | 11 |
F | B3 | B32 | 12 |
Og opprett hierarki i Power BI Desktop:
Inkluder alle kategorikolonner (H1, H2, H3) i det nye hierarkiet:
Etter disse trinnene bør du få følgende visualobjekt:
Legg til hurtigmeny i visuelle elementer
Slik legger du til en hurtigmeny i knappene på visualobjektet:
Lagre host
objekt i egenskapene for visualobjektet og kallmetoden createSelectionManager
til opprett utvalgsbehandling for å vise en hurtigmeny ved hjelp av Power BI Visuals API.
"use strict";
import "core-js/stable";
import "./../style/visual.less";
// default imports
import IVisualHost = powerbi.extensibility.visual.IVisualHost;
import ISelectionManager = powerbi.extensibility.ISelectionManager;
import ISelectionId = powerbi.visuals.ISelectionId;
export class Visual implements IVisual {
// visual properties
// ...
private div: HTMLDivElement;
private host: IVisualHost; // <== NEW PROPERTY
private selectionManager: ISelectionManager; // <== NEW PROPERTY
constructor(options: VisualConstructorOptions) {
// constructor body
// save the host in the visuals properties
this.host = options.host;
// create selection manager
this.selectionManager = this.host.createSelectionManager();
// ...
}
public update(options: VisualUpdateOptions) {
// update method body
// ...
}
// ...
}
Endre brødteksten for tilbakeringing av forEach
funksjonen til:
categoricalDataView.categories[categoricalDataView.categories.length - 1].values.forEach( (category: powerbi.PrimitiveValue, index: number) => {
// create selectionID for each category value
let selectionID: ISelectionId = this.host.createSelectionIdBuilder()
.withCategory(categoricalDataView.categories[0], index)
.createSelectionId();
let button = document.createElement("button");
button.innerText = category.toString();
// add event listener to click event
button.addEventListener("click", (event) => {
// call select method in the selection manager
this.selectionManager.select(selectionID);
});
button.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();
});
this.div.appendChild(button);
});
Bruk data på visualobjektet:
I det siste trinnet skal du få visualobjekt med valg og hurtigmeny:
Legg til neddrillingsstøtte for matrisedatavisningstilordning
Hvis du vil teste visualobjektet med datavisningstilordninger for matriser, må du først klargjøre eksempeldata:
Rad 1 | Rad 2 | Rad 3 | Kolonne 1 | Kolonne 2 | Kolonne 3 | Verdier |
---|---|---|---|---|---|---|
R1 | R11 | R111 | C1 | C11 | C111 | 1 |
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 |
Bruk deretter følgende datavisningstilordning på visualobjektet:
{
"dataRoles": [
{
"displayName": "Columns",
"name": "columns",
"kind": "Grouping"
},
{
"displayName": "Rows",
"name": "rows",
"kind": "Grouping"
},
{
"displayName": "Value",
"name": "value",
"kind": "Measure"
}
],
"drilldown": {
"roles": [
"columns",
"rows"
]
},
"dataViewMappings": [
{
"matrix": {
"columns": {
"for": {
"in": "columns"
}
},
"rows": {
"for": {
"in": "rows"
}
},
"values": {
"for": {
"in": "value"
}
}
}
}
]
}
Bruk data på visualobjektet:
Importer nødvendige grensesnitt for å behandle datavisningstilordninger for matriser:
// ...
import DataViewMatrix = powerbi.DataViewMatrix;
import DataViewMatrixNode = powerbi.DataViewMatrixNode;
import DataViewHierarchyLevel = powerbi.DataViewHierarchyLevel;
// ...
Opprett to egenskaper for to div
rader og kolonneelementer:
export class Visual implements IVisual {
// ...
private rowsDiv: HTMLDivElement;
private colsDiv: HTMLDivElement;
// ...
constructor(options: VisualConstructorOptions) {
// constructor body
// ...
// Create div elements and append to main div of the visual
this.rowsDiv = document.createElement("div");
this.target.appendChild(this.rowsDiv);
this.colsDiv = document.createElement("div");
this.target.appendChild(this.colsDiv);
}
// ...
}
Kontroller dataene før du gjengir elementer, og vis gjeldende hierarkinivå:
export class Visual implements IVisual {
// ...
constructor(options: VisualConstructorOptions) {
// constructor body
}
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 the visual doesn't receive the data no reason to continue rendering
if (!matrixDataView ||
!matrixDataView.columns ||
!matrixDataView.rows ) {
return
}
// to display current level of hierarchy
if (typeof this.textNode !== undefined) {
this.textNode.textContent = categoricalDataView.categories[categoricalDataView.categories.length - 1].source.displayName.toString();
}
// ...
}
// ...
}
Opprett funksjon treeWalker
for å krysse hierarkiet:
export class Visual implements IVisual {
// ...
public update(options: VisualUpdateOptions) {
// ...
// if the visual doesn't receive the data no reason to continue rendering
if (!matrixDataView ||
!matrixDataView.columns ||
!matrixDataView.rows ) {
return
}
const treeWalker = (matrixNode: DataViewMatrixNode, index: number, levels: DataViewHierarchyLevel[], div: HTMLDivElement) => {
// ...
if (matrixNode.children) {
// ...
// traversing child nodes
matrixNode.children.forEach((node, index) => treeWalker(node, index, levels, childDiv));
}
}
// traversing rows
const rowRoot: DataViewMatrixNode = matrixDataView.rows.root;
rowRoot.children.forEach((node, index) => treeWalker(node, index, matrixDataView.rows.levels, this.rowsDiv));
// traversing columns
const colRoot = matrixDataView.columns.root;
colRoot.children.forEach((node, index) => treeWalker(node, index, matrixDataView.columns.levels, this.colsDiv));
}
// ...
}
Generer valgene for datapunkter.
const treeWalker = (matrixNode: DataViewMatrixNode, index: number, levels: DataViewHierarchyLevel[], div: HTMLDivElement) => {
// generate selectionID for each node of matrix
const selectionID: ISelectionID = this.host.createSelectionIdBuilder()
.withMatrixNode(matrixNode, levels)
.createSelectionId();
// ...
if (matrixNode.children) {
// ...
// traversing child nodes
matrixNode.children.forEach((node, index) => treeWalker(node, index, levels, childDiv));
}
}
Opprett div
for hvert hierarkinivå:
const treeWalker = (matrixNode: DataViewMatrixNode, index: number, levels: DataViewHierarchyLevel[], div: HTMLDivElement) => {
// generate selectionID for each node of matrix
const selectionID: ISelectionID = this.host.createSelectionIdBuilder()
.withMatrixNode(matrixNode, levels)
.createSelectionId();
// ...
if (matrixNode.children) {
// create div element for level
const childDiv = document.createElement("div");
// add to current div
div.appendChild(childDiv);
// create paragraph element to display next
const p = document.createElement("p");
// display level name on paragraph element
const level = levels[matrixNode.level];
p.innerText = level.sources[level.sources.length - 1].displayName;
// add paragraph element to created child div
childDiv.appendChild(p);
// traversing child nodes
matrixNode.children.forEach((node, index) => treeWalker(node, index, levels, childDiv));
}
}
Opprett buttons
for å samhandle med visualobjekter og vise hurtigmeny for matrisedatapunkter:
const treeWalker = (matrixNode: DataViewMatrixNode, index: number, levels: DataViewHierarchyLevel[], div: HTMLDivElement) => {
// generate selectionID for each node of matrix
const selectionID: ISelectionID = this.host.createSelectionIdBuilder()
.withMatrixNode(matrixNode, levels)
.createSelectionId();
// create button element
let button = document.createElement("button");
// display node value/name of the button's text
button.innerText = matrixNode.value.toString();
// add event listener on click
button.addEventListener("click", (event) => {
// call select method in the selection manager
this.selectionManager.select(selectionID);
});
// display context menu on click
button.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();
});
div.appendChild(button);
if (matrixNode.children) {
// ...
}
}
Fjern div
elementer før du gjengir elementer på nytt:
public update(options: VisualUpdateOptions) {
// ...
const treeWalker = (matrixNode: DataViewMatrixNode, index: number, levels: DataViewHierarchyLevel[], div: HTMLDivElement) => {
// ...
}
// remove old elements
// to better performance use D3js pattern:
// https://d3js.org/#enter-exit
while (this.rowsDiv.firstChild) {
this.rowsDiv.removeChild(this.rowsDiv.firstChild);
}
// create label for row elements
const prow = document.createElement("p");
prow.innerText = "Rows";
this.rowsDiv.appendChild(prow);
while (this.colsDiv.firstChild) {
this.colsDiv.removeChild(this.colsDiv.firstChild);
}
// create label for columns elements
const pcol = document.createElement("p");
pcol.innerText = "Columns";
this.colsDiv.appendChild(pcol);
// render elements for rows
const rowRoot: DataViewMatrixNode = matrixDataView.rows.root;
rowRoot.children.forEach((node, index) => treeWalker(node, index, matrixDataView.rows.levels, this.rowsDiv));
// render elements for columns
const colRoot = matrixDataView.columns.root;
colRoot.children.forEach((node, index) => treeWalker(node, index, matrixDataView.columns.levels, this.colsDiv));
}
Til slutt bør du få et visualobjekt med hurtigmeny: