[WIP] Moving ViewerStudies collection to TypeSafeCollection implementation + Fixing sorting bug in findAllBy method in TypeSafeCollection

This commit is contained in:
Emanuel F. Oliveira 2017-01-17 17:32:42 -02:00
parent a4e7aa86ab
commit d25141f336
18 changed files with 143 additions and 77 deletions

View File

@ -64,13 +64,16 @@ Template.viewer.onCreated(() => {
// Set lesion tool buttons as disabled if pixel spacing is not available for active element
instance.autorun(OHIF.lesiontracker.pixelSpacingAutorunCheck);
// Update the ViewerStudies collection with the loaded studies
ViewerStudies.remove({});
// @TypeSafeStudies
debugger;
// Update the OHIF.viewer.Studies collection with the loaded studies
OHIF.viewer.Studies.removeAll();
instance.data.studies.forEach(study => {
study.selected = true;
study.displaySets = OHIF.viewerbase.createStacks(study);
ViewerStudies.insert(study);
OHIF.viewer.Studies.insert(study);
});
instance.data.timepointApi = new OHIF.measurements.TimepointApi(instance.data.currentTimepointId);

View File

@ -48,8 +48,11 @@ Template.viewer.onCreated(() => {
Session.set('activeViewport', ViewerData[contentId].activeViewport || 0);
// Update the ViewerStudies collection with the loaded studies
ViewerStudies.remove({});
// @TypeSafeStudies
debugger;
// Update the OHIF.viewer.Studies collection with the loaded studies
OHIF.viewer.Studies.removeAll();
ViewerData[contentId].studyInstanceUids = [];
instance.data.studies.forEach(study => {
@ -57,7 +60,7 @@ Template.viewer.onCreated(() => {
study.displaySets = OHIF.viewerbase.createStacks(study);
// const studyMetadata = new OHIF.metadata.StudyMetadata(study);
// study.displaySets = OHIF.viewerbase.sortingManager.getDisplaySets(studyMetadata);
ViewerStudies.insert(study);
OHIF.viewer.Studies.insert(study);
ViewerData[contentId].studyInstanceUids.push(study.studyInstanceUid);
});

View File

@ -135,16 +135,22 @@ function getActiveViewportImageId() {
}
function getAbstractPriorValue(imageId) {
const currentStudy = ViewerStudies.findOne({}, {
sort: {
studyDate: -1
},
limit: 1
// @TypeSafeStudies
debugger;
// @TODO: Implement MIN and MAX methods in TypeSafeCollection
// const currentStudy = ViewerStudies.findOne({}, {
// sort: {
// studyDate: -1
// },
// limit: 1
// });
const allStudies = OHIF.viewer.Studies.all({
sort: [ ['studyDate', 'desc'] ]
});
if (!currentStudy) {
if (allStudies.length < 1) {
return;
}
const currentStudy = allStudies[0];
const priorStudy = cornerstoneTools.metaData.get('study', imageId);
if (!priorStudy) {

View File

@ -403,7 +403,10 @@ HP.ProtocolEngine = class ProtocolEngine {
return;
}
var alreadyLoaded = ViewerStudies.findOne({
// @TypeSafeStudies
debugger;
var alreadyLoaded = OHIF.viewer.Studies.findBy({
studyInstanceUid: priorStudy.studyInstanceUid
});
@ -411,7 +414,7 @@ HP.ProtocolEngine = class ProtocolEngine {
getStudyMetadata(priorStudy.studyInstanceUid, study => {
study.abstractPriorValue = abstractPriorValue;
study.displaySets = OHIF.viewerbase.sortingManager.getDisplaySets(study);
ViewerStudies.insert(study);
OHIF.viewer.Studies.insert(study);
this.studies.push(study);
this.matchImages(viewport);
this.updateViewports();

View File

@ -170,7 +170,7 @@ const FrameLevelMeasurement = new SimpleSchema([
min: 0,
label: 'Frame index in Instance'
},
// TODO: In the future we should remove this in favour of searching ViewerStudies and display sets when
// TODO: In the future we should remove this in favour of searching OHIF.viewer.Studies and display sets when
// re-displaying measurements. Otherwise if a study moves servers the measurements will not be displayed correctly
imageId: {
type: String,

View File

@ -1,5 +1,6 @@
import { $ } from 'meteor/jquery';
import { OHIF } from 'meteor/ohif:core';
import 'meteor/ohif:viewerbase';
function findAndRenderDisplaySet(displaySets, viewportIndex, studyInstanceUid, seriesInstanceUid, sopInstanceUid, renderedCallback) {
// Find the proper stack to display
@ -29,8 +30,12 @@ function findAndRenderDisplaySet(displaySets, viewportIndex, studyInstanceUid, s
}
function renderIntoViewport(viewportIndex, studyInstanceUid, seriesInstanceUid, sopInstanceUid, renderedCallback) {
// @TypeSafeStudies
debugger;
// First, check if we already have this study loaded
const alreadyLoadedStudy = ViewerStudies.findOne({studyInstanceUid});
const alreadyLoadedStudy = OHIF.viewer.Studies.findBy({ studyInstanceUid });
if (alreadyLoadedStudy) {
// If the Study is already loaded, find the display set and render it
@ -47,10 +52,12 @@ function renderIntoViewport(viewportIndex, studyInstanceUid, seriesInstanceUid,
OHIF.log.warn('renderIntoViewport');
// Double check to make sure this study wasn't already inserted
// into ViewerStudies, so we don't cause duplicate entry errors
const loaded = ViewerStudies.findOne(loadedStudy._id);
// into OHIF.viewer.Studies, so we don't cause duplicate entry errors
const loaded = OHIF.viewer.Studies.findBy({
studyInstanceUid: loadedStudy.studyInstanceUid
});
if (!loaded) {
ViewerStudies.insert(loadedStudy);
OHIF.viewer.Studies.insert(loadedStudy);
}
findAndRenderDisplaySet(loadedStudy.displaySets, viewportIndex, studyInstanceUid, seriesInstanceUid, sopInstanceUid, renderedCallback)

View File

@ -1,8 +1,12 @@
import { Meteor } from 'meteor/meteor';
import { OHIF } from '../namespace';
import { TypeSafeCollection } from './lib/classes/TypeSafeCollection';
Studies = new TypeSafeCollection();
// Create main Studies collection which will be used across the entire viewer...
const Studies = new TypeSafeCollection();
ViewerStudies = new Meteor.Collection(null);
ViewerStudies._debugName = 'ViewerStudies';
// Make it publicly available on "OHIF.viewer" namespace...
OHIF.viewer.Studies = Studies;
// Subscriptions...
Meteor.subscribe('studyImportStatus');

View File

@ -1,6 +1,11 @@
import { Template } from 'meteor/templating';
import { OHIF } from 'meteor/ohif:core';
Template.studyBrowser.helpers({
studies() {
return ViewerStudies.find({
// @TypeSafeStudies
debugger;
return OHIF.viewer.Studies.findAllBy({
selected: true
});
}

View File

@ -585,14 +585,9 @@ Template.imageViewerViewport.onRendered(function() {
return;
}
// @TODO: Reconcile ViewerStudies and Studies Collection.
// const study = Studies.findBy({ studyInstanceUid });
// Look through the ViewerStudies collection for a
// study with this studyInstanceUid
const study = ViewerStudies.findOne({
studyInstanceUid: this.data.studyInstanceUid
});
// @TypeSafeStudies
debugger;
const study = OHIF.viewer.Studies.findBy({ studyInstanceUid });
data.study = study;
setDisplaySet(data, displaySetInstanceUid, templateData);
@ -669,7 +664,9 @@ Template.imageViewerViewport.events({
// Set the active viewport as the previous zoomed viewport
viewportIndexToZoom = layoutManager.zoomedViewportIndex || 0;
}
setActiveViewport($('.imageViewerViewport').get(viewportIndexToZoom));
// Set zoomed viewport as active...
const element = $('.imageViewerViewport').get(viewportIndexToZoom);
setActiveViewport(element);
});
}
});

View File

@ -4,7 +4,6 @@ import { Session } from 'meteor/session';
import { $ } from 'meteor/jquery';
import { OHIF } from 'meteor/ohif:core';
import 'meteor/ohif:viewerbase';
Template.studySeriesQuickSwitch.onCreated(() => {
const instance = Template.instance();
@ -29,13 +28,16 @@ Template.studySeriesQuickSwitch.onCreated(() => {
const viewportData = instance.getViewportData(viewportIndex);
// @TypeSafeStudies
debugger;
if (viewportData) {
// Finds the current study and return it
instance.study = ViewerStudies.findOne({
instance.study = OHIF.viewer.Studies.findBy({
studyInstanceUid: viewportData.studyInstanceUid
});
} else {
instance.study = ViewerStudies.findOne();
instance.study = OHIF.viewer.Studies.getElementByIndex(0);
}
if (!instance.study) {

View File

@ -1,4 +1,5 @@
import { Template } from 'meteor/templating';
import { OHIF } from 'meteor/ohif:core';
Template.studyTimepoint.onCreated(() => {
const instance = Template.instance();
@ -39,9 +40,12 @@ Template.studyTimepoint.events({
// Defines where will be the studies searched
let $studiesTarget = instance.$('.studyTimepoint');
// @TypeSafeStudies
debugger;
if (changed.isQuickSwitch) {
// Changes the current quick switch study
const study = ViewerStudies.findOne({
const study = OHIF.viewer.Studies.findBy({
studyInstanceUid: changed.studyInstanceUid
});
instance.data.currentStudy.set(study);

View File

@ -2,7 +2,7 @@ import { Template } from 'meteor/templating';
import { ReactiveVar } from 'meteor/reactive-var';
import { Tracker } from 'meteor/tracker';
import { _ } from 'meteor/underscore';
import { OHIF } from 'meteor/ohif:core';
import { OHIFError } from '../../../lib/classes/OHIFError';
Template.studyTimepointBrowser.onCreated(() => {
@ -21,8 +21,11 @@ Template.studyTimepointBrowser.onCreated(() => {
// Get the studies for a specific timepoint
instance.getStudies = timepoint => {
// @TypeSafeStudies
debugger;
if (!timepoint) {
return ViewerStudies.find().fetch();
return OHIF.viewer.Studies.all();
}
return timepoint.studyInstanceUids.map(studyInstanceUid => {
@ -31,7 +34,7 @@ Template.studyTimepointBrowser.onCreated(() => {
studyInstanceUid: studyInstanceUid
};
const loadedStudy = ViewerStudies.findOne(query);
const loadedStudy = OHIF.viewer.Studies.findBy(query);
if (loadedStudy) {
return loadedStudy;
}

View File

@ -3,6 +3,7 @@ import { Template } from 'meteor/templating';
import { ReactiveVar } from 'meteor/reactive-var';
import { _ } from 'meteor/underscore';
import { $ } from 'meteor/jquery';
import { OHIF } from 'meteor/ohif:core';
import { sortingManager } from '../../../lib/sortingManager';
Template.studyTimepointStudy.onCreated(() => {
@ -97,10 +98,12 @@ Template.studyTimepointStudy.events({
const isQuickSwitch = !_.isUndefined(instance.data.viewportIndex);
// @TypeSafeStudies
debugger;
// Check if the study already has series data,
// and if not, retrieve it.
if (!studyData.seriesList) {
const alreadyLoaded = ViewerStudies.findOne({ _id });
const alreadyLoaded = OHIF.viewer.Studies.findBy({ studyInstanceUid });
if (!alreadyLoaded) {
const $studies = instance.getStudyElement(true);
@ -108,12 +111,10 @@ Template.studyTimepointStudy.events({
getStudyMetadata(studyInstanceUid, study => {
study.displaySets = sortingManager.getDisplaySets(study);
instance.data.study = study;
ViewerStudies.insert(study, () => {
// To make sure studies are rendered in the DOM
// use minimongo insert callback
$studies.trigger('loadEnded');
instance.select(isQuickSwitch);
});
OHIF.viewer.Studies.insert(study);
// make sure studies are rendered in the DOM
$studies.trigger('loadEnded');
instance.select(isQuickSwitch);
});
} else {
studyData.seriesList = alreadyLoaded.seriesList;
@ -126,9 +127,11 @@ Template.studyTimepointStudy.events({
Template.studyTimepointStudy.helpers({
isLoading() {
// @TypeSafeStudies
debugger;
const instance = Template.instance();
const studyData = instance.data.study;
const alreadyLoaded = ViewerStudies.findOne({ _id: studyData._id });
const alreadyLoaded = OHIF.viewer.Studies.findBy({ studyInstanceUid: studyData.studyInstanceUid });
return instance.loading.get() && !alreadyLoaded;
},
modalities() {

View File

@ -1,5 +1,6 @@
import { Template } from 'meteor/templating';
import { Session } from 'meteor/session';
import { OHIF } from 'meteor/ohif:core';
import { viewportOverlayUtils } from '../../../lib/viewportOverlayUtils';
import { getElementIfNotEmpty } from '../../../lib/getElementIfNotEmpty';
import { getStackDataIfNotEmpty } from '../../../lib/getStackDataIfNotEmpty';
@ -217,17 +218,19 @@ Template.viewportOverlay.helpers({
return;
}
// @TypeSafeStudies
debugger
// Make sure there are more than two studies loaded in the viewer
const viewportStudies = ViewerStudies.find();
if (viewportStudies.count() < 2) {
const viewportStudies = OHIF.viewer.Studies.all();
if (viewportStudies.length < 2) {
return;
}
// Here we sort the collection in ascending order by study date, so
// that we can obtain the oldest study as the first element of the array
//
// TODO= Find out if we should encode studyDate as a Date in the ViewerStudies Collection
const viewportStudiesArray = _.sortBy(viewportStudies.fetch(), function(study) {
// TODO= Find out if we should encode studyDate as a Date in the OHIF.viewer.Studies Collection
const viewportStudiesArray = _.sortBy(viewportStudies, function(study) {
return viewportOverlayUtils.formatDateTime(study.studyDate, study.studyTime);
});

View File

@ -1,5 +1,13 @@
import { Viewerbase } from '../namespace';
/**
* Imports file with side effects only (files that do not export anything...)
*/
import './collections';
import './lib/stackImagePositionOffsetSynchronizer.js';
import './lib/debugReactivity';
/**
* Exported Functions
*/
@ -192,10 +200,3 @@ Viewerbase.TypeSafeCollection = TypeSafeCollection;
// OHIFError
import { OHIFError } from './lib/classes/OHIFError';
Viewerbase.OHIFError = OHIFError;
/**
* Imports for Side Effects Only (Files that do not export anything...)
*/
import './lib/stackImagePositionOffsetSynchronizer.js';
import './lib/debugReactivity';

View File

@ -67,6 +67,21 @@ export class TypeSafeCollection {
return propertyValue;
}
// [WIP]...
static compareToPropertyMapStrict(propertyMap, object) {
const hasOwnProperty = Object.prototype.hasOwnProperty;
const getPropertyValue = TypeSafeCollection.getPropertyValue;
for (let propertyName in propertyMap) {
if (hasOwnProperty.call(propertyMap, propertyName)) {
const propertyValue = getPropertyValue(object, propertyName);
if (propertyMap[propertyName] !== propertyValue) {
return false;
}
}
}
return true;
}
/**
* Checks if a sorting specifier is valid.
* A valid sorting specifier consists of an array of arrays being each subarray a pair
@ -194,7 +209,7 @@ export class TypeSafeCollection {
}
remove(propertyMap) {
let found = this.findAllBy(propertyMap),
let found = this.findAllEntriesBy(propertyMap),
foundCount = found.length,
removed = [];
if (foundCount > 0) {
@ -267,13 +282,11 @@ export class TypeSafeCollection {
* Find all elements that match a specified property map.
* Attention!!! The reactive source will not be notified if no valid property map is supplied...
* @param {Object} propertyMap A property map that will be macthed against all collection elements.
* @param {Object} options A set of options. Currently only "options.sort" option is supported.
* @param {Object.SortingSpecifier} options.sort An optional sorting specifier. If a sorting specifier is supplied
* but it's not valid, an exception will be thrown.
* @returns {Array} An array with all elements stored in the collection.
* @returns {Array} An array of entries of all elements that match the given criteria. Each set in
* in the array has the following format: [ elementData, elementId, elementIndex ].
*/
findAllBy(propertyMap, options) {
let found = [];
findAllEntriesBy(propertyMap) {
const found = [];
if (typeof propertyMap === OBJECT && propertyMap !== null) {
const hasOwn = Object.prototype.hasOwnProperty;
this._elements().forEach((item, index) => {
@ -289,6 +302,20 @@ export class TypeSafeCollection {
found.push([ payload, item.id, index ]);
});
}
return found;
}
/**
* Find all elements that match a specified property map.
* Attention!!! The reactive source will not be notified if no valid property map is supplied...
* @param {Object} propertyMap A property map that will be macthed against all collection elements.
* @param {Object} options A set of options. Currently only "options.sort" option is supported.
* @param {Object.SortingSpecifier} options.sort An optional sorting specifier. If a sorting specifier is supplied
* but it's not valid, an exception will be thrown.
* @returns {Array} An array with all elements that match the given criteria and sorted in the specified sorting order.
*/
findAllBy(propertyMap, options) {
const found = this.findAllEntriesBy(propertyMap).map(item => item[0]); // Only payload is relevant...
if (options instanceof Object && 'sort' in options) {
TypeSafeCollection.sortListBy(found, options.sort);
}

View File

@ -89,9 +89,6 @@ Package.onUse(function(api) {
});
api.addFiles('client/compatibility/dialogPolyfill.styl', 'client');
// ---------- Collections ----------
api.addFiles('client/collections.js', 'client');
// ---------- Components ----------
// Basic components
@ -201,11 +198,6 @@ Package.onUse(function(api) {
api.addFiles('client/components/viewer/studyTimepointBrowser/studyTimepointStudy.styl', 'client');
api.addFiles('client/components/viewer/studyTimepointBrowser/studyTimepointStudy.js', 'client');
// Library functions
// Collections
api.export('ViewerStudies', 'client');
api.export('dialogPolyfill', 'client');
api.mainModule('main.js', 'client');

View File

@ -1,4 +1,5 @@
import { OHIF } from 'meteor/ohif:core';
import 'meteor/ohif:viewerbase';
OHIF.viewer = OHIF.viewer || {};
@ -42,14 +43,16 @@ Template.viewer.onCreated(() => {
Session.set('activeViewport', ViewerData[contentId].activeViewport || 0);
// Update the ViewerStudies collection with the loaded studies
ViewerStudies.remove({});
// @TypeSafeStudies
debugger;
// Update the OHIF.viewer.Studies collection with the loaded studies
OHIF.viewer.Studies.removeAll();
ViewerData[contentId].studyInstanceUids = [];
instance.data.studies.forEach(study => {
study.selected = true;
study.displaySets = createStacks(study);
ViewerStudies.insert(study);
OHIF.viewer.Studies.insert(study);
ViewerData[contentId].studyInstanceUids.push(study.studyInstanceUid);
});