fix viewport overlay
This commit is contained in:
+116
-90
@@ -407,12 +407,14 @@ function App({ container_id, imageStacks, autoCacheStack, annotationJson, viewer
|
|||||||
total: number,
|
total: number,
|
||||||
windowCenter: string,
|
windowCenter: string,
|
||||||
windowWidth: string,
|
windowWidth: string,
|
||||||
|
slicePosition?: number,
|
||||||
}>>(() =>
|
}>>(() =>
|
||||||
Array(viewportGrid.rows * viewportGrid.cols).fill({
|
Array(viewportGrid.rows * viewportGrid.cols).fill({
|
||||||
index: 0,
|
index: 0,
|
||||||
total: 0,
|
total: 0,
|
||||||
windowCenter: "",
|
windowCenter: "",
|
||||||
windowWidth: "",
|
windowWidth: "",
|
||||||
|
slicePosition: 0,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -741,70 +743,76 @@ function App({ container_id, imageStacks, autoCacheStack, annotationJson, viewer
|
|||||||
|
|
||||||
// Update overlay info for a specific viewport
|
// Update overlay info for a specific viewport
|
||||||
|
|
||||||
const updateOverlay = useCallback((viewportIdx: number, viewport: any) => {
|
const updateOverlay = useCallback((viewportIdx: number, viewport: any) => {
|
||||||
console.log("updateOverlay called for viewportIdx:", viewportIdx, "viewport:", viewport);
|
if (!viewport) return;
|
||||||
if (!viewport) return;
|
|
||||||
|
|
||||||
let currentIndex = 0;
|
let currentIndex = 0;
|
||||||
let total = 0;
|
let total = 0;
|
||||||
let windowCenter = "";
|
let windowCenter = "";
|
||||||
let windowWidth = "";
|
let windowWidth = "";
|
||||||
console.log("Updating overlay for viewport:", viewportIdx, viewportModes[viewportIdx]);
|
let slicePosition = "";
|
||||||
|
|
||||||
if (viewportModes[viewportIdx] === "stack") {
|
if (viewportModes[viewportIdx] === "stack") {
|
||||||
currentIndex = typeof viewport.getCurrentImageIdIndex === "function"
|
currentIndex = typeof viewport.getCurrentImageIdIndex === "function"
|
||||||
? viewport.getCurrentImageIdIndex()
|
? viewport.getCurrentImageIdIndex()
|
||||||
: 0;
|
: 0;
|
||||||
const imageIds = typeof viewport.getImageIds === "function"
|
const imageIds = typeof viewport.getImageIds === "function"
|
||||||
? viewport.getImageIds()
|
? viewport.getImageIds()
|
||||||
: [];
|
: [];
|
||||||
total = imageIds.length;
|
total = imageIds.length;
|
||||||
if (typeof viewport.getProperties === "function") {
|
if (typeof viewport.getProperties === "function") {
|
||||||
const props = viewport.getProperties();
|
const props = viewport.getProperties();
|
||||||
if (props.voiRange) {
|
if (props.voiRange) {
|
||||||
const { lower, upper } = props.voiRange;
|
const { lower, upper } = props.voiRange;
|
||||||
windowCenter = ((upper + lower) / 2).toFixed(0);
|
windowCenter = ((upper + lower) / 2).toFixed(0);
|
||||||
windowWidth = (upper - lower).toFixed(0);
|
windowWidth = (upper - lower).toFixed(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (viewportModes[viewportIdx] === "volume") {
|
||||||
|
// For volume, get slice index and number of slices if available
|
||||||
|
if (typeof viewport.getSliceIndex === "function") {
|
||||||
|
currentIndex = viewport.getSliceIndex();
|
||||||
|
}
|
||||||
|
if (typeof viewport.getNumberOfSlices === "function") {
|
||||||
|
total = viewport.getNumberOfSlices();
|
||||||
|
}
|
||||||
|
// Get VOI from getProperties (may need to pass volumeId if multiple volumes)
|
||||||
|
if (typeof viewport.getProperties === "function") {
|
||||||
|
let props;
|
||||||
|
if (viewport.volumeIds && viewport.volumeIds.size > 0) {
|
||||||
|
// If multiple volumes, get the first one
|
||||||
|
const volumeId = Array.from(viewport.volumeIds)[0];
|
||||||
|
props = viewport.getProperties(volumeId);
|
||||||
|
} else {
|
||||||
|
props = viewport.getProperties();
|
||||||
|
}
|
||||||
|
if (props && props.voiRange) {
|
||||||
|
const { lower, upper } = props.voiRange;
|
||||||
|
windowCenter = ((upper + lower) / 2).toFixed(0);
|
||||||
|
windowWidth = (upper - lower).toFixed(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Try to get slice position in mm (distance along viewPlaneNormal from origin)
|
||||||
|
if (typeof viewport.getSlicePlaneCoordinates === "function") {
|
||||||
|
const coords = viewport.getSlicePlaneCoordinates();
|
||||||
|
if (coords && typeof coords.position === "number") {
|
||||||
|
slicePosition = coords.position.toFixed(2) + " mm";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (viewportModes[viewportIdx] === "volume") {
|
|
||||||
console.log(viewport)
|
|
||||||
// For volume, get slice index and number of slices if available
|
|
||||||
if (typeof viewport.getSliceIndex === "function") {
|
|
||||||
currentIndex = viewport.getSliceIndex();
|
|
||||||
}
|
|
||||||
if (typeof viewport.getNumberOfSlices === "function") {
|
|
||||||
total = viewport.getNumberOfSlices();
|
|
||||||
}
|
|
||||||
// Get VOI from getProperties (may need to pass volumeId if multiple volumes)
|
|
||||||
if (typeof viewport.getProperties === "function") {
|
|
||||||
let props;
|
|
||||||
if (viewport.volumeIds && viewport.volumeIds.size > 0) {
|
|
||||||
// If multiple volumes, get the first one
|
|
||||||
const volumeId = Array.from(viewport.volumeIds)[0];
|
|
||||||
props = viewport.getProperties(volumeId);
|
|
||||||
} else {
|
|
||||||
props = viewport.getProperties();
|
|
||||||
}
|
|
||||||
if (props && props.voiRange) {
|
|
||||||
const { lower, upper } = props.voiRange;
|
|
||||||
windowCenter = ((upper + lower) / 2).toFixed(0);
|
|
||||||
windowWidth = (upper - lower).toFixed(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setImageInfos(prev => {
|
setImageInfos(prev => {
|
||||||
const next = [...prev];
|
const next = [...prev];
|
||||||
next[viewportIdx] = {
|
next[viewportIdx] = {
|
||||||
index: currentIndex + 1,
|
index: currentIndex + 1,
|
||||||
total,
|
total,
|
||||||
windowCenter,
|
windowCenter,
|
||||||
windowWidth,
|
windowWidth,
|
||||||
};
|
slicePosition, // add this field
|
||||||
return next;
|
};
|
||||||
});
|
return next;
|
||||||
}, [viewportModes]);
|
});
|
||||||
|
}, [viewportModes]);
|
||||||
|
|
||||||
|
|
||||||
const [gridBtnActive, setGridBtnActive] = useState(false);
|
const [gridBtnActive, setGridBtnActive] = useState(false);
|
||||||
@@ -918,7 +926,6 @@ const updateOverlay = useCallback((viewportIdx: number, viewport: any) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (viewportModes[i] === 'stack') {
|
if (viewportModes[i] === 'stack') {
|
||||||
//if (imageIds && !restoringStateRef.current) {
|
|
||||||
if (imageIds && imageIds.length > 0) {
|
if (imageIds && imageIds.length > 0) {
|
||||||
viewport.setStack(imageIds);
|
viewport.setStack(imageIds);
|
||||||
}
|
}
|
||||||
@@ -950,6 +957,16 @@ const updateOverlay = useCallback((viewportIdx: number, viewport: any) => {
|
|||||||
volume.load();
|
volume.load();
|
||||||
viewport.setVolumes([{ volumeId }]);
|
viewport.setVolumes([{ volumeId }]);
|
||||||
viewport.render();
|
viewport.render();
|
||||||
|
|
||||||
|
// Always (re-)attach overlay update for each viewport
|
||||||
|
if ((element)._overlayListener) {
|
||||||
|
// Remove previous listener if present
|
||||||
|
viewport.element.removeEventListener(IMAGE_RENDERED, (element)._overlayListener);
|
||||||
|
}
|
||||||
|
const overlayListener = () => updateOverlay(i, viewport);
|
||||||
|
viewport.element.addEventListener(IMAGE_RENDERED, overlayListener);
|
||||||
|
(element)._overlayListener = overlayListener;
|
||||||
|
updateOverlay(i, viewport);
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
viewport.render();
|
viewport.render();
|
||||||
@@ -991,7 +1008,6 @@ const updateOverlay = useCallback((viewportIdx: number, viewport: any) => {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Always (re-)attach overlay update for each viewport
|
// Always (re-)attach overlay update for each viewport
|
||||||
if ((element)._overlayListener) {
|
if ((element)._overlayListener) {
|
||||||
// Remove previous listener if present
|
// Remove previous listener if present
|
||||||
@@ -1001,8 +1017,14 @@ const updateOverlay = useCallback((viewportIdx: number, viewport: any) => {
|
|||||||
viewport.element.addEventListener(IMAGE_RENDERED, overlayListener);
|
viewport.element.addEventListener(IMAGE_RENDERED, overlayListener);
|
||||||
(element)._overlayListener = overlayListener;
|
(element)._overlayListener = overlayListener;
|
||||||
updateOverlay(i, viewport);
|
updateOverlay(i, viewport);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const activeVolumeViewports = [];
|
const activeVolumeViewports = [];
|
||||||
for (let i = 0; i < viewportGrid.rows * viewportGrid.cols; i++) {
|
for (let i = 0; i < viewportGrid.rows * viewportGrid.cols; i++) {
|
||||||
const viewportId = `CT_${i}`;
|
const viewportId = `CT_${i}`;
|
||||||
@@ -1369,17 +1391,17 @@ const updateOverlay = useCallback((viewportIdx: number, viewport: any) => {
|
|||||||
}
|
}
|
||||||
// Attach to window with a unique name
|
// Attach to window with a unique name
|
||||||
|
|
||||||
window[`getViewport_${apiKey}`] = (idx: number) => {
|
window[`getViewport_${apiKey}`] = (idx: number) => {
|
||||||
const renderingEngine = renderingEngineRef.current;
|
const renderingEngine = renderingEngineRef.current;
|
||||||
if (!renderingEngine) return undefined;
|
if (!renderingEngine) return undefined;
|
||||||
return renderingEngine.getViewport(`CT_${idx}`);
|
return renderingEngine.getViewport(`CT_${idx}`);
|
||||||
};
|
};
|
||||||
window[`getAllViewports_${apiKey}`] = () => {
|
window[`getAllViewports_${apiKey}`] = () => {
|
||||||
const renderingEngine = renderingEngineRef.current;
|
const renderingEngine = renderingEngineRef.current;
|
||||||
if (!renderingEngine) return [];
|
if (!renderingEngine) return [];
|
||||||
// Return all currently active viewports as an array
|
// Return all currently active viewports as an array
|
||||||
return Array.from({ length: MAX_VIEWPORTS }, (_, i) => renderingEngine.getViewport(`CT_${i}`)).filter(Boolean);
|
return Array.from({ length: MAX_VIEWPORTS }, (_, i) => renderingEngine.getViewport(`CT_${i}`)).filter(Boolean);
|
||||||
};
|
};
|
||||||
|
|
||||||
window[`jumpToSliceByImageId_${apiKey}`] = jumpToSliceByImageId;
|
window[`jumpToSliceByImageId_${apiKey}`] = jumpToSliceByImageId;
|
||||||
window[`resetViewer_${apiKey}`] = resetViewer;
|
window[`resetViewer_${apiKey}`] = resetViewer;
|
||||||
@@ -1454,9 +1476,9 @@ const updateOverlay = useCallback((viewportIdx: number, viewport: any) => {
|
|||||||
console.log("viewport", viewportId, "properties", p);
|
console.log("viewport", viewportId, "properties", p);
|
||||||
// --- Volume orientation and slice index ---
|
// --- Volume orientation and slice index ---
|
||||||
if (modes[i] === "volume") {
|
if (modes[i] === "volume") {
|
||||||
console.log("Getting orientation for viewport", i);
|
console.log("Getting orientation for viewport", i);
|
||||||
console.log("viewport.viewportProperties", viewport.viewportProperties);
|
console.log("viewport.viewportProperties", viewport.viewportProperties);
|
||||||
o = viewport.viewportProperties?.orientation || null;
|
o = viewport.viewportProperties?.orientation || null;
|
||||||
if (typeof viewport.getSliceIndex === "function") {
|
if (typeof viewport.getSliceIndex === "function") {
|
||||||
vIdx = viewport.getSliceIndex();
|
vIdx = viewport.getSliceIndex();
|
||||||
}
|
}
|
||||||
@@ -1528,19 +1550,19 @@ const updateOverlay = useCallback((viewportIdx: number, viewport: any) => {
|
|||||||
console.log("viewport.getImageIds", viewport.getImageIds?.());
|
console.log("viewport.getImageIds", viewport.getImageIds?.());
|
||||||
if (!importedImageIds.length) continue;
|
if (!importedImageIds.length) continue;
|
||||||
try {
|
try {
|
||||||
const viewportImageIds = viewport.getImageIds?.() || [];
|
const viewportImageIds = viewport.getImageIds?.() || [];
|
||||||
if (
|
if (
|
||||||
viewportImageIds.length !== importedImageIds.length ||
|
viewportImageIds.length !== importedImageIds.length ||
|
||||||
!viewportImageIds.every((id, idx) => id === importedImageIds[idx])
|
!viewportImageIds.every((id, idx) => id === importedImageIds[idx])
|
||||||
) {
|
) {
|
||||||
console.warn(
|
console.warn(
|
||||||
`Viewport ${i}: importedImageIds do not match viewportImageIds`,
|
`Viewport ${i}: importedImageIds do not match viewportImageIds`,
|
||||||
{ importedImageIds, viewportImageIds }
|
{ importedImageIds, viewportImageIds }
|
||||||
);
|
);
|
||||||
allReady = false;
|
allReady = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} catch(e) {
|
} catch (e) {
|
||||||
allReady = false;
|
allReady = false;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -2371,8 +2393,12 @@ const updateOverlay = useCallback((viewportIdx: number, viewport: any) => {
|
|||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
// Volume mode: do not show image position
|
|
||||||
<div>
|
<div>
|
||||||
|
Slice: {imageInfos[i]?.index} / {imageInfos[i]?.total}
|
||||||
|
{imageInfos[i]?.slicePosition && (
|
||||||
|
<span> ({imageInfos[i]?.slicePosition})</span>
|
||||||
|
)}
|
||||||
|
<br />
|
||||||
WC: {imageInfos[i]?.windowCenter} WW: {imageInfos[i]?.windowWidth}
|
WC: {imageInfos[i]?.windowCenter} WW: {imageInfos[i]?.windowWidth}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
Reference in New Issue
Block a user