| .. | ||
| metadata | ||
| plugins | ||
| CommandsManager.js | ||
| HotkeysContext.js | ||
| HotkeysManager.js | ||
| ImageSet.js | ||
| index.js | ||
| MetadataProvider.js | ||
| OHIFError.js | ||
| OHIFStudyMetadataSource.js | ||
| OHIFStudySummary.js | ||
| README.md | ||
| ResizeViewportManager.js | ||
| StackImagePositionOffsetSynchronizer.js | ||
| StudyLoadingListener.js | ||
| StudyMetadataSource.js | ||
| StudyPrefetcher.js | ||
| TypeSafeCollection.js | ||
Table of contents
In this document, some important objects are described. In the files there are comments that can help better undestand their methods and properties.
The Resize Viewport Manager object
This object has multiple functions to manage window resize event. It relocates Dialogs, resizes viewport elements and scrollbars and some other UI components such as Study and Series Quick Switch, when available.
Usage
It's only necessary to bind handleResize function to the window resize event as follows. The ohif:viewerbase package needs to be imported by the referring code as well.
import { Viewerbase } from 'meteor/ohif:viewerbase';
const ResizeViewportManager = new Viewerbase.ResizeViewportManager();
window.addEventListener('resize', ResizeViewportManager.getResizeHandler());
An example os its usage can be found in ohif-viewerbase/client/components/viewer/viewerMain/viewerMain.js.
The Image Set object
An object that represents a list of images that are associated by any arbitrary criteria being thus content agnostic. Besides the main attributes (images and uid) it allows additional attributes to be appended to it (currently indiscriminately, but this should be changed).
Usage
ImageSet constructor requires an array of SOP instances like in the example below. It's necessary to import ohif:viewerbase.
import { Viewerbase } from 'meteor/ohif:viewerbase';
const imageSet = new Viewerbase.ImageSet(sopInstances);
imageSet.setAttributes({
displaySetInstanceUid: imageSet.uid,
seriesInstanceUid: seriesData.seriesInstanceUid,
seriesNumber: seriesData.seriesNumber,
seriesDescription: seriesData.seriesDescription,
numImageFrames: instances.length,
frameRate: instance.getRawValue('x00181063'),
modality: seriesData.modality,
isMultiFrame: isMultiFrame(instance)
});
// Sort instances by InstanceNumber (0020,0013)
imageSet.sortBy((a, b) => {
return (parseInt(a.getRawValue('x00200013', 0)) || 0) - (parseInt(b.getRawValue('x00200013', 0)) || 0);
});
Each SOP instance in this example is an instance of OHIFInstanceMetadata object, which is a specialization of InstanceMetadata. To read more about the Metadata API click here.
The Layout Manager object
Objects of this class are responsible for creating, organizing and maintaining (manage) viewport rendering. It creates a grid, positioning viewports accordingly to it's configuration keeping all viewports data (in viewportData property) for easy access from other components. It support many layout configurations and some of them were fully tested: 1x1, 1x2, 1x3, 2x1, 2x2, 2x3, 3x1, 3x2, 3x3. Other configurations may work as well. Finally it provides some useful functions to move through viewports and zoom it.
Usage
In order to use LayoutManager the ohif:viewerbase package needs to be imported by the referring code and instantiated as follows. An example os its usage is in ohif-viewerbase/client/components/viewer/viewerMain/viewerMain.js.
import { Viewerbase } from 'meteor/ohif:viewerbase';
// Get an array of studies object. This function needs to be implemented, it does not exist.
const studies = getArrayOfStudiesObjects();
const parentElement = document.getElementById('layoutManagerTarget');
const LayoutManager = new Viewerbase.LayoutManager(parentElement, studies);
The default configuration is 1x1, and to change it just set layoutProps and call updateViewports to update the layout as follows.
import { Viewerbase } from 'meteor/ohif:viewerbase';
// Get an array of studies object. This function needs to be implemented, it does not exist.
const studies = getArrayOfStudiesObjects();
const parentElement = document.getElementById('layoutManagerTarget');
const LayoutManager = new LayoutManager(parentElement, studies);
// Set the layout proprerties to 2x2 layout
LayoutManager.layoutProps = {
rows: 2,
columns: 2
};
// It will render four viewports: two in each row.
LayoutManager.updateViewports();
The layoutManagerTarget element will have a new class layout-2-2 (to allow further styling) and it's inner content will a new div#imageViewerViewports that has four inner elements like the following (some elements and attributes were removed for example purpose):
<div class="viewportContainer active" style="height:50%; width:50%;">
<div class="removable">
<div class="imageViewerViewport">
<canvas></canvas>
</div>
<div class="imageViewerViewportOverlay"></div>
<div class="imageViewerLoadingIndicator"></div>
<div class="imageViewerErrorLoadingIndicator"></div>
<div class="viewportOrientationMarkers"></div>
</div>
</div>
Each of this div.viewportContainer will have some classes to help CSS specific styling accordingly to the element's position in the grid: top, middle and bottom. This classes are added by viewer/components/gridLayout/ component in ohif-viewerbase package.
The Type Safe Collections
With the introduction of the new Study Metadata API in which study metadata is represented by class hierarchies (using prototype-based inheritance), the usage of standard Minimongo collections as a central client-side storage for this data became no longer an option. Standard Mongo and Minimongo collections internally flatten data (in other words, data gets serialized) before storage hence no functions or prototype chains are preserved. In that scenario, when an object is restored (fetched), what is returned is actually a flattened copy of the original object with no functions or prototype (it's no longer an instance of it's original class). As an attempt to overcome this limitation a new type of collection was intruduced: the TypeSafeCollection.
The TypeSafeCollection is a simple list-like collection which tries to implement an API similar but not compatible with Mongo's API. It supports basic features like search by attribute map and ID, retrieval by index, sorting of result sets, insertion, removal and reactive operations but, unlike Mongo's API, it (still) lacks support to advanced functionality like complex search criterea or flexible sorting options.
Implementation
The TypeSafeCollection is implemented on top of the JavaScript Array object. Each element inserted in the collection is appended to the end of its internal array as a key-value pair (KVP) object where the key is a unique randomly generated ID string and the value is the element itself. Once the object has been successfully stored, the generated ID (its ID) is returned to the client code and can later be used to access that specific element. At this point, an important difference to the Minimongo API can be highlighted: a TypeSafeCollection instance will never make any changes to the stored element (e.g., no "_id" property will ever be assigned to the original object). Another relevant feature that is supported by this design decision is that not only objects can be stored in this collections, but literally anything.
Inside the codebase, the value attribute of each KVP entry in the collection is refered to as the payload of the entry since it's what really matters to the user. Hence, this term will also be used here to refer to the value that has been stored in the collection. That being said, we can approach another important feature of these collections: A single payload cannot be stored more than once in a given collection. When an attempt of inserting a payload which is already present in the collection is detected, the insert operation will fail and null will be returned. In that regard, the collection behaves like Set object not permitting a payload to be stored more than once. Strict equality is used when comparing payloads, thus cloned objects are not considered the same. This feature adds an additional garantee that a given study/series/instance will not be listed more than once (it was designed as a replacement for central study collections which were always checked for duplicates).
Please refer to the codebase for the full TypeSafeCollection API.
Usage
In order to use the TypeSafeCollection class, the ohif:viewerbase package needs to be imported by the referring code and instantiated as follows:
import { Viewerbase } from 'meteor/ohif:viewerbase'; // i.e., Viewerbase.TypeSafeCollection
OR
import { OHIF } from 'meteor/ohif:core';
import 'meteor/ohif:viewerbase'; // i.e., OHIF.viewerbase.TypeSafeCollection
// The later is preferred when the client code already makes use of the "OHIF" namespace making the second
// "import" a garantee that the ".viewerbase" namespace has been properly loaded.
A few usage examples:
const Users = new OHIF.viewerbase.TypeSafeCollection();
[[ ... ]]
// Insert a User object...
let userId = Users.insert({
data: {
firstName: 'John',
lastName: 'Doe',
age: 45
},
getFullName() {
return `${this.data.firstName} ${this.data.lastName}`;
},
getAge() {
return this.data.age;
}
});
[[ ... ]]
let theUserWeJustStored = Users.findById(userId); // ;-)
[[ ... ]]
// Retrieve a single user with "Doe" as `lastName`...
let myUser = Users.findBy({ 'data.lastName': 'Doe' });
// Or all users with "Doe" as `lastName`, sorted by `firstName` in ascending
// order and using the `age` attribute to break ties in descending order...
let myUsers = Users.findAllBy({ 'data.lastName': 'Doe' }, {
sort: [ [ 'data.firstName', 'asc' ], [ 'data.age', 'desc' ] ]
});