init
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
import { useRef, useCallback, type ReactNode, useMemo } from 'react';
|
||||
import type { InstanceStylingGroup } from '../types';
|
||||
import {
|
||||
InstanceStylingContext,
|
||||
type InstanceStylingController,
|
||||
} from './instanceStylingContext';
|
||||
|
||||
interface InstanceStylingProviderProps {
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provider for centralized instance styling management.
|
||||
* Components can register/unregister styling groups and listen for changes.
|
||||
*/
|
||||
export function InstanceStylingProvider({
|
||||
children,
|
||||
}: InstanceStylingProviderProps) {
|
||||
const stylingGroupsRef = useRef<Map<string, InstanceStylingGroup>>(new Map());
|
||||
const listenersRef = useRef<Set<() => void>>(new Set());
|
||||
const nextIdRef = useRef(0);
|
||||
|
||||
const getStylingGroups = useCallback(() => {
|
||||
return Array.from(stylingGroupsRef.current.values());
|
||||
}, []);
|
||||
|
||||
const addEventListener = useCallback((callback: () => void): void => {
|
||||
listenersRef.current.add(callback);
|
||||
// Call once immediately to initialize with current state
|
||||
callback();
|
||||
}, []);
|
||||
|
||||
const removeEventListener = useCallback((callback: () => void): void => {
|
||||
listenersRef.current.delete(callback);
|
||||
}, []);
|
||||
|
||||
const notifyListeners = useCallback(() => {
|
||||
listenersRef.current.forEach((listener) => listener());
|
||||
}, []);
|
||||
|
||||
const registerStylingGroup = useCallback(
|
||||
(group: InstanceStylingGroup): string => {
|
||||
const id = `styling-group-${nextIdRef.current++}`;
|
||||
stylingGroupsRef.current.set(id, group);
|
||||
notifyListeners();
|
||||
return id;
|
||||
},
|
||||
[notifyListeners]
|
||||
);
|
||||
|
||||
const unregisterStylingGroup = useCallback(
|
||||
(id: string): void => {
|
||||
const deleted = stylingGroupsRef.current.delete(id);
|
||||
if (deleted) {
|
||||
notifyListeners();
|
||||
}
|
||||
},
|
||||
[notifyListeners]
|
||||
);
|
||||
|
||||
const controller: InstanceStylingController = useMemo(
|
||||
() => ({
|
||||
getStylingGroups,
|
||||
addEventListener,
|
||||
removeEventListener,
|
||||
registerStylingGroup,
|
||||
unregisterStylingGroup,
|
||||
}),
|
||||
[
|
||||
getStylingGroups,
|
||||
addEventListener,
|
||||
removeEventListener,
|
||||
registerStylingGroup,
|
||||
unregisterStylingGroup,
|
||||
]
|
||||
);
|
||||
|
||||
return (
|
||||
<InstanceStylingContext.Provider value={controller}>
|
||||
{children}
|
||||
</InstanceStylingContext.Provider>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { Cognite3DViewer } from '@cognite/reveal';
|
||||
import type { RevealContextProps } from '../types';
|
||||
import { RevealContext } from './revealContext';
|
||||
import { InstanceStylingProvider } from './InstanceStylingProvider';
|
||||
import { useOptionalRevealKeepAlive } from '../components/RevealKeepAlive';
|
||||
import { RevealSettingsController } from '../settings/RevealSettingsController';
|
||||
|
||||
export function RevealProvider({
|
||||
children,
|
||||
sdk,
|
||||
color,
|
||||
viewerOptions,
|
||||
}: RevealContextProps) {
|
||||
const keepAlive = useOptionalRevealKeepAlive();
|
||||
const keepAliveRef = useRef(keepAlive);
|
||||
keepAliveRef.current = keepAlive;
|
||||
|
||||
const [viewerData] = useState(() => {
|
||||
const createViewer = () =>
|
||||
new Cognite3DViewer({
|
||||
sdk,
|
||||
useFlexibleCameraManager: true,
|
||||
...viewerOptions,
|
||||
});
|
||||
|
||||
const viewer = keepAlive
|
||||
? keepAlive.getOrCreateViewer(sdk, createViewer)
|
||||
: createViewer();
|
||||
|
||||
if (color) {
|
||||
viewer.setBackgroundColor({ color, alpha: 1 });
|
||||
}
|
||||
|
||||
return { viewer, sdk };
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const controller = new RevealSettingsController('medium');
|
||||
controller.applyToViewer(viewerData.viewer);
|
||||
return () => controller.dispose();
|
||||
}, [viewerData.viewer]);
|
||||
|
||||
useEffect(() => {
|
||||
if (color) {
|
||||
viewerData.viewer.setBackgroundColor({ color, alpha: 1 });
|
||||
}
|
||||
}, [color, viewerData.viewer]);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
if (!keepAliveRef.current) {
|
||||
viewerData.viewer.dispose();
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<RevealContext.Provider value={viewerData}>
|
||||
<InstanceStylingProvider>{children}</InstanceStylingProvider>
|
||||
</RevealContext.Provider>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import { createContext } from 'react';
|
||||
import type { InstanceStylingGroup } from '../types';
|
||||
|
||||
export interface InstanceStylingController {
|
||||
getStylingGroups: () => InstanceStylingGroup[];
|
||||
addEventListener: (callback: () => void) => void;
|
||||
removeEventListener: (callback: () => void) => void;
|
||||
registerStylingGroup: (group: InstanceStylingGroup) => string;
|
||||
unregisterStylingGroup: (id: string) => void;
|
||||
}
|
||||
|
||||
export const InstanceStylingContext = createContext<
|
||||
InstanceStylingController | undefined
|
||||
>(undefined);
|
||||
@@ -0,0 +1,12 @@
|
||||
import { createContext } from 'react';
|
||||
import type { Cognite3DViewer } from '@cognite/reveal';
|
||||
import type { CogniteClient } from '@cognite/sdk';
|
||||
|
||||
export interface RevealContextValue {
|
||||
viewer: Cognite3DViewer;
|
||||
sdk: CogniteClient;
|
||||
}
|
||||
|
||||
export const RevealContext = createContext<RevealContextValue | undefined>(
|
||||
undefined
|
||||
);
|
||||
Reference in New Issue
Block a user