diff --git a/react-components/src/components/Image360CollectionContainer/Image360CollectionContainer.tsx b/react-components/src/components/Image360CollectionContainer/Image360CollectionContainer.tsx index 21177fdf543..b327d685d18 100644 --- a/react-components/src/components/Image360CollectionContainer/Image360CollectionContainer.tsx +++ b/react-components/src/components/Image360CollectionContainer/Image360CollectionContainer.tsx @@ -38,7 +38,11 @@ export function Image360CollectionContainer({ return collection; } - return await viewer.add360ImageSet('events', { site_id: siteId }); + return await viewer.add360ImageSet( + 'events', + { site_id: siteId }, + { preMultipliedRotation: false } + ); } } diff --git a/react-components/src/components/Image360Details/Image360Details.tsx b/react-components/src/components/Image360Details/Image360Details.tsx new file mode 100644 index 00000000000..e26bd7edd33 --- /dev/null +++ b/react-components/src/components/Image360Details/Image360Details.tsx @@ -0,0 +1,89 @@ +/*! + * Copyright 2023 Cognite AS + */ + +import { useState, type ReactElement, useCallback, useEffect } from 'react'; +import styled from 'styled-components'; +import { Image360HistoricalDetails } from '../Image360HistoricalDetails/Image360HistoricalDetails'; +import { useReveal } from '../..'; +import { type Image360 } from '@cognite/reveal'; +import { Button } from '@cognite/cogs.js'; + +export function Image360Details(): ReactElement { + const viewer = useReveal(); + const [enteredEntity, setEnteredEntity] = useState(); + const [is360HistoricalPanelExpanded, setIs360HistoricalPanelExpanded] = useState(false); + const handleExpand = useCallback((isExpanded: boolean) => { + setIs360HistoricalPanelExpanded(isExpanded); + }, []); + + const clearEnteredImage360 = (): void => { + setEnteredEntity(undefined); + }; + + const exitImage360Image = (): void => { + viewer.exit360Image(); + }; + + const collections = viewer.get360ImageCollections(); + + useEffect(() => { + collections.forEach((collection) => { + collection.on('image360Entered', setEnteredEntity); + collection.on('image360Exited', clearEnteredImage360); + }); + return () => { + collections.forEach((collection) => { + collection.off('image360Entered', setEnteredEntity); + collection.off('image360Exited', clearEnteredImage360); + }); + }; + }, [viewer, collections]); + + return ( + <> + {enteredEntity !== undefined && ( + <> + + + + + + + + )} + + ); +} + +const StyledExitButton = styled(Button)` + border-radius: 8px; +`; + +const ExitButtonContainer = styled.div` + position: absolute; + right: 20px; + top: 20px; + background-color: #ffffff; + height: 36px; + width: 36px; + border-radius: 8px; + outline: none; +`; + +const Image360HistoricalPanel = styled.div<{ isExpanded: boolean }>` + position: absolute; + bottom: ${({ isExpanded }) => (isExpanded ? '0px' : '40px')}; + display: flex; + flex-direction: column; + height: fit-content; + width: fit-content; + max-width: 100%; + min-width: fill-available; + transition: transform 0.25s ease-in-out; + transform: ${({ isExpanded }) => (isExpanded ? 'translateY(0)' : 'translateY(100%)')}; +`; diff --git a/react-components/src/index.ts b/react-components/src/index.ts index 3e5f19e7a89..048b6ea1e6b 100644 --- a/react-components/src/index.ts +++ b/react-components/src/index.ts @@ -10,6 +10,7 @@ export { PointCloudContainer } from './components/PointCloudContainer/PointCloud export { CadModelContainer } from './components/CadModelContainer/CadModelContainer'; export { Image360CollectionContainer } from './components/Image360CollectionContainer/Image360CollectionContainer'; export { Image360HistoricalDetails } from './components/Image360HistoricalDetails/Image360HistoricalDetails'; +export { Image360Details } from './components/Image360Details/Image360Details'; export { ViewerAnchor } from './components/ViewerAnchor/ViewerAnchor'; export { RevealToolbar } from './components/RevealToolbar/RevealToolbar'; export { RevealKeepAlive } from './components/RevealKeepAlive/RevealKeepAlive'; diff --git a/react-components/stories/Image360Details.stories.tsx b/react-components/stories/Image360Details.stories.tsx new file mode 100644 index 00000000000..a7ffa9a45fe --- /dev/null +++ b/react-components/stories/Image360Details.stories.tsx @@ -0,0 +1,36 @@ +/*! + * Copyright 2023 Cognite AS + */ +import type { Meta, StoryObj } from '@storybook/react'; +import { Image360CollectionContainer, Image360Details, RevealContainer } from '../src'; +import { createSdkByUrlToken } from './utilities/createSdkByUrlToken'; +import { Color } from 'three'; +import { useState } from 'react'; + +const meta = { + title: 'Example/Image360Details', + component: Image360Details, + tags: ['autodocs'] +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +const sdk = createSdkByUrlToken(); + +export const Main: Story = { + render: () => { + const [loading, setLoading] = useState(true); + return ( + + { + setLoading(false); + }} + /> + {!loading && } + + ); + } +}; diff --git a/react-components/stories/Image360HistoricalDetails.stories.ts b/react-components/stories/Image360HistoricalDetails.stories.ts deleted file mode 100644 index e620e035740..00000000000 --- a/react-components/stories/Image360HistoricalDetails.stories.ts +++ /dev/null @@ -1,69 +0,0 @@ -/*! - * Copyright 2023 Cognite AS - */ -import type { Meta, StoryObj } from '@storybook/react'; -import { Image360HistoricalDetails } from '../src'; -import { It, Mock } from 'moq.ts'; -import { type Cognite3DViewer, type Image360, type Image360Revision } from '@cognite/reveal'; - -const meta = { - title: 'Example/Image360HistoricalDetails', - component: Image360HistoricalDetails, - tags: ['autodocs'] -} satisfies Meta; - -export default meta; -type Story = StoryObj; - -const revisionMocks = [ - new Mock() - .setup(async (p) => await p.getPreviewThumbnailUrl()) - .returns(Promise.resolve(undefined)) - .setup((p) => p.date) - .returns(undefined) - .object(), - new Mock() - .setup(async (p) => await p.getPreviewThumbnailUrl()) - .returns(Promise.resolve(undefined)) - .setup((p) => p.date) - .returns(new Date('2024.01.13 13:23')) - .object(), - new Mock() - .setup(async (p) => await p.getPreviewThumbnailUrl()) - .returns(Promise.resolve(undefined)) - .setup((p) => p.date) - .returns(new Date('2025.01.14 13:23')) - .object(), - new Mock() - .setup(async (p) => await p.getPreviewThumbnailUrl()) - .returns(Promise.resolve(undefined)) - .setup((p) => p.date) - .returns(new Date('2026.01.15 15:23')) - .object(), - new Mock() - .setup(async (p) => await p.getPreviewThumbnailUrl()) - .returns(Promise.resolve(undefined)) - .setup((p) => p.date) - .returns(new Date('2024.01.16 23:23')) - .object() -]; - -const viewerMock = new Mock() - .setup(async (p) => { - await p.enter360Image(It.IsAny()); - }) - .returns(Promise.resolve()); -const image360Mock = new Mock() - .setup((p) => p.getRevisions()) - .returns(revisionMocks) - .setup((p) => p.id) - .returns('Station-Id') - .setup((p) => p.label) - .returns('Station Name'); - -export const Main: Story = { - args: { - viewer: viewerMock.object(), - image360Entity: image360Mock.object() - } -};