I'm currently successfully displaying a stack of images in a React component but am unsure where to place an event listener in order to access the currentImageIdIndex when scrolling.

import React, { useEffect, useRef, useCallback } from "react";
import cornerstone from "cornerstone-core";
import cornerstoneMath from "cornerstone-math";
import cornerstoneTools from "cornerstone-tools";
import cornerstoneFileImageLoader from "cornerstone-file-image-loader";
import Hammer from "hammerjs";

function StackImageViewport(props) {
  const viewerRef = useRef(null);

  const base64StringToArrayBuffer = useCallback((base64) => {
    var binary_string = window.atob(base64);
    var len = binary_string.length;
    var bytes = new Uint8Array(len);
    for (var i = 0; i < len; i++) {
      bytes[i] = binary_string.charCodeAt(i);
    }
    return bytes.buffer;
  }, []);

  const initializeCornerstone = () => {
    // Initialise cornerstone and link to DOM element
    cornerstoneTools.external.cornerstone = cornerstone;
    cornerstoneTools.external.cornerstoneMath = cornerstoneMath;
    cornerstoneFileImageLoader.external.cornerstone = cornerstone;
    cornerstoneTools.external.Hammer = Hammer;
    cornerstoneTools.init();
    cornerstone.enable(viewerRef.current);
  };

  const setCornerstoneTools = () => {
    // define Cornerstone Tools
    const StackScrollTool = cornerstoneTools.StackScrollTool;
    const StackScrollMouseWheelTool =
      cornerstoneTools.StackScrollMouseWheelTool;
    const WindowingTool = cornerstoneTools.WwwcTool;

    // Add tools

    cornerstoneTools.addTool(StackScrollTool);
    cornerstoneTools.addTool(StackScrollMouseWheelTool);
    cornerstoneTools.addTool(WindowingTool);

    // set tools to Active state
    cornerstoneTools.setToolActive("StackScroll", { mouseButtonMask: 1 });
    cornerstoneTools.setToolActive("StackScrollMouseWheel", {});
    cornerstoneTools.setToolActive("Wwwc", { mouseButtonMask: 2 });
  };

  const displayStack = (stackMediaArray) => {
    let mediaArray = [];


    // 'stackMediaArray' is an array of images, each containing a buffer of the image
    Promise.all(
      stackMediaArray.map((mediaObject) => {
        return new Promise((resolve, reject) => {
          let imageBuffer = base64StringToArrayBuffer(mediaObject.buffer);
          const imageId =
            cornerstoneFileImageLoader.fileManager.addBuffer(imageBuffer);
          mediaArray.push(imageId);

          resolve(mediaObject);
        }).catch(console.error);
      })
    );

    //define the stack
    const stack = {
      currentImageIdIndex: 0,
      imageIds: mediaArray,
    };

    // load images and set the stack
    cornerstone.loadAndCacheImage(mediaArray[0]).then((image) => {
      cornerstone.displayImage(viewerRef.current, image);
      cornerstoneTools.addStackStateManager(viewerRef.current, ["stack"]);
      cornerstoneTools.addToolState(viewerRef.current, "stack", stack);
    });

    setCornerstoneTools();
  };

  useEffect(() => {
    if (!viewerRef.current) {
      return;
    }
    initializeCornerstone();
    displayStack(props.stackMediaArray);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [viewerRef]);

  return (
    <>
      <div ref={viewerRef} id="viewer" className="flex h-1/2-screen"></div>
    </>
  );
}

export default StackImageViewport;

This attempts to answer the question:

https://github.com/cornerstonejs/cornerstoneTools/issues/1121

however, I don't want to access DOM elements to add the event listener to.

It's also clear that events are accessible in Cornertsone.js:

https://github.com/cornerstonejs/cornerstoneTools/blob/master/src/events.js

... but I'm still not sure where to place the event listener ?

Any help would be much appreciated.

Thanks.

1

There are 1 answers

2
Francisco Maria Calisto On BEST ANSWER

Listening to events in ReactJS might be confusing for someone new, even more, when using a new tool such as CornerstoneJS. However, you can create an event listener by using the window.addEventListener method, just like you would in a Vanilla JavaScript. Note that this might change from browser to mobile environments. Moreover, your cornerstoneFileImageLoader can also be a challenge.

For this purpose, you can follow the structure:

window.addEventListener('keydown', (event) => {
    ...
});

But now, we need to understand "where" to place it. Imagine that all of your pages are just components, as ReactJS is a component-based system. Meaning that the event listener need to happen inside the component.

For instance, you can do like that:

import React from 'react';

const App = (props) => {
  window.addEventListener('keydown', (event) => {
      ...
  });
  return (
    <div className='container'>
      <h1>Welcome to the Keydown Listening Component</h1>
    </div>
  );
};