ui(components): Viewport components updated to ui-next with design updates (#4886)
This commit is contained in:
1 parent
4e09f85d5d
commit
a8ac297e16
53 files changed
+933
-326
No files matched your search
@@ -1,6 +1,6 @@
|
||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { ViewportActionArrows } from '@ohif/ui';
|
||||
import { ViewportActionArrows } from '@ohif/ui-next';
|
||||
import { useViewportGrid } from '@ohif/ui-next';
|
||||
import { utils } from '@ohif/extension-cornerstone';
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { ViewportActionButton } from '@ohif/ui';
|
||||
import { ViewportActionButton } from '@ohif/ui-next';
|
||||
import { Icons, Tooltip, TooltipTrigger, TooltipContent } from '@ohif/ui-next';
|
||||
|
||||
export default function _getStatusComponent({ isHydrated, onStatusClick }) {
|
||||
@@ -56,4 +56,4 @@ export default function _getStatusComponent({ isHydrated, onStatusClick }) {
|
||||
{!ToolTipMessage && <StatusArea />}
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { ViewportActionArrows } from '@ohif/ui';
|
||||
import { ViewportActionArrows } from '@ohif/ui-next';
|
||||
import { useViewportGrid } from '@ohif/ui-next';
|
||||
import createSEGToolGroupAndAddTools from '../utils/initSEGToolGroup';
|
||||
import promptHydrateSEG from '../utils/promptHydrateSEG';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { ViewportActionButton } from '@ohif/ui';
|
||||
import { ViewportActionButton } from '@ohif/ui-next';
|
||||
import { Icons, Tooltip, TooltipTrigger, TooltipContent } from '@ohif/ui-next';
|
||||
|
||||
export default function _getStatusComponent({ isHydrated, onStatusClick }) {
|
||||
@@ -56,4 +56,4 @@ export default function _getStatusComponent({ isHydrated, onStatusClick }) {
|
||||
{!ToolTipMessage && <StatusArea />}
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -5,7 +5,7 @@ import { ExtensionManager, useToolbar } from '@ohif/core';
|
||||
|
||||
import { setTrackingUniqueIdentifiersForElement } from '../tools/modules/dicomSRModule';
|
||||
|
||||
import { ViewportActionArrows } from '@ohif/ui';
|
||||
import { ViewportActionArrows } from '@ohif/ui-next';
|
||||
import createReferencedImageDisplaySet from '../utils/createReferencedImageDisplaySet';
|
||||
import { usePositionPresentationStore } from '@ohif/extension-cornerstone';
|
||||
import { useViewportGrid } from '@ohif/ui-next';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
|
||||
import { SOPClassHandlerId, SOPClassHandlerId3D } from './id';
|
||||
import { ViewportActionButton } from '@ohif/ui';
|
||||
import { ViewportActionButton } from '@ohif/ui-next';
|
||||
import i18n from '@ohif/i18n';
|
||||
|
||||
export default function onModeEnter({ servicesManager }) {
|
||||
|
||||
@@ -3,7 +3,8 @@ import { useResizeDetector } from 'react-resize-detector';
|
||||
import * as cs3DTools from '@cornerstonejs/tools';
|
||||
import { Enums, eventTarget, getEnabledElement } from '@cornerstonejs/core';
|
||||
import { MeasurementService } from '@ohif/core';
|
||||
import { AllInOneMenu, useViewportDialog } from '@ohif/ui';
|
||||
import { AllInOneMenu } from '@ohif/ui-next';
|
||||
import { useViewportDialog } from '@ohif/ui';
|
||||
import type { Types as csTypes } from '@cornerstonejs/core';
|
||||
|
||||
import { setEnabledElement } from '../state';
|
||||
@@ -99,7 +100,7 @@ const OHIFCornerstoneViewport = React.memo(
|
||||
const [viewportDialogState] = useViewportDialog();
|
||||
// useCallback for scroll bar height calculation
|
||||
const setImageScrollBarHeight = useCallback(() => {
|
||||
const scrollbarHeight = `${elementRef.current.clientHeight - 40}px`;
|
||||
const scrollbarHeight = `${elementRef.current.clientHeight - 10}px`;
|
||||
setScrollbarHeight(scrollbarHeight);
|
||||
}, [elementRef]);
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import { vec3 } from 'gl-matrix';
|
||||
import PropTypes from 'prop-types';
|
||||
import { metaData, Enums, utilities } from '@cornerstonejs/core';
|
||||
import type { ImageSliceData } from '@cornerstonejs/core/types';
|
||||
import { ViewportOverlay } from '@ohif/ui';
|
||||
import { ViewportOverlay } from '@ohif/ui-next';
|
||||
import type { InstanceMetadata } from '@ohif/core/src/types';
|
||||
import { formatDICOMDate, formatDICOMTime, formatNumberPrecision } from './utils';
|
||||
import { utils } from '@ohif/core';
|
||||
@@ -368,7 +368,7 @@ function OverlayItem(props) {
|
||||
title={title}
|
||||
>
|
||||
{label ? <span className="mr-1 shrink-0">{label}</span> : null}
|
||||
<span className="ml-1 mr-2 shrink-0">{value}</span>
|
||||
<span className="ml-0 mr-2 shrink-0">{value}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -387,10 +387,10 @@ function VOIOverlayItem({ voi, customization }: OverlayItemProps) {
|
||||
className="overlay-item flex flex-row"
|
||||
style={{ color: customization?.color }}
|
||||
>
|
||||
<span className="mr-1 shrink-0">W:</span>
|
||||
<span className="ml-1 mr-2 shrink-0">{windowWidth.toFixed(0)}</span>
|
||||
<span className="mr-1 shrink-0">L:</span>
|
||||
<span className="ml-1 shrink-0">{windowCenter.toFixed(0)}</span>
|
||||
<span className="mr-0.5 shrink-0 opacity-[0.67]">W:</span>
|
||||
<span className="mr-2.5 shrink-0">{windowWidth.toFixed(0)}</span>
|
||||
<span className="mr-0.5 shrink-0 opacity-[0.67]">L:</span>
|
||||
<span className="shrink-0">{windowCenter.toFixed(0)}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -404,7 +404,7 @@ function ZoomOverlayItem({ scale, customization }: OverlayItemProps) {
|
||||
className="overlay-item flex flex-row"
|
||||
style={{ color: (customization && customization.color) || undefined }}
|
||||
>
|
||||
<span className="mr-1 shrink-0">Zoom:</span>
|
||||
<span className="mr-0.5 shrink-0 opacity-[0.67]">Zoom:</span>
|
||||
<span>{scale.toFixed(2)}x</span>
|
||||
</div>
|
||||
);
|
||||
@@ -428,7 +428,7 @@ function InstanceNumberOverlayItem({
|
||||
<span>
|
||||
{instanceNumber !== undefined && instanceNumber !== null ? (
|
||||
<>
|
||||
<span className="mr-1 shrink-0">I:</span>
|
||||
<span className="mr-0.5 shrink-0 opacity-[0.67]">I:</span>
|
||||
<span>{`${instanceNumber} (${imageIndex + 1}/${numberOfSlices})`}</span>
|
||||
</>
|
||||
) : (
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Enums, VolumeViewport3D, utilities as csUtils } from '@cornerstonejs/core';
|
||||
import { ImageScrollbar } from '@ohif/ui';
|
||||
import { ImageScrollbar } from '@ohif/ui-next';
|
||||
|
||||
function CornerstoneImageScrollbar({
|
||||
viewportData,
|
||||
|
||||
@@ -3,19 +3,18 @@
|
||||
--marker-height: 100px;
|
||||
--scrollbar-width: 20px;
|
||||
pointer-events: none;
|
||||
font-size: 15px;
|
||||
line-height: 18px;
|
||||
}
|
||||
.ViewportOrientationMarkers .orientation-marker {
|
||||
position: absolute;
|
||||
}
|
||||
.ViewportOrientationMarkers .top-mid {
|
||||
top: 0.6rem;
|
||||
top: 0.38rem;
|
||||
left: 50%;
|
||||
}
|
||||
.ViewportOrientationMarkers .left-mid {
|
||||
top: 47%;
|
||||
left: 5px;
|
||||
left: 0.38rem;
|
||||
}
|
||||
.ViewportOrientationMarkers .right-mid {
|
||||
top: 47%;
|
||||
|
||||
@@ -119,8 +119,8 @@ function ViewportOrientationMarkers({
|
||||
className={classNames(
|
||||
'overlay-text',
|
||||
`${m}-mid orientation-marker`,
|
||||
'text-aqua-pale',
|
||||
'text-[13px]',
|
||||
'text-highlight/65',
|
||||
'text-base',
|
||||
'leading-5'
|
||||
)}
|
||||
key={`${m}-mid orientation-marker`}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { ReactElement, useCallback, useEffect, useState } from 'react';
|
||||
import { SwitchButton } from '@ohif/ui';
|
||||
import { Switch } from '@ohif/ui-next';
|
||||
import { StackViewport, VolumeViewport } from '@cornerstonejs/core';
|
||||
import { ColorbarProps } from '../../types/Colorbar';
|
||||
import { utilities } from '@cornerstonejs/core';
|
||||
@@ -22,7 +22,7 @@ export function setViewportColorbar(
|
||||
colorbarOptions.ticks = {
|
||||
position: 'left',
|
||||
style: {
|
||||
font: '12px Arial',
|
||||
font: '13px Inter',
|
||||
color: '#000000',
|
||||
maxNumTicks: 8,
|
||||
tickSize: 5,
|
||||
@@ -101,12 +101,18 @@ export function Colorbar({
|
||||
}, [viewportId]);
|
||||
|
||||
return (
|
||||
<div className="all-in-one-menu-item flex w-full justify-center">
|
||||
<div className="mr-2 w-[28px]"></div>
|
||||
<SwitchButton
|
||||
label="Display Color bar"
|
||||
<div
|
||||
className="hover:bg-accent flex h-8 w-full flex-shrink-0 cursor-pointer items-center px-2 text-base hover:rounded"
|
||||
onClick={() => {
|
||||
onSetColorbar();
|
||||
}}
|
||||
>
|
||||
<div className="flex w-7 flex-shrink-0 items-center justify-center"></div>
|
||||
<span className="flex-grow">Display Color bar</span>
|
||||
<Switch
|
||||
className="ml-2 flex-shrink-0"
|
||||
checked={showColorbar}
|
||||
onChange={() => {
|
||||
onCheckedChange={() => {
|
||||
onSetColorbar();
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React, { ReactElement, useCallback, useEffect, useRef, useState, useMemo } from 'react';
|
||||
import { AllInOneMenu, ButtonGroup, SwitchButton } from '@ohif/ui';
|
||||
import React, { ReactElement, useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { AllInOneMenu, Switch, Tabs, TabsList, TabsTrigger } from '@ohif/ui-next';
|
||||
|
||||
import { StackViewport, Types } from '@cornerstonejs/core';
|
||||
import { ColormapProps } from '../../types/Colormap';
|
||||
|
||||
@@ -26,6 +27,7 @@ export function Colormap({
|
||||
|
||||
const onSetColorLUT = useCallback(
|
||||
props => {
|
||||
debugger;
|
||||
// TODO: Better way to check if it's a fusion
|
||||
const oneOpacityColormaps = ['Grayscale', 'X Ray'];
|
||||
const opacity =
|
||||
@@ -64,20 +66,9 @@ export function Colormap({
|
||||
return colormap;
|
||||
};
|
||||
|
||||
const buttons = useMemo(() => {
|
||||
return displaySets.map((displaySet, index) => ({
|
||||
children: displaySet.Modality,
|
||||
key: index,
|
||||
style: {
|
||||
minWidth: `calc(100% / ${displaySets.length})`,
|
||||
fontSize: '0.8rem',
|
||||
textAlign: 'center',
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
}));
|
||||
}, [displaySets]);
|
||||
const activeIndex = displaySets.findIndex(
|
||||
ds => ds.displaySetInstanceUID === activeDisplaySetRef.current.displaySetInstanceUID
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setActiveDisplaySet(displaySets[displaySets.length - 1]);
|
||||
@@ -85,46 +76,52 @@ export function Colormap({
|
||||
|
||||
return (
|
||||
<>
|
||||
{buttons.length > 1 && (
|
||||
<div className="all-in-one-menu-item flex w-full justify-center">
|
||||
<ButtonGroup
|
||||
onActiveIndexChange={index => {
|
||||
{displaySets.length > 1 && (
|
||||
<div className="flex h-8 w-full flex-shrink-0 items-center justify-center px-2 text-base">
|
||||
<Tabs
|
||||
value={String(activeIndex)}
|
||||
onValueChange={val => {
|
||||
const index = parseInt(val, 10);
|
||||
setActiveDisplaySet(displaySets[index]);
|
||||
setPrePreviewColormap(null);
|
||||
}}
|
||||
activeIndex={
|
||||
displaySets.findIndex(
|
||||
ds => ds.displaySetInstanceUID === activeDisplaySetRef.current.displaySetInstanceUID
|
||||
) || 1
|
||||
}
|
||||
className="w-[70%] text-[10px]"
|
||||
>
|
||||
{buttons.map(({ children, key, style }) => (
|
||||
<div
|
||||
key={key}
|
||||
style={style}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
))}
|
||||
</ButtonGroup>
|
||||
<TabsList>
|
||||
{displaySets.map((ds, i) => (
|
||||
<TabsTrigger
|
||||
key={i}
|
||||
value={String(i)}
|
||||
>
|
||||
{ds.Modality}
|
||||
</TabsTrigger>
|
||||
))}
|
||||
</TabsList>
|
||||
</Tabs>
|
||||
</div>
|
||||
)}
|
||||
<div className="all-in-one-menu-item flex w-full justify-center">
|
||||
<SwitchButton
|
||||
label="Preview in viewport"
|
||||
<div
|
||||
className="hover:bg-accent flex h-8 w-full flex-shrink-0 cursor-pointer items-center px-2 text-base hover:rounded"
|
||||
onClick={() => setShowPreview(!showPreview)}
|
||||
>
|
||||
<span className="flex-shrink-0">Preview in viewport</span>
|
||||
<Switch
|
||||
className="ml-auto flex-shrink-0"
|
||||
checked={showPreview}
|
||||
onChange={checked => {
|
||||
onCheckedChange={checked => {
|
||||
setShowPreview(checked);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<AllInOneMenu.DividerItem />
|
||||
<AllInOneMenu.ItemPanel>
|
||||
<AllInOneMenu.ItemPanel
|
||||
maxHeight="calc(100vh - 250px)"
|
||||
className="min-h-[200px] flex-grow"
|
||||
>
|
||||
{colormaps.map((colormap, index) => (
|
||||
<AllInOneMenu.Item
|
||||
key={index}
|
||||
label={colormap.description}
|
||||
useIconSpace={false}
|
||||
onClick={() => {
|
||||
onSetColorLUT({
|
||||
viewportId,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React, { ReactElement, useState, useEffect, useCallback } from 'react';
|
||||
import { VolumeLightingProps } from '../../types/ViewportPresets';
|
||||
import { Numeric } from '@ohif/ui-next';
|
||||
|
||||
export function VolumeLighting({
|
||||
servicesManager,
|
||||
@@ -8,135 +9,75 @@ export function VolumeLighting({
|
||||
hasShade,
|
||||
}: VolumeLightingProps): ReactElement {
|
||||
const { cornerstoneViewportService } = servicesManager.services;
|
||||
const [ambient, setAmbient] = useState(null);
|
||||
const [diffuse, setDiffuse] = useState(null);
|
||||
const [specular, setSpecular] = useState(null);
|
||||
const [lightingValues, setLightingValues] = useState({
|
||||
ambient: null,
|
||||
diffuse: null,
|
||||
specular: null,
|
||||
});
|
||||
|
||||
const onAmbientChange = useCallback(() => {
|
||||
commandsManager.runCommand('setVolumeLighting', { viewportId, options: { ambient } });
|
||||
}, [ambient, commandsManager, viewportId]);
|
||||
|
||||
const onDiffuseChange = useCallback(() => {
|
||||
commandsManager.runCommand('setVolumeLighting', { viewportId, options: { diffuse } });
|
||||
}, [diffuse, commandsManager, viewportId]);
|
||||
|
||||
const onSpecularChange = useCallback(() => {
|
||||
commandsManager.runCommand('setVolumeLighting', { viewportId, options: { specular } });
|
||||
}, [specular, commandsManager, viewportId]);
|
||||
|
||||
const calculateBackground = value => {
|
||||
const percentage = ((value - 0) / (1 - 0)) * 100;
|
||||
return `linear-gradient(to right, #5acce6 0%, #5acce6 ${percentage}%, #3a3f99 ${percentage}%, #3a3f99 100%)`;
|
||||
};
|
||||
// Single callback to handle all lighting property changes
|
||||
const onLightingChange = useCallback(
|
||||
(property, value) => {
|
||||
commandsManager.runCommand('setVolumeLighting', {
|
||||
viewportId,
|
||||
options: { [property]: value },
|
||||
});
|
||||
setLightingValues(prev => ({
|
||||
...prev,
|
||||
[property]: value,
|
||||
}));
|
||||
},
|
||||
[commandsManager, viewportId]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
|
||||
const { actor } = viewport.getActors()[0];
|
||||
const ambient = actor.getProperty().getAmbient();
|
||||
const diffuse = actor.getProperty().getDiffuse();
|
||||
const specular = actor.getProperty().getSpecular();
|
||||
setAmbient(ambient);
|
||||
setDiffuse(diffuse);
|
||||
setSpecular(specular);
|
||||
}, [viewportId, cornerstoneViewportService]);
|
||||
const disableOption = hasShade ? '' : 'ohif-disabled !opacity-40';
|
||||
const disableSlider = !hasShade;
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className={`all-in-one-menu-item flex w-full flex-row !items-center justify-between gap-[10px] ${disableOption}`}
|
||||
>
|
||||
<label
|
||||
className="block text-white"
|
||||
htmlFor="ambient"
|
||||
>
|
||||
Ambient
|
||||
</label>
|
||||
{ambient !== null && (
|
||||
<input
|
||||
className="bg-inputfield-main h-2 w-[120px] cursor-pointer appearance-none rounded-lg"
|
||||
value={ambient}
|
||||
onChange={e => {
|
||||
setAmbient(e.target.value);
|
||||
onAmbientChange();
|
||||
}}
|
||||
id="ambient"
|
||||
disabled={disableSlider}
|
||||
max={1}
|
||||
min={0}
|
||||
type="range"
|
||||
step={0.1}
|
||||
style={{
|
||||
background: calculateBackground(ambient),
|
||||
'--thumb-inner-color': '#5acce6',
|
||||
'--thumb-outer-color': '#090c29',
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
className={`all-in-one-menu-item flex w-full flex-row !items-center justify-between gap-[10px] ${disableOption}`}
|
||||
>
|
||||
<label
|
||||
className="block text-white"
|
||||
htmlFor="diffuse"
|
||||
>
|
||||
Diffuse
|
||||
</label>
|
||||
{diffuse !== null && (
|
||||
<input
|
||||
className="bg-inputfield-main h-2 w-[120px] cursor-pointer appearance-none rounded-lg"
|
||||
value={diffuse}
|
||||
onChange={e => {
|
||||
setDiffuse(e.target.value);
|
||||
onDiffuseChange();
|
||||
}}
|
||||
disabled={disableSlider}
|
||||
id="diffuse"
|
||||
max={1}
|
||||
min={0}
|
||||
type="range"
|
||||
step={0.1}
|
||||
style={{
|
||||
background: calculateBackground(diffuse),
|
||||
'--thumb-inner-color': '#5acce6',
|
||||
'--thumb-outer-color': '#090c29',
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
const property = actor.getProperty();
|
||||
|
||||
<div
|
||||
className={`all-in-one-menu-item flex w-full flex-row !items-center justify-between gap-[10px] ${disableOption}`}
|
||||
>
|
||||
<label
|
||||
className="block text-white"
|
||||
htmlFor="specular"
|
||||
>
|
||||
Specular
|
||||
</label>
|
||||
{specular !== null && (
|
||||
<input
|
||||
className="bg-inputfield-main h-2 w-[120px] cursor-pointer appearance-none rounded-lg"
|
||||
value={specular}
|
||||
disabled={disableSlider}
|
||||
onChange={e => {
|
||||
setSpecular(e.target.value);
|
||||
onSpecularChange();
|
||||
}}
|
||||
id="specular"
|
||||
max={1}
|
||||
min={0}
|
||||
type="range"
|
||||
step={0.1}
|
||||
style={{
|
||||
background: calculateBackground(specular),
|
||||
'--thumb-inner-color': '#5acce6',
|
||||
'--thumb-outer-color': '#090c29',
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
const values = {
|
||||
ambient: property.getAmbient(),
|
||||
diffuse: property.getDiffuse(),
|
||||
specular: property.getSpecular(),
|
||||
};
|
||||
|
||||
setLightingValues(values);
|
||||
}, [viewportId, cornerstoneViewportService]);
|
||||
|
||||
const disableOption = hasShade ? '' : 'ohif-disabled !opacity-40';
|
||||
|
||||
// Configuration for our lighting properties
|
||||
const lightingProperties = [
|
||||
{ key: 'ambient', label: 'Ambient' },
|
||||
{ key: 'diffuse', label: 'Diffuse' },
|
||||
{ key: 'specular', label: 'Specular' },
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="my-1 mt-2 flex flex-col space-y-2">
|
||||
{lightingProperties.map(
|
||||
({ key, label }) =>
|
||||
lightingValues[key] !== null && (
|
||||
<div
|
||||
key={key}
|
||||
className={`w-full pl-2 pr-1 ${disableOption}`}
|
||||
>
|
||||
<Numeric.Container
|
||||
mode="singleRange"
|
||||
min={0}
|
||||
max={1}
|
||||
step={0.1}
|
||||
value={lightingValues[key]}
|
||||
onChange={value => onLightingChange(key, value)}
|
||||
>
|
||||
<div className="flex flex-row items-center">
|
||||
<Numeric.Label className="w-16">{label}</Numeric.Label>
|
||||
<Numeric.SingleRange sliderClassName="mx-2 flex-grow" />
|
||||
</div>
|
||||
</Numeric.Container>
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
+5
-5
@@ -1,5 +1,5 @@
|
||||
import React, { ReactElement, useState } from 'react';
|
||||
import { AllInOneMenu } from '@ohif/ui';
|
||||
import { AllInOneMenu } from '@ohif/ui-next';
|
||||
import { VolumeRenderingOptionsProps } from '../../types/ViewportPresets';
|
||||
import { VolumeRenderingQuality } from './VolumeRenderingQuality';
|
||||
import { VolumeShift } from './VolumeShift';
|
||||
@@ -26,11 +26,11 @@ export function VolumeRenderingOptions({
|
||||
commandsManager={commandsManager}
|
||||
servicesManager={servicesManager}
|
||||
/>
|
||||
<div className="all-in-one-menu-item mt-2 flex !h-[20px] w-full justify-start">
|
||||
<div className="text-aqua-pale text-[13px]">LIGHTING</div>
|
||||
<div className="mt-2 flex h-8 !h-[20px] w-full flex-shrink-0 items-center justify-start px-2 text-base">
|
||||
<div className="text-muted-foreground text-sm">Lighting</div>
|
||||
</div>
|
||||
<div className="bg-primary-dark mt-1 mb-1 h-[2px] w-full"></div>
|
||||
<div className="all-in-one-menu-item flex w-full justify-center">
|
||||
<div className="bg-background mt-1 mb-1 h-px w-full"></div>
|
||||
<div className="hover:bg-accent flex h-8 w-full flex-shrink-0 items-center px-2 text-base hover:rounded">
|
||||
<VolumeShade
|
||||
commandsManager={commandsManager}
|
||||
servicesManager={servicesManager}
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { AllInOneMenu } from '@ohif/ui';
|
||||
import { AllInOneMenu } from '@ohif/ui-next';
|
||||
import { Icons } from '@ohif/ui-next';
|
||||
import React, { ReactElement } from 'react';
|
||||
import { VolumeRenderingPresetsProps } from '../../types/ViewportPresets';
|
||||
|
||||
+19
-30
@@ -1,5 +1,6 @@
|
||||
import React, { ReactElement, useCallback, useState, useEffect } from 'react';
|
||||
import { VolumeRenderingQualityProps } from '../../types/ViewportPresets';
|
||||
import { Numeric } from '@ohif/ui-next';
|
||||
|
||||
export function VolumeRenderingQuality({
|
||||
volumeRenderingQualityRange,
|
||||
@@ -22,11 +23,6 @@ export function VolumeRenderingQuality({
|
||||
[commandsManager, viewportId]
|
||||
);
|
||||
|
||||
const calculateBackground = value => {
|
||||
const percentage = ((value - 0) / (1 - 0)) * 100;
|
||||
return `linear-gradient(to right, #5acce6 0%, #5acce6 ${percentage}%, #3a3f99 ${percentage}%, #3a3f99 100%)`;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
|
||||
const { actor } = viewport.getActors()[0];
|
||||
@@ -41,33 +37,26 @@ export function VolumeRenderingQuality({
|
||||
setQuality(Math.sqrt(averageSpacing / (sampleDistance * 0.5)));
|
||||
}
|
||||
}, [cornerstoneViewportService, viewportId]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="all-in-one-menu-item flex w-full flex-row !items-center justify-between gap-[10px]">
|
||||
<label
|
||||
className="block text-white"
|
||||
htmlFor="volume"
|
||||
>
|
||||
Quality
|
||||
</label>
|
||||
{quality !== null && (
|
||||
<input
|
||||
className="bg-inputfield-main h-2 w-[120px] cursor-pointer appearance-none rounded-lg"
|
||||
value={quality}
|
||||
id="volume"
|
||||
max={max}
|
||||
<div className="my-1 mt-2 flex flex-col space-y-2">
|
||||
{quality !== null && (
|
||||
<div className="w-full pl-2 pr-1">
|
||||
<Numeric.Container
|
||||
mode="singleRange"
|
||||
min={min}
|
||||
type="range"
|
||||
max={max}
|
||||
step={step}
|
||||
onChange={e => onChange(parseInt(e.target.value, 10))}
|
||||
style={{
|
||||
background: calculateBackground((quality - min) / (max - min)),
|
||||
'--thumb-inner-color': '#5acce6',
|
||||
'--thumb-outer-color': '#090c29',
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
value={quality}
|
||||
onChange={onChange}
|
||||
>
|
||||
<div className="flex flex-row items-center">
|
||||
<Numeric.Label className="w-16">Quality</Numeric.Label>
|
||||
<Numeric.SingleRange sliderClassName="mx-2 flex-grow" />
|
||||
</div>
|
||||
</Numeric.Container>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { ReactElement, useCallback, useEffect, useState } from 'react';
|
||||
import { SwitchButton } from '@ohif/ui';
|
||||
import { Switch } from '@ohif/ui-next';
|
||||
import { VolumeShadeProps } from '../../types/ViewportPresets';
|
||||
|
||||
export function VolumeShade({
|
||||
@@ -28,15 +28,18 @@ export function VolumeShade({
|
||||
}, [viewportId, cornerstoneViewportService]);
|
||||
|
||||
return (
|
||||
<SwitchButton
|
||||
key={key}
|
||||
label="Shade"
|
||||
checked={shade}
|
||||
onChange={() => {
|
||||
setShade(!shade);
|
||||
onClickShade(!shade);
|
||||
onShadeChange(!shade);
|
||||
}}
|
||||
/>
|
||||
<>
|
||||
<span className="flex-grow">Shade</span>
|
||||
<Switch
|
||||
className="ml-2 flex-shrink-0"
|
||||
key={key}
|
||||
checked={shade}
|
||||
onCheckedChange={() => {
|
||||
setShade(!shade);
|
||||
onClickShade(!shade);
|
||||
onShadeChange(!shade);
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import React, { ReactElement, useCallback, useEffect, useState, useRef } from 'react';
|
||||
import { VolumeShiftProps } from '../../types/ViewportPresets';
|
||||
import { Numeric } from '@ohif/ui-next';
|
||||
|
||||
export function VolumeShift({
|
||||
viewportId,
|
||||
@@ -46,48 +47,32 @@ export function VolumeShift({
|
||||
viewportId,
|
||||
shift: shiftDifference,
|
||||
});
|
||||
setShift(newShift);
|
||||
},
|
||||
[commandsManager, viewportId, viewport]
|
||||
);
|
||||
|
||||
const calculateBackground = value => {
|
||||
const percentage = ((value - 0) / (1 - 0)) * 100;
|
||||
return `linear-gradient(to right, #5acce6 0%, #5acce6 ${percentage}%, #3a3f99 ${percentage}%, #3a3f99 100%)`;
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="all-in-one-menu-item flex w-full flex-row !items-center justify-between gap-[10px]">
|
||||
<label
|
||||
className="block text-white"
|
||||
htmlFor="shift"
|
||||
>
|
||||
Shift
|
||||
</label>
|
||||
{step !== null && (
|
||||
<input
|
||||
className="bg-inputfield-main h-2 w-[120px] cursor-pointer appearance-none rounded-lg"
|
||||
<div className="my-1 mt-2 flex flex-col space-y-2">
|
||||
{step !== null && minShift !== null && maxShift !== null && (
|
||||
<div className="w-full pl-2 pr-1">
|
||||
<Numeric.Container
|
||||
mode="singleRange"
|
||||
min={minShift}
|
||||
max={maxShift}
|
||||
step={step}
|
||||
value={shift}
|
||||
onChange={e => {
|
||||
const shiftValue = parseInt(e.target.value, 10);
|
||||
setShift(shiftValue);
|
||||
onChangeRange(shiftValue);
|
||||
}}
|
||||
id="shift"
|
||||
onChange={onChangeRange}
|
||||
onMouseDown={() => setIsBlocking(true)}
|
||||
onMouseUp={() => setIsBlocking(false)}
|
||||
max={maxShift}
|
||||
min={minShift}
|
||||
type="range"
|
||||
step={step}
|
||||
style={{
|
||||
background: calculateBackground((shift - minShift) / (maxShift - minShift)),
|
||||
'--thumb-inner-color': '#5acce6',
|
||||
'--thumb-outer-color': '#090c29',
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
>
|
||||
<div className="flex flex-row items-center">
|
||||
<Numeric.Label className="w-16">Shift</Numeric.Label>
|
||||
<Numeric.SingleRange sliderClassName="mx-2 flex-grow" />
|
||||
</div>
|
||||
</Numeric.Container>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { ReactElement, useCallback } from 'react';
|
||||
import { AllInOneMenu } from '@ohif/ui';
|
||||
import { AllInOneMenu } from '@ohif/ui-next';
|
||||
import { WindowLevelPreset } from '../../types/WindowLevel';
|
||||
import { CommandsManager } from '@ohif/core';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -45,6 +45,7 @@ export function WindowLevel({
|
||||
key={`${modality}-${index}`}
|
||||
label={preset.description}
|
||||
secondaryLabel={`${preset.window} / ${preset.level}`}
|
||||
useIconSpace={false}
|
||||
onClick={() => onSetWindowLevel(preset)}
|
||||
/>
|
||||
))}
|
||||
|
||||
+5
-3
@@ -1,7 +1,7 @@
|
||||
import React, { ReactElement, useCallback, useEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import classNames from 'classnames';
|
||||
import { AllInOneMenu } from '@ohif/ui';
|
||||
import { AllInOneMenu } from '@ohif/ui-next';
|
||||
import { useViewportGrid } from '@ohif/ui-next';
|
||||
import { Colormap } from './Colormap';
|
||||
import { Colorbar } from './Colorbar';
|
||||
@@ -119,8 +119,8 @@ export function WindowLevelActionMenu({
|
||||
iconClassName={classNames(
|
||||
// Visible on hover and for the active viewport
|
||||
activeViewportId === viewportId ? 'visible' : 'invisible group-hover/pane:visible',
|
||||
'flex shrink-0 cursor-pointer rounded active:text-white text-primary-light',
|
||||
isLight ? ' hover:bg-secondary-dark' : 'hover:bg-secondary-light/60'
|
||||
'flex shrink-0 cursor-pointer rounded active:text-foreground text-highlight',
|
||||
isLight ? ' hover:bg-primary/30' : 'hover:bg-primary/30'
|
||||
)}
|
||||
menuStyle={{ maxHeight: vpHeight - 32, minWidth: 218 }}
|
||||
onVisibilityChange={() => {
|
||||
@@ -144,8 +144,10 @@ export function WindowLevelActionMenu({
|
||||
key="colorLUTPresets"
|
||||
itemLabel="Color LUT"
|
||||
itemIcon="icon-color-lut"
|
||||
className="flex h-[calc(100%-32px)] flex-col"
|
||||
>
|
||||
<Colormap
|
||||
className="flex h-full w-full flex-col"
|
||||
colormaps={colormaps}
|
||||
viewportId={viewportId}
|
||||
displaySets={displaySets.filter(ds => !nonWLModalities.includes(ds.Modality))}
|
||||
|
||||
@@ -8,7 +8,7 @@ import React, {
|
||||
} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { Types, ViewportActionCornersLocations } from '@ohif/ui';
|
||||
import { Types, ViewportActionCornersLocations } from '@ohif/ui-next';
|
||||
import ViewportActionCornersService, {
|
||||
ActionComponentInfo,
|
||||
} from '../services/ViewportActionCornersService/ViewportActionCornersService';
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
import { PubSubService } from '@ohif/core';
|
||||
import { ViewportActionCornersLocations } from '@ohif/ui';
|
||||
import { ViewportActionCornersLocations } from '@ohif/ui-next';
|
||||
import { ReactNode } from 'react';
|
||||
|
||||
export type ActionComponentInfo = {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ViewportActionCorners } from '@ohif/ui';
|
||||
import { ViewportActionCorners } from '@ohif/ui-next';
|
||||
|
||||
export default {
|
||||
'ui.viewportActionCorner': ViewportActionCorners,
|
||||
|
||||
@@ -4,7 +4,7 @@ import getContextModule from './getContextModule';
|
||||
import getPanelModule from './getPanelModule';
|
||||
import getViewportModule from './getViewportModule';
|
||||
import { id } from './id.js';
|
||||
import { ViewportActionButton } from '@ohif/ui';
|
||||
import { ViewportActionButton } from '@ohif/ui-next';
|
||||
import i18n from '@ohif/i18n';
|
||||
import { measurementTrackingMode } from './contexts/TrackedMeasurementsContext/promptBeginTracking';
|
||||
import getCustomizationModule from './getCustomizationModule';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { useState, useEffect, useCallback } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { ViewportActionArrows } from '@ohif/ui';
|
||||
import { ViewportActionArrows } from '@ohif/ui-next';
|
||||
import { useViewportGrid, Icons, Tooltip, TooltipTrigger, TooltipContent } from '@ohif/ui-next';
|
||||
|
||||
import { annotation } from '@cornerstonejs/tools';
|
||||
@@ -325,7 +325,7 @@ function _getStatusComponent(isTracked, t) {
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<span>
|
||||
<Icons.StatusTracking className="text-muted-foreground" />
|
||||
<Icons.StatusTracking className="text-muted-foreground mt-0.5 ml-0.5" />
|
||||
</span>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent
|
||||
|
||||
Reference in new issue
Block a user