基于PresentationRules个性化显示iModel的内容
iModel.js Presentation库
iModel.js Presentation库帮助从iModel中检索数据,并负责统一选择。从iModel中检索的数据是由使用者使用表示规则以声明方式定义的,这就是为什么该库通常很称为“表示规则引擎”。
要使用该库,需要在前后端执行一些步骤:
更多参考链接见官方文档https://www.imodeljs.org/learning/presentation/
使用
其实在使用的时候,用户更多的是只需要关注ruleset.json的内容,其中ruleset.json中定义的显示规则决定了控件(主要是树形控件,表格控件,属性框控件)所显示的imodel中的内容。其中ruleset定义了丰富的显示规则,用户只需要专注于编辑ruleset.json中的 显示规则,几乎不用修改任何代码,即可实现自己的个性化显示需求。
以下是一个tree形控件的ruleset.json内容示例:
{
"$schema": "../../node_modules/@bentley/presentation-common/Ruleset.schema.json",
"id": "imodel-content-tree/Default",
"supportedSchemas": {
"schemaNames": ["BisCore"]
},
"rules": [
{
"ruleType": "RootNodes",
"autoExpand": true,
"specifications": [
{
"specType": "InstanceNodesOfSpecificClasses",
"classes": [
{
"schemaName": "BisCore",
"classNames": ["Subject"]
}
],
"instanceFilter": "this.Parent = NULL",
"arePolymorphic": false,
"groupByClass": true,
"groupByLabel": false
}
]
},
{
"ruleType": "ChildNodes",
"condition": "ParentNode.IsOfClass(\"Subject\", \"BisCore\")",
"specifications": [
{
"specType": "RelatedInstanceNodes",
"relationshipPaths": [
{
"relationship": {
"schemaName": "BisCore",
"className": "SubjectOwnsSubjects"
},
"direction": "Forward",
"targetClass": {
"schemaName": "BisCore",
"className": "Subject"
}
}
],
"instanceFilter": "json_extract(this.JsonProperties, \"$.Subject.Job.Bridge\") <> NULL OR ifnull(json_extract(this.JsonProperties, \"$.Subject.Model.Type\"), \"\") = \"Hierarchy\"",
"hideNodesInHierarchy": true,
"groupByClass": true,
"groupByLabel": false
},
{
"specType": "RelatedInstanceNodes",
"relationshipPaths": [
{
"relationship": {
"schemaName": "BisCore",
"className": "SubjectOwnsSubjects"
},
"direction": "Forward",
"targetClass": {
"schemaName": "BisCore",
"className": "Subject"
}
}
],
"instanceFilter": "json_extract(this.JsonProperties, \"$.Subject.Job.Bridge\") = NULL AND ifnull(json_extract(this.JsonProperties, \"$.Subject.Model.Type\"), \"\") <> \"Hierarchy\"",
"groupByClass": true,
"groupByLabel": false
}
]
},
{
"ruleType": "ChildNodes",
"condition": "ParentNode.IsOfClass(\"Subject\", \"BisCore\")",
"specifications": [
{
"specType": "InstanceNodesOfSpecificClasses",
"classes": {
"schemaName": "BisCore",
"classNames": ["Model"]
},
"arePolymorphic": true,
"relatedInstances": [
{
"relationshipPath": {
"relationship": {
"schemaName": "BisCore",
"className": "ModelModelsElement"
},
"direction": "Forward",
"targetClass": {
"schemaName": "BisCore",
"className": "InformationPartitionElement"
}
},
"alias": "partition",
"isRequired": true
}
],
"instanceFilter": "(parent.ECInstanceId = partition.Parent.Id OR json_extract(parent.JsonProperties, \"$.Subject.Model.TargetPartition\") = printf(\"0x%x\", partition.ECInstanceId)) AND NOT this.IsPrivate AND json_extract(partition.JsonProperties, \"$.PhysicalPartition.Model.Content\") = NULL",
"groupByClass": true,
"groupByLabel": false
},
{
"specType": "InstanceNodesOfSpecificClasses",
"classes": {
"schemaName": "BisCore",
"classNames": ["Model"]
},
"arePolymorphic": true,
"relatedInstances": [
{
"relationshipPath": {
"relationship": {
"schemaName": "BisCore",
"className": "ModelModelsElement"
},
"direction": "Forward",
"targetClass": {
"schemaName": "BisCore",
"className": "InformationPartitionElement"
}
},
"alias": "partition",
"isRequired": true
}
],
"instanceFilter": "(parent.ECInstanceId = partition.Parent.Id OR json_extract(parent.JsonProperties, \"$.Subject.Model.TargetPartition\") = printf(\"0x%x\", partition.ECInstanceId)) AND NOT this.IsPrivate AND json_extract(partition.JsonProperties, \"$.PhysicalPartition.Model.Content\") <> NULL",
"hideNodesInHierarchy": true,
"groupByClass": true,
"groupByLabel": false
}
]
},
{
"ruleType": "ChildNodes",
"condition": "ParentNode.IsOfClass(\"ISubModeledElement\", \"BisCore\")",
"specifications": [
{
"specType": "RelatedInstanceNodes",
"relationshipPaths": [
{
"relationship": {
"schemaName": "BisCore",
"className": "ModelModelsElement"
},
"direction": "Backward"
}
],
"instanceFilter": "NOT this.IsPrivate",
"hideNodesInHierarchy": true,
"groupByClass": true,
"groupByLabel": false
}
]
},
{
"ruleType": "ChildNodes",
"condition": "ParentNode.IsOfClass(\"GeometricModel3d\", \"BisCore\")",
"specifications": [
{
"specType": "RelatedInstanceNodes",
"relationshipPaths": [
[
{
"relationship": {
"schemaName": "BisCore",
"className": "ModelContainsElements"
},
"direction": "Forward"
},
{
"relationship": {
"schemaName": "BisCore",
"className": "GeometricElement3dIsInCategory"
},
"direction": "Forward"
}
]
],
"suppressSimilarAncestorsCheck": true,
"groupByClass": true,
"groupByLabel": false
}
]
},
{
"ruleType": "ChildNodes",
"condition": "ParentNode.IsOfClass(\"GeometricModel2d\", \"BisCore\")",
"specifications": [
{
"specType": "RelatedInstanceNodes",
"relationshipPaths": [
[
{
"relationship": {
"schemaName": "BisCore",
"className": "ModelContainsElements"
},
"direction": "Forward"
},
{
"relationship": {
"schemaName": "BisCore",
"className": "GeometricElement2dIsInCategory"
},
"direction": "Forward"
}
]
],
"suppressSimilarAncestorsCheck": true,
"groupByClass": true,
"groupByLabel": false
}
]
},
{
"ruleType": "ChildNodes",
"condition": "ParentNode.IsOfClass(\"Model\", \"BisCore\")",
"onlyIfNotHandled": true,
"specifications": [
{
"specType": "RelatedInstanceNodes",
"relationshipPaths": [
[
{
"relationship": {
"schemaName": "BisCore",
"className": "ModelContainsElements"
},
"direction": "Forward"
}
]
],
"suppressSimilarAncestorsCheck": true,
"groupByClass": true,
"groupByLabel": false
}
]
},
{
"ruleType": "ChildNodes",
"condition": "ParentNode.IsOfClass(\"SpatialCategory\", \"BisCore\")",
"specifications": [
{
"specType": "RelatedInstanceNodes",
"relationshipPaths": [
{
"relationship": {
"schemaName": "BisCore",
"className": "GeometricElement3dIsInCategory"
},
"direction": "Backward"
}
],
"instanceFilter": "this.Model.Id = parent.parent.ECInstanceId ANDALSO this.Parent = NULL",
"groupByClass": true,
"groupByLabel": false
}
]
},
{
"ruleType": "ChildNodes",
"condition": "ParentNode.IsOfClass(\"DrawingCategory\", \"BisCore\")",
"specifications": [
{
"specType": "RelatedInstanceNodes",
"relationshipPaths": [
{
"relationship": {
"schemaName": "BisCore",
"className": "GeometricElement2dIsInCategory"
},
"direction": "Backward"
}
],
"instanceFilter": "this.Model.Id = parent.parent.ECInstanceId ANDALSO this.Parent = NULL",
"groupByClass": true,
"groupByLabel": false
}
]
},
{
"ruleType": "ChildNodes",
"condition": "ParentNode.IsOfClass(\"Element\", \"BisCore\")",
"onlyIfNotHandled": true,
"specifications": [
{
"specType": "RelatedInstanceNodes",
"relationshipPaths": [
{
"relationship": {
"schemaName": "BisCore",
"className": "ElementOwnsChildElements"
},
"direction": "Forward"
}
],
"groupByClass": true,
"groupByLabel": false
}
]
},
{
"ruleType": "ImageIdOverride",
"condition": "ThisNode.IsInstanceNode ANDALSO ThisNode.IsOfClass(\"Subject\", \"BisCore\")",
"imageIdExpression": "IIF(this.Parent.Id = NULL, \"icon-imodel-hollow-2\", \"icon-folder\")"
},
{
"ruleType": "ImageIdOverride",
"condition": "ThisNode.IsInstanceNode ANDALSO ThisNode.IsOfClass(\"Model\", \"BisCore\")",
"imageIdExpression": "\"icon-model\""
},
{
"ruleType": "ImageIdOverride",
"condition": "ThisNode.IsInstanceNode ANDALSO ThisNode.IsOfClass(\"Category\", \"BisCore\")",
"imageIdExpression": "\"icon-layers\""
},
{
"ruleType": "ImageIdOverride",
"condition": "ThisNode.IsInstanceNode ANDALSO ThisNode.IsOfClass(\"Element\", \"BisCore\")",
"imageIdExpression": "\"icon-item\""
},
{
"ruleType": "ImageIdOverride",
"condition": "ThisNode.IsClassGroupingNode",
"imageIdExpression": "\"icon-ec-class\""
}
]
}
通过将其导入到typescript中,示例代码如下:
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
import * as React from "react";
import { useCallback } from "react"; // tslint:disable-line: no-duplicate-imports
import { IModelApp, IModelConnection } from "@bentley/imodeljs-frontend";
import { useOptionalDisposable } from "@bentley/ui-core";
import { ControlledTree, SelectionMode, usePagedTreeNodeLoader, useTreeModelSource, useVisibleTreeNodes } from "@bentley/ui-components";
import { IPresentationTreeDataProvider, PresentationTreeDataProvider, useUnifiedSelectionTreeEventHandler } from "@bentley/presentation-components";
const RULESET_TREE = require("./Tree.ruleset.json"); // tslint:disable-line: no-var-requires
/** React properties for the tree component, that accepts an iModel connection with ruleset id */
export interface IModelConnectionProps {
/** iModel whose contents should be displayed in the tree */
imodel: IModelConnection;
}
/** React properties for the tree component, that accepts a data provider */
export interface DataProviderProps {
/** Custom tree data provider. */
dataProvider: IPresentationTreeDataProvider;
}
/** React properties for the tree component */
export type Props = IModelConnectionProps | DataProviderProps;
/** Tree component for the viewer app */
export default function SimpleTreeComponent(props: Props) {
const imodel = (props as IModelConnectionProps).imodel;
const imodelDataProvider = useOptionalDisposable(useCallback(() => {
if (imodel)
return new PresentationTreeDataProvider({ imodel, ruleset: RULESET_TREE });
return undefined;
}, [imodel]));
const dataProvider = imodelDataProvider ?? (props as DataProviderProps).dataProvider;
const modelSource = useTreeModelSource(dataProvider);
const nodeLoader = usePagedTreeNodeLoader(dataProvider, 20, modelSource);
const eventsHandler = useUnifiedSelectionTreeEventHandler({ nodeLoader, collapsedChildrenDisposalEnabled: true });
return (
<>
<h3 data-testid="tree-component-header">{IModelApp.i18n.translate("SimpleViewer:components.tree")}</h3>
<div style={{ flex: "1" }}>
<ControlledTree
nodeLoader={nodeLoader}
visibleNodes={useVisibleTreeNodes(modelSource)}
treeEvents={eventsHandler}
selectionMode={SelectionMode.Extended}
iconsEnabled={true}
/>
</div>
</>
);
}
我们即可得到如下显示效果:
由于表格控件,属性框控件也是使用类似的规则,即可实现用户的个性化显示需求,在此不再赘述。若要了解更多相关统一选择内容请参见iModel.js前端统一选择一致性机制。