基于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前端统一选择一致性机制。