Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(grid): remove viewportIndex and only rely on viewportId #3591

Merged
merged 33 commits into from
Aug 30, 2023

Conversation

sedghi
Copy link
Member

@sedghi sedghi commented Aug 9, 2023

Context

During the development of OHIF, the reliance on viewport index has proven to be problematic. This issue has seen in several ways:

  • Inconsistent Viewport Indexing with Layout Changes: A change from a 2x2 to a 3x3 grid alters the viewport index, causing unnecessary re-rendering, even though the display sets remain the same. This has resulted in a lack of optimization in grid rendering during stage and layout changes.

  • Viewport Movement Problems: for moving a viewport (similar to moving a person's window in Zoom, which we have in plan to support in future), the change in viewport index forces React to re-render the whole grid (as right now we have the key as viewportIndex). While the element itself hasn't changed, the viewport index change causes a problematic full re-render.

Changes Made

  • Removed Viewport Index: All occurrences of the viewport index have been replaced with viewportId. This prevents the above issues related to the inconsistency of the viewport index.
  • Changed Viewport Grid State: The viewport grid state has been modified from an array to a map, using viewport IDs as keys. This provides a more stable mapping of viewports.

Migration Guide

You should not rely on viewportIndex and activeViewportIndex anymore.

Instead try

const { activeViewportId, viewports } = viewportGridService.getState() OR useViewportGrid()

Viewports also has been changed from an array to a Map

viewports: new Map(
    Object.entries({
      default: {
        viewportId: 'default',
        displaySetInstanceUIDs: [],
        viewportOptions: {
          viewportId: 'default',
        },
        displaySetSelectors: [],
        displaySetOptions: [{}],
        x: 0, // left
        y: 0, // top
        width: 100,
        height: 100,
        viewportLabel: null,
      },
    })
  ),

So you need to viewports.get(viewportId instead of viewports[viewportIndex]

Testing

The implemented changes have been tested, and the following features are working as expected:

  • Rendering a default viewport
  • Rendering a TMTV
  • Rendering segmentation and RT struct
  • Enabling double-click on a thumbnail
  • Changing layout, going MPR, adding measurements
  • Toggle One Up works
  • Viewport Labels (ABCD) works
  • Presentation States is preserved
  • Change from 2x2 to 3x3 works

Cheers

@netlify
Copy link

netlify bot commented Aug 9, 2023

Deploy Preview for ohif-platform-docs ready!

Name Link
🔨 Latest commit 50d0d1e
🔍 Latest deploy log https://app.netlify.com/sites/ohif-platform-docs/deploys/64efa069daf4fd00087a860e
😎 Deploy Preview https://deploy-preview-3591--ohif-platform-docs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

@netlify
Copy link

netlify bot commented Aug 9, 2023

Deploy Preview for ohif-dev ready!

Name Link
🔨 Latest commit 50d0d1e
🔍 Latest deploy log https://app.netlify.com/sites/ohif-dev/deploys/64efa0699eb45100078023c7
😎 Deploy Preview https://deploy-preview-3591--ohif-dev.netlify.app/
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

@sedghi sedghi marked this pull request as draft August 9, 2023 21:03
@sedghi sedghi changed the title fix/remove viewportIndex feat(grid): remove viewportIndex and only rely on viewportId Aug 9, 2023
@sedghi sedghi marked this pull request as ready for review August 14, 2023 19:39
throw new Error('Should have viewport ID afterwards');
}

public enableViewport(viewportId: string, elementRef: HTMLDivElement): void {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why doesn't this have the viewport options any longer - are those always already provided?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we were only using viewportOptions to grab viewportId, so just using viewportId now

@sedghi
Copy link
Member Author

sedghi commented Aug 23, 2023

@jbocce Thanks for thorough review, applied/fixed based on your comment

@jbocce
Copy link
Contributor

jbocce commented Aug 24, 2023

@sedghi
Copy link
Member Author

sedghi commented Aug 24, 2023

@jbocce applied all three comments

@sedghi
Copy link
Member Author

sedghi commented Aug 24, 2023

@jbocce I think I got it working for the double click too

@jbocce
Copy link
Contributor

jbocce commented Aug 25, 2023

@jbocce I think I got it working for the double click too

Yes. Thank you for that. See my comments.

@sedghi sedghi requested a review from jbocce August 25, 2023 13:15
Copy link
Contributor

@jbocce jbocce left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved.

Copy link
Contributor

@wayfarer3130 wayfarer3130 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are some smallish changes, and a couple of questions, but I think this is important enough that we should proceed on it.
If you decide to include any of the fixes, that is great, but otherwise I wouldn't worry about them - you decide which comments are still worth applying.

const nextViewportIndex = (activeViewportIndex + 1) % viewports.length;
viewportGridService.setActiveViewportIndex(nextViewportIndex);
const { activeViewportId, viewports } = viewportGridService.getState();
const nextViewportIndex = (activeViewportId + 1) % viewports.size;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about adding get viewport ids function that returns a list, and takes an optional sorting parameter. Then you still setActiveViewportId, but you provide it an actual viewport - and you can decide based on the mode or extension how things get sorted. That is, implement in the service itself, based on the getState call:
getViewportIds(sortFunction) {
return [...getState().viewports].map(viewport => viewport.viewportId).sort(sortFunction)
That says nothing about indices, just gets the ids of interest. You could add a filter function to it too.

import viewportLabels from '../utils/viewportLabels';

const DEFAULT_STATE = {
activeViewportIndex: 0,
interface Viewport {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add export types on the interfaces?

platform/ui/src/contextProviders/ViewportGridProvider.tsx Outdated Show resolved Hide resolved
if (setActiveViewportIndexImplementation) {
this.serviceImplementation._setActiveViewportIndex =
setActiveViewportIndexImplementation;
if (setActiveViewportIdImplementation) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might consider:
this.serviceImplementation._setActiveViewport = setActiveViewportIdImplementation || this.serviceImplementation._setActiveViewport;

@@ -16,12 +16,18 @@ describe('OHIF Double Click', () => {
.should('be.eq', numExpectedViewports);

for (let i = 0; i < numExpectedViewports; i += 1) {
cy.wait(2000);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you merge the CINE fix in CS3D, then this wait gets removed and you just do a waitDicomImage() above line 18.
I'd really like to see it do waitDicomImage instead of cy.wait as it is much more reliable, and is fast on fast systems, and slow on slower connections.

}
displaySet,
seriesMatchingRules,
// Todo: why we have images here since the matching type does not have it
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need the actual instance any longer.

...(updatedViewport.viewportOptions ||
previousViewport.viewportOptions),
};
const viewportOptions = merge(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this need a real merge? It feels like it might cause mixtures that aren't intended, where one version has a value for key A, and the next one has a value for keyB, but doesn't specifically null out keyA, then keyA still applies.
Not saying it doesn't, just asking.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is fine

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants