ไฮไลต์จุดข้อมูลใน Power BI Visuals
บทความนี้อธิบายวิธีการไฮไลท์ข้อมูลบนวิชวล Power BI
ตามค่าเริ่มต้น เมื่อเลือก values
องค์ประกอบ อาร์เรย์ ใน dataView
ออบเจ็กต์ จะถูกกรองให้แสดงเฉพาะค่าที่เลือกเท่านั้น values
เมื่อกรองอาร์เรย์ วิชวลอื่น ๆ ทั้งหมดบนหน้าจะแสดงเฉพาะข้อมูลที่เลือกเท่านั้น
ถ้าคุณตั้งค่าคุณสมบัติ ในsupportsHighlight
ไฟล์ของคุณcapabilities.json
เป็น true
highlights
จะส่งผลให้อาร์เรย์แบบvalues
ไม่มีการกรองเต็มรูปแบบพร้อมกับอาร์เรย์ อาร์เรย์ highlights
มีความยาวเท่ากับอาร์เรย์ค่า และค่าที่ไม่ได้เลือกจะถูกตั้งค่า null
เป็น เมื่อเปิดใช้งานคุณสมบัตินี้ ข้อมูลที่เหมาะสมในวิชวลจะถูกเน้นโดยการ values
เปรียบเทียบอาร์เรย์กับ highlights
อาร์เรย์
ในตัวอย่าง โปรดสังเกตว่า:
- หากไม่มี การสนับสนุนการไฮไลต์ การเลือกจะเป็นค่าเดียวใน
values
อาร์เรย์และแถบเดียวที่แสดงในมุมมองข้อมูล - ด้วย การสนับสนุนไฮไลต์ ค่าทั้งหมดจะอยู่ใน
values
อาร์เรย์ อาร์เรย์highlights
ประกอบด้วยnull
ค่าสําหรับองค์ประกอบที่ไม่ได้ไฮไลต์ แถบทั้งหมดจะปรากฏในมุมมองข้อมูล และแถบที่ไฮไลต์จะเป็นสีที่แตกต่างกัน
นอกจากนี้ยังสามารถเลือกได้หลายรายการและการไฮไลต์บางส่วน ค่าที่ไฮไลต์ไว้จะแสดงในมุมมองข้อมูล
หมายเหตุ
การแมปมุมมองข้อมูลแบบตารางไม่สนับสนุนคุณลักษณะการไฮไลต์
ไฮไลต์จุดข้อมูลด้วยการแมปมุมมองข้อมูลตามประเภท
สําหรับวิชวลที่มีการแมปมุมมองข้อมูลตามประเภท ให้capabilities.json
เพิ่ม"supportsHighlight": true
ไปยังไฟล์ ตัวอย่างเช่น:
{
"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
}
หลังจากที่คุณลบโค้ดที่ไม่จําเป็นออกแล้ว โค้ดแหล่งที่มาของวิชวลเริ่มต้นจะมีลักษณะดังตัวอย่างต่อไปนี้:
"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);
}
}
นําเข้าอินเทอร์เฟสที่จําเป็นเพื่อประมวลผลข้อมูลจาก Power BI:
import DataViewCategorical = powerbi.DataViewCategorical;
import DataViewCategoryColumn = powerbi.DataViewCategoryColumn;
import PrimitiveValue = powerbi.PrimitiveValue;
import DataViewValueColumn = powerbi.DataViewValueColumn;
สร้างองค์ประกอบราก div
สําหรับค่าหมวดหมู่:
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);
}
// ...
}
ล้างเนื้อหาขององค์ประกอบ div ก่อนแสดงข้อมูลใหม่:
// ...
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);
}
// ...
}
รับค่าหมวดหมู่และหน่วยวัดจาก 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;
// ...
}
โดยที่ categoryValues
เป็นอาร์เรย์ของค่า measureValues
หมวดหมู่ เป็นอาร์เรย์ของหน่วยวัด และ measureHighlights
เป็นส่วนที่ไฮไลต์ของค่า
หมายเหตุ
ถ้าค่าของ measureHighlights
คุณสมบัติน้อยกว่าค่าของ categoryValues
คุณสมบัติ ค่าดังกล่าวจะถูกเน้นบางส่วน
categoryValues
ระบุอาร์เรย์ และรับค่าและไฮไลต์ที่สอดคล้องกัน:
// ...
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);
});
สร้าง div
องค์ประกอบ และ p
เพื่อแสดงและแสดงภาพค่ามุมมองข้อมูลใน 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);
});
ใช้ลักษณะที่จําเป็นสําหรับองค์ประกอบเพื่อใช้ flexbox
และกําหนดสีสําหรับองค์ประกอบ div:
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;
}
มุมมองของวิชวลต่อไปนี้เป็นผลลัพธ์:
ไฮไลต์จุดข้อมูลด้วยการแมปมุมมองข้อมูลแบบเมทริกซ์
สําหรับวิชวลที่มีการแมปมุมมองข้อมูลแบบเมทริกซ์ ให้capabilities.json
เพิ่ม "supportsHighlight": true
ไปยังไฟล์ ตัวอย่างเช่น:
{
"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
}
ข้อมูลตัวอย่างเพื่อสร้างลําดับชั้นสําหรับการแมปมุมมองข้อมูลแบบเมทริกซ์:
Row1 | Row2 | Row3 | คอลัมน์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 |
สร้างโครงการวิชวลเริ่มต้นและใช้ตัวอย่างของ capabilities.json
ไฟล์
หลังจากที่คุณลบโค้ดที่ไม่จําเป็นออกแล้ว โค้ดแหล่งที่มาของวิชวลเริ่มต้นจะมีลักษณะดังต่อไปนี้:
"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);
}
}
นําเข้าอินเทอร์เฟซที่จําเป็นเพื่อประมวลผลข้อมูลจาก Power BI:
import DataViewMatrix = powerbi.DataViewMatrix;
import DataViewMatrixNode = powerbi.DataViewMatrixNode;
import DataViewHierarchyLevel = powerbi.DataViewHierarchyLevel;
สร้างองค์ประกอบสอง div
อย่างสําหรับเค้าโครงวิชวล:
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";
}
ตรวจสอบข้อมูลใน update
วิธีการ เพื่อให้แน่ใจว่าวิชวลได้รับข้อมูล:
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
}
// ...
}
ล้างเนื้อหาของ div
องค์ประกอบก่อนที่จะแสดงข้อมูลใหม่:
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);
// ...
}
treeWalker
สร้างฟังก์ชันเพื่อสํารวจโครงสร้างข้อมูลเมทริกซ์:
public update(options: VisualUpdateOptions) {
// ...
const treeWalker = (matrixNode: DataViewMatrixNode, index: number, levels: DataViewHierarchyLevel[], div: HTMLDivElement) => {
}
// ...
}
โดยที่ matrixNode
คือโหนด levels
ปัจจุบัน คือคอลัมน์เมตาดาต้าของระดับ div
ลําดับชั้นนี้ - องค์ประกอบหลักสําหรับองค์ประกอบ HTML ย่อย
treeWalker
เป็นฟังก์ชันแบบเรียกใช้ซ้ํา จําเป็นต้องสร้างdiv
องค์ประกอบ และ p
สําหรับข้อความเป็นส่วนหัว และเรียกใช้ฟังก์ชันสําหรับองค์ประกอบย่อยของโหนด:
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));
}
}
// ...
}
เรียกใช้ฟังก์ชันสําหรับองค์ประกอบระดับสูงของคอลัมน์และแถวของโครงสร้างมุมมองข้อมูลแบบเมทริกซ์:
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));
}
สร้าง selectionID สําหรับโหนดและสร้างปุ่มเพื่อแสดงโหนด:
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();
});
// ...
}
// ...
}
ขั้นตอนหลักของการไฮไลต์คือการสร้างอาร์เรย์ของค่าอื่น
ออบเจ็กต์ของโหนดเทอร์มินัลมีคุณสมบัติสองประการสําหรับอาร์เรย์ค่า ค่า และไฮไลต์:
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
}
}
}
โดย value
ที่ แสดงค่าของโหนดโดยไม่ต้องใช้ตัวเลือกจากวิ highlight
ชวลอื่น ๆ แสดงว่าส่วนใดของข้อมูลถูกไฮไลต์
หมายเหตุ
ถ้าค่า ของ highlight
น้อยกว่าค่าของ value
จะถูก value
เน้นเพียงบางส่วน
เพิ่มรหัสเพื่อประมวลผลอาร์เรย์ของ values
โหนดหากแสดง:
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) {
// ...
}
}
// ...
}
ผลลัพธ์คือวิชวลที่มีปุ่มและค่า เช่นhighlighted value/default value