From 69b0165f0dfd4ad30ca93424567522fc2f45b3fd Mon Sep 17 00:00:00 2001 From: Savelii Novikov Date: Wed, 12 Jul 2023 17:26:12 +0200 Subject: [PATCH] Styling extracted as a hook --- .../Reveal3DResources/Reveal3DResources.tsx | 77 ++------------- react-components/src/hooks/types.ts | 33 ++++--- .../src/hooks/useCalculateModelsStyling.tsx | 95 +++++++++++++++++++ react-components/src/utilities/FdmSDK.ts | 14 --- react-components/src/utilities/constants.ts | 5 +- 5 files changed, 123 insertions(+), 101 deletions(-) create mode 100644 react-components/src/hooks/useCalculateModelsStyling.tsx diff --git a/react-components/src/components/Reveal3DResources/Reveal3DResources.tsx b/react-components/src/components/Reveal3DResources/Reveal3DResources.tsx index 86124e11a5a..30a1b329f07 100644 --- a/react-components/src/components/Reveal3DResources/Reveal3DResources.tsx +++ b/react-components/src/components/Reveal3DResources/Reveal3DResources.tsx @@ -1,18 +1,14 @@ /*! * Copyright 2023 Cognite AS */ -import { useRef, type ReactElement, useContext, useState, useEffect, useMemo } from 'react'; +import { useRef, type ReactElement, useContext, useState, useEffect } from 'react'; import { type NodeAppearance, type Cognite3DViewer, type PointCloudAppearance } from '@cognite/reveal'; import { ModelsLoadingStateContext } from './ModelsLoadingContext'; -import { - CadModelContainer, - type CadModelStyling, - type NodeStylingGroup -} from '../CadModelContainer/CadModelContainer'; +import { CadModelContainer, type CadModelStyling } from '../CadModelContainer/CadModelContainer'; import { PointCloudContainer, type PointCloudModelStyling @@ -26,8 +22,8 @@ import { type AddResourceOptions } from './types'; import { type CogniteExternalId } from '@cognite/sdk'; -import { useFdmAssetMappings } from '../../hooks/useFdmAssetMappings'; import { type FdmAssetMappingsConfig } from '../../hooks/types'; +import { useCalculateModelsStyling } from '../../hooks/useCalculateModelsStyling'; export type FdmAssetStylingGroup = { fdmAssetExternalIds: CogniteExternalId[]; @@ -59,76 +55,15 @@ export const Reveal3DResources = ({ const viewer = useReveal(); const numModelsLoaded = useRef(0); - const stylingExternalIds = useMemo( - () => styling?.groups?.flatMap((group) => group.fdmAssetExternalIds) ?? [], - [styling] - ); - - const { data: mappings } = useFdmAssetMappings(stylingExternalIds, fdmAssetMappingConfig); - useEffect(() => { getTypedModels(resources, viewer).then(setReveal3DModels).catch(console.error); }, [resources, viewer]); - useEffect(() => { - if (styling === undefined || reveal3DModels === undefined) return; - - const modelsStyling = reveal3DModels.map((model) => { - let modelStyling: PointCloudModelStyling | CadModelStyling; - - switch (model.type) { - case 'cad': { - const modelNodeMappings = mappings?.find( - (mapping) => - mapping.modelId === model.modelId && mapping.revisionId === model.revisionId - ); - - const newStylingGroups: NodeStylingGroup[] | undefined = - styling.groups !== null ? [] : undefined; - - styling.groups?.forEach((group) => { - const connectedExternalIds = group.fdmAssetExternalIds.filter((externalId) => - modelNodeMappings?.mappings.some( - (modelNodeMapping) => modelNodeMapping.externalId === externalId - ) - ); - - const newGroup: NodeStylingGroup = { - style: group.style.cad, - nodeIds: connectedExternalIds.map((externalId) => { - const mapping = modelNodeMappings?.mappings.find( - (mapping) => mapping.externalId === externalId - ); - return mapping?.nodeId ?? -1; - }) - }; - - if (connectedExternalIds.length > 0) newStylingGroups?.push(newGroup); - }); - - modelStyling = { - defaultStyle: styling.defaultStyle?.cad, - groups: newStylingGroups - }; - break; - } - case 'pointcloud': { - modelStyling = { - defaultStyle: styling.defaultStyle?.pointcloud - }; - break; - } - default: { - modelStyling = {}; - console.warn(`Unknown model type: ${model.type}`); - break; - } - } - return modelStyling; - }); + const modelsStyling = useCalculateModelsStyling(reveal3DModels, styling, fdmAssetMappingConfig); + useEffect(() => { setReveal3DModelsStyling(modelsStyling); - }, [mappings, styling, reveal3DModels, mappings]); + }, [modelsStyling]); const image360CollectionAddOptions = resources.filter( (resource): resource is AddImageCollection360Options => diff --git a/react-components/src/hooks/types.ts b/react-components/src/hooks/types.ts index a416fc55eb5..feb77073956 100644 --- a/react-components/src/hooks/types.ts +++ b/react-components/src/hooks/types.ts @@ -1,18 +1,21 @@ +/*! + * Copyright 2023 Cognite AS + */ import { type Source } from '../utilities/FdmSDK'; export type FdmAssetMappingsConfig = { - /** - * 3D Data model source - */ - source: Source; - /* - * FDM space where model assets are located - */ - assetFdmSpace: string; - }; - - export type ThreeDModelMappings = { - modelId: number; - revisionId: number; - mappings: Array<{ nodeId: number; externalId: string }>; - }; \ No newline at end of file + /** + * 3D Data model source + */ + source: Source; + /* + * FDM space where model assets are located + */ + assetFdmSpace: string; +}; + +export type ThreeDModelMappings = { + modelId: number; + revisionId: number; + mappings: Array<{ nodeId: number; externalId: string }>; +}; diff --git a/react-components/src/hooks/useCalculateModelsStyling.tsx b/react-components/src/hooks/useCalculateModelsStyling.tsx new file mode 100644 index 00000000000..9fd61fc668d --- /dev/null +++ b/react-components/src/hooks/useCalculateModelsStyling.tsx @@ -0,0 +1,95 @@ +/*! + * Copyright 2023 Cognite AS + */ +import { useMemo } from 'react'; +import { type FdmAssetMappingsConfig } from './types'; +import { type Reveal3DResourcesStyling } from '../components/Reveal3DResources/Reveal3DResources'; +import { type TypedReveal3DModel } from '../components/Reveal3DResources/types'; +import { useFdmAssetMappings } from './useFdmAssetMappings'; +import { type PointCloudModelStyling } from '../components/PointCloudContainer/PointCloudContainer'; +import { + type CadModelStyling, + type NodeStylingGroup +} from '../components/CadModelContainer/CadModelContainer'; + +/** + * Calculates the styling for the models based on the styling configuration and the mappings. + * @param models Models to calculate styling for. + * @param styling Styling configuration. + * @param fdmAssetMappingConfig Configuration for the FDM asset mappings. + * @returns + */ +export const useCalculateModelsStyling = ( + models?: TypedReveal3DModel[], + styling?: Reveal3DResourcesStyling, + fdmAssetMappingConfig?: FdmAssetMappingsConfig +): Array => { + const stylingExternalIds = useMemo( + () => styling?.groups?.flatMap((group) => group.fdmAssetExternalIds) ?? [], + [styling] + ); + + const { data: mappings } = useFdmAssetMappings(stylingExternalIds, fdmAssetMappingConfig); + + const modelsStyling = useMemo(() => { + if (styling === undefined || models === undefined) return []; + + const internalModelsStyling = models.map((model) => { + let modelStyling: PointCloudModelStyling | CadModelStyling; + + switch (model.type) { + case 'cad': { + const modelNodeMappings = mappings?.find( + (mapping) => + mapping.modelId === model.modelId && mapping.revisionId === model.revisionId + ); + + const newStylingGroups: NodeStylingGroup[] | undefined = + styling.groups !== null ? [] : undefined; + + styling.groups?.forEach((group) => { + const connectedExternalIds = group.fdmAssetExternalIds.filter((externalId) => + modelNodeMappings?.mappings.some( + (modelNodeMapping) => modelNodeMapping.externalId === externalId + ) + ); + + const newGroup: NodeStylingGroup = { + style: group.style.cad, + nodeIds: connectedExternalIds.map((externalId) => { + const mapping = modelNodeMappings?.mappings.find( + (mapping) => mapping.externalId === externalId + ); + return mapping?.nodeId ?? -1; + }) + }; + + if (connectedExternalIds.length > 0) newStylingGroups?.push(newGroup); + }); + + modelStyling = { + defaultStyle: styling.defaultStyle?.cad, + groups: newStylingGroups + }; + break; + } + case 'pointcloud': { + modelStyling = { + defaultStyle: styling.defaultStyle?.pointcloud + }; + break; + } + default: { + modelStyling = {}; + console.warn(`Unknown model type: ${model.type}`); + break; + } + } + return modelStyling; + }); + + return internalModelsStyling; + }, [mappings, styling, models, mappings]); + + return modelsStyling; +}; diff --git a/react-components/src/utilities/FdmSDK.ts b/react-components/src/utilities/FdmSDK.ts index 44197ad3d89..edfd866b161 100644 --- a/react-components/src/utilities/FdmSDK.ts +++ b/react-components/src/utilities/FdmSDK.ts @@ -41,20 +41,6 @@ export class FdmSDK { this._sdk = sdk; } - public async getInstancesByExternalIds>( - items: Item[], - source: Source - ): Promise { - const result = await this._sdk.post(this._byIdsEndpoint, { - data: { items, sources: [{ source }] } - }); - - if (result.status === 200) { - return result.data.items; - } - throw new Error(`Failed to fetch instances. Status: ${result.status}`); - } - public async filterInstances>( filter: any, instanceType: InstanceType, diff --git a/react-components/src/utilities/constants.ts b/react-components/src/utilities/constants.ts index 2ce263bd7a9..142f2605c02 100644 --- a/react-components/src/utilities/constants.ts +++ b/react-components/src/utilities/constants.ts @@ -1 +1,4 @@ -export const DEFAULT_QUERY_STALE_TIME = 1000 * 60 * 10 ; // 10 minutes \ No newline at end of file +/*! + * Copyright 2023 Cognite AS + */ +export const DEFAULT_QUERY_STALE_TIME = 1000 * 60 * 10; // 10 minutes