Merk
Tilgang til denne siden krever autorisasjon. Du kan prøve å logge på eller endre kataloger.
Tilgang til denne siden krever autorisasjon. Du kan prøve å endre kataloger.
Hierarkiidentitetsfilter-API-en gjør det mulig for visualobjekter som bruker Matrisedatavisning-tilordning, å filtrere data på flere felt om gangen basert på datapunkter som bruker en hierarkistruktur.
Denne API-en er nyttig i følgende scenarioer:
- Filtrere hierarkier basert på datapunkter
- Egendefinerte visualobjekter som bruker semantiske modeller med grupper etter nøkler
Merk
Hierarkiidentitetsfilter-API-en er tilgjengelig fra API versjon 5.9.0
Filtergrensesnittet vises i følgende kode:
interface IHierarchyIdentityFilter<IdentityType> extends IFilter {
target: IHierarchyIdentityFilterTarget;
hierarchyData: IHierarchyIdentityFilterNode<IdentityType>[];
}
$schema:
https://powerbi.com/product/schema#hierarchyIdentity(arvet fra IFilter)filterType: FilterType.HierarchyIdentity (arvet fra IFilter)
mål: Matrise med relevante kolonner i spørringen. Foreløpig støttes bare én enkelt rolle. derfor er ikke målet obligatorisk og bør være tomt.
hierarchyData: de merkede og umerkede elementene i et hierarkitre der hver
IHierarchyIdentityFilterNode<IdentityType>representerer et enkelt verdivalg.
type IHierarchyIdentityFilterTarget = IQueryNameTarget[]
interface IQueryNameTarget {
queryName: string;
}
- queryName: spørringsnavnet for kildekolonnen i spørringen. Den kommer fra
DataViewMetadataColumn
interface IHierarchyIdentityFilterNode<IdentityType> {
identity: IdentityType;
children?: IHierarchyIdentityFilterNode<IdentityType>[];
operator: HierarchyFilterNodeOperators;
}
identitet: Nodeidentiteten i DataView. Bør
IdentityTypeværeCustomVisualOpaqueIdentityunderordnede: Liste over underordnede node som er relevante for gjeldende utvalg
operator: Operatoren for enkeltobjekter i treet. Operatoren kan være ett av følgende tre alternativer:
type HierarchyFilterNodeOperators = "Selected" | "NotSelected" | "Inherited";Valgt: verdien er eksplisitt valgt.
NotSelected: verdien er eksplisitt ikke valgt.
Arvet: Verdivalg er i henhold til den overordnede verdien i hierarkiet, eller standard hvis det er rotverdien.
Husk følgende regler når du definerer hierarkiidentitetsfilteret:
- Ta identitetene fra DataView.
- Hver identitetsbane må være en gyldig bane i DataView.
- Hvert blad skal ha en operator av Valgt eller Ikke valgt.
- Hvis du vil sammenligne identiteter, bruker du
ICustomVisualsOpaqueUtils.compareCustomVisualOpaqueIdentitiesfunksjonen. - Identitetene kan endres etter feltendringer (for eksempel legge til eller fjerne felt). Power BI tilordner de oppdaterte identitetene til eksisterende filter.hierarchyData.
Slik bruker du API-en for hierarkiidentitetsfilteret
Følgende kode er et eksempel på hvordan du bruker hierarkiidentitetsfilter-API-en i et egendefinert visualobjekt:
import { IHierarchyIdentityFilterTarget, IHierarchyIdentityFilterNode, HierarchyIdentityFilter } from "powerbi-models"
const target: IHierarchyIdentityFilterTarget = [];
const hierarchyData: IHierarchyIdentityFilterNode<CustomVisualOpaqueIdentity>[] = [
{
identity: {...},
operator: "Selected",
children: [
{
identity: {...},
operator: "NotSelected"
}
]
},
{
identity: {...},
operator: "Inherited",
children: [
{
identity: {...},
operator: "Selected"
}
]
}
];
const filter = new HierarchyIdentityFilter(target, hierarchyData).toJSON();
Hvis du vil bruke filteret, bruker du applyJsonFilter API-kallet:
this.host.applyJsonFilter(filter, "general", "filter", action);
Hvis du vil gjenopprette det aktive JSON-filteret, bruker jsonFilters du egenskapen som ble funnet i VisualUpdateOptions:
export interface VisualUpdateOptions extends extensibility.VisualUpdateOptions {
//...
jsonFilters?: IFilter[];
}
Validering av hierarkirelaterte felt (valgfritt)
Filteret HierarchyIdnetity støttes bare for hierarkisk relaterte felt. Power BI validerer som standard ikke hvis feltene er hierarkisk relatert.
Hvis du vil aktivere hierarkisk relatert validering, legger du til egenskapen areHierarchicallyRelated i den relevante rollebetingelsen i den capabilities.json filen:
"dataViewMappings": [
{
"conditions": [
{
"Rows": {
"min": 1,
"areHierarchicallyRelated": true <------ NEW ------>
},
"Value": {
"min": 0
}
}
],
...
}
]
Felt er hierarkisk relatert hvis følgende betingelser oppfylles:
Ingen inkludert relasjonskant er mange til mange kardinaliteter, og heller ikke
ConceptualNavigationBehavior.Weak.Alle feltene i filteret finnes i banen.
Hver relasjon i banen har samme retning eller toveis.
Relasjonsretningen samsvarer med kardinaliteten for én til mange eller toveis.
Eksempel på hierarkirelasjoner
Gitt for eksempel følgende enhetsrelasjon:
- A, B er hierarkisk relatert: sann
- B, C er hierarkisk relatert: sann
- A, B, C er hierarkisk relatert: sann
- A, C, E er hierarkisk relatert: sann (A --> E --> C)
- A, B, E er hierarkisk relatert: sann (B --> A --> E)
- A, B, C, E er hierarkisk relatert: sann (B --> A --> E --> C)
- A, B, C, D er hierarkisk relatert: usann (brutt regel #3)
- C, D er hierarkisk relatert: sann
- B, C, D er hierarkisk relatert: usann (brutt regel #3)
- A, C, D, E er hierarkisk relatert: usann (brutt regel #3)
Merk
Når disse valideringene er aktivert, og feltene ikke er hierarkisk relaterte, gjengis ikke visualobjektet, og en feilmelding vises:
Når disse valideringene er deaktivert, og filtervisualobjektet bruker et filter som inneholder noder relatert til ikke-hierarkisk relaterte felt, kan det hende at andre visualobjekter ikke gjengis riktig når mål er i bruk:
Kodeeksempel for oppdatering av hierarkidatatreet etter nytt valg
Følgende kode viser hvordan du oppdaterer hierarchyData treet etter et nytt valg:
type CompareIdentitiesFunc = (id1: CustomVisualOpaqueIdentity, id2: CustomVisualOpaqueIdentity) => boolean;
/**
* Updates the filter tree following a new node selection.
* Prunes irrelevant branches after node insertion/removal if necessary.
* @param path Identities path to the selected node.
* @param treeNodes Array of IHierarchyIdentityFilterNode representing a valid filter tree.
* @param compareIdentities Compare function for CustomVisualOpaqueIdentity to determine equality. Pass the ICustomVisualsOpaqueUtils.compareCustomVisualOpaqueIdentities function.
* @returns A valid filter tree after the update
*/
function updateFilterTreeOnNodeSelection(
path: CustomVisualOpaqueIdentity[],
treeNodes: IHierarchyIdentityFilterNode<CustomVisualOpaqueIdentity>[],
compareIdentities: CompareIdentitiesFunc
): IHierarchyIdentityFilterNode<CustomVisualOpaqueIdentity>[] {
if (!path) return treeNodes;
const root: IHierarchyIdentityFilterNode<CustomVisualOpaqueIdentity> = {
identity: null,
children: treeNodes || [],
operator: 'Inherited',
};
let currentNodesLevel = root.children;
let isClosestSelectedParentSelected = root.operator === 'Selected';
let parents: { node: IHierarchyIdentityFilterNode<CustomVisualOpaqueIdentity>, index: number }[] = [{ node: root, index: -1 }];
let shouldFixTree = false;
path.forEach((identity, level) => {
const index = currentNodesLevel.findIndex((node) => compareIdentities(node.identity, identity));
const isLastNodeInPath = level === path.length - 1
if (index === -1) {
const newNode: IHierarchyIdentityFilterNode<CustomVisualOpaqueIdentity> = {
identity,
children: [],
operator: isLastNodeInPath ? (isClosestSelectedParentSelected ? 'NotSelected' : 'Selected') : 'Inherited',
};
currentNodesLevel.push(newNode);
currentNodesLevel = newNode.children;
if (newNode.operator !== 'Inherited') {
isClosestSelectedParentSelected = newNode.operator === 'Selected';
}
} else {
const currentNode = currentNodesLevel[index];
if (isLastNodeInPath) {
const partial = currentNode.children && currentNode.children.length;
if (partial) {
/**
* The selected node has subtree.
* Therefore, selecting this node should lead to one of the following scenarios:
* 1. The node should have Selected operator and its subtree should be pruned.
* 2. The node and its subtree should be pruned form the tree and the tree should be fixed.
*/
// The subtree should be always pruned.
currentNode.children = [];
if (currentNode.operator === 'NotSelected' || (currentNode.operator === 'Inherited' && isClosestSelectedParentSelected )) {
/**
* 1. The selected node has NotSelected operator.
* 2. The selected node has Inherited operator, and its parent has Slected operator.
* In both cases the node should be pruned from the tree and the tree shoud be fixed.
*/
currentNode.operator = 'Inherited'; // to ensure it will be pruned
parents.push({ node: currentNode, index });
shouldFixTree = true;
} else {
/**
* 1. The selected node has Selected operator.
* 2. The selected node has Inherited operator, but its parent doesn't have Selected operator.
* In both cases the node should stay with Selected operator pruned from the tree and the tree should be fixed.
* Note that, node with Selected oprator and parent with Selector operator is not valid state.
*/
currentNode.operator = 'Selected';
}
} else {
// Leaf node. The node should be pruned from the tree and the tree should be fixed.
currentNode.operator = 'Inherited'; // to ensure it will be pruned
parents.push({ node: currentNode, index });
shouldFixTree = true;
}
} else {
// If it's not the last noded in path we just continue traversing the tree
currentNode.children = currentNode.children || [];
currentNodesLevel = currentNode.children
if (currentNode.operator !== 'Inherited') {
isClosestSelectedParentSelected = currentNode.operator === 'Selected';
// We only care about the closet parent with Selected/NotSelected operator and its children
parents = [];
}
parents.push({ node: currentNode, index });
}
}
});
// Prune brnaches with Inherited leaf
if (shouldFixTree) {
for (let i = parents.length - 1; i >= 1; i--) {
// Normalize to empty array
parents[i].node.children = parents[i].node.children || [];
if (!parents[i].node.children.length && (parents[i].node.operator === 'Inherited')) {
// Remove the node from its parent children array
removeElement(parents[i - 1].node.children, parents[i].index);
} else {
// Node has children or Selected/NotSelected operator
break;
}
}
}
return root.children;
}
/**
* Removes an element from the array without preserving order.
* @param arr - The array from which to remove the element.
* @param index - The index of the element to be removed.
*/
function removeElement(arr: any[], index: number): void {
if (!arr || !arr.length || index < 0 || index >= arr.length) return;
arr[index] = arr[arr.length - 1];
arr.pop();
}