Improved loading indicators. Added % loaded to viewports and thumbnails

This commit is contained in:
Erik Ziegler 2015-10-31 17:01:47 +01:00
parent eac9669aa4
commit 587999b8dd
13 changed files with 129 additions and 40 deletions

View File

@ -2,7 +2,7 @@
<meta charset="utf-8"> <meta charset="utf-8">
<title>Lesion Tracker</title> <title>Lesion Tracker</title>
<meta name="description" content="Prototype viewer application for oncology"> <meta name="description" content="Prototype viewer application for oncology">
<meta name="viewport" content="user-scalable=no, initial-scale=1, minimal-ui, maximum-scale=1, minimum-scale=1" /> <meta name="viewport" content="user-scalable=no, initial-scale=1,maximum-scale=1, minimum-scale=1" />
<link rel="shortcut icon" type="image/png" href="images/logo.png" sizes="16x16 32x32 64x64"> <link rel="shortcut icon" type="image/png" href="images/logo.png" sizes="16x16 32x32 64x64">
<!--Best display for mobile devices--> <!--Best display for mobile devices-->
<meta http-equiv="cleartype" content="on"> <meta http-equiv="cleartype" content="on">

View File

@ -23,7 +23,7 @@ Template.viewer.onCreated(function() {
viewer: {} viewer: {}
}; };
OHIF.viewer.loadIndicatorDelay = 3000; OHIF.viewer.loadIndicatorDelay = 500;
OHIF.viewer.defaultTool = 'wwwc'; OHIF.viewer.defaultTool = 'wwwc';
OHIF.viewer.refLinesEnabled = true; OHIF.viewer.refLinesEnabled = true;
OHIF.viewer.isPlaying = {}; OHIF.viewer.isPlaying = {};

View File

@ -2,7 +2,7 @@
<meta charset="utf-8"> <meta charset="utf-8">
<title>OHIF Viewer</title> <title>OHIF Viewer</title>
<meta name="description" content="Open Health Imaging Foundation DICOM Viewer"> <meta name="description" content="Open Health Imaging Foundation DICOM Viewer">
<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1,maximum-scale=1,user-scalable=no, minimal-ui"> <meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1,maximum-scale=1,user-scalable=no">
<!--Best display for mobile devices--> <!--Best display for mobile devices-->
<meta http-equiv="cleartype" content="on"> <meta http-equiv="cleartype" content="on">
<meta name="MobileOptimized" content="320"> <meta name="MobileOptimized" content="320">

View File

@ -1,4 +1,10 @@
<template name="imageThumbnail"> <template name="imageThumbnail">
<div class="imageThumbnail"> <div class="imageThumbnail">
<div class="imageThumbnailLoadingIndicator thumbnailLoadingIndicator">
<p>Loading {{percentComplete}}</p>
</div>
<div class="imageThumbnailErrorLoadingIndicator thumbnailLoadingIndicator">
<p>Error</p>
</div>
</div> </div>
</template> </template>

View File

@ -1,11 +1,33 @@
Template.imageThumbnail.onRendered(function() { Template.imageThumbnail.onRendered(function() {
var instance = this.data.instances[0]; var instance = this.data.stack.instances[0];
var element = this.find('.imageThumbnail'); var element = this.find('.imageThumbnail');
cornerstone.enable(element); cornerstone.enable(element);
var imageId = getImageId(instance); var imageId = getImageId(instance);
cornerstone.loadAndCacheImage(imageId).then(function(image) { var elem = $(element);
cornerstone.displayImage(element, image); elem.find('.imageThumbnailLoadingIndicator').css('display', 'block');
});
var thumbnailIndex = $('.imageThumbnail').index(element);
ThumbnailLoading[thumbnailIndex] = imageId;
this.data.thumbnailIndex = thumbnailIndex;
cornerstone.loadAndCacheImage(imageId).then(function(image) {
cornerstone.displayImage(element, image);
delete ThumbnailLoading[thumbnailIndex];
elem.find('.imageThumbnailLoadingIndicator').css('display', 'none');
}, function(error) {
elem.find('.imageThumbnailErrorLoadingIndicator').css('display', 'block');
});
});
Template.imageThumbnail.helpers({
'percentComplete': function() {
var percentComplete = Session.get('CornerstoneThumbnailLoadProgress' + this.thumbnailIndex);
if (percentComplete && percentComplete !== 100) {
return percentComplete + '%';
}
}
}); });

View File

@ -2,4 +2,22 @@
width: 90px width: 90px
height: 90px height: 90px
background-color: black background-color: black
margin: 0 auto margin: 0 auto
position: relative
.thumbnailLoadingIndicator
display: none
pointer-events: none
color: #f8a13f
height: 20px
width: 100%
top: 0
left: 0
right: 0
bottom: 0
margin: auto
position: absolute
p
text-align: center
font-size: 10pt

View File

@ -1,5 +1,14 @@
Template.studyBrowser.helpers({ Template.studyBrowser.helpers({
studies : function() { studies : function() {
return Session.get('studies'); var studies = Session.get('studies');
var array = [];
studies.forEach(function(study, index) {
array.push({
studyIndex: index,
study: study
});
});
return array;
} }
}); });

View File

@ -26,13 +26,8 @@ function thumbnailDragStartHandler(e, data) {
var imageThumbnail = $(targetThumbnail); var imageThumbnail = $(targetThumbnail);
// Store this data for use during drag and drop // Store this data for use during drag and drop
OHIF.viewer.dragAndDropData = { OHIF.viewer.dragAndDropData = data;
studyInstanceUid: imageThumbnail.data('studyInstanceUid'),
seriesInstanceUid: imageThumbnail.data('seriesInstanceUid')
};
$.extend(OHIF.viewer.dragAndDropData, data);
// Clone the image thumbnail // Clone the image thumbnail
var targetId = targetThumbnail.id + 'DragClone'; var targetId = targetThumbnail.id + 'DragClone';
var clone = cloneElement(targetThumbnail, targetId); var clone = cloneElement(targetThumbnail, targetId);
@ -204,6 +199,8 @@ Template.thumbnailEntry.events({
// Touch drag/drop events // Touch drag/drop events
'touchstart .thumbnailEntry, mousedown .thumbnailEntry': function(e) { 'touchstart .thumbnailEntry, mousedown .thumbnailEntry': function(e) {
var data = Template.parentData(2); var data = Template.parentData(2);
data.studyInstanceUid = this.stack.instances[0].studyInstanceUid;
data.seriesInstanceUid = this.stack.seriesInstanceUid;
thumbnailDragStartHandler(e, data); thumbnailDragStartHandler(e, data);
}, },
'touchmove .thumbnailEntry': function(e) { 'touchmove .thumbnailEntry': function(e) {
@ -216,9 +213,6 @@ Template.thumbnailEntry.events({
Template.thumbnailEntry.helpers({ Template.thumbnailEntry.helpers({
seriesDescription : function() { seriesDescription : function() {
if (!this.seriesDescription) { return this.stack.seriesDescription || '';
return '';
}
return this.seriesDescription;
} }
}); });

View File

@ -1,6 +1,15 @@
Template.thumbnails.helpers({ Template.thumbnails.helpers({
thumbnails: function() { thumbnails: function() {
var stacks = createStacks(this); var stacks = createStacks(this.study);
return stacks; var studyIndex = this.studyIndex;
}
var array = [];
stacks.forEach(function(stack, index) {
array.push({
thumbnailIndex: index * (studyIndex + 1),
stack: stack
});
});
return array;
}
}); });

View File

@ -104,13 +104,11 @@ function loadSeriesIntoViewport(data) {
// If you have problems, replace it with this line instead: // If you have problems, replace it with this line instead:
// cornerstone.enable(element); // cornerstone.enable(element);
var startLoadingHandler = cornerstoneTools.loadHandlerManager.getStartLoadHandler();
var endLoadingHandler = cornerstoneTools.loadHandlerManager.getEndLoadHandler(); var endLoadingHandler = cornerstoneTools.loadHandlerManager.getEndLoadHandler();
var errorLoadingHandler = cornerstoneTools.loadHandlerManager.getErrorLoadingHandler(); var errorLoadingHandler = cornerstoneTools.loadHandlerManager.getErrorLoadingHandler();
if (startLoadingHandler) { ViewportLoading[viewportIndex] = imageId;
startLoadingHandler(element);
}
cornerstone.loadAndCacheImage(imageId).then(function(image) { cornerstone.loadAndCacheImage(imageId).then(function(image) {
if (data.viewport) { if (data.viewport) {
@ -118,10 +116,9 @@ function loadSeriesIntoViewport(data) {
} else { } else {
cornerstone.displayImage(element, image); cornerstone.displayImage(element, image);
} }
delete ViewportLoading[viewportIndex];
if (endLoadingHandler) { endLoadingHandler(element);
endLoadingHandler(element);
}
cornerstone.resize(element, true); cornerstone.resize(element, true);
@ -216,18 +213,42 @@ function loadSeriesIntoViewport(data) {
} }
}, function(error) { }, function(error) {
if (errorLoadingHandler) { errorLoadingHandler(element, imageId, error);
errorLoadingHandler(element, imageId, error);
}
}); });
} }
function getKeysByValue(object, value) {
// http://stackoverflow.com/questions/9907419/javascript-object-get-key-by-value
return Object.keys(object).filter(function(key) {
return object[key] === value;
});
}
Meteor.startup(function() {
ViewportLoading = {};
ThumbnailLoading = {};
$(cornerstone).on('CornerstoneImageLoadProgress', function(e, eventData) {
viewportIndices = getKeysByValue(ViewportLoading, eventData.imageId);
viewportIndices.forEach(function(viewportIndex) {
Session.set('CornerstoneLoadProgress' + viewportIndex, eventData.percentComplete);
});
thumbnailIndices = getKeysByValue(ThumbnailLoading, eventData.imageId);
thumbnailIndices.forEach(function(thumbnailIndex) {
Session.set('CornerstoneThumbnailLoadProgress' + thumbnailIndex, eventData.percentComplete);
});
});
});
Template.imageViewerViewport.onRendered(function() { Template.imageViewerViewport.onRendered(function() {
log.info("imageViewerViewport onRendered"); log.info("imageViewerViewport onRendered");
var element = this.find(".imageViewerViewport");
$(element).siblings('.imageViewerLoadingIndicator').css('display', 'block');
var studies = Session.get('studies'); var studies = Session.get('studies');
var activeViewport = Session.get('activeViewport'); var activeViewport = Session.get('activeViewport');
var element = this.find(".imageViewerViewport");
var data = { var data = {
element: element, element: element,
@ -240,6 +261,7 @@ Template.imageViewerViewport.onRendered(function() {
if (this.data.seriesInstanceUid === undefined || this.data.studyInstanceUid === undefined) { if (this.data.seriesInstanceUid === undefined || this.data.studyInstanceUid === undefined) {
element.classList.add('empty'); element.classList.add('empty');
$(element).siblings('.imageViewerLoadingIndicator').css('display', 'none');
$(element).siblings('.viewportInstructions').show(); $(element).siblings('.viewportInstructions').show();
return; return;
} }

View File

@ -1,7 +1,7 @@
<template name="loadingIndicator"> <template name="loadingIndicator">
<div class="imageViewerLoadingIndicator loadingIndicator"> <div class="imageViewerLoadingIndicator loadingIndicator">
<div class="indicatorContents"> <div class="indicatorContents">
<p>Loading...</p> <p>Loading... {{percentComplete}}</p>
</div> </div>
</div> </div>
<div class="imageViewerErrorLoadingIndicator loadingIndicator"> <div class="imageViewerErrorLoadingIndicator loadingIndicator">

View File

@ -58,4 +58,13 @@ errorLoadingHandler = function(element, imageId, error, source) {
if (error) { if (error) {
errorLoadingIndicator.find('.details').text("Details: " + error); errorLoadingIndicator.find('.details').text("Details: " + error);
} }
}; };
Template.loadingIndicator.helpers({
'percentComplete': function(e) {
var percentComplete = Session.get('CornerstoneLoadProgress' + this.viewportIndex);
if (percentComplete && percentComplete !== 100) {
return percentComplete + '%';
}
}
});

View File

@ -1,3 +1,3 @@
// Create package logger using loglevel // Create package logger using loglevel
// https://atmospherejs.com/spacejamio/loglevel // https://atmospherejs.com/spacejamio/loglevel
log = loglevel.createPackageLogger('viewerbase', defaultLevel = 'warn'); log = loglevel.createPackageLogger('viewerbase', defaultLevel = 'info');