Improved loading indicators. Added % loaded to viewports and thumbnails
This commit is contained in:
parent
eac9669aa4
commit
587999b8dd
@ -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">
|
||||||
|
|||||||
@ -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 = {};
|
||||||
|
|||||||
@ -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">
|
||||||
|
|||||||
@ -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>
|
||||||
@ -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 + '%';
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
@ -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
|
||||||
@ -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;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -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;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -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;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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">
|
||||||
|
|||||||
@ -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 + '%';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
@ -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');
|
||||||
Loading…
Reference in New Issue
Block a user