parent
f84aeac3c3
commit
c5c5ddf282
@ -79,10 +79,6 @@ export class MetadataProvider {
|
||||
// the imagePlane object for easier use in the Viewer
|
||||
metadata.imagePlane = this.getImagePlane(instanceMetadata);
|
||||
|
||||
if (metadata.instance && !metadata.instance.multiframeMetadata) {
|
||||
metadata.instance.multiframeMetadata = this.getMultiframeModuleMetadata(data);
|
||||
}
|
||||
|
||||
// Add the metadata to the imageId lookup object
|
||||
this.metadataLookup.set(imageId, metadata);
|
||||
}
|
||||
@ -117,10 +113,8 @@ export class MetadataProvider {
|
||||
|
||||
if(image.data) {
|
||||
value = this.getFromDataSet(image.data, type, tag);
|
||||
} else if(image.instance) {
|
||||
value = image.instance[attrName];
|
||||
} else {
|
||||
value = image[attrName];
|
||||
value = image.instance[attrName];
|
||||
}
|
||||
|
||||
return value == null ? defaultValue : value;
|
||||
@ -219,7 +213,7 @@ export class MetadataProvider {
|
||||
imageMetadata.instance.frameTime = imageMetadata.instance.frameTime || this.getFromDataSet(image.data, 'string', 'x00181063');
|
||||
imageMetadata.instance.frameTimeVector = imageMetadata.instance.frameTimeVector || this.getFromDataSet(image.data, 'string', 'x00181065');
|
||||
|
||||
if (!imageMetadata.instance.multiframeMetadata) {
|
||||
if ((image.data || image.instance) && !imageMetadata.instance.multiframeMetadata) {
|
||||
imageMetadata.instance.multiframeMetadata = this.getMultiframeModuleMetadata(image);
|
||||
}
|
||||
|
||||
|
||||
@ -274,7 +274,6 @@ Template.cineDialog.events({
|
||||
|
||||
Template.cineDialog.helpers({
|
||||
isPlaying() {
|
||||
Session.get('UpdateCINE');
|
||||
return viewportUtils.isPlaying();
|
||||
},
|
||||
|
||||
|
||||
@ -14,7 +14,6 @@ import { updateCrosshairsSynchronizer } from '../../../lib/updateCrosshairsSynch
|
||||
import { toolManager } from '../../../lib/toolManager';
|
||||
import { updateOrientationMarkers } from '../../../lib/updateOrientationMarkers';
|
||||
import { getInstanceClassDefaultViewport } from '../../../lib/instanceClassSpecificViewport';
|
||||
import { PlayClipManager } from '../../../lib/classes/PlayClipManager';
|
||||
import { OHIFError } from '../../../lib/classes/OHIFError';
|
||||
|
||||
const allCornerstoneEvents = 'CornerstoneToolsMouseDown CornerstoneToolsMouseDownActivate ' +
|
||||
@ -260,12 +259,9 @@ const loadDisplaySetIntoViewport = (data, templateData) => {
|
||||
|
||||
cornerstoneTools.addToolState(element, 'playClip', cineToolData);
|
||||
|
||||
const playClipManager = PlayClipManager.getInstance();
|
||||
const playClipController = playClipManager.add(element, displaySet);
|
||||
|
||||
// Autoplay datasets that have framerates set
|
||||
if (multiframeMetadata && multiframeMetadata.isMultiframeImage && multiframeMetadata.averageFrameRate > 0) {
|
||||
playClipController.play();
|
||||
cornerstoneTools.playClip(element);
|
||||
}
|
||||
|
||||
// Enable mouse, mouseWheel, touch, and keyboard input on the element
|
||||
@ -591,9 +587,6 @@ Template.imageViewerViewport.onDestroyed(function() {
|
||||
// for compatibility with other systems
|
||||
$element.trigger('OHIFDestroyedViewport');
|
||||
|
||||
// Disable the PlayClipController for the current element
|
||||
PlayClipManager.getInstance().remove(element);
|
||||
|
||||
// Disable the viewport element with Cornerstone
|
||||
// This also triggers the removal of the element from all available
|
||||
// synchronizers, such as the one used for reference lines.
|
||||
|
||||
@ -10,7 +10,6 @@ import { ResizeViewportManager } from '../../../lib/classes/ResizeViewportManage
|
||||
import { LayoutManager } from '../../../lib/classes/LayoutManager';
|
||||
import { StudyPrefetcher } from '../../../lib/classes/StudyPrefetcher';
|
||||
import { StudyLoadingListener } from '../../../lib/classes/StudyLoadingListener';
|
||||
import { PlayClipManager } from '../../../lib/classes/PlayClipManager';
|
||||
|
||||
Meteor.startup(() => {
|
||||
window.ResizeViewportManager = window.ResizeViewportManager || new ResizeViewportManager();
|
||||
@ -43,9 +42,6 @@ Template.viewerMain.onRendered(() => {
|
||||
studyLoadingListener.clear();
|
||||
studyLoadingListener.addStudies(studies);
|
||||
|
||||
// Remove all PlayClipControllers from PlayClipManager
|
||||
PlayClipManager.getInstance().clear();
|
||||
|
||||
OHIF.viewerbase.layoutManager = new LayoutManager(parentElement, studies);
|
||||
studyPrefetcher.setStudies(studies);
|
||||
|
||||
|
||||
@ -204,10 +204,6 @@ Viewerbase.ResizeViewportManager = ResizeViewportManager;
|
||||
import { StudyLoadingListener } from './lib/classes/StudyLoadingListener';
|
||||
Viewerbase.StudyLoadingListener = StudyLoadingListener;
|
||||
|
||||
// PlayClipManager
|
||||
import { PlayClipManager } from './lib/classes/PlayClipManager';
|
||||
Viewerbase.PlayClipManager = PlayClipManager;
|
||||
|
||||
// StudyMetadata, SeriesMetadata, InstanceMetadata
|
||||
import { StudyMetadata } from './lib/classes/metadata/StudyMetadata';
|
||||
import { SeriesMetadata } from './lib/classes/metadata/SeriesMetadata';
|
||||
|
||||
@ -1,306 +0,0 @@
|
||||
import { $ } from 'meteor/jquery';
|
||||
import { Tracker } from 'meteor/tracker';
|
||||
import { Session } from 'meteor/session';
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
|
||||
class PlayClipController {
|
||||
constructor(element, displaySet) {
|
||||
this._isPlaying = false;
|
||||
this.element = element;
|
||||
this.displaySet = displaySet;
|
||||
this._playComputation = null;
|
||||
}
|
||||
|
||||
_getStackProgress() {
|
||||
return Session.get('StackProgress:' + this.displaySet.displaySetInstanceUid);
|
||||
}
|
||||
|
||||
_getToolState(toolType) {
|
||||
const toolState = cornerstoneTools.getToolState(this.element, toolType);
|
||||
if (toolState && toolState.data) {
|
||||
return toolState.data[0];
|
||||
}
|
||||
}
|
||||
|
||||
_countFramesByStatus(stackProgress, startIndex, endIndex, status) {
|
||||
const framesStatus = stackProgress.framesStatus;
|
||||
const framesCount = framesStatus.length;
|
||||
let currentIndex = startIndex;
|
||||
let count = 0;
|
||||
|
||||
do {
|
||||
if (framesStatus[currentIndex] === status) {
|
||||
count++;
|
||||
}
|
||||
|
||||
if(currentIndex === endIndex) {
|
||||
break;
|
||||
}
|
||||
|
||||
currentIndex = (currentIndex + 1) % framesCount;
|
||||
} while (true)
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
_isLoopEnabled() {
|
||||
const playClipToolState = this._getToolState('playClip');
|
||||
return playClipToolState && playClipToolState.loop;
|
||||
}
|
||||
|
||||
_getCurrentIndex() {
|
||||
const stackToolState = this._getToolState('stack');
|
||||
return stackToolState.currentImageIdIndex || 0;
|
||||
}
|
||||
|
||||
_isLastFrame() {
|
||||
const stackToolState = this._getToolState('stack');
|
||||
const currentIndex = (stackToolState && stackToolState.currentImageIdIndex) || 0;
|
||||
const imagesCount = stackToolState ? stackToolState.imageIds.length : 0;
|
||||
|
||||
return (imagesCount === 0) || (currentIndex === imagesCount - 1);
|
||||
}
|
||||
|
||||
_getFrameDistance(startIndex, endIndex) {
|
||||
const framesCount = this.displaySet.numImageFrames;
|
||||
return startIndex <= endIndex ? endIndex - startIndex : framesCount - (startIndex - endIndex);
|
||||
}
|
||||
|
||||
_getLastRelativeFrame(startFrame) {
|
||||
const numImageFrames = this.displaySet.numImageFrames;
|
||||
|
||||
if (this._isLoopEnabled()) {
|
||||
// Easiest way to get the previous index without having to check if it's negative
|
||||
return (startFrame + numImageFrames - 1) % numImageFrames;
|
||||
}
|
||||
|
||||
// Return the last index of the array
|
||||
return numImageFrames - 1;
|
||||
}
|
||||
|
||||
isPlaying() {
|
||||
return this._isPlaying;
|
||||
}
|
||||
|
||||
play() {
|
||||
if (this._isPlaying) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._isPlaying = true;
|
||||
|
||||
const playClipToolState = this._getToolState('playClip');
|
||||
const startIndex = this._getCurrentIndex();
|
||||
const endIndex = this._getLastRelativeFrame(startIndex);
|
||||
const framesToPlay = this._getFrameDistance(startIndex, endIndex);
|
||||
const playTimeRemaining = framesToPlay / playClipToolState.framesPerSecond;
|
||||
|
||||
const play = playComputation => {
|
||||
playComputation.stop();
|
||||
|
||||
try {
|
||||
cornerstoneTools.playClip(this.element);
|
||||
} catch(e) {
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
|
||||
this._playComputation = Tracker.autorun(playComputation => {
|
||||
const stackProgress = this._getStackProgress();
|
||||
|
||||
if (!stackProgress) {
|
||||
return;
|
||||
} else if (!stackProgress.multiFrame) {
|
||||
play(playComputation);
|
||||
return;
|
||||
}
|
||||
|
||||
const framesToLoad = this._countFramesByStatus(stackProgress, startIndex, endIndex, false);
|
||||
const loadTimeRemaining = framesToLoad / stackProgress.framesPerSecond;
|
||||
|
||||
if ((stackProgress.percentComplete === 100) ||
|
||||
(loadTimeRemaining < playTimeRemaining)) {
|
||||
play(playComputation);
|
||||
this._attachNewImageListener();
|
||||
}
|
||||
});
|
||||
|
||||
// Update the UpdateCINE session property
|
||||
Session.set('UpdateCINE', Random.id());
|
||||
}
|
||||
|
||||
stop() {
|
||||
if (!this._isPlaying) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._playComputation) {
|
||||
this._playComputation.stop();
|
||||
this._playComputation = null;
|
||||
}
|
||||
|
||||
try {
|
||||
cornerstoneTools.stopClip(this.element);
|
||||
} catch(e) {
|
||||
console.log(e);
|
||||
}
|
||||
|
||||
this._isPlaying = false;
|
||||
this._detachNewImageListener();
|
||||
|
||||
// Update the UpdateCINE session property
|
||||
Session.set('UpdateCINE', Random.id());
|
||||
}
|
||||
|
||||
togglePlay() {
|
||||
if(this._isPlaying) {
|
||||
this.stop();
|
||||
} else {
|
||||
this.play();
|
||||
}
|
||||
}
|
||||
|
||||
_isNextFrameLoaded() {
|
||||
const stackProgress = this._getStackProgress();
|
||||
|
||||
if (!stackProgress || !stackProgress.framesStatus) {
|
||||
return;
|
||||
}
|
||||
|
||||
const stackToolState = this._getToolState('stack');
|
||||
const currentImageIdIndex = stackToolState.currentImageIdIndex || 0;
|
||||
const isLoopEnabled = this._isLoopEnabled();
|
||||
|
||||
let nextImageIndex = currentImageIdIndex + 1;
|
||||
|
||||
if ((nextImageIndex >= stackToolState.imageIds.length) && isLoopEnabled) {
|
||||
nextImageIndex = 0;
|
||||
}
|
||||
|
||||
return stackProgress.framesStatus && stackProgress.framesStatus[nextImageIndex];
|
||||
}
|
||||
|
||||
_newImageEventHandler(e, eventData) {
|
||||
if (this._isLastFrame() && !this._isLoopEnabled()) {
|
||||
return this.stop();
|
||||
} else if (!this._isNextFrameLoaded()) {
|
||||
// Stop the clip and play it again in order to wait for the next frames (buffer)
|
||||
this.stop();
|
||||
this.play();
|
||||
}
|
||||
}
|
||||
|
||||
_attachNewImageListener() {
|
||||
this._detachNewImageListener();
|
||||
$(this.element).on('CornerstoneNewImage.PlayClipManager', this._newImageEventHandler.bind(this));
|
||||
}
|
||||
|
||||
_detachNewImageListener() {
|
||||
$(this.element).off('CornerstoneNewImage.PlayClipManager');
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.stop();
|
||||
}
|
||||
}
|
||||
|
||||
class PlayClipManager {
|
||||
constructor() {
|
||||
this.elementControllers = [];
|
||||
}
|
||||
|
||||
add(element, displaySet) {
|
||||
const playClipController = new PlayClipController(element, displaySet);
|
||||
|
||||
// Remove any other PlayClipController for this `element`
|
||||
this.remove(element);
|
||||
|
||||
// Add the new PlayClipController for this `element`
|
||||
this.elementControllers.push({
|
||||
element,
|
||||
playClipController
|
||||
});
|
||||
|
||||
return playClipController;
|
||||
}
|
||||
|
||||
remove (element) {
|
||||
const index = this._indexOf(element);
|
||||
|
||||
if (index === -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
const elementController = this.elementControllers[index];
|
||||
const playClipController = elementController.playClipController;
|
||||
|
||||
playClipController.destroy();
|
||||
this.elementControllers.splice(index, 1);
|
||||
}
|
||||
|
||||
get (element) {
|
||||
const index = this._indexOf(element);
|
||||
|
||||
if (index >= 0) {
|
||||
const elementController = this.elementControllers[index];
|
||||
return elementController.playClipController;
|
||||
}
|
||||
}
|
||||
|
||||
_indexOf(element) {
|
||||
const elementControllers = this.elementControllers;
|
||||
const length = elementControllers.length;
|
||||
|
||||
for(let i = 0; i < length; i++) {
|
||||
if (elementControllers[i].element === element) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
_forEach(callback) {
|
||||
const elementControllers = this.elementControllers;
|
||||
const length = elementControllers.length;
|
||||
|
||||
for (let i = 0; i < length; i++) {
|
||||
const elementControllers = this.elementControllers[i];
|
||||
const element = elementControllers.element;
|
||||
const playClipController = elementControllers.playClipController;
|
||||
|
||||
callback(element, playClipController);
|
||||
}
|
||||
}
|
||||
|
||||
playAll() {
|
||||
this._forEach((element, playClipController) => {
|
||||
playClipController.play();
|
||||
});
|
||||
}
|
||||
|
||||
stopAll() {
|
||||
this._forEach((element, playClipController) => {
|
||||
playClipController.stop();
|
||||
});
|
||||
}
|
||||
|
||||
clear() {
|
||||
this._forEach((element, playClipController) => {
|
||||
playClipController.destroy();
|
||||
});
|
||||
|
||||
this.elementControllers = [];
|
||||
}
|
||||
|
||||
// Singleton
|
||||
static getInstance() {
|
||||
if (!PlayClipManager._instance) {
|
||||
PlayClipManager._instance = new PlayClipManager();
|
||||
}
|
||||
|
||||
return PlayClipManager._instance;
|
||||
}
|
||||
}
|
||||
|
||||
export { PlayClipManager };
|
||||
@ -6,7 +6,6 @@ import { _ } from 'meteor/underscore';
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
import { updateOrientationMarkers } from './updateOrientationMarkers';
|
||||
import { getInstanceClassDefaultViewport } from './instanceClassSpecificViewport';
|
||||
import { PlayClipManager } from './classes/PlayClipManager';
|
||||
|
||||
/**
|
||||
* Get a cornerstone enabledElement for a DOM Element
|
||||
@ -196,12 +195,16 @@ const toggleDialog = element => {
|
||||
const toggleCinePlay = () => {
|
||||
// Get the active viewport element
|
||||
const element = getActiveViewportElement();
|
||||
const playClipManager = PlayClipManager.getInstance();
|
||||
const playClipController = playClipManager.get(element);
|
||||
|
||||
if (playClipController) {
|
||||
playClipController.togglePlay();
|
||||
// Check if it's playing the clip to toggle it
|
||||
if (isPlaying()) {
|
||||
cornerstoneTools.stopClip(element);
|
||||
} else {
|
||||
cornerstoneTools.playClip(element);
|
||||
}
|
||||
|
||||
// Update the UpdateCINE session property
|
||||
Session.set('UpdateCINE', Random.id());
|
||||
};
|
||||
|
||||
// Show/hide the CINE dialog
|
||||
@ -216,11 +219,29 @@ const isPlaying = () => {
|
||||
Session.get('UpdateCINE');
|
||||
Session.get('LayoutManagerUpdated');
|
||||
|
||||
// Get the viewport element and its current playClip tool state
|
||||
const element = getActiveViewportElement();
|
||||
const playClipManager = PlayClipManager.getInstance();
|
||||
const playClipController = playClipManager.get(element);
|
||||
// Empty Elements throws cornerstore exception
|
||||
if (!element || !$(element).find('canvas').length) {
|
||||
return;
|
||||
}
|
||||
|
||||
return playClipController && playClipController.isPlaying();
|
||||
const toolState = cornerstoneTools.getToolState(element, 'playClip');
|
||||
|
||||
// Stop here if the tool state is not defined yet
|
||||
if (!toolState) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the clip state
|
||||
const clipState = toolState.data[0];
|
||||
|
||||
if(clipState) {
|
||||
// Return true if the clip is playing
|
||||
return !_.isUndefined(clipState.intervalId);
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
// Check if a study has multiple frames
|
||||
|
||||
Loading…
Reference in New Issue
Block a user