เพิ่มการสนับสนุนการดูรายละเอียดแนวลึก
เมื่อวิชวลมีลําดับชั้น คุณสามารถอนุญาตให้ผู้ใช้ใช้คุณลักษณะการดูรายละเอียดแนวลึกของ Power BI เพื่อดูรายละเอียดเพิ่มเติม
อ่านเพิ่มเติมเกี่ยวกับคุณลักษณะการดูรายละเอียดแนวลึกของ Power BI ที่โหมดดูรายละเอียดแนวลึกในบริการของ Power BI เมื่อต้องการอนุญาตให้วิชวลเปิดใช้งานหรือปิดใช้งานคุณลักษณะการดูรายละเอียดแบบไดนามิก ดู ตัวควบคุมการดูรายละเอียดแนวลึกแบบไดนามิก
เปิดใช้งานการสนับสนุนการดูรายละเอียดแนวลึกในวิชวล
เพื่อสนับสนุนการดําเนินการดูรายละเอียดแนวลึกในวิชวลของคุณ ให้เพิ่มเขตข้อมูลใหม่ลงใน capabilities.json
ที่มี drill-down
ชื่อ เขตข้อมูลนี้มีหนึ่งคุณสมบัติที่เรียกว่า roles
ที่ประกอบด้วยชื่อของ dataRole ที่คุณต้องการเปิดใช้งานการดําเนินการดูรายละเอียดแนวลึก
"drilldown": {
"roles": [
"category"
]
}
หมายเหตุ
dataRole การดูรายละเอียดแนวลึกต้องเป็นชนิดGrouping
max
คุณสมบัติ ในเงื่อนไข dataRole ต้องได้รับการตั้งค่าเป็น 1
เมื่อคุณเพิ่มบทบาทลงในเขตข้อมูลการดูรายละเอียดแนวลึก ผู้ใช้สามารถลากหลายเขตข้อมูลลงในบทบาทข้อมูลได้
ตัวอย่างเช่น:
{
"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"
}
}
]
}
}
}
]
}
สร้างวิชวลที่มีการสนับสนุนการดูรายละเอียดแนวลึก
หากต้องการสร้างวิชวลที่มีการสนับสนุนการดูรายละเอียดแนวลึก ให้เรียกใช้คําสั่งต่อไปนี้:
pbiviz new testDrillDown -t default
หากต้องการสร้างวิชวลตัวอย่างเริ่มต้น ให้ใช้ตัวอย่างด้านบนของ capabilities.json
กับวิชวลที่สร้างขึ้นใหม่
สร้างคุณสมบัติ สําหรับ div
คอนเทนเนอร์ เพื่อเก็บองค์ประกอบ HTML ของวิชวล:
"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);
}
}
อัปเดตคอนสตรักเตอร์ของวิชวล:
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);
}
}
}
หากต้องการสร้าง button
ให้อัปเดต update
วิธีการ ของวิชวล:
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);
})
}
// ...
ใช้ลักษณะอย่างง่ายใน .\style\visual.less
:
button {
margin: 5px;
min-width: 50px;
min-height: 50px;
}
เตรียมข้อมูลตัวอย่างสําหรับการทดสอบวิชวล:
H1 | H2 | H3 | ค่า |
---|---|---|---|
ท | A1 | A11 | 1 |
ท | A1 | A12 | 2 |
ท | A2 | A21 | 3 |
ท | A2 | A22 | 4 |
ท | A3 | A31 | 5 |
ท | A3 | A32 | 6 |
B | B1 | B11 | 7 |
B | B1 | B12 | 8 |
B | B2 | B21 | 9 |
B | B2 | B22 | 10 |
B | B3 | B31 | 11 |
B | B3 | B32 | 12 |
และสร้างลําดับชั้นใน Power BI Desktop:
รวมคอลัมน์หมวดหมู่ทั้งหมด (H1, H2, H3) ไปยังลําดับชั้นใหม่:
หลังจากขั้นตอนเหล่านั้นคุณควรได้รับวิชวลต่อไปนี้:
เพิ่มเมนูบริบทไปยังองค์ประกอบวิชวล
เมื่อต้องเพิ่มเมนูบริบทไปยังปุ่มบนวิชวล:
บันทึก host
วัตถุในคุณสมบัติของวิชวลและเรียกใช้ createSelectionManager
เมธอด เพื่อสร้างตัวจัดการการเลือกเพื่อแสดงเมนูบริบทโดยใช้ 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
// ...
}
// ...
}
เปลี่ยนเนื้อความของ forEach
การเรียกกลับฟังก์ชันเป็น:
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);
});
นําข้อมูลไปใช้กับวิชวล:
ในขั้นตอนสุดท้าย คุณควรได้รับวิชวลที่มีการเลือกและเมนูบริบท:
เพิ่มการสนับสนุนการดูรายละเอียดแนวลึกสําหรับการแมปมุมมองข้อมูลแบบเมทริกซ์
หากต้องการทดสอบวิชวลด้วยการแมปมุมมองข้อมูลแบบเมทริกซ์ ก่อนอื่นให้เตรียมข้อมูลตัวอย่าง:
แถวที่ 1 | แถวที่ 2 | แถวที่ 3 | คอลัมน์ 1 | คอลัมน์ 2 | คอลัมน์ 3 | ค่า |
---|---|---|---|---|---|---|
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 |
จากนั้นใช้การแมปมุมมองข้อมูลต่อไปนี้กับวิชวล:
{
"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"
}
}
}
}
]
}
นําข้อมูลไปใช้กับวิชวล:
นําเข้าอินเทอร์เฟสที่จําเป็นเพื่อประมวลผลการแมปมุมมองข้อมูลแบบเมทริกซ์:
// ...
import DataViewMatrix = powerbi.DataViewMatrix;
import DataViewMatrixNode = powerbi.DataViewMatrixNode;
import DataViewHierarchyLevel = powerbi.DataViewHierarchyLevel;
// ...
สร้างคุณสมบัติสองรายการสําหรับองค์ประกอบแถวและคอลัมน์สอง div
รายการ:
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);
}
// ...
}
ตรวจสอบข้อมูลก่อนแสดงองค์ประกอบและแสดงระดับลําดับชั้นปัจจุบัน:
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();
}
// ...
}
// ...
}
สร้างฟังก์ชัน treeWalker
สําหรับการท่องไปตามลําดับชั้น:
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));
}
// ...
}
สร้างการเลือกสําหรับจุดข้อมูล
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));
}
}
สร้าง div
สําหรับแต่ละระดับของลําดับชั้น:
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));
}
}
สร้าง buttons
เพื่อโต้ตอบกับวิชวลและแสดงเมนูบริบทสําหรับจุดข้อมูลเมทริกซ์:
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) {
// ...
}
}
ล้าง div
องค์ประกอบก่อนที่จะแสดงองค์ประกอบอีกครั้ง:
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));
}
สุดท้าย คุณควรได้รับวิชวลที่มีเมนูบริบท: