2D Example app

2D Example app

This example describes how to load a DICOM dataset into a 2D viewport, as a stack of images rather than a volume.  This can also be used to load any 2D modality, including CR, DR, DX, MG, US, XA, or any other imaging modality.  Similar design patterns are used as was described in 3D Example app.  Be sure to open the JavaScript console to look at various printouts to better understand the object model.

HelloFoviaDetail

This example includes
  •  use of scanDICOMDir to return a list of available studies/series
  •  use of Fovia.UI.HTMLViewport2D  for rendering contents
  •  use of onImageMetaDataReceived callback to access information on the rendered frame
  •  use of onDrawCallback to draw a DICOM overlay on the rendered frame
The same techniques as described in 3D Example app can be used to describe how to use:
  •  setMouseAdaptor to chagne default mouse behavior
  •  setCustomMouseAdaptor to create custom voxel value mouse adaptor
  •  setOverrideMouseAdaptor to create a hotspot in the window to reset the viewport
  •  use of a resize handler to respond to windows resize events
View source /foviaserver/public/apps/hellofovia/2d.js

To run the example, click on the local link of http://localhost:8088/apps/hellofovia/2d.html

Loading Data


Fovia.ServerContext.scanDICOMDir(directoryPath) is used to parse the directory and returns a JSON object that describes the DICOM structure of all files in the directory.  By reading the JSON tree structure, a user interface can be built that allows the user to select which study/series to load. 

Review the ScanDirResults in the web console for these lines:

// print out the study details for each study found
for (var i = 0; i < scanDirResults.getNumStudies(); i++) {
   console.log("ScanDirSeriesResults[" + i + "]");
   console.log(scanDirResults.findStudy(i));
}


Each study contains one or more ScanDirSeriesResults for each DICOM series, which includes the seriesInstanceUID, the dicomSeries (SeriesDataContext), and a property containsSubSeries.  If containsSubSeries is true, an array of subSeries(SeriesDataContext) objects is available that organizes the DICOM series into chunks based the internal splitting logic, review DICOM Splitting for more details. 

HTML2DViewport


The above code created a Fovia.UI.HTMLViewport2D that is associated an HTML canvas object with a Fovia.renderEngine2D.  It is the resonsibility of the HTMLViewport to paint a returned image onto the HTML canvas, draw other elements (such as annotation, DICOM overlay, crosss-reference lines, etc.), and manage and respond to mouse/touch event.

The constructor is synchronous call, and take the HTML canvas name, viewport width/height, as well as an optional boolean to indicate if the viewport is repaintable.  If it is repaintable, an internal copy of the last rendered image is preserved so the client can initiate a repaint(), which causes the last rendered image to be painted on the canvas, and allows the client application to trigger a redraw of the canvas without a round trip to the server.

After construction, an asynchronous call is made to init that associates the seriesDataContext with the viewport.  There are two optional callbacks that can be assocated wth this object, specifically the onDrawCallback and onMetaDataReceived.  These are called each time an image is returned from the server.  These will be described below.

The last line triggers a renderFinal operation, which internally updates the canvas with the new rendered image.  Unlike 3D/MPR viewports, the render/image quality and performance due to calls to render and renderFinal only effect the compression encoding.  render will always use the higher compression interactiveJPEG quality setting, while the renderFinal will use either the finalJPEG quality setting or lossless compressed PNG, based on the Server Configuration Settings.


// create a 2D viewport using the full browser window (synchronous call)
var viewport = new Fovia.UI.HTMLViewport2D("fovia", 512, 512);

// initialize the viewport with the first series, and once this is
// complete, trigger a renderFinal to generate the image
viewport.init(sdc, onDrawCallback, onImageMetaDataReceived).then(function () {
    viewport.renderFinal();
});


onMetaDataReceived and onDrawCallback


The Fovia.UI.HTMLViewportD.init call takes two callbacks.  The onMetaDataReceived in called as soon an an image is returned from the server, but before it is drawn on the canvas.  This call gives the application a chance to capture date related to the frame that may be useful for on-screen drawing, or trigger additional events to other viewports / rendering engines.  The onDrawCallback is called at the end of the rendering pipeline, after the image is drawn onto the canvas.  This allows the application to draw onto the HTML canvas (and overtop of the image). 
var onImageMetaDataReceived = function (data) {
    // data.dicomTags -- dicom tags associated with this image. (Image-level DICOM Tags)
    // data.imageStats -- internal time to create intermediate/final image, and the PNG/JPG image
    // data.
renderParams -- Fovia.renderParams2D used to create the image
    // data.scrollObject -- spacing and currentSlice out of totalSlice when navigating in slab/MPR mode
    // data.viewport -- the Fovia.UI.HTMLViewport2D for which this image will be drawn into
    // data.seriesDataContext -- seriesDataContext used to create this image
}

The onDrawCallback in this example drawn patient demographics, and specific image information, as well as the command key instructions at the bottom of the viewport.

var onDrawCallback = function (htmlFoviaViewport, canvas, width, height, onDrawCallbackComplete) {
    //
htmlFoviaViewport -- the Fovia.UI.HTMLViewport3D for which the image will be drawn into.  The
    // client most likely has its own refernce to this object, but is was returned for completeness
    // width / height -- size of the associated htmlViewport and canvas
    // canvas -- HTML Canvas object for which this image will be drawn into, and how the appplicaiton will
    // get the context for its drawing.  Do not try to get this directly from the htmlViewport since in the
    // cases of double buffer, the canvas may be a double buffer and not the actual screen context
    var context = canvas.getContext("2d");
    // this MUST be the last statement executed so the client API knows all rendering of this frame
    // is complete.  If the application implements the
onDrawCallback asynchronously, it is most likely
    // the case
onDrawCallbackComplete should occur be invoked once all client drawing is complete.  If
    // this is a double buffer viewport, this is the only way the client API knows drawing is complete and
    // that it is safe to copy the double buffer into the screen canvas.
    onDrawCallbackComplete();
}