dwv.App = function(mobile)
var originalImage = null;
var toolBox = new dwv.tool.ToolBox(this);
var undoStack = new dwv.tool.UndoStack(this);
this.getImage = function() { return image; };
this.setImage = function(img) { image = img; };
this.restoreOriginalImage = function() { image = originalImage; };
// Get the image data array
this.getImageData = function() { return imageData; };
this.getToolBox = function() { return toolBox; };
this.getImageLayer = function() { return imageLayer; };
this.getDrawLayer = function() { return drawLayer; };
// Get the temporary layer
this.getTempLayer = function() { return tempLayer; };
// Get the information layer
this.getInfoLayer = function() { return infoLayer; };
this.getUndoStack = function() { return undoStack; };
* Initialise the HTML for the application.
// bind open files with method
document.getElementById('imagefiles').addEventListener('change', this.onChangeFiles, false);
document.getElementById('imageurl').addEventListener('change', this.onChangeURL, false);
* Default behavior. Usually used in tools.
this.handleKeyDown = function(event)
if( event.keyCode === 90 && event.ctrlKey ) // CRTL-Z
self.getUndoStack().undo();
else if( event.keyCode === 89 && event.ctrlKey ) // CRTL-Y
self.getUndoStack().redo();
this.onChangeFiles = function(evt)
self.loadFiles(evt.target.files);
this.loadFiles = function(files)
//TODO: for (var i = 0; i < files.length; ++i) {
if( files[0].type.match("image.*") )
var reader = new FileReader();
reader.onload = function(event){
image.src = event.target.result;
image.onload = function(e){
var data = dwv.image.getDataFromImage(image, files[0]);
reader.onprogress = dwv.gui.updateProgress;
reader.onerror = function(){
alert("An error occurred while reading the image file.");
reader.readAsDataURL(files[0]);
var reader = new FileReader();
reader.onload = function(event){
var data = dwv.image.getDataFromDicomBuffer(event.target.result);
reader.onprogress = dwv.gui.updateProgress;
reader.onerror = function(){
alert("An error occurred while reading the DICOM file.");
reader.readAsArrayBuffer(files[0]);
this.onChangeURL = function(evt)
self.loadURL(evt.target.value);
this.loadURL = function(url)
var request = new XMLHttpRequest();
request.open('GET', url, true);
request.responseType = "arraybuffer";
request.onload = function(ev) {
var view = new DataView(request.response);
var isJpeg = view.getUint32(0) === 0xffd8ffe0;
var isPng = view.getUint32(0) === 0x89504e47;
var isGif = view.getUint32(0) === 0x47494638;
if( isJpeg || isPng || isGif ) {
var bytes = new Uint8Array(request.response);
for (var i = 0; i < bytes.byteLength; ++i) {
binary += String.fromCharCode(bytes[i]);
image.src = "data:image/" + imgStr + ";base64," + window.btoa(binary);
image.onload = function(e){
var data = dwv.image.getDataFromImage(image, 0);
var data = dwv.image.getDataFromDicomBuffer(request.response);
if( error.name && error.message) {
alert(error.name+": "+error.message+".");
alert("Error: "+error+".");
console.log(error.stack);
request.onerror = function(){
alert("An error occurred while retrieving the file.");
request.onprogress = dwv.gui.updateProgress;
* Generate the image data and draw it.
this.generateAndDrawImage = function()
// generate image data from DICOM
self.getImage().generateImageData(imageData);
// set the image data of the layer
self.getImageLayer().setImageData(imageData);
self.getImageLayer().draw();
* To be called once the image is loaded.
* Linked with the window.onresize method.
this.alignLayers = function()
drawLayer.align(imageLayer);
tempLayer.align(imageLayer);
infoLayer.align(imageLayer);
var plotDiv = document.getElementById("plot");
plotDiv.style.top = app.getImageLayer().getCanvas().offsetTop
+ app.getImageLayer().getCanvas().height
plotDiv.style.left = app.getImageLayer().getCanvas().offsetLeft
+ app.getImageLayer().getCanvas().width
* To be called once the image is loaded.
this.setLayersZoom = function(zoomX,zoomY,cx,cy)
if( imageLayer ) imageLayer.zoom(zoomX,zoomY,cx,cy);
if( drawLayer ) drawLayer.zoom(zoomX,zoomY,cx,cy);
* The general-purpose event handler. This function just determines the mouse
* position relative to the canvas element.
function eventHandler(event)
// flag not to get confused between touch and mouse
// Store the event position relative to the image canvas
// in an extra member of the event:
// event._x and event._y.
if( event.type === "touchstart"
|| event.type === "touchend"
|| event.type === "touchmove")
// If there's one or two fingers inside this element
if (event.targetTouches.length === 1
|| event.targetTouches.length === 2) {
var touch = event.targetTouches[0];
event._x = touch.pageX - parseInt(app.getImageLayer().getOffset().left, 10);
event._y = touch.pageY - parseInt(app.getImageLayer().getOffset().top, 10);
if (event.targetTouches.length === 2) {
touch = event.targetTouches[1];
event._x1 = touch.pageX - parseInt(app.getImageLayer().getOffset().left, 10);
event._y1 = touch.pageY - parseInt(app.getImageLayer().getOffset().top, 10);
if( event.type === "mousemove"
|| event.type === "mousedown"
|| event.type === "mouseup"
|| event.type === "mousewheel"
|| event.type === "dblclick"
|| event.type === "DOMMouseScroll" )
event._x = event.offsetX === undefined ? event.layerX : event.offsetX;
event._y = event.offsetY === undefined ? event.layerY : event.offsetY;
// Call the event handler of the tool.
var func = self.getToolBox().getSelectedTool()[event.type];
* To be called once the image is loaded.
function createLayers(width,height)
imageLayer = new dwv.html.Layer("imageLayer");
imageLayer.initialise(width, height);
imageLayer.fillContext();
imageLayer.display(true);
drawLayer = new dwv.html.Layer("drawLayer");
drawLayer.initialise(width, height);
tempLayer = new dwv.html.Layer("tempLayer");
tempLayer.initialise(width, height);
infoLayer = new dwv.html.Layer("infoLayer");
infoLayer.initialise(width, height);
* Create the DICOM tags table.
* @param dataInfo The data information.
* To be called once the DICOM has been parsed.
function createTagsTable(dataInfo)
// tag list table (without the pixel data)
if(dataInfo.PixelData) dataInfo.PixelData.value = "...";
var node = document.getElementById("tags");
// remove possible previous
while (node.hasChildNodes()) {
node.removeChild(node.firstChild);
var table = dwv.html.toTable(dataInfo);
table.className = "tagList";
node.appendChild(dwv.html.getHtmlSearchForm(table));
* To be called once the DICOM has been parsed.
function postLoadInit(data)
// create the DICOM tags table
createTagsTable(data.info);
originalImage = data.image;
var width = image.getSize().getNumberOfColumns() * zoomX;
var height = image.getSize().getNumberOfRows() * zoomY;
createLayers(width, height);
self.setLayersZoom(zoomX, zoomY, 0, 0);
// get the image data from the image layer
imageData = self.getImageLayer().getContext().getImageData(
image.getSize().getNumberOfColumns(),
image.getSize().getNumberOfRows());
// initialise the toolbox
// note: the window/level tool is responsible for doing the first display.
// add the HTML for the history
dwv.gui.appendUndoHtml();
// Attach event listeners.
tempLayer.getCanvas().addEventListener('mousedown', eventHandler, false);
tempLayer.getCanvas().addEventListener('mousemove', eventHandler, false);
tempLayer.getCanvas().addEventListener('mouseup', eventHandler, false);
tempLayer.getCanvas().addEventListener('mousewheel', eventHandler, false);
tempLayer.getCanvas().addEventListener('touchstart', eventHandler, false);
tempLayer.getCanvas().addEventListener('touchmove', eventHandler, false);
tempLayer.getCanvas().addEventListener('touchend', eventHandler, false);
tempLayer.getCanvas().addEventListener('DOMMouseScroll', eventHandler, false);
tempLayer.getCanvas().addEventListener('dblclick', eventHandler, false);
window.addEventListener('keydown', eventHandler, true);