@itwin/tree-widget-react 3.17.0 → 3.17.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -2
- package/lib/cjs/tree-widget-react/components/trees/categories-tree/CategoriesTreeDefinition.js +3 -2
- package/lib/cjs/tree-widget-react/components/trees/categories-tree/CategoriesTreeDefinition.js.map +1 -1
- package/lib/cjs/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeIdsCache.d.ts +3 -3
- package/lib/cjs/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeIdsCache.js +22 -21
- package/lib/cjs/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeIdsCache.js.map +1 -1
- package/lib/cjs/tree-widget-react/components/trees/categories-tree/internal/CategoriesVisibilityHandler.js +57 -107
- package/lib/cjs/tree-widget-react/components/trees/categories-tree/internal/CategoriesVisibilityHandler.js.map +1 -1
- package/lib/cjs/tree-widget-react/components/trees/common/CategoriesVisibilityUtils.js +22 -12
- package/lib/cjs/tree-widget-react/components/trees/common/CategoriesVisibilityUtils.js.map +1 -1
- package/lib/cjs/tree-widget-react/components/trees/common/internal/Utils.d.ts +25 -0
- package/lib/cjs/tree-widget-react/components/trees/common/internal/Utils.js +83 -0
- package/lib/cjs/tree-widget-react/components/trees/common/internal/Utils.js.map +1 -0
- package/lib/cjs/tree-widget-react/components/trees/models-tree/ModelsTreeDefinition.d.ts +1 -0
- package/lib/cjs/tree-widget-react/components/trees/models-tree/ModelsTreeDefinition.js +78 -23
- package/lib/cjs/tree-widget-react/components/trees/models-tree/ModelsTreeDefinition.js.map +1 -1
- package/lib/cjs/tree-widget-react/components/trees/models-tree/Utils.d.ts +5 -3
- package/lib/cjs/tree-widget-react/components/trees/models-tree/Utils.js +5 -14
- package/lib/cjs/tree-widget-react/components/trees/models-tree/Utils.js.map +1 -1
- package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/AlwaysAndNeverDrawnElementInfo.js +5 -4
- package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/AlwaysAndNeverDrawnElementInfo.js.map +1 -1
- package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/FilteredTree.d.ts +7 -1
- package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/FilteredTree.js +52 -0
- package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/FilteredTree.js.map +1 -1
- package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.d.ts +15 -0
- package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.js +134 -3
- package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.js.map +1 -1
- package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/ModelsTreeVisibilityHandler.js +247 -123
- package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/ModelsTreeVisibilityHandler.js.map +1 -1
- package/lib/cjs/tree-widget-react-internal.d.ts +1 -1
- package/lib/cjs/tree-widget-react-internal.js +1 -1
- package/lib/cjs/tree-widget-react-internal.js.map +1 -1
- package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeDefinition.js +3 -2
- package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeDefinition.js.map +1 -1
- package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeIdsCache.d.ts +3 -3
- package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeIdsCache.js +23 -22
- package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeIdsCache.js.map +1 -1
- package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesVisibilityHandler.js +59 -109
- package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesVisibilityHandler.js.map +1 -1
- package/lib/esm/tree-widget-react/components/trees/common/CategoriesVisibilityUtils.js +23 -13
- package/lib/esm/tree-widget-react/components/trees/common/CategoriesVisibilityUtils.js.map +1 -1
- package/lib/esm/tree-widget-react/components/trees/common/internal/Utils.d.ts +25 -0
- package/lib/esm/tree-widget-react/components/trees/common/internal/Utils.js +74 -0
- package/lib/esm/tree-widget-react/components/trees/common/internal/Utils.js.map +1 -0
- package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTreeDefinition.d.ts +1 -0
- package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTreeDefinition.js +74 -19
- package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTreeDefinition.js.map +1 -1
- package/lib/esm/tree-widget-react/components/trees/models-tree/Utils.d.ts +5 -3
- package/lib/esm/tree-widget-react/components/trees/models-tree/Utils.js +4 -13
- package/lib/esm/tree-widget-react/components/trees/models-tree/Utils.js.map +1 -1
- package/lib/esm/tree-widget-react/components/trees/models-tree/internal/AlwaysAndNeverDrawnElementInfo.js +4 -3
- package/lib/esm/tree-widget-react/components/trees/models-tree/internal/AlwaysAndNeverDrawnElementInfo.js.map +1 -1
- package/lib/esm/tree-widget-react/components/trees/models-tree/internal/FilteredTree.d.ts +7 -1
- package/lib/esm/tree-widget-react/components/trees/models-tree/internal/FilteredTree.js +52 -0
- package/lib/esm/tree-widget-react/components/trees/models-tree/internal/FilteredTree.js.map +1 -1
- package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.d.ts +15 -0
- package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.js +133 -2
- package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.js.map +1 -1
- package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeVisibilityHandler.js +230 -106
- package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeVisibilityHandler.js.map +1 -1
- package/lib/esm/tree-widget-react-internal.d.ts +1 -1
- package/lib/esm/tree-widget-react-internal.js +1 -1
- package/lib/esm/tree-widget-react-internal.js.map +1 -1
- package/package.json +1 -1
|
@@ -8,7 +8,8 @@ exports.AlwaysAndNeverDrawnElementInfo = exports.SET_CHANGE_DEBOUNCE_TIME = void
|
|
|
8
8
|
const rxjs_1 = require("rxjs");
|
|
9
9
|
const core_bentley_1 = require("@itwin/core-bentley");
|
|
10
10
|
const presentation_core_interop_1 = require("@itwin/presentation-core-interop");
|
|
11
|
-
const Utils_js_1 = require("
|
|
11
|
+
const Utils_js_1 = require("../../common/internal/Utils.js");
|
|
12
|
+
const Utils_js_2 = require("../Utils.js");
|
|
12
13
|
/** @internal */
|
|
13
14
|
exports.SET_CHANGE_DEBOUNCE_TIME = 20;
|
|
14
15
|
class AlwaysAndNeverDrawnElementInfo {
|
|
@@ -109,9 +110,9 @@ class AlwaysAndNeverDrawnElementInfo {
|
|
|
109
110
|
}
|
|
110
111
|
queryAlwaysOrNeverDrawnElementInfo(set, requestId) {
|
|
111
112
|
const elementInfo = set?.size
|
|
112
|
-
? (0, rxjs_1.from)(set).pipe((0, rxjs_1.bufferCount)(
|
|
113
|
+
? (0, rxjs_1.from)(set).pipe((0, rxjs_1.bufferCount)((0, Utils_js_1.getOptimalBatchSize)({ totalSize: set.size, maximumBatchSize: 1000 })), (0, Utils_js_1.releaseMainThreadOnItemsCount)(2), (0, rxjs_1.mergeMap)((block, index) => this.queryElementInfo(block, `${requestId}-${index}`), 10))
|
|
113
114
|
: rxjs_1.EMPTY;
|
|
114
|
-
return elementInfo.pipe((0, Utils_js_1.releaseMainThreadOnItemsCount)(
|
|
115
|
+
return elementInfo.pipe((0, Utils_js_1.releaseMainThreadOnItemsCount)(500), (0, rxjs_1.reduce)((acc, { categoryId, rootCategoryId, modelId, elementsPath }) => {
|
|
115
116
|
const elementIdInList = elementsPath[elementsPath.length - 1];
|
|
116
117
|
const additionalPropsGetter = (id, additionalProps) => {
|
|
117
118
|
if (id === elementIdInList) {
|
|
@@ -121,7 +122,7 @@ class AlwaysAndNeverDrawnElementInfo {
|
|
|
121
122
|
// Existing entries can keep their value, if it's a new entry it's not in the list.
|
|
122
123
|
return additionalProps ?? { isInAlwaysOrNeverDrawnSet: false };
|
|
123
124
|
};
|
|
124
|
-
(0,
|
|
125
|
+
(0, Utils_js_2.updateChildrenTree)({ tree: acc, idsToAdd: [modelId, rootCategoryId, ...elementsPath], additionalPropsGetter });
|
|
125
126
|
return acc;
|
|
126
127
|
}, (() => new Map())()));
|
|
127
128
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AlwaysAndNeverDrawnElementInfo.js","sourceRoot":"","sources":["../../../../../../../src/tree-widget-react/components/trees/models-tree/internal/AlwaysAndNeverDrawnElementInfo.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\n * Copyright (c) Bentley Systems, Incorporated. All rights reserved.\n * See LICENSE.md in the project root for license terms and full copyright notice.\n *--------------------------------------------------------------------------------------------*/\n\nimport {\n BehaviorSubject,\n bufferCount,\n debounceTime,\n defer,\n EMPTY,\n filter,\n first,\n from,\n fromEventPattern,\n map,\n mergeMap,\n of,\n reduce,\n scan,\n share,\n shareReplay,\n startWith,\n Subject,\n switchMap,\n take,\n takeUntil,\n tap,\n} from \"rxjs\";\nimport { Guid, Id64 } from \"@itwin/core-bentley\";\nimport { createECSqlQueryExecutor } from \"@itwin/presentation-core-interop\";\nimport { releaseMainThreadOnItemsCount, updateChildrenTree } from \"../Utils.js\";\n\nimport type { Observable, Subscription } from \"rxjs\";\nimport type { GuidString, Id64Arg, Id64Array, Id64Set, Id64String } from \"@itwin/core-bentley\";\nimport type { Viewport } from \"@itwin/core-frontend\";\nimport type { ChildrenTree } from \"../Utils.js\";\n\n/** @internal */\nexport const SET_CHANGE_DEBOUNCE_TIME = 20;\n\ntype SetType = \"always\" | \"never\";\n\ninterface GetElementsTreeByModelProps {\n /** Only always/never drawn elements that have the specified models will be returned. */\n modelIds: Id64Arg;\n /**\n * The type of set from which tree should be retrieved.\n * `always` - ChildrenTree will be created from `alwaysDrawn` set.\n * `never` - ChildrenTree will be created from `neverDrawn` set.\n */\n setType: SetType;\n}\ninterface GetElementsTreeByCategoryProps extends GetElementsTreeByModelProps {\n /**\n * Categories of root elements.\n *\n * Elements are filtered by given categories. Children of those elements are also included, no matter their category.\n */\n categoryIds: Id64Arg;\n}\ninterface GetElementsTreeByElementProps extends GetElementsTreeByCategoryProps {\n /** Path to element for which to get its' child always/never drawn elements. When undefined, models and categories will be used to get the always/never drawn elements. */\n parentElementIdsPath: Array<Id64Arg>;\n}\n\n/** @internal */\nexport type GetElementsTreeProps = GetElementsTreeByModelProps | GetElementsTreeByCategoryProps | GetElementsTreeByElementProps;\n\n/**\n * - `categoryId` is assigned only to the elements in always/never drawn set.\n * - `isInAlwaysOrNeverDrawnSet` flag determines if key (ECInstanceId) is in always/never set.\n * @internal\n */\nexport type MapEntry = { isInAlwaysOrNeverDrawnSet: true; categoryId: Id64String } | { isInAlwaysOrNeverDrawnSet: false };\n\ntype CachedNodesMap = ChildrenTree<MapEntry>;\n\nexport class AlwaysAndNeverDrawnElementInfo implements Disposable {\n #subscriptions: Subscription[];\n #alwaysDrawn: { cacheEntryObs: Observable<CachedNodesMap>; latestCacheEntryValue?: CachedNodesMap };\n #neverDrawn: { cacheEntryObs: Observable<CachedNodesMap>; latestCacheEntryValue?: CachedNodesMap };\n #disposeSubject = new Subject<void>();\n readonly #viewport: Viewport;\n #componentId: GuidString;\n #componentName: string;\n\n #suppressors: Observable<number>;\n #suppress = new Subject<boolean>();\n\n constructor(viewport: Viewport, componentId?: GuidString) {\n this.#viewport = viewport;\n this.#alwaysDrawn = { cacheEntryObs: this.createCacheEntryObservable(\"always\") };\n this.#neverDrawn = { cacheEntryObs: this.createCacheEntryObservable(\"never\") };\n this.#suppressors = this.#suppress.pipe(\n scan((acc, suppress) => acc + (suppress ? 1 : -1), 0),\n startWith(0),\n shareReplay(1),\n );\n this.#subscriptions = [this.#alwaysDrawn.cacheEntryObs.subscribe(), this.#neverDrawn.cacheEntryObs.subscribe()];\n this.#componentId = componentId ?? Guid.createValue();\n this.#componentName = \"AlwaysAndNeverDrawnElementInfo\";\n }\n\n public suppressChangeEvents() {\n this.#suppress.next(true);\n }\n\n public resumeChangeEvents() {\n this.#suppress.next(false);\n }\n\n public getElementsTree({ setType, modelIds, ...props }: GetElementsTreeProps): Observable<CachedNodesMap> {\n const cache = setType === \"always\" ? this.#alwaysDrawn : this.#neverDrawn;\n const getElements = (rootTreeNodes: CachedNodesMap | undefined): CachedNodesMap => {\n if (!rootTreeNodes) {\n return new Map();\n }\n const pathToElements = [modelIds];\n if (\"categoryIds\" in props && props.categoryIds) {\n pathToElements.push(props.categoryIds);\n if (\"parentElementIdsPath\" in props && props.parentElementIdsPath) {\n props.parentElementIdsPath.forEach((parentElementIds) => pathToElements.push(parentElementIds));\n }\n }\n return this.getChildrenTree({ currentChildrenTree: rootTreeNodes, pathToElements, currentIdsIndex: 0 });\n };\n\n return !cache.latestCacheEntryValue\n ? cache.cacheEntryObs.pipe(map(getElements))\n : this.#suppressors.pipe(\n take(1),\n mergeMap((suppressionCount) =>\n suppressionCount > 0 ? of(cache.latestCacheEntryValue).pipe(map(getElements)) : cache.cacheEntryObs.pipe(map(getElements)),\n ),\n );\n }\n\n private getChildrenTree<T extends object>({\n currentChildrenTree,\n pathToElements,\n currentIdsIndex,\n }: {\n currentChildrenTree: ChildrenTree<T>;\n pathToElements: Array<Id64Arg>;\n currentIdsIndex: number;\n }): ChildrenTree<T> {\n if (currentIdsIndex >= pathToElements.length) {\n return currentChildrenTree;\n }\n const result: ChildrenTree<T> = new Map();\n for (const parentId of Id64.iterable(pathToElements[currentIdsIndex])) {\n const entry = currentChildrenTree.get(parentId);\n if (entry?.children) {\n const childrenTreeOfChildren = this.getChildrenTree({\n currentChildrenTree: entry.children,\n pathToElements,\n currentIdsIndex: currentIdsIndex + 1,\n });\n childrenTreeOfChildren.forEach((val, childId) => result.set(childId, val));\n }\n }\n return result;\n }\n\n private createCacheEntryObservable(setType: SetType): Observable<CachedNodesMap> {\n const event = setType === \"always\" ? this.#viewport.onAlwaysDrawnChanged : this.#viewport.onNeverDrawnChanged;\n const getIds = setType === \"always\" ? () => this.#viewport.alwaysDrawn : () => this.#viewport.neverDrawn;\n\n const resultSubject = new BehaviorSubject<CachedNodesMap | undefined>(undefined);\n\n const obs: Observable<CachedNodesMap> = fromEventPattern(\n (handler) => event.addListener(handler),\n (handler) => event.removeListener(handler),\n ).pipe(\n // Fire the observable once at the beginning\n startWith(undefined),\n // Reset result subject as soon as a new event is emitted.\n // This will make newly subscribed observers wait for the debounce period to pass\n // instead of consuming the cached value which at this point becomes invalid.\n tap(() => resultSubject.next(undefined)),\n // Check if cache updates are not suppressed.\n switchMap(() =>\n this.#suppressors.pipe(\n filter((suppressors) => suppressors === 0),\n take(1),\n ),\n ),\n debounceTime(SET_CHANGE_DEBOUNCE_TIME),\n // Cancel pending request if dispose() is called.\n takeUntil(this.#disposeSubject),\n // If multiple requests are sent at once, preserve only the result of the newest.\n switchMap(() => this.queryAlwaysOrNeverDrawnElementInfo(getIds(), `${setType}Drawn`)),\n tap((cacheEntry) => {\n const value = setType === \"always\" ? this.#alwaysDrawn : this.#neverDrawn;\n value.latestCacheEntryValue = cacheEntry;\n }),\n // Share the result by using a subject which always emits the saved result.\n share({\n connector: () => resultSubject,\n resetOnRefCountZero: false,\n }),\n // Wait until the result is available.\n first((x): x is CachedNodesMap => !!x, new Map()),\n );\n return obs;\n }\n\n public [Symbol.dispose]() {\n this.#subscriptions.forEach((x) => x.unsubscribe());\n this.#subscriptions = [];\n this.#disposeSubject.next();\n }\n\n private queryAlwaysOrNeverDrawnElementInfo(set: Id64Set | undefined, requestId: string): Observable<CachedNodesMap> {\n const elementInfo = set?.size\n ? from(set).pipe(\n bufferCount(Math.ceil(set.size / Math.ceil(set.size / 5000))),\n mergeMap((block, index) => this.queryElementInfo(block, `${requestId}-${index}`), 10),\n )\n : EMPTY;\n return elementInfo.pipe(\n releaseMainThreadOnItemsCount(1000),\n reduce(\n (acc, { categoryId, rootCategoryId, modelId, elementsPath }) => {\n const elementIdInList = elementsPath[elementsPath.length - 1];\n const additionalPropsGetter = (id: Id64String, additionalProps?: MapEntry): MapEntry => {\n if (id === elementIdInList) {\n // Last element in elementsPath is in always/never drawn set. We want to mark, that it is in the set, and save it's categoryId.\n return { isInAlwaysOrNeverDrawnSet: true, categoryId };\n }\n // Existing entries can keep their value, if it's a new entry it's not in the list.\n return additionalProps ?? { isInAlwaysOrNeverDrawnSet: false };\n };\n updateChildrenTree({ tree: acc, idsToAdd: [modelId, rootCategoryId, ...elementsPath], additionalPropsGetter });\n return acc;\n },\n ((): CachedNodesMap => new Map())(),\n ),\n );\n }\n\n private queryElementInfo(\n elementIds: Id64Array,\n requestId: string,\n ): Observable<{\n rootCategoryId: Id64String;\n modelId: Id64String;\n categoryId: Id64String;\n elementsPath: Id64Array;\n }> {\n return defer(() => {\n const executor = createECSqlQueryExecutor(this.#viewport.iModel);\n return executor.createQueryReader(\n {\n ctes: [\n `\n ElementInfo(modelId, rootCategoryId, categoryId, parentId, elementsPath) AS (\n SELECT\n Model.Id modelId,\n Category.Id rootCategoryId,\n Category.Id categoryId,\n Parent.Id parentId,\n CAST(IdToHex(ECInstanceId) AS TEXT) elementsPath\n FROM bis.GeometricElement3d\n WHERE InVirtualSet(?, ECInstanceId)\n\n UNION ALL\n\n SELECT\n e.modelId modelId,\n p.Category.Id rootCategoryId,\n e.categoryId categoryId,\n p.Parent.Id parentId,\n CAST(IdToHex(p.ECInstanceId) AS TEXT) || ';' || e.elementsPath\n FROM bis.GeometricElement3d p\n JOIN ElementInfo e ON p.ECInstanceId = e.parentId\n )\n `,\n ],\n ecsql: `\n SELECT elementsPath elementsPath, modelId modelId, categoryId categoryId, rootCategoryId rootCategoryId\n FROM ElementInfo\n WHERE parentId IS NULL\n `,\n bindings: [{ type: \"idset\", value: elementIds }],\n },\n {\n rowFormat: \"ECSqlPropertyNames\",\n restartToken: `${this.#componentName}/${this.#componentId}/${requestId}`,\n },\n );\n }).pipe(\n map((row) => {\n return { elementsPath: row.elementsPath.split(\";\"), modelId: row.modelId, categoryId: row.categoryId, rootCategoryId: row.rootCategoryId };\n }),\n );\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"AlwaysAndNeverDrawnElementInfo.js","sourceRoot":"","sources":["../../../../../../../src/tree-widget-react/components/trees/models-tree/internal/AlwaysAndNeverDrawnElementInfo.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\n * Copyright (c) Bentley Systems, Incorporated. All rights reserved.\n * See LICENSE.md in the project root for license terms and full copyright notice.\n *--------------------------------------------------------------------------------------------*/\n\nimport {\n BehaviorSubject,\n bufferCount,\n debounceTime,\n defer,\n EMPTY,\n filter,\n first,\n from,\n fromEventPattern,\n map,\n mergeMap,\n of,\n reduce,\n scan,\n share,\n shareReplay,\n startWith,\n Subject,\n switchMap,\n take,\n takeUntil,\n tap,\n} from \"rxjs\";\nimport { Guid, Id64 } from \"@itwin/core-bentley\";\nimport { createECSqlQueryExecutor } from \"@itwin/presentation-core-interop\";\nimport { getOptimalBatchSize, releaseMainThreadOnItemsCount } from \"../../common/internal/Utils.js\";\nimport { updateChildrenTree } from \"../Utils.js\";\n\nimport type { Observable, Subscription } from \"rxjs\";\nimport type { GuidString, Id64Arg, Id64Array, Id64Set, Id64String } from \"@itwin/core-bentley\";\nimport type { Viewport } from \"@itwin/core-frontend\";\nimport type { ChildrenTree } from \"../Utils.js\";\n\n/** @internal */\nexport const SET_CHANGE_DEBOUNCE_TIME = 20;\n\ntype SetType = \"always\" | \"never\";\n\ninterface GetElementsTreeByModelProps {\n /** Only always/never drawn elements that have the specified models will be returned. */\n modelIds: Id64Arg;\n /**\n * The type of set from which tree should be retrieved.\n * `always` - ChildrenTree will be created from `alwaysDrawn` set.\n * `never` - ChildrenTree will be created from `neverDrawn` set.\n */\n setType: SetType;\n}\ninterface GetElementsTreeByCategoryProps extends GetElementsTreeByModelProps {\n /**\n * Categories of root elements.\n *\n * Elements are filtered by given categories. Children of those elements are also included, no matter their category.\n */\n categoryIds: Id64Arg;\n}\ninterface GetElementsTreeByElementProps extends GetElementsTreeByCategoryProps {\n /** Path to element for which to get its' child always/never drawn elements. When undefined, models and categories will be used to get the always/never drawn elements. */\n parentElementIdsPath: Array<Id64Arg>;\n}\n\n/** @internal */\nexport type GetElementsTreeProps = GetElementsTreeByModelProps | GetElementsTreeByCategoryProps | GetElementsTreeByElementProps;\n\n/**\n * - `categoryId` is assigned only to the elements in always/never drawn set.\n * - `isInAlwaysOrNeverDrawnSet` flag determines if key (ECInstanceId) is in always/never set.\n * @internal\n */\nexport type MapEntry = { isInAlwaysOrNeverDrawnSet: true; categoryId: Id64String } | { isInAlwaysOrNeverDrawnSet: false };\n\ntype CachedNodesMap = ChildrenTree<MapEntry>;\n\nexport class AlwaysAndNeverDrawnElementInfo implements Disposable {\n #subscriptions: Subscription[];\n #alwaysDrawn: { cacheEntryObs: Observable<CachedNodesMap>; latestCacheEntryValue?: CachedNodesMap };\n #neverDrawn: { cacheEntryObs: Observable<CachedNodesMap>; latestCacheEntryValue?: CachedNodesMap };\n #disposeSubject = new Subject<void>();\n readonly #viewport: Viewport;\n #componentId: GuidString;\n #componentName: string;\n\n #suppressors: Observable<number>;\n #suppress = new Subject<boolean>();\n\n constructor(viewport: Viewport, componentId?: GuidString) {\n this.#viewport = viewport;\n this.#alwaysDrawn = { cacheEntryObs: this.createCacheEntryObservable(\"always\") };\n this.#neverDrawn = { cacheEntryObs: this.createCacheEntryObservable(\"never\") };\n this.#suppressors = this.#suppress.pipe(\n scan((acc, suppress) => acc + (suppress ? 1 : -1), 0),\n startWith(0),\n shareReplay(1),\n );\n this.#subscriptions = [this.#alwaysDrawn.cacheEntryObs.subscribe(), this.#neverDrawn.cacheEntryObs.subscribe()];\n this.#componentId = componentId ?? Guid.createValue();\n this.#componentName = \"AlwaysAndNeverDrawnElementInfo\";\n }\n\n public suppressChangeEvents() {\n this.#suppress.next(true);\n }\n\n public resumeChangeEvents() {\n this.#suppress.next(false);\n }\n\n public getElementsTree({ setType, modelIds, ...props }: GetElementsTreeProps): Observable<CachedNodesMap> {\n const cache = setType === \"always\" ? this.#alwaysDrawn : this.#neverDrawn;\n const getElements = (rootTreeNodes: CachedNodesMap | undefined): CachedNodesMap => {\n if (!rootTreeNodes) {\n return new Map();\n }\n const pathToElements = [modelIds];\n if (\"categoryIds\" in props && props.categoryIds) {\n pathToElements.push(props.categoryIds);\n if (\"parentElementIdsPath\" in props && props.parentElementIdsPath) {\n props.parentElementIdsPath.forEach((parentElementIds) => pathToElements.push(parentElementIds));\n }\n }\n return this.getChildrenTree({ currentChildrenTree: rootTreeNodes, pathToElements, currentIdsIndex: 0 });\n };\n\n return !cache.latestCacheEntryValue\n ? cache.cacheEntryObs.pipe(map(getElements))\n : this.#suppressors.pipe(\n take(1),\n mergeMap((suppressionCount) =>\n suppressionCount > 0 ? of(cache.latestCacheEntryValue).pipe(map(getElements)) : cache.cacheEntryObs.pipe(map(getElements)),\n ),\n );\n }\n\n private getChildrenTree<T extends object>({\n currentChildrenTree,\n pathToElements,\n currentIdsIndex,\n }: {\n currentChildrenTree: ChildrenTree<T>;\n pathToElements: Array<Id64Arg>;\n currentIdsIndex: number;\n }): ChildrenTree<T> {\n if (currentIdsIndex >= pathToElements.length) {\n return currentChildrenTree;\n }\n const result: ChildrenTree<T> = new Map();\n for (const parentId of Id64.iterable(pathToElements[currentIdsIndex])) {\n const entry = currentChildrenTree.get(parentId);\n if (entry?.children) {\n const childrenTreeOfChildren = this.getChildrenTree({\n currentChildrenTree: entry.children,\n pathToElements,\n currentIdsIndex: currentIdsIndex + 1,\n });\n childrenTreeOfChildren.forEach((val, childId) => result.set(childId, val));\n }\n }\n return result;\n }\n\n private createCacheEntryObservable(setType: SetType): Observable<CachedNodesMap> {\n const event = setType === \"always\" ? this.#viewport.onAlwaysDrawnChanged : this.#viewport.onNeverDrawnChanged;\n const getIds = setType === \"always\" ? () => this.#viewport.alwaysDrawn : () => this.#viewport.neverDrawn;\n\n const resultSubject = new BehaviorSubject<CachedNodesMap | undefined>(undefined);\n\n const obs: Observable<CachedNodesMap> = fromEventPattern(\n (handler) => event.addListener(handler),\n (handler) => event.removeListener(handler),\n ).pipe(\n // Fire the observable once at the beginning\n startWith(undefined),\n // Reset result subject as soon as a new event is emitted.\n // This will make newly subscribed observers wait for the debounce period to pass\n // instead of consuming the cached value which at this point becomes invalid.\n tap(() => resultSubject.next(undefined)),\n // Check if cache updates are not suppressed.\n switchMap(() =>\n this.#suppressors.pipe(\n filter((suppressors) => suppressors === 0),\n take(1),\n ),\n ),\n debounceTime(SET_CHANGE_DEBOUNCE_TIME),\n // Cancel pending request if dispose() is called.\n takeUntil(this.#disposeSubject),\n // If multiple requests are sent at once, preserve only the result of the newest.\n switchMap(() => this.queryAlwaysOrNeverDrawnElementInfo(getIds(), `${setType}Drawn`)),\n tap((cacheEntry) => {\n const value = setType === \"always\" ? this.#alwaysDrawn : this.#neverDrawn;\n value.latestCacheEntryValue = cacheEntry;\n }),\n // Share the result by using a subject which always emits the saved result.\n share({\n connector: () => resultSubject,\n resetOnRefCountZero: false,\n }),\n // Wait until the result is available.\n first((x): x is CachedNodesMap => !!x, new Map()),\n );\n return obs;\n }\n\n public [Symbol.dispose]() {\n this.#subscriptions.forEach((x) => x.unsubscribe());\n this.#subscriptions = [];\n this.#disposeSubject.next();\n }\n\n private queryAlwaysOrNeverDrawnElementInfo(set: Id64Set | undefined, requestId: string): Observable<CachedNodesMap> {\n const elementInfo = set?.size\n ? from(set).pipe(\n bufferCount(getOptimalBatchSize({ totalSize: set.size, maximumBatchSize: 1000 })),\n releaseMainThreadOnItemsCount(2),\n mergeMap((block, index) => this.queryElementInfo(block, `${requestId}-${index}`), 10),\n )\n : EMPTY;\n return elementInfo.pipe(\n releaseMainThreadOnItemsCount(500),\n reduce(\n (acc, { categoryId, rootCategoryId, modelId, elementsPath }) => {\n const elementIdInList = elementsPath[elementsPath.length - 1];\n const additionalPropsGetter = (id: Id64String, additionalProps?: MapEntry): MapEntry => {\n if (id === elementIdInList) {\n // Last element in elementsPath is in always/never drawn set. We want to mark, that it is in the set, and save it's categoryId.\n return { isInAlwaysOrNeverDrawnSet: true, categoryId };\n }\n // Existing entries can keep their value, if it's a new entry it's not in the list.\n return additionalProps ?? { isInAlwaysOrNeverDrawnSet: false };\n };\n updateChildrenTree({ tree: acc, idsToAdd: [modelId, rootCategoryId, ...elementsPath], additionalPropsGetter });\n return acc;\n },\n ((): CachedNodesMap => new Map())(),\n ),\n );\n }\n\n private queryElementInfo(\n elementIds: Id64Array,\n requestId: string,\n ): Observable<{\n rootCategoryId: Id64String;\n modelId: Id64String;\n categoryId: Id64String;\n elementsPath: Id64Array;\n }> {\n return defer(() => {\n const executor = createECSqlQueryExecutor(this.#viewport.iModel);\n return executor.createQueryReader(\n {\n ctes: [\n `\n ElementInfo(modelId, rootCategoryId, categoryId, parentId, elementsPath) AS (\n SELECT\n Model.Id modelId,\n Category.Id rootCategoryId,\n Category.Id categoryId,\n Parent.Id parentId,\n CAST(IdToHex(ECInstanceId) AS TEXT) elementsPath\n FROM bis.GeometricElement3d\n WHERE InVirtualSet(?, ECInstanceId)\n\n UNION ALL\n\n SELECT\n e.modelId modelId,\n p.Category.Id rootCategoryId,\n e.categoryId categoryId,\n p.Parent.Id parentId,\n CAST(IdToHex(p.ECInstanceId) AS TEXT) || ';' || e.elementsPath\n FROM bis.GeometricElement3d p\n JOIN ElementInfo e ON p.ECInstanceId = e.parentId\n )\n `,\n ],\n ecsql: `\n SELECT elementsPath elementsPath, modelId modelId, categoryId categoryId, rootCategoryId rootCategoryId\n FROM ElementInfo\n WHERE parentId IS NULL\n `,\n bindings: [{ type: \"idset\", value: elementIds }],\n },\n {\n rowFormat: \"ECSqlPropertyNames\",\n restartToken: `${this.#componentName}/${this.#componentId}/${requestId}`,\n },\n );\n }).pipe(\n map((row) => {\n return { elementsPath: row.elementsPath.split(\";\"), modelId: row.modelId, categoryId: row.categoryId, rootCategoryId: row.rootCategoryId };\n }),\n );\n }\n}\n"]}
|
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
import { HierarchyFilteringPath, HierarchyNode } from "@itwin/presentation-hierarchies";
|
|
2
|
-
import type { Id64String } from "@itwin/core-bentley";
|
|
2
|
+
import type { Id64Arg, Id64Set, Id64String } from "@itwin/core-bentley";
|
|
3
3
|
import type { ClassGroupingNodeKey, InstancesNodeKey } from "@itwin/presentation-hierarchies";
|
|
4
4
|
import type { ECClassHierarchyInspector } from "@itwin/presentation-shared";
|
|
5
|
+
import type { ChildrenTree } from "../Utils.js";
|
|
6
|
+
interface GetElementsFromUnfilteredChildrenTreeProps {
|
|
7
|
+
childrenTree: ChildrenTree;
|
|
8
|
+
parentIdsPath: Array<Id64Arg>;
|
|
9
|
+
}
|
|
5
10
|
/** @internal */
|
|
6
11
|
export interface FilteredTree {
|
|
7
12
|
getVisibilityChangeTargets(node: HierarchyNode & {
|
|
8
13
|
key: ClassGroupingNodeKey | InstancesNodeKey;
|
|
9
14
|
}): VisibilityChangeTargets;
|
|
15
|
+
getElementsFromUnfilteredChildrenTree(props: GetElementsFromUnfilteredChildrenTreeProps): Id64Set | undefined;
|
|
10
16
|
}
|
|
11
17
|
export declare const SUBJECT_CLASS_NAME: "BisCore.Subject";
|
|
12
18
|
export declare const MODEL_CLASS_NAME: "BisCore.GeometricModel3d";
|
|
@@ -9,6 +9,7 @@ exports.parseCategoryKey = parseCategoryKey;
|
|
|
9
9
|
exports.createFilteredTree = createFilteredTree;
|
|
10
10
|
const core_bentley_1 = require("@itwin/core-bentley");
|
|
11
11
|
const presentation_hierarchies_1 = require("@itwin/presentation-hierarchies");
|
|
12
|
+
const Utils_js_1 = require("../Utils.js");
|
|
12
13
|
exports.SUBJECT_CLASS_NAME = "BisCore.Subject";
|
|
13
14
|
exports.MODEL_CLASS_NAME = "BisCore.GeometricModel3d";
|
|
14
15
|
exports.CATEGORY_CLASS_NAME = "BisCore.SpatialCategory";
|
|
@@ -55,8 +56,59 @@ async function createFilteredTree(imodelAccess, filteringPaths) {
|
|
|
55
56
|
}
|
|
56
57
|
return {
|
|
57
58
|
getVisibilityChangeTargets: (node) => getVisibilityChangeTargets(root, node),
|
|
59
|
+
getElementsFromUnfilteredChildrenTree: ({ childrenTree, parentIdsPath }) => getElementsFromUnfilteredChildrenTree({ parentIdsPath, root, childrenTree }),
|
|
58
60
|
};
|
|
59
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* Unfiltered tree can contain ids of models/categories/elements which are not present in the filtered tree.
|
|
64
|
+
* This function retrieves only those ids which are either filter tree targets, or are their children (direct and indirect).
|
|
65
|
+
*/
|
|
66
|
+
function getElementsFromUnfilteredChildrenTree(props) {
|
|
67
|
+
if (props.childrenTree.size === 0 || props.parentIdsPath.length === 0) {
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
70
|
+
let lookupParents = [props.root];
|
|
71
|
+
for (const parentIds of props.parentIdsPath) {
|
|
72
|
+
// When filtered node does not have children, it is filter target and because of this, all elements in the childrenTree are in the filtered tree
|
|
73
|
+
if (lookupParents.every((parent) => !parent.children)) {
|
|
74
|
+
return (0, Utils_js_1.getIdsFromChildrenTree)({ tree: props.childrenTree });
|
|
75
|
+
}
|
|
76
|
+
const parentNodes = findMatchingFilteredNodes(lookupParents, parentIds);
|
|
77
|
+
if (parentNodes.length === 0) {
|
|
78
|
+
return undefined;
|
|
79
|
+
}
|
|
80
|
+
lookupParents = parentNodes;
|
|
81
|
+
}
|
|
82
|
+
// We have unfiltered children tree and filtered nodes that are parents of first level nodes in unfiltered children tree.
|
|
83
|
+
// We can start filtering unfiltered children tree based on filtered nodes.
|
|
84
|
+
const result = getChildrenTreeIdsMatchingFilteredNodes({ tree: props.childrenTree, filteredNodes: lookupParents });
|
|
85
|
+
return result.size > 0 ? result : undefined;
|
|
86
|
+
}
|
|
87
|
+
function getChildrenTreeIdsMatchingFilteredNodes({ tree, filteredNodes, }) {
|
|
88
|
+
const getIdsRecursively = (childrenTree, parentFilteredNodes) => {
|
|
89
|
+
// If one of the parent filtered nodes does not have children, it is filter target and because of this, all elements in the childrenTree are in the filtered tree.
|
|
90
|
+
const hasParentFilterTarget = parentFilteredNodes.some((filteredNode) => "isFilterTarget" in filteredNode && filteredNode.isFilterTarget);
|
|
91
|
+
if (hasParentFilterTarget) {
|
|
92
|
+
return (0, Utils_js_1.getIdsFromChildrenTree)({ tree: childrenTree });
|
|
93
|
+
}
|
|
94
|
+
const result = new Set();
|
|
95
|
+
childrenTree.forEach((entry, id) => {
|
|
96
|
+
const nodes = findMatchingFilteredNodes(parentFilteredNodes, id);
|
|
97
|
+
// If no filtered nodes match this id, skip it since it's not in the filtered tree.
|
|
98
|
+
if (nodes.length === 0) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
// Id was found in filtered nodes children, add it to the result.
|
|
102
|
+
result.add(id);
|
|
103
|
+
if (entry.children) {
|
|
104
|
+
// Continue recursively for children
|
|
105
|
+
getIdsRecursively(entry.children, nodes).forEach((childId) => result.add(childId));
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
return result;
|
|
109
|
+
};
|
|
110
|
+
return getIdsRecursively(tree, filteredNodes);
|
|
111
|
+
}
|
|
60
112
|
function getVisibilityChangeTargets(root, node) {
|
|
61
113
|
let lookupParents = [root];
|
|
62
114
|
const changeTargets = {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FilteredTree.js","sourceRoot":"","sources":["../../../../../../../src/tree-widget-react/components/trees/models-tree/internal/FilteredTree.ts"],"names":[],"mappings":";AAAA;;;gGAGgG;;;AAqDhG,4CAGC;AAWD,gDAwCC;AAzGD,sDAAmD;AACnD,8EAAmI;AAsCtH,QAAA,kBAAkB,GAAG,iBAA0B,CAAC;AAChD,QAAA,gBAAgB,GAAG,0BAAmC,CAAC;AACvD,QAAA,mBAAmB,GAAG,yBAAkC,CAAC;AACzD,QAAA,kBAAkB,GAAG,4BAAqC,CAAC;AAIxE,SAAS,iBAAiB,CAAC,OAAe,EAAE,UAAkB;IAC5D,OAAO,GAAG,OAAO,IAAI,UAAU,EAAE,CAAC;AACpC,CAAC;AAED,gBAAgB;AAChB,SAAgB,gBAAgB,CAAC,GAAgB;IAC/C,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC7C,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC;AACjC,CAAC;AAUD,gBAAgB;AACT,KAAK,UAAU,kBAAkB,CAAC,YAAuC,EAAE,cAAwC;IACxH,MAAM,IAAI,GAAyB;QACjC,QAAQ,EAAE,IAAI,GAAG,EAAE;KACpB,CAAC;IAEF,KAAK,MAAM,aAAa,IAAI,cAAc,EAAE,CAAC;QAC3C,MAAM,cAAc,GAAG,iDAAsB,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC;QAE5E,IAAI,UAAU,GAA4C,IAAI,CAAC;QAC/D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,cAAc,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC/C,IAAI,MAAM,IAAI,UAAU,IAAI,UAAU,CAAC,cAAc,EAAE,CAAC;gBACtD,MAAM;YACR,CAAC;YAED,MAAM,UAAU,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC;YACrC,IAAI,CAAC,kDAAuB,CAAC,wBAAwB,CAAC,UAAU,CAAC,EAAE,CAAC;gBAClE,MAAM;YACR,CAAC;YAED,MAAM,WAAW,GAAiC,UAAU,CAAC,QAAQ,EAAE,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;YAC1F,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;gBAC9B,UAAU,GAAG,WAAW,CAAC;gBACzB,SAAS;YACX,CAAC;YAED,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,YAAY,EAAE,UAAU,CAAC,SAAS,CAAC,CAAC;YAC/D,MAAM,OAAO,GAAqB,sBAAsB,CAAC;gBACvD,IAAI;gBACJ,EAAE,EAAE,UAAU,CAAC,EAAE;gBACjB,cAAc,EAAE,CAAC,KAAK,cAAc,CAAC,MAAM,GAAG,CAAC;gBAC/C,MAAM,EAAE,UAA8B;aACvC,CAAC,CAAC;YACH,CAAC,UAAU,CAAC,QAAQ,KAAK,IAAI,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;YAChE,UAAU,GAAG,OAAO,CAAC;QACvB,CAAC;IACH,CAAC;IAED,OAAO;QACL,0BAA0B,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,0BAA0B,CAAC,IAAI,EAAE,IAAI,CAAC;KAC7E,CAAC;AACJ,CAAC;AAED,SAAS,0BAA0B,CAAC,IAA0B,EAAE,IAAsE;IACpI,IAAI,aAAa,GAAmD,CAAC,IAAI,CAAC,CAAC;IAC3E,MAAM,aAAa,GAA4B,EAAE,CAAC;IAElD,+CAA+C;IAC/C,KAAK,MAAM,SAAS,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;QACxC,IAAI,CAAC,2CAAgB,CAAC,WAAW,CAAC,SAAS,CAAC,EAAE,CAAC;YAC7C,SAAS;QACX,CAAC;QAED,4IAA4I;QAC5I,oEAAoE;QACpE,MAAM,WAAW,GAAG,yBAAyB,CAC3C,aAAa,EACb,SAAS,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAC5C,CAAC;QACF,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7B,OAAO,aAAa,CAAC;QACvB,CAAC;QACD,aAAa,GAAG,WAAW,CAAC;IAC9B,CAAC;IACD,MAAM,GAAG,GAAG,wCAAa,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;IAC3I,4CAA4C;IAC5C,MAAM,aAAa,GAAG,yBAAyB,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC;IACpE,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/B,OAAO,aAAa,CAAC;IACvB,CAAC;IAED,aAAa,CAAC,OAAO,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,8BAA8B,CAAC,aAAa,EAAE,YAAY,CAAC,CAAC,CAAC;IACrG,OAAO,aAAa,CAAC;AACvB,CAAC;AAED,SAAS,yBAAyB,CAAC,aAA6D,EAAE,GAAY;IAC5G,OAAO,aAAa,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE;QACtC,MAAM,aAAa,GAAG,KAAK,EAAoB,CAAC;QAChD,KAAK,MAAM,EAAE,IAAI,mBAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YACpC,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;YACtC,IAAI,IAAI,EAAE,CAAC;gBACT,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC3B,CAAC;QACH,CAAC;QACD,OAAO,aAAa,CAAC;IACvB,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,8BAA8B,CAAC,aAAsC,EAAE,IAAsB;IACpG,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;QACxB,SAAS,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC;QAC/B,OAAO;IACT,CAAC;IAED,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC5B,6DAA6D;QAC7D,SAAS,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC;IACjC,CAAC;IAED,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACnB,OAAO;IACT,CAAC;IAED,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;QAC3C,8BAA8B,CAAC,aAAa,EAAE,KAAK,CAAC,CAAC;IACvD,CAAC;AACH,CAAC;AAED,SAAS,SAAS,CAAC,aAAsC,EAAE,IAAsB;IAC/E,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;QAClB,KAAK,SAAS;YACZ,CAAC,aAAa,CAAC,QAAQ,KAAK,IAAI,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACpD,OAAO;QACT,KAAK,OAAO;YACV,CAAC,aAAa,CAAC,MAAM,KAAK,IAAI,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAClD,OAAO;QACT,KAAK,UAAU;YACb,CAAC,aAAa,CAAC,UAAU,KAAK,IAAI,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,iBAAiB,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;YACvF,OAAO;QACT,KAAK,SAAS;YACZ,MAAM,WAAW,GAAG,iBAAiB,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;YACrE,MAAM,QAAQ,GAAG,CAAC,aAAa,CAAC,QAAQ,KAAK,IAAI,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;YACzE,IAAI,QAAQ,EAAE,CAAC;gBACb,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,cAAc,EAAE,IAAI,CAAC,cAAc,EAAE,CAAC,CAAC;YACjE,CAAC;iBAAM,CAAC;gBACN,aAAa,CAAC,QAAQ,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,cAAc,EAAE,IAAI,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YACzG,CAAC;IACL,CAAC;AACH,CAAC;AAED,SAAS,sBAAsB,CAAC,EAC9B,IAAI,EACJ,EAAE,EACF,cAAc,EACd,MAAM,GAMP;IACC,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;QAC3C,OAAO;YACL,EAAE;YACF,cAAc;YACd,IAAI;SACL,CAAC;IACJ,CAAC;IAED,IAAI,IAAI,KAAK,UAAU,EAAE,CAAC;QACxB,IAAA,qBAAM,EAAC,MAAM,IAAI,MAAM,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC;QACpD,OAAO;YACL,EAAE;YACF,cAAc;YACd,IAAI;YACJ,OAAO,EAAE,MAAM,CAAC,EAAE;SACnB,CAAC;IACJ,CAAC;IAED,IAAI,MAAM,IAAI,MAAM,IAAI,MAAM,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;QACnD,OAAO;YACL,EAAE;YACF,cAAc;YACd,IAAI;YACJ,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,UAAU,EAAE,MAAM,CAAC,EAAE;SACtB,CAAC;IACJ,CAAC;IAED,IAAI,MAAM,IAAI,MAAM,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAClD,OAAO;YACL,EAAE;YACF,cAAc;YACd,IAAI;YACJ,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,UAAU,EAAE,MAAM,CAAC,UAAU;SAC9B,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;AAC9C,CAAC;AAED,KAAK,UAAU,OAAO,CAAC,gBAA2C,EAAE,SAAiB;IACnF,IAAI,MAAM,gBAAgB,CAAC,gBAAgB,CAAC,SAAS,EAAE,0BAAkB,CAAC,EAAE,CAAC;QAC3E,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,IAAI,MAAM,gBAAgB,CAAC,gBAAgB,CAAC,SAAS,EAAE,wBAAgB,CAAC,EAAE,CAAC;QACzE,OAAO,OAAO,CAAC;IACjB,CAAC;IACD,IAAI,MAAM,gBAAgB,CAAC,gBAAgB,CAAC,SAAS,EAAE,2BAAmB,CAAC,EAAE,CAAC;QAC5E,OAAO,UAAU,CAAC;IACpB,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC","sourcesContent":["/*---------------------------------------------------------------------------------------------\n * Copyright (c) Bentley Systems, Incorporated. All rights reserved.\n * See LICENSE.md in the project root for license terms and full copyright notice.\n *--------------------------------------------------------------------------------------------*/\n\nimport { assert, Id64 } from \"@itwin/core-bentley\";\nimport { HierarchyFilteringPath, HierarchyNode, HierarchyNodeIdentifier, HierarchyNodeKey } from \"@itwin/presentation-hierarchies\";\n\nimport type { Id64Arg, Id64String } from \"@itwin/core-bentley\";\nimport type { ClassGroupingNodeKey, InstancesNodeKey } from \"@itwin/presentation-hierarchies\";\nimport type { ECClassHierarchyInspector } from \"@itwin/presentation-shared\";\n\ninterface FilteredTreeRootNode {\n children: Map<Id64String, FilteredTreeNode>;\n}\n\ninterface BaseFilteredTreeNode {\n id: string;\n children?: Map<Id64String, FilteredTreeNode>;\n isFilterTarget: boolean;\n}\n\ninterface GenericFilteredTreeNode extends BaseFilteredTreeNode {\n type: \"subject\" | \"model\";\n}\n\ninterface CategoryFilteredTreeNode extends BaseFilteredTreeNode {\n type: \"category\";\n modelId: Id64String;\n}\n\ninterface ElementFilteredTreeNode extends BaseFilteredTreeNode {\n type: \"element\";\n modelId: Id64String;\n categoryId: Id64String;\n}\n\ntype FilteredTreeNode = GenericFilteredTreeNode | CategoryFilteredTreeNode | ElementFilteredTreeNode;\n\n/** @internal */\nexport interface FilteredTree {\n getVisibilityChangeTargets(node: HierarchyNode & { key: ClassGroupingNodeKey | InstancesNodeKey }): VisibilityChangeTargets;\n}\n\nexport const SUBJECT_CLASS_NAME = \"BisCore.Subject\" as const;\nexport const MODEL_CLASS_NAME = \"BisCore.GeometricModel3d\" as const;\nexport const CATEGORY_CLASS_NAME = \"BisCore.SpatialCategory\" as const;\nexport const ELEMENT_CLASS_NAME = \"BisCore.GeometricElement3d\" as const;\n\ntype CategoryKey = `${Id64String}-${Id64String}`;\n\nfunction createCategoryKey(modelId: string, categoryId: string): CategoryKey {\n return `${modelId}-${categoryId}`;\n}\n\n/** @internal */\nexport function parseCategoryKey(key: CategoryKey) {\n const [modelId, categoryId] = key.split(\"-\");\n return { modelId, categoryId };\n}\n\n/** @internal */\nexport interface VisibilityChangeTargets {\n subjects?: Set<Id64String>;\n models?: Set<Id64String>;\n categories?: Set<CategoryKey>;\n elements?: Map<CategoryKey, Map<Id64String, { isFilterTarget: boolean }>>;\n}\n\n/** @internal */\nexport async function createFilteredTree(imodelAccess: ECClassHierarchyInspector, filteringPaths: HierarchyFilteringPath[]): Promise<FilteredTree> {\n const root: FilteredTreeRootNode = {\n children: new Map(),\n };\n\n for (const filteringPath of filteringPaths) {\n const normalizedPath = HierarchyFilteringPath.normalize(filteringPath).path;\n\n let parentNode: FilteredTreeRootNode | FilteredTreeNode = root;\n for (let i = 0; i < normalizedPath.length; i++) {\n if (\"type\" in parentNode && parentNode.isFilterTarget) {\n break;\n }\n\n const identifier = normalizedPath[i];\n if (!HierarchyNodeIdentifier.isInstanceNodeIdentifier(identifier)) {\n break;\n }\n\n const currentNode: FilteredTreeNode | undefined = parentNode.children?.get(identifier.id);\n if (currentNode !== undefined) {\n parentNode = currentNode;\n continue;\n }\n\n const type = await getType(imodelAccess, identifier.className);\n const newNode: FilteredTreeNode = createFilteredTreeNode({\n type,\n id: identifier.id,\n isFilterTarget: i === normalizedPath.length - 1,\n parent: parentNode as FilteredTreeNode,\n });\n (parentNode.children ??= new Map()).set(identifier.id, newNode);\n parentNode = newNode;\n }\n }\n\n return {\n getVisibilityChangeTargets: (node) => getVisibilityChangeTargets(root, node),\n };\n}\n\nfunction getVisibilityChangeTargets(root: FilteredTreeRootNode, node: HierarchyNode & { key: ClassGroupingNodeKey | InstancesNodeKey }) {\n let lookupParents: Array<FilteredTreeRootNode | FilteredTreeNode> = [root];\n const changeTargets: VisibilityChangeTargets = {};\n\n // find the filtered parent nodes of the `node`\n for (const parentKey of node.parentKeys) {\n if (!HierarchyNodeKey.isInstances(parentKey)) {\n continue;\n }\n\n // tree node might be merged from multiple instances. As filtered tree stores only one instance per node, we need to find all matching nodes\n // and use them when checking for matching node in one level deeper.\n const parentNodes = findMatchingFilteredNodes(\n lookupParents,\n parentKey.instanceKeys.map((key) => key.id),\n );\n if (parentNodes.length === 0) {\n return changeTargets;\n }\n lookupParents = parentNodes;\n }\n const ids = HierarchyNode.isInstancesNode(node) ? node.key.instanceKeys.map(({ id }) => id) : node.groupedInstanceKeys.map(({ id }) => id);\n // find filtered nodes that match the `node`\n const filteredNodes = findMatchingFilteredNodes(lookupParents, ids);\n if (filteredNodes.length === 0) {\n return changeTargets;\n }\n\n filteredNodes.forEach((filteredNode) => collectVisibilityChangeTargets(changeTargets, filteredNode));\n return changeTargets;\n}\n\nfunction findMatchingFilteredNodes(lookupParents: Array<FilteredTreeRootNode | FilteredTreeNode>, ids: Id64Arg): Array<FilteredTreeNode> {\n return lookupParents.flatMap((lookup) => {\n const childrenArray = Array<FilteredTreeNode>();\n for (const id of Id64.iterable(ids)) {\n const node = lookup.children?.get(id);\n if (node) {\n childrenArray.push(node);\n }\n }\n return childrenArray;\n });\n}\n\nfunction collectVisibilityChangeTargets(changeTargets: VisibilityChangeTargets, node: FilteredTreeNode) {\n if (node.isFilterTarget) {\n addTarget(changeTargets, node);\n return;\n }\n\n if (node.type === \"element\") {\n // need to add parent ids as filter target will be an element\n addTarget(changeTargets, node);\n }\n\n if (!node.children) {\n return;\n }\n\n for (const child of node.children.values()) {\n collectVisibilityChangeTargets(changeTargets, child);\n }\n}\n\nfunction addTarget(filterTargets: VisibilityChangeTargets, node: FilteredTreeNode) {\n switch (node.type) {\n case \"subject\":\n (filterTargets.subjects ??= new Set()).add(node.id);\n return;\n case \"model\":\n (filterTargets.models ??= new Set()).add(node.id);\n return;\n case \"category\":\n (filterTargets.categories ??= new Set()).add(createCategoryKey(node.modelId, node.id));\n return;\n case \"element\":\n const categoryKey = createCategoryKey(node.modelId, node.categoryId);\n const elements = (filterTargets.elements ??= new Map()).get(categoryKey);\n if (elements) {\n elements.set(node.id, { isFilterTarget: node.isFilterTarget });\n } else {\n filterTargets.elements.set(categoryKey, new Map([[node.id, { isFilterTarget: node.isFilterTarget }]]));\n }\n }\n}\n\nfunction createFilteredTreeNode({\n type,\n id,\n isFilterTarget,\n parent,\n}: {\n type: FilteredTreeNode[\"type\"];\n id: string;\n isFilterTarget: boolean;\n parent: FilteredTreeNode | FilteredTreeRootNode;\n}): FilteredTreeNode {\n if (type === \"subject\" || type === \"model\") {\n return {\n id,\n isFilterTarget,\n type,\n };\n }\n\n if (type === \"category\") {\n assert(\"type\" in parent && parent.type === \"model\");\n return {\n id,\n isFilterTarget,\n type,\n modelId: parent.id,\n };\n }\n\n if (\"type\" in parent && parent.type === \"category\") {\n return {\n id,\n isFilterTarget,\n type,\n modelId: parent.modelId,\n categoryId: parent.id,\n };\n }\n\n if (\"type\" in parent && parent.type === \"element\") {\n return {\n id,\n isFilterTarget,\n type,\n modelId: parent.modelId,\n categoryId: parent.categoryId,\n };\n }\n\n throw new Error(\"Invalid parent node type\");\n}\n\nasync function getType(hierarchyChecker: ECClassHierarchyInspector, className: string) {\n if (await hierarchyChecker.classDerivesFrom(className, SUBJECT_CLASS_NAME)) {\n return \"subject\";\n }\n if (await hierarchyChecker.classDerivesFrom(className, MODEL_CLASS_NAME)) {\n return \"model\";\n }\n if (await hierarchyChecker.classDerivesFrom(className, CATEGORY_CLASS_NAME)) {\n return \"category\";\n }\n return \"element\";\n}\n"]}
|
|
1
|
+
{"version":3,"file":"FilteredTree.js","sourceRoot":"","sources":["../../../../../../../src/tree-widget-react/components/trees/models-tree/internal/FilteredTree.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\n * Copyright (c) Bentley Systems, Incorporated. All rights reserved.\n * See LICENSE.md in the project root for license terms and full copyright notice.\n *--------------------------------------------------------------------------------------------*/\n\nimport { assert, Id64 } from \"@itwin/core-bentley\";\nimport { HierarchyFilteringPath, HierarchyNode, HierarchyNodeIdentifier, HierarchyNodeKey } from \"@itwin/presentation-hierarchies\";\nimport { getIdsFromChildrenTree } from \"../Utils.js\";\n\nimport type { Id64Arg, Id64Set, Id64String } from \"@itwin/core-bentley\";\nimport type { ClassGroupingNodeKey, InstancesNodeKey } from \"@itwin/presentation-hierarchies\";\nimport type { ECClassHierarchyInspector } from \"@itwin/presentation-shared\";\nimport type { ChildrenTree } from \"../Utils.js\";\n\ninterface FilteredTreeRootNode {\n children: Map<Id64String, FilteredTreeNode>;\n}\n\ninterface BaseFilteredTreeNode {\n id: string;\n children?: Map<Id64String, FilteredTreeNode>;\n isFilterTarget: boolean;\n}\n\ninterface GenericFilteredTreeNode extends BaseFilteredTreeNode {\n type: \"subject\" | \"model\";\n}\n\ninterface CategoryFilteredTreeNode extends BaseFilteredTreeNode {\n type: \"category\";\n modelId: Id64String;\n}\n\ninterface ElementFilteredTreeNode extends BaseFilteredTreeNode {\n type: \"element\";\n modelId: Id64String;\n categoryId: Id64String;\n}\n\ntype FilteredTreeNode = GenericFilteredTreeNode | CategoryFilteredTreeNode | ElementFilteredTreeNode;\n\ninterface GetElementsFromUnfilteredChildrenTreeProps {\n childrenTree: ChildrenTree;\n parentIdsPath: Array<Id64Arg>;\n}\n\n/** @internal */\nexport interface FilteredTree {\n getVisibilityChangeTargets(node: HierarchyNode & { key: ClassGroupingNodeKey | InstancesNodeKey }): VisibilityChangeTargets;\n getElementsFromUnfilteredChildrenTree(props: GetElementsFromUnfilteredChildrenTreeProps): Id64Set | undefined;\n}\n\nexport const SUBJECT_CLASS_NAME = \"BisCore.Subject\" as const;\nexport const MODEL_CLASS_NAME = \"BisCore.GeometricModel3d\" as const;\nexport const CATEGORY_CLASS_NAME = \"BisCore.SpatialCategory\" as const;\nexport const ELEMENT_CLASS_NAME = \"BisCore.GeometricElement3d\" as const;\n\ntype CategoryKey = `${Id64String}-${Id64String}`;\n\nfunction createCategoryKey(modelId: string, categoryId: string): CategoryKey {\n return `${modelId}-${categoryId}`;\n}\n\n/** @internal */\nexport function parseCategoryKey(key: CategoryKey) {\n const [modelId, categoryId] = key.split(\"-\");\n return { modelId, categoryId };\n}\n\n/** @internal */\nexport interface VisibilityChangeTargets {\n subjects?: Set<Id64String>;\n models?: Set<Id64String>;\n categories?: Set<CategoryKey>;\n elements?: Map<CategoryKey, Map<Id64String, { isFilterTarget: boolean }>>;\n}\n\n/** @internal */\nexport async function createFilteredTree(imodelAccess: ECClassHierarchyInspector, filteringPaths: HierarchyFilteringPath[]): Promise<FilteredTree> {\n const root: FilteredTreeRootNode = {\n children: new Map(),\n };\n\n for (const filteringPath of filteringPaths) {\n const normalizedPath = HierarchyFilteringPath.normalize(filteringPath).path;\n\n let parentNode: FilteredTreeRootNode | FilteredTreeNode = root;\n for (let i = 0; i < normalizedPath.length; i++) {\n if (\"type\" in parentNode && parentNode.isFilterTarget) {\n break;\n }\n\n const identifier = normalizedPath[i];\n if (!HierarchyNodeIdentifier.isInstanceNodeIdentifier(identifier)) {\n break;\n }\n\n const currentNode: FilteredTreeNode | undefined = parentNode.children?.get(identifier.id);\n if (currentNode !== undefined) {\n parentNode = currentNode;\n continue;\n }\n\n const type = await getType(imodelAccess, identifier.className);\n const newNode: FilteredTreeNode = createFilteredTreeNode({\n type,\n id: identifier.id,\n isFilterTarget: i === normalizedPath.length - 1,\n parent: parentNode as FilteredTreeNode,\n });\n (parentNode.children ??= new Map()).set(identifier.id, newNode);\n parentNode = newNode;\n }\n }\n\n return {\n getVisibilityChangeTargets: (node) => getVisibilityChangeTargets(root, node),\n getElementsFromUnfilteredChildrenTree: ({ childrenTree, parentIdsPath }) => getElementsFromUnfilteredChildrenTree({ parentIdsPath, root, childrenTree }),\n };\n}\n\n/**\n * Unfiltered tree can contain ids of models/categories/elements which are not present in the filtered tree.\n * This function retrieves only those ids which are either filter tree targets, or are their children (direct and indirect).\n */\nfunction getElementsFromUnfilteredChildrenTree(props: GetElementsFromUnfilteredChildrenTreeProps & { root: FilteredTreeRootNode }): Id64Set | undefined {\n if (props.childrenTree.size === 0 || props.parentIdsPath.length === 0) {\n return undefined;\n }\n\n let lookupParents: Array<FilteredTreeRootNode | FilteredTreeNode> = [props.root];\n for (const parentIds of props.parentIdsPath) {\n // When filtered node does not have children, it is filter target and because of this, all elements in the childrenTree are in the filtered tree\n if (lookupParents.every((parent) => !parent.children)) {\n return getIdsFromChildrenTree({ tree: props.childrenTree });\n }\n\n const parentNodes = findMatchingFilteredNodes(lookupParents, parentIds);\n if (parentNodes.length === 0) {\n return undefined;\n }\n lookupParents = parentNodes;\n }\n\n // We have unfiltered children tree and filtered nodes that are parents of first level nodes in unfiltered children tree.\n // We can start filtering unfiltered children tree based on filtered nodes.\n const result = getChildrenTreeIdsMatchingFilteredNodes({ tree: props.childrenTree, filteredNodes: lookupParents });\n return result.size > 0 ? result : undefined;\n}\n\nfunction getChildrenTreeIdsMatchingFilteredNodes({\n tree,\n filteredNodes,\n}: {\n tree: ChildrenTree;\n filteredNodes: Array<FilteredTreeNode | FilteredTreeRootNode>;\n}): Id64Set {\n const getIdsRecursively = (childrenTree: ChildrenTree, parentFilteredNodes: Array<FilteredTreeNode | FilteredTreeRootNode>): Id64Set => {\n // If one of the parent filtered nodes does not have children, it is filter target and because of this, all elements in the childrenTree are in the filtered tree.\n const hasParentFilterTarget = parentFilteredNodes.some((filteredNode) => \"isFilterTarget\" in filteredNode && filteredNode.isFilterTarget);\n if (hasParentFilterTarget) {\n return getIdsFromChildrenTree({ tree: childrenTree });\n }\n const result = new Set<Id64String>();\n childrenTree.forEach((entry, id) => {\n const nodes = findMatchingFilteredNodes(parentFilteredNodes, id);\n // If no filtered nodes match this id, skip it since it's not in the filtered tree.\n if (nodes.length === 0) {\n return;\n }\n // Id was found in filtered nodes children, add it to the result.\n result.add(id);\n if (entry.children) {\n // Continue recursively for children\n getIdsRecursively(entry.children, nodes).forEach((childId) => result.add(childId));\n }\n });\n return result;\n };\n\n return getIdsRecursively(tree, filteredNodes);\n}\n\nfunction getVisibilityChangeTargets(root: FilteredTreeRootNode, node: HierarchyNode & { key: ClassGroupingNodeKey | InstancesNodeKey }) {\n let lookupParents: Array<FilteredTreeRootNode | FilteredTreeNode> = [root];\n const changeTargets: VisibilityChangeTargets = {};\n\n // find the filtered parent nodes of the `node`\n for (const parentKey of node.parentKeys) {\n if (!HierarchyNodeKey.isInstances(parentKey)) {\n continue;\n }\n\n // tree node might be merged from multiple instances. As filtered tree stores only one instance per node, we need to find all matching nodes\n // and use them when checking for matching node in one level deeper.\n const parentNodes = findMatchingFilteredNodes(\n lookupParents,\n parentKey.instanceKeys.map((key) => key.id),\n );\n if (parentNodes.length === 0) {\n return changeTargets;\n }\n lookupParents = parentNodes;\n }\n const ids = HierarchyNode.isInstancesNode(node) ? node.key.instanceKeys.map(({ id }) => id) : node.groupedInstanceKeys.map(({ id }) => id);\n // find filtered nodes that match the `node`\n const filteredNodes = findMatchingFilteredNodes(lookupParents, ids);\n if (filteredNodes.length === 0) {\n return changeTargets;\n }\n\n filteredNodes.forEach((filteredNode) => collectVisibilityChangeTargets(changeTargets, filteredNode));\n return changeTargets;\n}\n\nfunction findMatchingFilteredNodes(lookupParents: Array<FilteredTreeRootNode | FilteredTreeNode>, ids: Id64Arg): Array<FilteredTreeNode> {\n return lookupParents.flatMap((lookup) => {\n const childrenArray = Array<FilteredTreeNode>();\n for (const id of Id64.iterable(ids)) {\n const node = lookup.children?.get(id);\n if (node) {\n childrenArray.push(node);\n }\n }\n return childrenArray;\n });\n}\n\nfunction collectVisibilityChangeTargets(changeTargets: VisibilityChangeTargets, node: FilteredTreeNode) {\n if (node.isFilterTarget) {\n addTarget(changeTargets, node);\n return;\n }\n\n if (node.type === \"element\") {\n // need to add parent ids as filter target will be an element\n addTarget(changeTargets, node);\n }\n\n if (!node.children) {\n return;\n }\n\n for (const child of node.children.values()) {\n collectVisibilityChangeTargets(changeTargets, child);\n }\n}\n\nfunction addTarget(filterTargets: VisibilityChangeTargets, node: FilteredTreeNode) {\n switch (node.type) {\n case \"subject\":\n (filterTargets.subjects ??= new Set()).add(node.id);\n return;\n case \"model\":\n (filterTargets.models ??= new Set()).add(node.id);\n return;\n case \"category\":\n (filterTargets.categories ??= new Set()).add(createCategoryKey(node.modelId, node.id));\n return;\n case \"element\":\n const categoryKey = createCategoryKey(node.modelId, node.categoryId);\n const elements = (filterTargets.elements ??= new Map()).get(categoryKey);\n if (elements) {\n elements.set(node.id, { isFilterTarget: node.isFilterTarget });\n } else {\n filterTargets.elements.set(categoryKey, new Map([[node.id, { isFilterTarget: node.isFilterTarget }]]));\n }\n }\n}\n\nfunction createFilteredTreeNode({\n type,\n id,\n isFilterTarget,\n parent,\n}: {\n type: FilteredTreeNode[\"type\"];\n id: string;\n isFilterTarget: boolean;\n parent: FilteredTreeNode | FilteredTreeRootNode;\n}): FilteredTreeNode {\n if (type === \"subject\" || type === \"model\") {\n return {\n id,\n isFilterTarget,\n type,\n };\n }\n\n if (type === \"category\") {\n assert(\"type\" in parent && parent.type === \"model\");\n return {\n id,\n isFilterTarget,\n type,\n modelId: parent.id,\n };\n }\n\n if (\"type\" in parent && parent.type === \"category\") {\n return {\n id,\n isFilterTarget,\n type,\n modelId: parent.modelId,\n categoryId: parent.id,\n };\n }\n\n if (\"type\" in parent && parent.type === \"element\") {\n return {\n id,\n isFilterTarget,\n type,\n modelId: parent.modelId,\n categoryId: parent.categoryId,\n };\n }\n\n throw new Error(\"Invalid parent node type\");\n}\n\nasync function getType(hierarchyChecker: ECClassHierarchyInspector, className: string) {\n if (await hierarchyChecker.classDerivesFrom(className, SUBJECT_CLASS_NAME)) {\n return \"subject\";\n }\n if (await hierarchyChecker.classDerivesFrom(className, MODEL_CLASS_NAME)) {\n return \"model\";\n }\n if (await hierarchyChecker.classDerivesFrom(className, CATEGORY_CLASS_NAME)) {\n return \"category\";\n }\n return \"element\";\n}\n"]}
|
package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { Observable } from "rxjs";
|
|
|
2
2
|
import type { GuidString, Id64Arg, Id64Array, Id64Set, Id64String } from "@itwin/core-bentley";
|
|
3
3
|
import type { HierarchyNodeIdentifiersPath, LimitingECSqlQueryExecutor } from "@itwin/presentation-hierarchies";
|
|
4
4
|
import type { ModelsTreeDefinition } from "../ModelsTreeDefinition.js";
|
|
5
|
+
import type { ChildrenTree } from "../Utils.js";
|
|
5
6
|
type ModelsTreeHierarchyConfiguration = ConstructorParameters<typeof ModelsTreeDefinition>[0]["hierarchyConfig"];
|
|
6
7
|
/** @internal */
|
|
7
8
|
export declare class ModelsTreeIdsCache implements Disposable {
|
|
@@ -10,6 +11,20 @@ export declare class ModelsTreeIdsCache implements Disposable {
|
|
|
10
11
|
[Symbol.dispose](): void;
|
|
11
12
|
private querySubjects;
|
|
12
13
|
private queryModels;
|
|
14
|
+
private queryChildren;
|
|
15
|
+
private getChildrenTreeFromMap;
|
|
16
|
+
private getChildrenCountMap;
|
|
17
|
+
/**
|
|
18
|
+
* Populates #childrenLoadingMap with promises. When these promises resolve, they will populate #childrenMap with values and delete entries from #childrenLoadingMap.
|
|
19
|
+
*/
|
|
20
|
+
private createChildrenLoadingMapEntries;
|
|
21
|
+
private createChildrenMapEntries;
|
|
22
|
+
getChildrenTree({ elementIds }: {
|
|
23
|
+
elementIds: Id64Arg;
|
|
24
|
+
}): Observable<ChildrenTree>;
|
|
25
|
+
getAllChildrenCount({ elementIds }: {
|
|
26
|
+
elementIds: Id64Arg;
|
|
27
|
+
}): Observable<Map<Id64String, number>>;
|
|
13
28
|
private getSubjectInfos;
|
|
14
29
|
/** Returns ECInstanceIDs of Subjects that either have direct Model or at least one child Subject with a Model. */
|
|
15
30
|
getParentSubjectIds(): Observable<Id64Array>;
|
package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.js
CHANGED
|
@@ -8,7 +8,9 @@ exports.ModelsTreeIdsCache = void 0;
|
|
|
8
8
|
const rxjs_1 = require("rxjs");
|
|
9
9
|
const core_bentley_1 = require("@itwin/core-bentley");
|
|
10
10
|
const core_common_1 = require("@itwin/core-common");
|
|
11
|
-
const Utils_js_1 = require("../../common/Utils.js");
|
|
11
|
+
const Utils_js_1 = require("../../common/internal/Utils.js");
|
|
12
|
+
const Utils_js_2 = require("../../common/Utils.js");
|
|
13
|
+
const Utils_js_3 = require("../Utils.js");
|
|
12
14
|
/** @internal */
|
|
13
15
|
class ModelsTreeIdsCache {
|
|
14
16
|
#categoryElementCounts;
|
|
@@ -21,6 +23,9 @@ class ModelsTreeIdsCache {
|
|
|
21
23
|
#categoryKeyPaths;
|
|
22
24
|
#queryExecutor;
|
|
23
25
|
#hierarchyConfig;
|
|
26
|
+
#childrenMap;
|
|
27
|
+
/** Stores element ids which have children query scheduled to execute. */
|
|
28
|
+
#childrenLoadingMap;
|
|
24
29
|
#componentId;
|
|
25
30
|
#componentName;
|
|
26
31
|
constructor(queryExecutor, hierarchyConfig, componentId) {
|
|
@@ -30,6 +35,8 @@ class ModelsTreeIdsCache {
|
|
|
30
35
|
this.#modelKeyPaths = new Map();
|
|
31
36
|
this.#subjectKeyPaths = new Map();
|
|
32
37
|
this.#categoryKeyPaths = new Map();
|
|
38
|
+
this.#childrenMap = new Map();
|
|
39
|
+
this.#childrenLoadingMap = new Map();
|
|
33
40
|
this.#componentId = componentId ?? core_bentley_1.Guid.createValue();
|
|
34
41
|
this.#componentName = "ModelsTreeIdsCache";
|
|
35
42
|
}
|
|
@@ -78,6 +85,130 @@ class ModelsTreeIdsCache {
|
|
|
78
85
|
return { id: row.id, parentId: row.parentId };
|
|
79
86
|
}));
|
|
80
87
|
}
|
|
88
|
+
queryChildren({ elementIds }) {
|
|
89
|
+
if (elementIds.length === 0) {
|
|
90
|
+
return rxjs_1.EMPTY;
|
|
91
|
+
}
|
|
92
|
+
return (0, rxjs_1.defer)(() => {
|
|
93
|
+
const ctes = [
|
|
94
|
+
`
|
|
95
|
+
ElementChildren(id, parentId) AS (
|
|
96
|
+
SELECT ECInstanceId id, Parent.Id parentId
|
|
97
|
+
FROM ${this.#hierarchyConfig.elementClassSpecification}
|
|
98
|
+
WHERE Parent.Id IN (${elementIds.join(", ")})
|
|
99
|
+
|
|
100
|
+
UNION ALL
|
|
101
|
+
|
|
102
|
+
SELECT c.ECInstanceId id, c.Parent.Id
|
|
103
|
+
FROM ${this.#hierarchyConfig.elementClassSpecification} c
|
|
104
|
+
JOIN ElementChildren p ON c.Parent.Id = p.id
|
|
105
|
+
)
|
|
106
|
+
`,
|
|
107
|
+
];
|
|
108
|
+
const ecsql = `
|
|
109
|
+
SELECT id, parentId
|
|
110
|
+
FROM ElementChildren
|
|
111
|
+
`;
|
|
112
|
+
return this.#queryExecutor.createQueryReader({ ecsql, ctes }, { rowFormat: "ECSqlPropertyNames", limit: "unbounded", restartToken: `${this.#componentName}/${this.#componentId}/children/${core_bentley_1.Guid.createValue()}` });
|
|
113
|
+
}).pipe((0, rxjs_1.map)((row) => {
|
|
114
|
+
return { id: row.id, parentId: row.parentId };
|
|
115
|
+
}));
|
|
116
|
+
}
|
|
117
|
+
getChildrenTreeFromMap({ elementIds }) {
|
|
118
|
+
const result = new Map();
|
|
119
|
+
if (core_bentley_1.Id64.sizeOf(elementIds) === 0 || this.#childrenMap.size === 0) {
|
|
120
|
+
return result;
|
|
121
|
+
}
|
|
122
|
+
for (const elementId of core_bentley_1.Id64.iterable(elementIds)) {
|
|
123
|
+
const entry = this.#childrenMap.get(elementId);
|
|
124
|
+
if (!entry?.children) {
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
const elementChildrenTree = new Map();
|
|
128
|
+
result.set(elementId, { children: elementChildrenTree });
|
|
129
|
+
entry.children.forEach((childId) => {
|
|
130
|
+
const childrenTreeOfChild = this.getChildrenTreeFromMap({ elementIds: childId });
|
|
131
|
+
// Need to add children tree created from childId. This tree includes childId as root element
|
|
132
|
+
// If child does not have children, children tree won't be created. Need to add childId with undefined children
|
|
133
|
+
elementChildrenTree.set(childId, { children: childrenTreeOfChild.size > 0 ? childrenTreeOfChild : undefined });
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
return result;
|
|
137
|
+
}
|
|
138
|
+
getChildrenCountMap({ elementIds }) {
|
|
139
|
+
const result = new Map();
|
|
140
|
+
for (const elementId of core_bentley_1.Id64.iterable(elementIds)) {
|
|
141
|
+
const entry = this.#childrenMap.get(elementId);
|
|
142
|
+
if (entry?.children) {
|
|
143
|
+
let totalChildrenCount = entry.children.length;
|
|
144
|
+
this.getChildrenCountMap({ elementIds: entry.children }).forEach((childrenOfChildCount) => (totalChildrenCount += childrenOfChildCount));
|
|
145
|
+
result.set(elementId, totalChildrenCount);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return result;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Populates #childrenLoadingMap with promises. When these promises resolve, they will populate #childrenMap with values and delete entries from #childrenLoadingMap.
|
|
152
|
+
*/
|
|
153
|
+
createChildrenLoadingMapEntries({ elementsToQuery }) {
|
|
154
|
+
const getElementsToQueryPromise = async (batchedElementsToQuery) => (0, rxjs_1.firstValueFrom)(this.queryChildren({ elementIds: batchedElementsToQuery }).pipe(
|
|
155
|
+
// Want to have void at the end instead of void[], so using reduce
|
|
156
|
+
(0, rxjs_1.reduce)((acc, { parentId, id }) => {
|
|
157
|
+
let entry = this.#childrenMap.get(parentId);
|
|
158
|
+
if (!entry) {
|
|
159
|
+
entry = { children: [] };
|
|
160
|
+
this.#childrenMap.set(parentId, entry);
|
|
161
|
+
}
|
|
162
|
+
if (!entry.children) {
|
|
163
|
+
entry.children = [];
|
|
164
|
+
}
|
|
165
|
+
// Add child to parent's entry and add child to children map
|
|
166
|
+
entry.children.push(id);
|
|
167
|
+
if (!this.#childrenMap.has(id)) {
|
|
168
|
+
this.#childrenMap.set(id, { children: undefined });
|
|
169
|
+
}
|
|
170
|
+
return acc;
|
|
171
|
+
}, (() => { })()), (0, rxjs_1.tap)({ complete: () => batchedElementsToQuery.forEach((elementId) => this.#childrenLoadingMap.delete(elementId)) }), (0, rxjs_1.defaultIfEmpty)((() => { })())));
|
|
172
|
+
const maximumBatchSize = 1000;
|
|
173
|
+
const totalSize = elementsToQuery.length;
|
|
174
|
+
const optimalBatchSize = (0, Utils_js_3.getOptimalBatchSize)({ totalSize, maximumBatchSize });
|
|
175
|
+
const loadingMapEntries = new Array();
|
|
176
|
+
// Don't want to slice if its not necessary
|
|
177
|
+
if (totalSize <= maximumBatchSize) {
|
|
178
|
+
loadingMapEntries.push(getElementsToQueryPromise(elementsToQuery));
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
for (let i = 0; i < elementsToQuery.length; i += optimalBatchSize) {
|
|
182
|
+
loadingMapEntries.push(getElementsToQueryPromise(elementsToQuery.slice(i, i + optimalBatchSize)));
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
elementsToQuery.forEach((elementId, index) => this.#childrenLoadingMap.set(elementId, loadingMapEntries[Math.floor(index / optimalBatchSize)]));
|
|
186
|
+
return { loadingMapEntries: Promise.all(loadingMapEntries).then(() => { }) };
|
|
187
|
+
}
|
|
188
|
+
createChildrenMapEntries({ elementIds }) {
|
|
189
|
+
return (0, rxjs_1.from)(core_bentley_1.Id64.iterable(elementIds)).pipe((0, rxjs_1.reduce)((acc, elementId) => {
|
|
190
|
+
if (this.#childrenMap.has(elementId)) {
|
|
191
|
+
return acc;
|
|
192
|
+
}
|
|
193
|
+
const loadingPromise = this.#childrenLoadingMap.get(elementId);
|
|
194
|
+
if (loadingPromise) {
|
|
195
|
+
acc.existingPromises.push(loadingPromise);
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
acc.elementsToQuery.push(elementId);
|
|
199
|
+
}
|
|
200
|
+
return acc;
|
|
201
|
+
}, { existingPromises: new Array(), elementsToQuery: new Array() }), (0, rxjs_1.mergeMap)(async ({ elementsToQuery, existingPromises }) => {
|
|
202
|
+
existingPromises.push(this.createChildrenLoadingMapEntries({ elementsToQuery }).loadingMapEntries);
|
|
203
|
+
return Promise.all(existingPromises);
|
|
204
|
+
}));
|
|
205
|
+
}
|
|
206
|
+
getChildrenTree({ elementIds }) {
|
|
207
|
+
return this.createChildrenMapEntries({ elementIds }).pipe((0, rxjs_1.map)(() => this.getChildrenTreeFromMap({ elementIds })));
|
|
208
|
+
}
|
|
209
|
+
getAllChildrenCount({ elementIds }) {
|
|
210
|
+
return this.createChildrenMapEntries({ elementIds }).pipe((0, rxjs_1.map)(() => this.getChildrenCountMap({ elementIds })));
|
|
211
|
+
}
|
|
81
212
|
getSubjectInfos() {
|
|
82
213
|
this.#subjectInfos ??= (0, rxjs_1.forkJoin)({
|
|
83
214
|
subjectInfos: this.querySubjects().pipe((0, rxjs_1.reduce)((acc, subject) => {
|
|
@@ -103,7 +234,7 @@ class ModelsTreeIdsCache {
|
|
|
103
234
|
return subjectInfos;
|
|
104
235
|
})),
|
|
105
236
|
targetPartitionSubjects: this.queryModels().pipe((0, rxjs_1.reduce)((acc, model) => {
|
|
106
|
-
(0,
|
|
237
|
+
(0, Utils_js_2.pushToMap)(acc, model.id, model.parentId);
|
|
107
238
|
return acc;
|
|
108
239
|
}, new Map())),
|
|
109
240
|
}).pipe((0, rxjs_1.map)(({ subjectInfos, targetPartitionSubjects }) => {
|
|
@@ -358,7 +489,7 @@ class ModelsTreeIdsCache {
|
|
|
358
489
|
rowFormat: "ECSqlPropertyNames",
|
|
359
490
|
limit: "unbounded",
|
|
360
491
|
restartToken: `${this.#componentName}/${this.#componentId}/category-element-counts/${core_bentley_1.Guid.createValue()}`,
|
|
361
|
-
}))), (0, rxjs_1.reduce)(({ acc, createKey }, row) => {
|
|
492
|
+
}))), (0, Utils_js_1.releaseMainThreadOnItemsCount)(500), (0, rxjs_1.reduce)(({ acc, createKey }, row) => {
|
|
362
493
|
acc.set(createKey({ modelId: row.modelId, categoryId: row.categoryId }), {
|
|
363
494
|
modelId: row.modelId,
|
|
364
495
|
categoryId: row.categoryId,
|