Skip to content

Commit

Permalink
feat: slice button for RevealToolbar (#3492)
Browse files Browse the repository at this point in the history
* feat: slice button for RevealToolbar

* feat: expose SlicerButton and FitModelsButton
  • Loading branch information
haakonflatval-cognite authored Jul 21, 2023
1 parent e6b4297 commit ac23907
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 21 deletions.
45 changes: 24 additions & 21 deletions react-components/src/components/RevealToolbar/RevealToolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
* Copyright 2023 Cognite AS
*/

import { type ReactElement } from 'react';
import { type ReactElement, type JSX } from 'react';
import { Button, ToolBar, type ToolBarProps } from '@cognite/cogs.js';
import { FitModelsButton } from './FitModelsButton';
import { SlicerButton } from './SlicerButton';

const defaultStyle: ToolBarProps = {
style: {
Expand All @@ -14,32 +15,34 @@ const defaultStyle: ToolBarProps = {
}
};

export const RevealToolbar = (toolBarProps: ToolBarProps): ReactElement => {
if (toolBarProps.className === undefined && toolBarProps.style === undefined) {
toolBarProps = { ...toolBarProps, ...defaultStyle };
}
return (
<ToolBar {...toolBarProps}>
<>
<Button type="ghost" icon="Layers" aria-label="3D Resource layers" />
const defaultContent = (
<>
<Button type="ghost" icon="Layers" aria-label="3D Resource layers" />

<div className="cogs-toolbar-divider" />

<div className="cogs-toolbar-divider" />
<FitModelsButton />
<Button type="ghost" icon="Collapse" aria-label="Focus asset" />

<FitModelsButton />
<Button type="ghost" icon="Collapse" aria-label="Focus asset" />
<div className="cogs-toolbar-divider" />

<div className="cogs-toolbar-divider" />
<SlicerButton />
<Button type="ghost" icon="Ruler" aria-label="Make measurements" />

<Button type="ghost" icon="Slice" aria-label="Slice models" />
<Button type="ghost" icon="Ruler" aria-label="Make measurements" />
<div className="cogs-toolbar-divider" />

<div className="cogs-toolbar-divider" />
<Button type="ghost" icon="Settings" aria-label="Show settings" />
<Button type="ghost" icon="Help" aria-label="Display help" />
</>
);

<Button type="ghost" icon="Settings" aria-label="Show settings" />
<Button type="ghost" icon="Help" aria-label="Display help" />
</>
</ToolBar>
);
export const RevealToolbar = (
props: ToolBarProps & { toolBarContent?: JSX.Element }
): ReactElement => {
if (props.className === undefined && props.style === undefined) {
props = { ...props, ...defaultStyle };
}
return <ToolBar {...props}>{props.toolBarContent ?? defaultContent}</ToolBar>;
};

RevealToolbar.FitModelsButton = FitModelsButton;
113 changes: 113 additions & 0 deletions react-components/src/components/RevealToolbar/SlicerButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/*!
* Copyright 2023 Cognite AS
*/

import { type ReactElement, useState, useEffect } from 'react';

import { Box3, Plane, Vector3 } from 'three';

import { useReveal } from '../RevealContainer/RevealContext';
import { Button, Dropdown, Menu, RangeSlider } from '@cognite/cogs.js';

import styled from 'styled-components';

type SliceState = {
minHeight: number;
maxHeight: number;
topRatio: number;
bottomRatio: number;
};

export const SlicerButton = (): ReactElement => {
const viewer = useReveal();

const [sliceState, setSliceState] = useState<SliceState>({
minHeight: 0,
maxHeight: 0,
topRatio: 1,
bottomRatio: 0
});

const { minHeight, maxHeight, topRatio, bottomRatio } = sliceState;

// Heuristic to increase chance that update is propagated even
// if multiple additions/deletions of models occur.
const lastModel =
viewer.models.length === 0 ? undefined : viewer.models[viewer.models.length - 1];

useEffect(() => {
const box = new Box3();
viewer.models.forEach((model) => box.union(model.getModelBoundingBox()));

const newMaxY = box.max.y;
const newMinY = box.min.y;

if (maxHeight !== newMaxY || minHeight !== newMinY) {
setSliceState(getNewSliceState(sliceState, newMinY, newMaxY));
}
}, [viewer, viewer.models.length, lastModel]);

function changeSlicingState(newValues: number[]): void {
viewer.setGlobalClippingPlanes([
new Plane(new Vector3(0, 1, 0), -(minHeight + newValues[0] * (maxHeight - minHeight))),
new Plane(new Vector3(0, -1, 0), minHeight + newValues[1] * (maxHeight - minHeight))
]);

setSliceState({
maxHeight,
minHeight,
bottomRatio: newValues[0],
topRatio: newValues[1]
});
}

return (
<Dropdown
appendTo={() => document.body}
content={
<StyledMenu>
<RangeSlider
min={0}
max={1}
step={0.01}
setValue={changeSlicingState}
marks={{}}
value={[bottomRatio, topRatio]}
vertical
/>
</StyledMenu>
}
placement="right-end">
<Button type="ghost" icon="Slice" aria-label="Slice models" />
</Dropdown>
);
};

function getNewSliceState(oldSliceState: SliceState, newMin: number, newMax: number): SliceState {
function getRatioForNewRange(ratio: number): number {
if (ratio === 0 || ratio === 1) {
return ratio;
}

const oldMin = oldSliceState.minHeight;
const oldMax = oldSliceState.maxHeight;

const position = oldMin + ratio * (oldMax - oldMin);
const newRatio = (position - newMin) / (newMax - newMin);

return Math.min(1.0, Math.max(0.0, newRatio));
}

return {
maxHeight: newMax,
minHeight: newMin,
topRatio: getRatioForNewRange(oldSliceState.topRatio),
bottomRatio: getRatioForNewRange(oldSliceState.bottomRatio)
};
}

const StyledMenu = styled(Menu)`
height: 512px;
padding: 12px;
min-width: 0px;
`;
2 changes: 2 additions & 0 deletions react-components/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,7 @@ export type {
AddReveal3DModelOptions
} from './components/Reveal3DResources/types';
export { RevealToolbar } from './components/RevealToolbar/RevealToolbar';
export { SlicerButton } from './components/RevealToolbar/SlicerButton';
export { FitModelsButton } from './components/RevealToolbar/FitModelsButton';
export { useFdmAssetMappings } from './hooks/useFdmAssetMappings';
export { type FdmAssetMappingsConfig } from './hooks/types';

0 comments on commit ac23907

Please sign in to comment.