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

Switching between multiple images #1712

Open
stylekilla opened this issue Jul 18, 2024 · 4 comments
Open

Switching between multiple images #1712

stylekilla opened this issue Jul 18, 2024 · 4 comments
Labels
question Further information is requested
Milestone

Comments

@stylekilla
Copy link

stylekilla commented Jul 18, 2024

Hi ivmartel,

Nice work on creating and maintaining DWV.
I've been trying to get dwv (through npm install, v0.33) to work as a simple dicom image viewer in react (v18), but I'm having some trouble and was hoping to get some help.

I have read all of your documentation, the examples, and explored the provided dwv-react git repo.
Admittedly, I have found the documentation somewhat difficult to follow (both javascript and react are fairly new to me).

I have three independent dicom images that I want to view one at a time, changing the image .
I have generated three buttons that each pass their ID to the DWV component as a prop (see below).
The images render, but instead of overwriting what is in the layerGroup it creates a new layer within the group and I end up with three div's each with an id of layerGroup0-layer0 (see below).

Is there something basic I have missed about how DWV works?
I also can't workout why the size of each image double the size of the previous.

Any help is appreciated,
Thank you.

import React, { useEffect } from 'react';

import * as dwv from 'dwv';


export default function DvwComponent(props) {
  var app = new dwv.App();
  var options = new dwv.AppOptions();
  var viewConfig = new dwv.ViewConfig("layerGroup0");
  viewConfig.colourMap = "plain";
  viewConfig.opacity = 1;

  options.viewOnFirstLoadItem = true;
  options.dataViewConfigs = {'*': [viewConfig]};

  app.init(options);

  useEffect(() => {
    app.loadImageObject([props.imageObjects[props.currentImageIndex]]);
  }, [props.currentImageIndex])

  return (
    <div id="dwv">
      <div id="layerGroup0" className="layerGroup"></div>
    </div>
  )
}

Updating props.currentImageIndex three times gives:

<div id="dwv">
  <div id="layerGroup0" class="layerGroup">
    <div id="layerGroup0-layer-0" class="layer viewLayer" style="pointer-events: none;">
      <canvas width="1629" height="154"></canvas>
    </div>
    <div id="layerGroup0-layer-0" class="layer viewLayer" style="pointer-events: none;">
      <canvas width="1629" height="312"></canvas>
    </div>
    <div id="layerGroup0-layer-0" class="layer viewLayer" style="pointer-events: none;">
      <canvas width="1629" height="628"></canvas>
    </div>
  </div>
</div>
@ivmartel ivmartel added the question Further information is requested label Jul 18, 2024
@ivmartel ivmartel added this to the 0.34.0 milestone Jul 18, 2024
@stylekilla
Copy link
Author

stylekilla commented Jul 19, 2024

I'm not sure if it's helpful but I thought I would provide some additional information.
Say I have 3 images in the form imageObjects = [{ name: str, filename: str, data: ArrayBuffer }, ..., ...], when I use app.loadImageObject([props.imageObjects]) I would expect the app to create three new dataIdss: ['0', '1', '2'].
Doing some digging, it seems as though it should at least return one dataId (as per code from src/app/application.js:780 noted below).
Instead, if I run app.getDataIds(); after loading my image data, I get an empty list [].

loadImageObject = (data) => {
  // Get new data id
  const dataId = this.#dataController.getNextDataId();
  this.#loadController.loadImageObject(data, dataId);
};

However, if I only load ONE image (instead of three) then it returns ['0'], and then each time I load a new image I get the aforementioned behaviour of having multiple divs with the same properties but a different image, each div doubling in height.

Another question: when submitting three images in one action to be loaded and with only one dataId value being created, how do I access each of the three images I uploaded?

@ivmartel
Copy link
Owner

Hi, thanks for trying dwv!
The layerGroup is meant to display similar images on top of each others with some opacity at each layer. I created a fiddle as a simple example: https://jsfiddle.net/ivmartel/pvghxj1y/. The same data is loaded twice, you can toggle them by changing their opacity. Careful if you load un-related data, dwv shows data at a given position, if both images are not at that same position, one will be blank.
Regarding dataIds, the app.load methods load multiple buffers that make one data, typically these buffers are the different slices of that data. If you want to load different data, you have to call a load method for each.
The 'div doubling' must be related to your html/css, in order to display data on top of each other, the .layer class must have position: absolute;.

@ivmartel
Copy link
Owner

Hi @stylekilla, did you make some progress with your issue?

@stylekilla
Copy link
Author

stylekilla commented Sep 12, 2024

Hi @ivmartel, I did actually make some progress in the last 24 hours! It's been a whirlwind two months of doing everything except this, so your timing to ask for an update is impeccable.

Thank you for your example code and the clarification re the app.load methods.

I ended up handling the viewer with the following code. Grabbing the DOM element and setting the inner html to empty was the only way I could get it to work.

import React, { useEffect, useRef } from 'react';
import * as dwv from 'dwv';

export default function DwvComponent(props) {
  // Ref to store the dwv.App instance
  const appRef = useRef(null);
  const containerRef = useRef(null);

  useEffect(() => {
    // Initialize dwv.App only once
    if (!appRef.current) {
      const app = new dwv.App();
      const options = new dwv.AppOptions();
      const viewConfig = new dwv.ViewConfig("layerGroup0");

      viewConfig.colourMap = "plain";
      viewConfig.opacity = 1;

      options.viewOnFirstLoadItem = true;
      options.dataViewConfigs = {'*': [viewConfig]};

      app.init(options);
      appRef.current = app;
    }

    const app = appRef.current;

    // Cleanup previous content before loading new image
    const layerGroupElement = document.getElementById("layerGroup0");
    if (layerGroupElement) {
      layerGroupElement.innerHTML = '';
    }

    // Load image object when currentImageIndex changes
    if (props.imageObjects.length > 0) {
      const currentImage = props.imageObjects[props.currentImageIndex];
      if (currentImage) {
        app.loadImageObject([currentImage]);
      }
    }

    return () => {
      // Clean up the dwv.App instance if needed
    };
  }, [props.currentImageIndex, props.imageObjects]);

  return (
    <div id="dwv" ref={containerRef}>
      <div id="layerGroup0" className="layerGroup" style={{ width: '100%', height: '80vh' }}></div>
    </div>
  );
}

And the props.imageObjects are in the format:

const imageObject = {
  name: modality,
  filename: location.state.name,
  data: buffer,
};

I'm yet to do anything more complicated with the images (I want to add Window/Level sliders), but hopefully that is more straight forward now that I have something basic working.

Thanks again for your help.

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

No branches or pull requests

2 participants