diff --git a/screening/source/core-plugins/microscopy/1/as/webapps/image-viewer/html/image-viewer.js b/screening/source/core-plugins/microscopy/1/as/webapps/image-viewer/html/image-viewer.js new file mode 100644 index 0000000000000000000000000000000000000000..70b9381f58d6b3bda23a162b9b452add52104f21 --- /dev/null +++ b/screening/source/core-plugins/microscopy/1/as/webapps/image-viewer/html/image-viewer.js @@ -0,0 +1,941 @@ +// +// IMAGE VIEWER +// +function ImageViewerWidget(openbis, dataSetCode) { + this.init(openbis, dataSetCode); +} + +$.extend(ImageViewerWidget.prototype, { + init: function(openbis, dataSetCode){ + this.facade = new OpenbisFacade(openbis); + this.dataSetCode = dataSetCode; + this.panel = $("<div>") + }, + + load: function(callback){ + if(this.loaded){ + callback(); + }else{ + var thisImageViewer = this; + + var manager = new CallbackManager(function(){ + thisImageViewer.loaded = true; + callback(); + }); + + this.facade.tryGetDataStoreBaseURL(thisImageViewer.dataSetCode, manager.registerCallback(function(response){ + thisImageViewer.dataStoreUrl = response.result; + })); + + this.facade.getImageInfo(thisImageViewer.dataSetCode, manager.registerCallback(function(response){ + thisImageViewer.imageInfo = response.result; + })); + + this.facade.getImageResolutions(thisImageViewer.dataSetCode, manager.registerCallback(function(response){ + thisImageViewer.imageResolutions = response.result; + })); + } + }, + + render: function(){ + var thisImageViewer = this; + + this.load(function(){ + + var channelWidget = new ChannelChooserWidget(thisImageViewer.getChannels()); + channelWidget.addChangeListener(function(){ + imageWidget.setChannels(channelWidget.getSelectedOrMergedChannels()); + }); + thisImageViewer.panel.append(channelWidget.render()); + + var resolutionWidget = new ResolutionChooserWidget(thisImageViewer.getResolutions()); + resolutionWidget.addChangeListener(function(){ + imageWidget.setResolution(resolutionWidget.getSelectedResolution()); + }); + thisImageViewer.panel.append(resolutionWidget.render()); + + var channelStackWidget = new ChannelStackChooserWidget(thisImageViewer.getChannelStacks()); + channelStackWidget.addChangeListener(function(){ + imageWidget.setChannelStackId(channelStackWidget.getSelectedChannelStack().id); + }); + thisImageViewer.panel.append(channelStackWidget.render()); + + var imageWidget = new ImageWidget(); + imageWidget.setSessionToken(thisImageViewer.facade.getSession()); + imageWidget.setDataStoreUrl(thisImageViewer.dataStoreUrl); + imageWidget.setDataSetCode(thisImageViewer.dataSetCode); + imageWidget.setChannelStackId(channelStackWidget.getSelectedChannelStack().id); + imageWidget.setResolution(resolutionWidget.getSelectedResolution()); + imageWidget.setChannels(channelWidget.getSelectedOrMergedChannels()); + + thisImageViewer.panel.append(imageWidget.render()); + + }); + + return this.panel; + }, + + getChannels: function(){ + return this.imageInfo.imageDataset.imageDataset.imageParameters.channels; + }, + + getChannelStacks: function(){ + return this.imageInfo.channelStacks; + }, + + getResolutions: function(){ + return this.imageResolutions; + } + +}); + +// +// FACADE +// +function OpenbisFacade(openbis){ + this.init(openbis); +} + +$.extend(OpenbisFacade.prototype, { + init: function(openbis){ + this.openbis = openbis; + }, + + getSession: function(){ + return this.openbis.getSession(); + }, + + tryGetDataStoreBaseURL: function(dataSetCode, action){ + this.openbis.tryGetDataStoreBaseURL(dataSetCode, action); + }, + + getImageInfo: function(dataSetCode, callback){ + this.openbis.getImageInfo(dataSetCode, null, callback); + }, + + getImageResolutions: function(dataSetCode, callback){ + this.openbis.getImageResolutions(dataSetCode, callback); + } +}); + +// +// CHANNEL CHOOSER +// +function ChannelChooserWidget(channels) { + this.init(channels); +} + +$.extend(ChannelChooserWidget.prototype, { + + init: function(channels){ + this.channels = channels; + this.selectedChannel = null; + this.mergedChannels = channels.map(function(channel){ + return channel.code; + }); + + this.listeners = new ListenerManager(); + this.panel = $("<div>").addClass("widget"); + }, + + render: function(){ + var thisChooser = this; + + $("<div>").text("Channel:").appendTo(this.panel); + + var select = $("<select>").appendTo(this.panel); + + $("<option>").attr("value", "").text("Merged Channels").appendTo(select); + + this.channels.forEach(function(channel){ + $("<option>").attr("value", channel.code).text(channel.label).appendTo(select); + }); + + select.change(function(){ + if(select.val() == ""){ + thisChooser.setSelectedChannel(null); + }else{ + thisChooser.setSelectedChannel(select.val()); + } + }); + + var mergedChannels = $("<div>").addClass("mergedChannels").appendTo(this.panel); + + this.channels.forEach(function(channel){ + var mergedChannel = $("<span>").addClass("mergedChannel").appendTo(mergedChannels); + $("<input>").attr("type", "checkbox").attr("value", channel.code).appendTo(mergedChannel); + mergedChannel.append(channel.label); + }); + + mergedChannels.find("input").change(function(){ + var channels = [] + mergedChannels.find("input:checked").each(function(){ + var checkbox = $(this); + channels.push(checkbox.val()); + }); + thisChooser.setMergedChannels(channels); + }); + + this.rendered = true; + this.refresh(); + + return this.panel; + }, + + refresh: function(){ + if(!this.rendered){ + return; + } + + var thisChooser = this; + + var select = this.panel.find("select"); + var mergedChannels = this.panel.find(".mergedChannels"); + + if(this.getSelectedChannel()){ + select.val(this.getSelectedChannel()); + mergedChannels.hide(); + }else{ + select.val(""); + mergedChannels.find("input").each(function(){ + var checkbox = $(this); + var checked = $.inArray(checkbox.val(), thisChooser.getMergedChannels()) != -1; + checkbox.prop("checked", checked); + if(checked){ + checkbox.prop("disabled", thisChooser.getMergedChannels().length == 1); + } + }); + mergedChannels.show(); + } + }, + + getSelectedChannel: function(){ + return this.selectedChannel; + }, + + setSelectedChannel: function(channel){ + this.selectedChannel = channel; + this.refresh(); + this.notifyChangeListeners(); + }, + + getMergedChannels: function(){ + return this.mergedChannels; + }, + + setMergedChannels: function(channels){ + this.mergedChannels = channels; + this.refresh(); + this.notifyChangeListeners(); + }, + + getSelectedOrMergedChannels: function(){ + if(this.getSelectedChannel()){ + return [this.getSelectedChannel()]; + }else{ + return this.getMergedChannels(); + } + }, + + addChangeListener: function(listener){ + this.listeners.addListener('change', listener); + }, + + notifyChangeListeners: function(){ + this.listeners.notifyListeners('change'); + } + +}); + +// +// RESOLUTION CHOOSER +// +function ResolutionChooserWidget(resolutions) { + this.init(resolutions); +} + +$.extend(ResolutionChooserWidget.prototype, { + + init: function(resolutions){ + this.resolutions = resolutions; + this.selectedResolution = null; + this.listeners = new ListenerManager(); + this.panel = $("<div>").addClass("widget"); + }, + + render: function(){ + var thisChooser = this; + + $("<div>").text("Resolution:").appendTo(this.panel); + + var select = $("<select>").appendTo(this.panel); + + $("<option>").attr("value", "").text("Default").appendTo(select); + + this.resolutions.forEach(function(resolution){ + var value = resolution.width + "x" + resolution.height; + $("<option>").attr("value", value).text(value).appendTo(select); + }); + + select.change(function(){ + if(select.val() == ""){ + thisChooser.setSelectedResolution(null); + }else{ + thisChooser.setSelectedResolution(select.val()); + } + }); + + this.rendered = true; + this.refresh(); + + return this.panel; + }, + + refresh: function(){ + if(!this.rendered){ + return; + } + + var select = this.panel.find("select"); + if(this.selectedResolution){ + select.val(this.selectedResolution); + } + }, + + getSelectedResolution: function(){ + return this.selectedResolution; + }, + + setSelectedResolution: function(resolution){ + this.selectedResolution = resolution; + this.refresh(); + this.notifyChangeListeners(); + }, + + addChangeListener: function(listener){ + this.listeners.addListener('change', listener); + }, + + notifyChangeListeners: function(){ + this.listeners.notifyListeners('change'); + } + +}); + +// +// CHANNEL STACK CHOOSER +// +function ChannelStackChooserWidget(channelStacks) { + this.init(channelStacks); +} + +$.extend(ChannelStackChooserWidget.prototype, { + + init: function(channelStacks){ + var manager = new ChannelStackManager(channelStacks); + + if(manager.isMatrix()){ + this.widget = new ChannelStackMatrixChooserWidget(channelStacks); + }else{ + this.widget = new ChannelStackDefaultChooserWidget(channelStacks); + } + }, + + render: function(){ + return this.widget.render(); + }, + + getSelectedChannelStack: function(){ + return this.widget.getSelectedChannelStack(); + }, + + addChangeListener: function(listener){ + this.widget.addChangeListener(listener); + }, + + notifyChangeListeners: function(){ + this.widget.notifyChangeListeners(); + } + +}); + +// +// CHANNEL STACK MATRIX CHOOSER +// +function ChannelStackMatrixChooserWidget(channelStacks) { + this.init(channelStacks); +} + +$.extend(ChannelStackMatrixChooserWidget.prototype, { + + init: function(channelStacks){ + this.channelStackManager = new ChannelStackManager(channelStacks); + this.selectedTimePoint = this.channelStackManager.getTimePoints()[0]; + this.selectedDepth = this.channelStackManager.getDepths()[0]; + this.listeners = new ListenerManager(); + this.panel = $("<div>").addClass("widget"); + }, + + render: function(){ + var thisChooser = this; + + $("<div>").text("Channel Stack:").appendTo(this.panel); + + $("<span>").text("T:").appendTo(this.panel); + + var timeSelect = $("<select>").addClass("timeChooser").appendTo(this.panel); + + this.channelStackManager.getTimePoints().forEach(function(timePoint){ + $("<option>").attr("value", timePoint).text(timePoint).appendTo(timeSelect); + }); + + timeSelect.change(function(){ + thisChooser.setSelectedTimePoint(timeSelect.val()); + }); + + $("<span>").text("D:").appendTo(this.panel); + + var depthSelect = $("<select>").addClass("depthChooser").appendTo(this.panel); + + this.channelStackManager.getDepths().forEach(function(depth){ + $("<option>").attr("value", depth).text(depth).appendTo(depthSelect); + }); + + depthSelect.change(function(){ + thisChooser.setSelectedDepth(depthSelect.val()); + }); + + this.buttons = new MovieButtonsWidget(this.channelStackManager.getTimePoints().length); + + this.buttons.addChangeListener(function(){ + var frame = thisChooser.buttons.getSelectedFrame(); + thisChooser.setSelectedTimePoint(thisChooser.channelStackManager.getTimePoint(frame)); + }); + + this.panel.append(this.buttons.render()); + + this.rendered = true; + this.refresh(); + + return this.panel; + }, + + refresh: function(){ + if(!this.rendered){ + return; + } + + var timeSelect = this.panel.find("select.timeChooser"); + + if(this.selectedTimePoint){ + timeSelect.val(this.selectedTimePoint); + } + + var depthSelect = this.panel.find("select.depthChooser"); + + if(this.selectedDepth){ + depthSelect.val(this.selectedDepth); + } + }, + + getSelectedChannelStack: function(){ + return this.channelStackManager.getChannelStack(this.selectedTimePoint, this.selectedDepth); + }, + + setSelectedTimePoint: function(timePoint){ + if(this.selectedTimePoint != timePoint){ + this.selectedTimePoint = timePoint; + this.buttons.setSelectedFrame(this.channelStackManager.getTimePointIndex(timePoint)); + this.refresh(); + this.notifyChangeListeners(); + } + }, + + setSelectedDepth: function(depth){ + if(this.selectedDepth != depth){ + this.selectedDepth = depth; + this.refresh(); + this.notifyChangeListeners(); + } + }, + + addChangeListener: function(listener){ + this.listeners.addListener('change', listener); + }, + + notifyChangeListeners: function(){ + this.listeners.notifyListeners('change'); + } + +}); + +// +// CHANNEL STACK DEFAULT CHOOSER +// +function ChannelStackDefaultChooserWidget(channelStacks) { + this.init(channelStacks); +} + +$.extend(ChannelStackDefaultChooserWidget.prototype, { + + init: function(channelStacks){ + this.channelStackManager = new ChannelStackManager(channelStacks); + this.listeners = new ListenerManager(); + this.panel = $("<div>"); + }, + + render: function(){ + this.panel.append("Default channel stack chooser"); + return this.panel; + }, + + getSelectedChannelStack: function(){ + return null; + }, + + setSelectedChannelStack: function(channelStack){ + }, + + addChangeListener: function(listener){ + this.listeners.addListener('change', listener); + }, + + notifyChangeListeners: function(){ + this.listeners.notifyListeners('change'); + } + +}); + +// +// CHANNEL STACK MANAGER +// + +function ChannelStackManager(channelStacks) { + this.init(channelStacks); +} + +$.extend(ChannelStackManager.prototype, { + + init: function(channelStacks){ + this.channelStacks = channelStacks; + }, + + isMatrix: function(){ + return !this.isSeriesNumberPresent() && !this.isTimePointMissing() && !this.isDepthMissing() && this.isDepthConsistent(); + }, + + isSeriesNumberPresent: function(){ + return this.channelStacks.some(function(channelStack){ + return channelStack.seriesNumberOrNull; + }); + }, + + isTimePointMissing: function(){ + return this.channelStacks.some(function(channelStack){ + return channelStack.timePointOrNull == null; + }); + }, + + isDepthMissing: function(){ + return this.channelStacks.some(function(channelStack){ + return channelStack.depthOrNull == null; + }); + }, + + isDepthConsistent: function(){ + var map = this.getChannelStackMap(); + var depthCounts = {}; + + for(timePoint in map){ + var entry = map[timePoint]; + var depthCount = Object.keys(entry).length; + depthCounts[depthCount] = true; + } + + return Object.keys(depthCounts).length == 1; + }, + + getTimePoints: function(){ + if(!this.timePoints){ + var timePoints = {}; + + this.channelStacks.forEach(function(channelStack){ + if(channelStack.timePointOrNull != null){ + timePoints[channelStack.timePointOrNull] = true; + } + }); + + this.timePoints = Object.keys(timePoints); + } + return this.timePoints; + }, + + getTimePoint: function(index){ + return this.getTimePoints()[index]; + }, + + getTimePointIndex: function(timePoint){ + if(!this.timePointsMap){ + var map = {}; + + this.getTimePoints().forEach(function(timePoint, index){ + map[timePoint] = index; + }); + + this.timePointsMap = map; + } + + return this.timePointsMap[timePoint]; + }, + + getDepths: function(){ + if(!this.depths){ + var depths = {}; + + this.channelStacks.forEach(function(channelStack){ + if(channelStack.depthOrNull != null){ + depths[channelStack.depthOrNull] = true; + } + }); + + this.depths = Object.keys(depths); + } + return this.depths; + }, + + getDepth: function(index){ + return this.getDepths()[index]; + }, + + getDepthIndex: function(depth){ + if(!this.depthsMap){ + var map = {}; + + this.getDepths().forEach(function(depth, index){ + map[depth] = index; + }); + + this.depthsMap = map; + } + + return this.depthsMap[depth]; + }, + + getChannelStack: function(timePoint, depthLevel){ + var map = this.getChannelStackMap(); + var entry = map[timePoint]; + + if(entry){ + return entry[depthLevel]; + }else{ + return null; + } + }, + + getChannelStacks: function(){ + return this.channelStacks; + }, + + getChannelStackMap: function(){ + if(!this.channelStackMap){ + var map = {}; + this.channelStacks.forEach(function(channelStack){ + if(channelStack.timePointOrNull != null && channelStack.depthOrNull != null){ + var entry = map[channelStack.timePointOrNull]; + if(!entry){ + entry = {}; + map[channelStack.timePointOrNull] = entry; + } + entry[channelStack.depthOrNull] = channelStack; + } + }); + this.channelStackMap = map; + } + return this.channelStackMap; + } +}); + +// +// MOVIE BUTTONS WIDGET +// +function MovieButtonsWidget(frameCount) { + this.init(frameCount); +} + +$.extend(MovieButtonsWidget.prototype, { + + init: function(frameCount){ + this.frameCount = frameCount; + this.frameAction = null; + this.selectedDelay = 500; + this.selectedFrame = 0; + this.listeners = new ListenerManager(); + this.panel = $("<div>").addClass("widget"); + }, + + render: function(){ + var thisButtons = this; + + var play = $("<button>").addClass("play").text("Play").appendTo(this.panel); + + play.click(function(){ + thisButtons.play(); + }); + + var stop = $("<button>").addClass("stop").text("Stop").appendTo(this.panel); + + stop.click(function(){ + thisButtons.stop(); + }); + + var prev = $("<button>").addClass("prev").text("<<").appendTo(this.panel); + + prev.click(function(){ + thisButtons.setSelectedFrame(thisButtons.getSelectedFrame() - 1); + }); + + var next = $("<button>").addClass("next").text(">>").appendTo(this.panel); + + next.click(function(){ + thisButtons.setSelectedFrame(thisButtons.getSelectedFrame() + 1); + }); + + var delay = $("<input>").attr("type", "text").addClass("delay").appendTo(this.panel); + + delay.change(function(){ + thisButtons.setSelectedDelay(delay.val()); + }); + + this.rendered = true; + this.refresh(); + + return this.panel; + }, + + refresh: function(){ + if(!this.rendered){ + return; + } + + var play = this.panel.find("button.play"); + play.prop("disabled", this.frameAction != null); + + var stop = this.panel.find("button.stop"); + stop.prop("disabled", this.frameAction == null); + + var prev = this.panel.find("button.prev"); + prev.prop("disabled", this.getSelectedFrame() == 0); + + var next = this.panel.find("button.next"); + next.prop("disabled", this.getSelectedFrame() == (this.frameCount - 1)); + + var delay = this.panel.find("input.delay"); + delay.val(this.selectedDelay); + }, + + play: function(){ + if(this.frameAction){ + return; + } + + if(this.getSelectedFrame() == this.frameCount - 1){ + this.setSelectedFrame(0); + } + + var thisButtons = this; + + this.frameAction = function(){ + if(!thisButtons.frameAction){ + return; + } + + if(thisButtons.getSelectedFrame() < thisButtons.frameCount - 1){ + thisButtons.setSelectedFrame(thisButtons.getSelectedFrame() + 1); + setTimeout(thisButtons.frameAction, thisButtons.selectedDelay); + }else{ + thisButtons.stop(); + thisButtons.setSelectedFrame(0); + } + }; + + this.frameAction(); + }, + + stop: function(){ + this.frameAction = null; + this.refresh(); + }, + + getSelectedDelay: function(){ + return this.selectedDelay; + }, + + setSelectedDelay: function(delay){ + if(this.selectedDelay != delay){ + this.selectedDelay = delay; + this.refresh(); + } + }, + + getSelectedFrame: function(){ + return this.selectedFrame; + }, + + setSelectedFrame: function(frame){ + frame = Math.min(Math.max(0, frame), this.frameCount - 1); + + if(this.selectedFrame != frame){ + this.selectedFrame = frame; + this.refresh(); + this.notifyChangeListeners(); + } + }, + + addChangeListener: function(listener){ + this.listeners.addListener('change', listener); + }, + + notifyChangeListeners: function(){ + this.listeners.notifyListeners('change'); + } + +}); + +// +// IMAGE +// +function ImageWidget() { + this.init(); +} + +$.extend(ImageWidget.prototype, { + + init: function(){ + this.panel = $("<div>") + }, + + render: function(){ + $("<img>").appendTo(this.panel); + this.rendered = true; + this.refresh(); + return this.panel; + }, + + refresh: function(){ + if(!this.rendered){ + return; + } + + var url = this.dataStoreUrl + "/datastore_server_screening"; + url += "?sessionID=" + this.sessionToken; + url += "&dataset=" + this.dataSetCode; + url += "&channelStackId=" + this.channelStackId; + + this.channels.forEach(function(channel){ + url += "&channel=" + channel; + }); + + if(this.resolution){ + url += "&mode=thumbnail" + this.resolution; + }else{ + url += "&mode=thumbnail480x480"; + } + + this.panel.find("img").attr("src", url); + }, + + setDataStoreUrl: function(dataStoreUrl){ + this.dataStoreUrl = dataStoreUrl; + this.refresh(); + }, + + setSessionToken: function(sessionToken){ + this.sessionToken = sessionToken; + this.refresh(); + }, + + setDataSetCode: function(dataSetCode){ + this.dataSetCode = dataSetCode; + this.refresh(); + }, + + setChannelStackId: function(channelStackId){ + this.channelStackId = channelStackId; + this.refresh(); + }, + + setChannels: function(channels){ + this.channels = channels; + this.refresh(); + }, + + setResolution: function(resolution){ + this.resolution = resolution; + this.refresh(); + } + +}); + +// +// CALLBACK MANAGER +// +function CallbackManager(callback) { + this.init(callback); +} + +$.extend(CallbackManager.prototype, { + + init: function(callback){ + this.callback = callback; + this.callbacks = {}; + }, + + registerCallback: function(callback){ + var manager = this; + + var wrapper = function(){ + callback.apply(this, arguments); + + delete manager.callbacks[callback] + + for(c in manager.callbacks){ + return; + } + + manager.callback(); + } + + this.callbacks[callback] = callback; + return wrapper; + } +}); + + +// +// LISTENER MANAGER +// +function ListenerManager() { + this.init(); +} + +$.extend(ListenerManager.prototype, { + + init: function(){ + this.listeners = {}; + }, + + addListener: function(eventType, listener){ + if(!this.listeners[eventType]){ + this.listeners[eventType] = [] + } + this.listeners[eventType].push(listener); + }, + + notifyListeners: function(eventType){ + if(this.listeners[eventType]){ + this.listeners[eventType].forEach(function(listener){ + listener(); + }); + } + } +}); diff --git a/screening/source/core-plugins/microscopy/1/as/webapps/image-viewer/html/index.html b/screening/source/core-plugins/microscopy/1/as/webapps/image-viewer/html/index.html index 897bc025937e7ec83b80c321309aea65b09432a3..c92f89f6844bf156d586721d7736a5bde2dedf1e 100644 --- a/screening/source/core-plugins/microscopy/1/as/webapps/image-viewer/html/index.html +++ b/screening/source/core-plugins/microscopy/1/as/webapps/image-viewer/html/index.html @@ -7,6 +7,7 @@ <script src="jquery.js"></script> <script src="openbis.js"></script> <script src="openbis-screening.js"></script> + <script src="image-viewer.js"></script> <style> @@ -16,7 +17,7 @@ </style> -</head> +</head> <body> <script> @@ -29,752 +30,6 @@ }); }); - // - // IMAGE VIEWER - // - function ImageViewerWidget(openbis, dataSetCode) { - this.init(openbis, dataSetCode); - } - - $.extend(ImageViewerWidget.prototype, { - init: function(openbis, dataSetCode){ - this.facade = new OpenbisFacade(openbis); - this.dataSetCode = dataSetCode; - this.panel = $("<div>") - }, - - load: function(callback){ - if(this.loaded){ - callback(); - }else{ - var thisImageViewer = this; - - var manager = new CallbackManager(function(){ - thisImageViewer.loaded = true; - callback(); - }); - - this.facade.tryGetDataStoreBaseURL(thisImageViewer.dataSetCode, manager.registerCallback(function(response){ - thisImageViewer.dataStoreUrl = response.result; - })); - - this.facade.getImageInfo(thisImageViewer.dataSetCode, manager.registerCallback(function(response){ - thisImageViewer.imageInfo = response.result; - })); - - this.facade.getImageResolutions(thisImageViewer.dataSetCode, manager.registerCallback(function(response){ - thisImageViewer.imageResolutions = response.result; - })); - } - }, - - render: function(){ - var thisImageViewer = this; - - this.load(function(){ - - var channelWidget = new ChannelChooserWidget(thisImageViewer.getChannels()); - channelWidget.addChangeListener(function(){ - imageWidget.setChannels(channelWidget.getSelectedOrMergedChannels()); - }); - thisImageViewer.panel.append(channelWidget.render()); - - var resolutionWidget = new ResolutionChooserWidget(thisImageViewer.getResolutions()); - resolutionWidget.addChangeListener(function(){ - imageWidget.setResolution(resolutionWidget.getSelectedResolution()); - }); - thisImageViewer.panel.append(resolutionWidget.render()); - - var channelStackWidget = new ChannelStackChooserWidget(thisImageViewer.getChannelStacks()); - channelStackWidget.addChangeListener(function(){ - imageWidget.setChannelStackId(channelStackWidget.getSelectedChannelStack().id); - }); - thisImageViewer.panel.append(channelStackWidget.render()); - - var imageWidget = new ImageWidget(); - imageWidget.setSessionToken(thisImageViewer.facade.getSession()); - imageWidget.setDataStoreUrl(thisImageViewer.dataStoreUrl); - imageWidget.setDataSetCode(thisImageViewer.dataSetCode); - imageWidget.setChannelStackId(channelStackWidget.getSelectedChannelStack().id); - imageWidget.setResolution(resolutionWidget.getSelectedResolution()); - imageWidget.setChannels(channelWidget.getSelectedOrMergedChannels()); - - thisImageViewer.panel.append(imageWidget.render()); - - }); - - return this.panel; - }, - - getChannels: function(){ - return this.imageInfo.imageDataset.imageDataset.imageParameters.channels; - }, - - getChannelStacks: function(){ - return this.imageInfo.channelStacks; - }, - - getResolutions: function(){ - return this.imageResolutions; - } - - }); - - // - // FACADE - // - function OpenbisFacade(openbis){ - this.init(openbis); - } - - $.extend(OpenbisFacade.prototype, { - init: function(openbis){ - this.openbis = openbis; - }, - - getSession: function(){ - return this.openbis.getSession(); - }, - - tryGetDataStoreBaseURL: function(dataSetCode, action){ - this.openbis.tryGetDataStoreBaseURL(dataSetCode, action); - }, - - getImageInfo: function(dataSetCode, callback){ - this.openbis.getImageInfo(dataSetCode, null, callback); - }, - - getImageResolutions: function(dataSetCode, callback){ - this.openbis.getImageResolutions(dataSetCode, callback); - } - }); - - // - // CHANNEL CHOOSER - // - function ChannelChooserWidget(channels) { - this.init(channels); - } - - $.extend(ChannelChooserWidget.prototype, { - - init: function(channels){ - this.channels = channels; - this.selectedChannel = null; - this.mergedChannels = channels.map(function(channel){ - return channel.code; - }); - - this.listeners = new ListenerManager(); - this.panel = $("<div>").addClass("widget"); - }, - - render: function(){ - var thisChooser = this; - - $("<div>").text("Channel:").appendTo(this.panel); - - var select = $("<select>").appendTo(this.panel); - - $("<option>").attr("value", "").text("Merged Channels").appendTo(select); - - this.channels.forEach(function(channel){ - $("<option>").attr("value", channel.code).text(channel.label).appendTo(select); - }); - - select.change(function(){ - if(select.val() == ""){ - thisChooser.setSelectedChannel(null); - }else{ - thisChooser.setSelectedChannel(select.val()); - } - }); - - var mergedChannels = $("<div>").addClass("mergedChannels").appendTo(this.panel); - - this.channels.forEach(function(channel){ - var mergedChannel = $("<span>").addClass("mergedChannel").appendTo(mergedChannels); - $("<input>").attr("type", "checkbox").attr("value", channel.code).appendTo(mergedChannel); - mergedChannel.append(channel.label); - }); - - mergedChannels.find("input").change(function(){ - var channels = [] - mergedChannels.find("input:checked").each(function(){ - var checkbox = $(this); - channels.push(checkbox.val()); - }); - thisChooser.setMergedChannels(channels); - }); - - this.rendered = true; - this.refresh(); - - return this.panel; - }, - - refresh: function(){ - if(!this.rendered){ - return; - } - - var thisChooser = this; - - var select = this.panel.find("select"); - var mergedChannels = this.panel.find(".mergedChannels"); - - if(this.getSelectedChannel()){ - select.val(this.getSelectedChannel()); - mergedChannels.hide(); - }else{ - select.val(""); - mergedChannels.find("input").each(function(){ - var checkbox = $(this); - var checked = $.inArray(checkbox.val(), thisChooser.getMergedChannels()) != -1; - checkbox.prop("checked", checked); - if(checked){ - checkbox.prop("disabled", thisChooser.getMergedChannels().length == 1); - } - }); - mergedChannels.show(); - } - }, - - getSelectedChannel: function(){ - return this.selectedChannel; - }, - - setSelectedChannel: function(channel){ - this.selectedChannel = channel; - this.refresh(); - this.notifyChangeListeners(); - }, - - getMergedChannels: function(){ - return this.mergedChannels; - }, - - setMergedChannels: function(channels){ - this.mergedChannels = channels; - this.refresh(); - this.notifyChangeListeners(); - }, - - getSelectedOrMergedChannels: function(){ - if(this.getSelectedChannel()){ - return [this.getSelectedChannel()]; - }else{ - return this.getMergedChannels(); - } - }, - - addChangeListener: function(listener){ - this.listeners.addListener('change', listener); - }, - - notifyChangeListeners: function(){ - this.listeners.notifyListeners('change'); - } - - }); - - // - // RESOLUTION CHOOSER - // - function ResolutionChooserWidget(resolutions) { - this.init(resolutions); - } - - $.extend(ResolutionChooserWidget.prototype, { - - init: function(resolutions){ - this.resolutions = resolutions; - this.selectedResolution = null; - this.listeners = new ListenerManager(); - this.panel = $("<div>").addClass("widget"); - }, - - render: function(){ - var thisChooser = this; - - $("<div>").text("Resolution:").appendTo(this.panel); - - var select = $("<select>").appendTo(this.panel); - - $("<option>").attr("value", "").text("Default").appendTo(select); - - this.resolutions.forEach(function(resolution){ - var value = resolution.width + "x" + resolution.height; - $("<option>").attr("value", value).text(value).appendTo(select); - }); - - select.change(function(){ - if(select.val() == ""){ - thisChooser.setSelectedResolution(null); - }else{ - thisChooser.setSelectedResolution(select.val()); - } - }); - - this.rendered = true; - this.refresh(); - - return this.panel; - }, - - refresh: function(){ - if(!this.rendered){ - return; - } - - var select = this.panel.find("select"); - if(this.selectedResolution){ - select.val(this.selectedResolution); - } - }, - - getSelectedResolution: function(){ - return this.selectedResolution; - }, - - setSelectedResolution: function(resolution){ - this.selectedResolution = resolution; - this.refresh(); - this.notifyChangeListeners(); - }, - - addChangeListener: function(listener){ - this.listeners.addListener('change', listener); - }, - - notifyChangeListeners: function(){ - this.listeners.notifyListeners('change'); - } - - }); - - // - // CHANNEL STACK CHOOSER - // - function ChannelStackChooserWidget(channelStacks) { - this.init(channelStacks); - } - - $.extend(ChannelStackChooserWidget.prototype, { - - init: function(channelStacks){ - var manager = new ChannelStackManager(channelStacks); - - if(manager.isMatrix()){ - this.widget = new ChannelStackMatrixChooserWidget(channelStacks); - }else{ - this.widget = new ChannelStackDefaultChooserWidget(channelStacks); - } - }, - - render: function(){ - return this.widget.render(); - }, - - getSelectedChannelStack: function(){ - return this.widget.getSelectedChannelStack(); - }, - - addChangeListener: function(listener){ - this.widget.addChangeListener(listener); - }, - - notifyChangeListeners: function(){ - this.widget.notifyChangeListeners(); - } - - }); - - // - // CHANNEL STACK MATRIX CHOOSER - // - function ChannelStackMatrixChooserWidget(channelStacks) { - this.init(channelStacks); - } - - $.extend(ChannelStackMatrixChooserWidget.prototype, { - - init: function(channelStacks){ - this.channelStackManager = new ChannelStackManager(channelStacks); - this.selectedTimePoint = this.channelStackManager.getTimePoints()[0]; - this.selectedDepth = this.channelStackManager.getDepths()[0]; - this.listeners = new ListenerManager(); - this.panel = $("<div>").addClass("widget"); - }, - - render: function(){ - var thisChooser = this; - - $("<div>").text("Channel Stack:").appendTo(this.panel); - - $("<span>").text("T:").appendTo(this.panel); - - var timeSelect = $("<select>").addClass("timeChooser").appendTo(this.panel); - - this.channelStackManager.getTimePoints().forEach(function(timePoint){ - $("<option>").attr("value", timePoint).text(timePoint).appendTo(timeSelect); - }); - - timeSelect.change(function(){ - thisChooser.setSelectedTimePoint(timeSelect.val()); - }); - - $("<span>").text("D:").appendTo(this.panel); - - var depthSelect = $("<select>").addClass("depthChooser").appendTo(this.panel); - - this.channelStackManager.getDepths().forEach(function(depth){ - $("<option>").attr("value", depth).text(depth).appendTo(depthSelect); - }); - - depthSelect.change(function(){ - thisChooser.setSelectedDepth(depthSelect.val()); - }); - - this.rendered = true; - this.refresh(); - - return this.panel; - }, - - refresh: function(){ - if(!this.rendered){ - return; - } - - var timeSelect = this.panel.find("select.timeChooser"); - - if(this.selectedTimePoint){ - timeSelect.val(this.selectedTimePoint); - } - - var depthSelect = this.panel.find("select.depthChooser"); - - if(this.selectedDepth){ - depthSelect.val(this.selectedDepth); - } - }, - - getSelectedChannelStack: function(){ - return this.channelStackManager.getChannelStack(this.selectedTimePoint, this.selectedDepth); - }, - - setSelectedTimePoint: function(timePoint){ - this.selectedTimePoint = timePoint; - this.refresh(); - this.notifyChangeListeners(); - }, - - setSelectedDepth: function(depth){ - this.selectedDepth = depth; - this.refresh(); - this.notifyChangeListeners(); - }, - - addChangeListener: function(listener){ - this.listeners.addListener('change', listener); - }, - - notifyChangeListeners: function(){ - this.listeners.notifyListeners('change'); - } - - }); - - // - // CHANNEL STACK DEFAULT CHOOSER - // - function ChannelStackDefaultChooserWidget(channelStacks) { - this.init(channelStacks); - } - - $.extend(ChannelStackDefaultChooserWidget.prototype, { - - init: function(channelStacks){ - this.channelStackManager = new ChannelStackManager(channelStacks); - this.listeners = new ListenerManager(); - this.panel = $("<div>"); - }, - - render: function(){ - this.panel.append("Default channel stack chooser"); - return this.panel; - }, - - getSelectedChannelStack: function(){ - return null; - }, - - setSelectedChannelStack: function(channelStack){ - }, - - addChangeListener: function(listener){ - this.listeners.addListener('change', listener); - }, - - notifyChangeListeners: function(){ - this.listeners.notifyListeners('change'); - } - - }); - - // - // CHANNEL STACK MANAGER - // - - function ChannelStackManager(channelStacks) { - this.init(channelStacks); - } - - $.extend(ChannelStackManager.prototype, { - - init: function(channelStacks){ - this.channelStacks = channelStacks; - }, - - isMatrix: function(){ - return !this.isSeriesNumberPresent() && !this.isTimePointMissing() && !this.isDepthMissing() && this.isDepthConsistent(); - }, - - isSeriesNumberPresent: function(){ - return this.channelStacks.some(function(channelStack){ - return channelStack.seriesNumberOrNull; - }); - }, - - isTimePointMissing: function(){ - return this.channelStacks.some(function(channelStack){ - return channelStack.timePointOrNull == null; - }); - }, - - isDepthMissing: function(){ - return this.channelStacks.some(function(channelStack){ - return channelStack.depthOrNull == null; - }); - }, - - isDepthConsistent: function(){ - var map = this.getChannelStackMap(); - var depthCounts = {}; - - for(timePoint in map){ - var entry = map[timePoint]; - var depthCount = Object.keys(entry).length; - depthCounts[depthCount] = true; - } - - return Object.keys(depthCounts).length == 1; - }, - - getTimePoints: function(){ - if(!this.timePoints){ - var timePoints = {}; - - this.channelStacks.forEach(function(channelStack){ - if(channelStack.timePointOrNull != null){ - timePoints[channelStack.timePointOrNull] = true; - } - }); - - this.timePoints = Object.keys(timePoints); - } - return this.timePoints; - }, - - getDepths: function(){ - if(!this.depths){ - var depths = {}; - - this.channelStacks.forEach(function(channelStack){ - if(channelStack.depthOrNull != null){ - depths[channelStack.depthOrNull] = true; - } - }); - - this.depths = Object.keys(depths); - } - return this.depths; - }, - - getChannelStack: function(timePoint, depthLevel){ - var map = this.getChannelStackMap(); - var entry = map[timePoint]; - - if(entry){ - return entry[depthLevel]; - }else{ - return null; - } - }, - - getChannelStacks: function(){ - return this.channelStacks; - }, - - getChannelStackMap: function(){ - if(!this.channelStackMap){ - var map = {}; - this.channelStacks.forEach(function(channelStack){ - if(channelStack.timePointOrNull != null && channelStack.depthOrNull != null){ - var entry = map[channelStack.timePointOrNull]; - if(!entry){ - entry = {}; - map[channelStack.timePointOrNull] = entry; - } - entry[channelStack.depthOrNull] = channelStack; - } - }); - this.channelStackMap = map; - } - return this.channelStackMap; - } - }); - - // - // IMAGE - // - function ImageWidget() { - this.init(); - } - - $.extend(ImageWidget.prototype, { - - init: function(){ - this.panel = $("<div>") - }, - - render: function(){ - $("<img>").appendTo(this.panel); - this.rendered = true; - this.refresh(); - return this.panel; - }, - - refresh: function(){ - if(!this.rendered){ - return; - } - - var url = this.dataStoreUrl + "/datastore_server_screening"; - url += "?sessionID=" + this.sessionToken; - url += "&dataset=" + this.dataSetCode; - url += "&channelStackId=" + this.channelStackId; - - this.channels.forEach(function(channel){ - url += "&channel=" + channel; - }); - - if(this.resolution){ - url += "&mode=thumbnail" + this.resolution; - }else{ - url += "&mode=thumbnail480x480"; - } - - this.panel.find("img").attr("src", url); - }, - - setDataStoreUrl: function(dataStoreUrl){ - this.dataStoreUrl = dataStoreUrl; - this.refresh(); - }, - - setSessionToken: function(sessionToken){ - this.sessionToken = sessionToken; - this.refresh(); - }, - - setDataSetCode: function(dataSetCode){ - this.dataSetCode = dataSetCode; - this.refresh(); - }, - - setChannelStackId: function(channelStackId){ - this.channelStackId = channelStackId; - this.refresh(); - }, - - setChannels: function(channels){ - this.channels = channels; - this.refresh(); - }, - - setResolution: function(resolution){ - this.resolution = resolution; - this.refresh(); - } - - }); - - // - // CALLBACK MANAGER - // - function CallbackManager(callback) { - this.init(callback); - } - - $.extend(CallbackManager.prototype, { - - init: function(callback){ - this.callback = callback; - this.callbacks = {}; - }, - - registerCallback: function(callback){ - var manager = this; - - var wrapper = function(){ - callback.apply(this, arguments); - - delete manager.callbacks[callback] - - for(c in manager.callbacks){ - return; - } - - manager.callback(); - } - - this.callbacks[callback] = callback; - return wrapper; - } - }); - - - // - // LISTENER MANAGER - // - function ListenerManager() { - this.init(); - } - - $.extend(ListenerManager.prototype, { - - init: function(){ - this.listeners = {}; - }, - - addListener: function(eventType, listener){ - if(!this.listeners[eventType]){ - this.listeners[eventType] = [] - } - this.listeners[eventType].push(listener); - }, - - notifyListeners: function(eventType){ - if(this.listeners[eventType]){ - this.listeners[eventType].forEach(function(listener){ - listener(); - }); - } - } - }); - </script> </body> </html>