/** * Project  : AMDA-NG * Name : PlotTabResultUI.js * @class amdaUI.PlotTabResultUI * @extends Ext. panel.Panel * @brief Plot Tab Result UI definition (View) * @author * @version $Id: PlotTabResultUI.js benjamin */ Ext.define('amdaUI.PlotTabResultUI', { extend: 'Ext.panel.Panel', alias: 'widget.plotTabResult', requires: [ 'amdaPlotComp.PlotZoomPlug', 'amdaPlotComp.PlotExtendShiftPlug', 'amdaPlotComp.PlotContextManager', 'amdaPlotComp.PlotResultImage' ], panelImage: null, crtContext: null, interactiveId: '', navToolBar: null, isTTNavBar: false, crtTTFileIndex: 0, disableSynchronize: false, multiplot: false, plotName: '', listParams: [], hiddenForm: null, constructor: function (config) { this.addEvents({ 'pagesize': true }); this.init(config); this.callParent(arguments); }, updateConfig: function (name, multiplot) { this.multiplot = multiplot; this.plotName = name; this.findParentByType('window').setTitle(this.plotName + (this.multiplot ? ' - Synchronized to Multiplot' : '')); }, getImageSize: function () { if (!this.crtContext) return { width: 0, height: 0 }; return { width: this.crtContext.page.width * this.sliderPage.getValue() / 100., height: this.crtContext.page.height * this.sliderPage.getValue() / 100. } }, getImageUrl: function (resultFolder, plotFile) { return 'data/' + sessionID + '/RES/' + resultFolder + '/' + plotFile; }, toPixelOnSourceImage: function (value) { return value * 100 / this.sliderPage.getValue(); }, toPixelOnResultImage: function (value) { return value * this.sliderPage.getValue() / 100; }, createZoomItemsForPanel: function (panelId) { var zoomPlugin = this.getPlugin('plot-zoom-plugin-id'); if (zoomPlugin == null) return; var panelContext = amdaPlotComp.PlotContextManager.getPanelById(this.crtContext, panelId); var size = this.getImageSize(); // We need a list of parameters to compute the number of points needed to apply FFT this.listParams = panelContext["parameters"]; zoomPlugin.path_context_file = 'data/' + sessionID + '/RES/' + this.configResult.folder + '/' + "plotFunction0_context.xml"; zoomPlugin.setParameters(this.listParams); var me = this; var insertIntervalItem = null; var plotFunctionItem = null; Ext.each(panelContext.plotArea.axes, function (axis) { //Events for zoom on a time axis var onMinTimeSelection = function (posX) { //Panel and axis context must be retrieved by using the crtContext var panelContext = amdaPlotComp.PlotContextManager.getPanelById(me.crtContext, panelId); var axisContext = amdaPlotComp.PlotContextManager.getPanelAxisById(panelContext, axis.id); var sourceXPos = me.toPixelOnSourceImage(posX); var crtTimestamp = amdaPlotComp.PlotContextManager.toAxisValue(axisContext, panelContext.plotArea.x, panelContext.plotArea.x + panelContext.plotArea.width, sourceXPos); var crtTime = new Date(crtTimestamp * 1000); crtTime = Ext.Date.add(crtTime, Ext.Date.MINUTE, crtTime.getTimezoneOffset()); zoomPlugin.setMinValue(crtTime); }; var onMaxTimeSelection = function (posX) { //Panel and axis context must be retrieved by using the crtContext var panelContext = amdaPlotComp.PlotContextManager.getPanelById(me.crtContext, panelId); var axisContext = amdaPlotComp.PlotContextManager.getPanelAxisById(panelContext, axis.id); var sourceXPos = me.toPixelOnSourceImage(posX); var crtTimestamp = amdaPlotComp.PlotContextManager.toAxisValue(axisContext, panelContext.plotArea.x, panelContext.plotArea.x + panelContext.plotArea.width, sourceXPos); var crtTime = new Date(crtTimestamp * 1000); crtTime = Ext.Date.add(crtTime, Ext.Date.MINUTE, crtTime.getTimezoneOffset()); zoomPlugin.setMaxValue(crtTime); }; //Events for zoom on a Y axis var onMinYValueSelection = function (posY) { //Panel and axis context must be retrieved by using the crtContext var panelContext = amdaPlotComp.PlotContextManager.getPanelById(me.crtContext, panelId); var axisContext = amdaPlotComp.PlotContextManager.getPanelAxisById(panelContext, axis.id); var sourceYPos = me.toPixelOnSourceImage(posY); var crtValue = amdaPlotComp.PlotContextManager.toAxisValue(axisContext, panelContext.plotArea.y + panelContext.plotArea.height, panelContext.plotArea.y, sourceYPos); zoomPlugin.setMinValue(crtValue); }; var onMaxYValueSelection = function (posY) { //Panel and axis context must be retrieved by using the crtContext var panelContext = amdaPlotComp.PlotContextManager.getPanelById(me.crtContext, panelId); var axisContext = amdaPlotComp.PlotContextManager.getPanelAxisById(panelContext, axis.id); var sourceYPos = me.toPixelOnSourceImage(posY); var crtValue = amdaPlotComp.PlotContextManager.toAxisValue(axisContext, panelContext.plotArea.y + panelContext.plotArea.height, panelContext.plotArea.y, sourceYPos); zoomPlugin.setMaxValue(crtValue); }; //Events for zoom on X axis var onMinXValueSelection = function (posX) { //Panel and axis context must be retrieved by using the crtContext var panelContext = amdaPlotComp.PlotContextManager.getPanelById(me.crtContext, panelId); var axisContext = amdaPlotComp.PlotContextManager.getPanelAxisById(panelContext, axis.id); var sourceXPos = me.toPixelOnSourceImage(posX); var crtValue = amdaPlotComp.PlotContextManager.toAxisValue(axisContext, panelContext.plotArea.x, panelContext.plotArea.x + panelContext.plotArea.width, sourceXPos); zoomPlugin.setMinValue(crtValue); }; var onMaxXValueSelection = function (posX) { //Panel and axis context must be retrieved by using the crtContext var panelContext = amdaPlotComp.PlotContextManager.getPanelById(me.crtContext, panelId); var axisContext = amdaPlotComp.PlotContextManager.getPanelAxisById(panelContext, axis.id); var sourceXPos = me.toPixelOnSourceImage(posX); var crtValue = amdaPlotComp.PlotContextManager.toAxisValue(axisContext, panelContext.plotArea.x, panelContext.plotArea.x + panelContext.plotArea.width, sourceXPos); zoomPlugin.setMaxValue(crtValue); }; switch (axis.id) { case 'timeAxis': me.contextualMenu.add({ text: 'Zoom on Time Axis', handler: function (item, e) { zoomPlugin.show(me.interactiveId, axis.id, panelContext.id); zoomPlugin.resetMinMaxValue(); me.panelImage.startZoom(true, 0/*me.toPixelOnResultImage(panelContext.y)*/, size.height /*me.toPixelOnResultImage(panelContext.height)*/, onMinTimeSelection, onMaxTimeSelection); }, scope: this }); //plotFunction Menu plotFunctionItem = { text: 'Apply a Function on Interval', handler: function (item, e) { zoomPlugin.show(me.interactiveId, axis.id, panelContext.id, true); zoomPlugin.resetMinMaxValue(); me.panelImage.startZoom(true, 0, size.height, onMinTimeSelection, onMaxTimeSelection); }, scope: this }; insertIntervalItem = { text: 'Insert Interval in TimeTable or Catalog', handler: function (item, e) { zoomPlugin.show(me.interactiveId, axis.id, panelContext.id); zoomPlugin.resetMinMaxValue(); me.panelImage.startZoom(true, 0/*me.toPixelOnResultImage(panelContext.y)*/, size.height /*me.toPixelOnResultImage(panelContext.height)*/, onMinTimeSelection, onMaxTimeSelection); }, scope: this }; break; case 'y-left': me.contextualMenu.add({ text: 'Zoom on Y Left Axis', handler: function (item, e) { zoomPlugin.show(me.interactiveId, axis.id, panelContext.id); zoomPlugin.resetMinMaxValue(); me.panelImage.startZoom(false, me.toPixelOnResultImage(panelContext.x), me.toPixelOnResultImage(panelContext.width), onMinYValueSelection, onMaxYValueSelection); } }); break; case 'y-right': me.contextualMenu.add({ text: 'Zoom on Y Right Axis', handler: function (item, e) { zoomPlugin.show(me.interactiveId, axis.id, panelContext.id); zoomPlugin.resetMinMaxValue(); me.panelImage.startZoom(false, me.toPixelOnResultImage(panelContext.x), me.toPixelOnResultImage(panelContext.width), onMinYValueSelection, onMaxYValueSelection); } }); break; case 'xaxis_id': me.contextualMenu.add({ text: 'Zoom on X Axis', handler: function (item, e) { zoomPlugin.show(me.interactiveId, axis.id, panelContext.id); zoomPlugin.resetMinMaxValue(); me.panelImage.startZoom(true, me.toPixelOnResultImage(panelContext.y), me.toPixelOnResultImage(panelContext.height), onMinXValueSelection, onMaxXValueSelection); } }); break; case 'epochAxis': //Nothing to add break; } }); if (insertIntervalItem != null) { me.contextualMenu.add('-'); me.contextualMenu.add(insertIntervalItem); } if (plotFunctionItem != null) { me.contextualMenu.insert(0, '-'); me.contextualMenu.insert(0, plotFunctionItem); } }, getAxisValue: function (axis, pixelMin, pixelMax, pixelVal) { var val = amdaPlotComp.PlotContextManager.toAxisValue(axis, pixelMin, pixelMax, pixelVal); return parseFloat(val).toPrecision(5); }, createPlotImage: function (resultFolder, plotFile) { var me = this; var size = this.getImageSize(); this.panelImage = Ext.create('amdaPlotComp.PlotResultImage', { src: this.getImageUrl(resultFolder, plotFile), width: size.width, height: size.height, onMouseMove: function (x, y) { if (!me.crtContext) return; var sourceXPos = me.toPixelOnSourceImage(x); var sourceYPos = me.toPixelOnSourceImage(y); var panel = amdaPlotComp.PlotContextManager.getPanel(me.crtContext, sourceXPos, sourceYPos); var text = ''; if (me.panelImage) { if (!panel) { me.panelImage.resetCursor(); text += 'No panel'; } else { text += 'Panel Id : '; text += panel.id; if (amdaPlotComp.PlotContextManager.isInPlotArea(panel, sourceXPos, sourceYPos)) { /*me.panelImage.updateCursor( me.toPixelOnResultImage(panel.plotArea.x), me.toPixelOnResultImage(panel.plotArea.y), me.toPixelOnResultImage(panel.plotArea.width), me.toPixelOnResultImage(panel.plotArea.height), x, y);*/ me.panelImage.updateCursor( me.toPixelOnResultImage(0), me.toPixelOnResultImage(0), me.toPixelOnResultImage(me.crtContext.page.width), me.toPixelOnResultImage(me.crtContext.page.height), x, y); var xText = ''; var yLeftText = ''; var yRightText = ''; var intervalText = ''; Ext.each(panel.plotArea.axes, function (axis) { switch (axis.id) { case 'timeAxis': var crtTimestamp = amdaPlotComp.PlotContextManager.toAxisValue(axis, panel.plotArea.x, panel.plotArea.x + panel.plotArea.width, sourceXPos); var crtTime = new Date(crtTimestamp * 1000); intervalText = amdaPlotComp.PlotContextManager.getIntervalCoordInfo(me.crtContext, panel, crtTimestamp); xText = crtTime.toJSON(); break; case 'y-left': yLeftText = me.getAxisValue(axis, panel.plotArea.y + panel.plotArea.height, panel.plotArea.y, sourceYPos); break; case 'y-right': yRightText = me.getAxisValue(axis, panel.plotArea.y + panel.plotArea.height, panel.plotArea.y, sourceYPos); break; case 'xaxis_id': xText = me.getAxisValue(axis, panel.plotArea.x, panel.plotArea.x + panel.plotArea.width, sourceXPos); break; case 'epochAxis': xText = me.getAxisValue(axis, panel.plotArea.x, panel.plotArea.x + panel.plotArea.width, sourceXPos); break; } }); if (xText != '') text += (', X : ' + xText); if (yLeftText != '') text += (', Y Left : ' + yLeftText); if (yRightText != '') text += (', Y Right : ' + yRightText); if (intervalText != '') text += (', ' + intervalText); } else me.panelImage.resetCursor(); } } me.coordinatesField.setText(text); }, onContextMenu: function (absoluteX, absoluteY, imageX, imageY) { if (!me.crtContext) return; me.contextualMenu.removeAll(true); var sourceXPos = me.toPixelOnSourceImage(imageX); var sourceYPos = me.toPixelOnSourceImage(imageY); var panel = amdaPlotComp.PlotContextManager.getPanel(me.crtContext, sourceXPos, sourceYPos); var timeAxisContext = amdaPlotComp.PlotContextManager.getPanelAxisById(panel, 'timeAxis'); if (timeAxisContext == null) return; var crtTimestamp = amdaPlotComp.PlotContextManager.toAxisValue(timeAxisContext, panel.plotArea.x, panel.plotArea.x + panel.plotArea.width, sourceXPos); if (panel != null) { if (panel.plotArea.hasSpectro) { me.contextualMenu.add([ { text: 'Instant cut at this position', handler: function () { var crtTime = new Date(crtTimestamp * 1000); //crtTime = Ext.Date.add(crtTime, Ext.Date.MINUTE, crtTime.getTimezoneOffset()); me.callInteractivePlot({ 'action': 'instant', 'interactiveId': this.interactiveId, 'panelId': panel.id, 'time': crtTime.toISOString() }); }, scope: me }, '-' ]); } if (amdaPlotComp.PlotContextManager.isInPlotArea(panel, sourceXPos, sourceYPos)) me.createZoomItemsForPanel(panel.id); } if (me.contextualMenu.items.getCount() > 0) me.contextualMenu.add('-'); me.contextualMenu.add([ { text: 'Extend/Shift Time interval', disabled: me.isTTNavBar, handler: function () { var extendShiftPlugin = this.getPlugin('plot-extendshift-plugin-id'); extendShiftPlugin.show(me.interactiveId); }, scope: me }, '-', { text: 'Save Plot', handler: function () { if (me.hiddenForm == null) me.hiddenForm = Ext.create('Ext.form.Panel', { title: 'hiddenForm', renderTo: Ext.getBody(), standardSubmit: true, url: 'php/downloadPlot.php', timeout: 120000, height: 100, width: 100, hidden: true, items: [] }); me.hiddenForm.getForm().submit({ params: { sessionId: sessionID, interactiveId: me.interactiveId }, success: function (form, action) { }, failure: function (form, action) { } }); } } ]); if (amdaPlotComp.PlotContextManager.isInterval(me.crtContext, panel, crtTimestamp)) { var allintervalParams = amdaPlotComp.PlotContextManager.getAllIntervalParams(me.crtContext, panel, crtTimestamp); if (allintervalParams.length > 0) { var links = amdaPlotComp.PlotContextManager.getIntervalLinks(allintervalParams); if (links.length > 0) { var menu = Ext.create('Ext.menu.Menu', { plain: true }); var realLinks = amdaPlotComp.PlotContextManager.setIntervalsRef(links, menu); me.contextualMenu.add('-'); me.contextualMenu.add([ { text: 'Open references (' + realLinks.length + ')', menu: menu, scope: me }]); } } } me.contextualMenu.showAt(absoluteX, absoluteY); } }); return this.panelImage; }, updatePlotImage: function (configResult, newPlot) { this.crtContext = configResult.context; this.crtTTFileIndex = configResult.ttFileIndex; if (this.isTTNavBar != (!configResult.isInterval) || (this.isSuperposeMode != this.crtContext.page.superposeMode)) { //Update navigation bar this.updateNavToolBar(!configResult.isInterval, this.crtContext.page.superposeMode); } this.updateTimeTableInfo(); this.panelImage.setSrc(this.getImageUrl(configResult.folder, configResult.plotFile)); var size = this.getImageSize(); this.panelImage.setSize(size.width, size.height); this.panelImage.refreshMe(); }, updateTimeTableInfo: function () { if (!this.navToolBar) return; var ttNameField = this.navToolBar.items.get('tt-table-' + this.interactiveId); if (ttNameField) ttNameField.setValue(this.crtContext.page.ttName); var ttNumberField = this.navToolBar.items.get('tt-number-' + this.interactiveId); if (ttNumberField) ttNumberField.setValue(this.crtContext.page.ttIndex + 1); var ttTotalField = this.navToolBar.items.get('tt-total-' + this.interactiveId); if (ttTotalField) ttTotalField.setValue(this.crtContext.page.ttNbIntervals); }, callInteractivePlot: function (obj, postProcess = () => null) { loadMask.show(true); var plotModule = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.plot.id); obj['multiplot'] = this.multiplot; AmdaAction.interactivePlot(obj, function (result, e) { loadMask.hide(); var t = e.getTransaction(); if (e.status) { if (result) { if (result.success) { plotModule.updateInteractiveSession(result, false, obj['panelId'], obj['time']); } else myDesktopApp.errorMsg('Interactive action error - ' + result.message); } else myDesktopApp.errorMsg('Cannot execute interactive action'); } else { // FAILURE myDesktopApp.errorMsg('Error System - ' + e.message); } }, this); }, updateNavToolBar: function (isTimeTable, isSuperposeMode) { if (this.navToolBar) this.navToolBar.removeAll(true); var commonItemsCfg = [ '-', { xtype: 'tbspacer', width: 20 }, '->', { text: 'Get HST Data', scope: this, menu: [ { text: 'Giant Planet Auroral Emissions', scope: this, handler: function () { var me = this; myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.astro.id, true, function (module) { var startTime = new Date(me.crtContext.page.startTime * 1000); startTime = Ext.Date.add(startTime, Ext.Date.MINUTE, startTime.getTimezoneOffset()); var stopTime = new Date(me.crtContext.page.stopTime * 1000); stopTime = Ext.Date.add(stopTime, Ext.Date.MINUTE, stopTime.getTimezoneOffset()); module.createWindow(startTime, stopTime); }); } }] }]; if (isTimeTable) { var navigationItemsCfg = [{ text: 'Previous', scope: this, handler: function () { var ttFileIndex = this.crtTTFileIndex; var ttintervalIndex = this.crtContext.page.ttIndex; if (ttintervalIndex <= 0 && ttFileIndex > 0) { --ttFileIndex; } else --ttintervalIndex; this.callInteractivePlot({ 'action': 'goto', 'interactiveId': this.interactiveId, 'ttFileIndex': ttFileIndex, 'intIndex': ttintervalIndex }); } }, '-', { text: 'Next', scope: this, handler: function () { var ttFileIndex = this.crtTTFileIndex; var ttintervalIndex = this.crtContext.page.ttIndex; if (ttintervalIndex >= this.crtContext.page.ttNbIntervals - 1) { ++ttFileIndex; ttintervalIndex = 0; } else ++ttintervalIndex; this.callInteractivePlot({ 'action': 'goto', 'interactiveId': this.interactiveId, 'ttFileIndex': ttFileIndex, 'intIndex': ttintervalIndex }); } }, '-', { text: 'Use This Time Inteval', scope: this, handler: function () { var timeObj = new Object(); var startTime = new Date(this.crtContext.page.startTime * 1000); timeObj.start = Ext.Date.add(startTime, Ext.Date.MINUTE, startTime.getTimezoneOffset()); var stopTime = new Date(this.crtContext.page.stopTime * 1000); timeObj.stop = Ext.Date.add(stopTime, Ext.Date.MINUTE, stopTime.getTimezoneOffset()); var plotModule = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.plot.id); plotModule.setTimeInterval(timeObj); } }, '-', { text: 'Go to Interval #', scope: this, handler: function (bt) { var ttGotoNumberField = this.navToolBar.items.get('tt-goto-number-' + this.interactiveId); var goToIndex = ttGotoNumberField.getValue() - 1; if ((goToIndex < 0) || (goToIndex >= this.crtContext.page.ttNbIntervals)) myDesktopApp.errorMsg('This interval number is outside of the current timeTable'); else this.callInteractivePlot({ 'action': 'goto', 'interactiveId': this.interactiveId, 'ttFileIndex': this.crtTTFileIndex, 'intIndex': goToIndex }); } }, { xtype: 'numberfield', id: 'tt-goto-number-' + this.interactiveId, hideTrigger: true, width: 50, minValue: 1 }, ' ', ' ', ' ', { xtype: 'textfield', id: 'tt-table-' + this.interactiveId, labelAlign: 'right', labelWidth: 30, fieldLabel: 'Table', width: 130, disabled: true }, { xtype: 'textfield', id: 'tt-number-' + this.interactiveId, labelAlign: 'right', labelWidth: 30, fieldLabel: 'Int #', width: 90, disabled: true }, { xtype: 'textfield', id: 'tt-total-' + this.interactiveId, labelAlign: 'right', labelWidth: 30, fieldLabel: 'Total', width: 90, disabled: true }]; } else { var navigationItemsCfg = [ { text: 'Backward', scope: this, handler: function () { this.callInteractivePlot({ 'action': 'backward', 'interactiveId': this.interactiveId }); } }, '-', { text: '1/2 Backward', scope: this, handler: function () { this.callInteractivePlot({ 'action': 'halfbackward', 'interactiveId': this.interactiveId }); } }, '-', { text: '1/4 Backward', scope: this, handler: function () { this.callInteractivePlot({ 'action': 'quarterbackward', 'interactiveId': this.interactiveId }); } }, '-', { text: '1/4 Forward', scope: this, handler: function () { this.callInteractivePlot({ 'action': 'quarterforward', 'interactiveId': this.interactiveId }); } }, '-', { text: '1/2 Forward', scope: this, handler: function () { this.callInteractivePlot({ 'action': 'halfforward', 'interactiveId': this.interactiveId }); } }, '-', { text: 'Forward', scope: this, handler: function () { this.callInteractivePlot({ 'action': 'forward', 'interactiveId': this.interactiveId }); } }]; } var toolItemsCfg = navigationItemsCfg; Ext.each(commonItemsCfg, function (item) { toolItemsCfg.push(item); }); if (!this.navToolBar) { var toolConfig = { dock: 'top', items: toolItemsCfg }; this.navToolBar = Ext.create('Ext.toolbar.Toolbar', toolConfig); } else this.navToolBar.add(toolItemsCfg); this.navToolBar.setDisabled(isSuperposeMode); this.isTTNavBar = isTimeTable; this.isSuperposeMode = isSuperposeMode; }, init: function (configResult) { this.crtContext = configResult.context; this.configResult = configResult; this.interactiveId = configResult.interactiveId; this.multiplot = (configResult.multiplot == true); this.coordinatesField = new Ext.toolbar.TextItem({ width: 300, text: '' }); this.sliderPage = new Ext.slider.Single({ width: 130, value: 75, increment: 5, minValue: 50, maxValue: 100, fieldLabel: 'Resize', labelWidth: 40, listeners: { scope: this, changecomplete: function (s, v) { var zoomPlugin = this.getPlugin('plot-zoom-plugin-id'); zoomPlugin.close(); var size = this.getImageSize(); this.panelImage.width = size.width; this.panelImage.height = size.height; this.panelImage.doComponentLayout(); this.fireEvent('pagesize', this, v); } } }); var mouseToolbar = { xtype: 'toolbar', height: 25, dock: 'bottom', items: [ this.coordinatesField, '->', this.sliderPage ] }; this.contextualMenu = Ext.create('Ext.menu.Menu', { width: 200, plain: true, items: [] }); this.updateNavToolBar(!configResult.isInterval, this.crtContext.page.superposeMode); this.updateTimeTableInfo(); var plotResultTabPanelConfig = { preventHeader: true, autoScroll: true, items: [this.createPlotImage(configResult.folder, configResult.plotFile)], dockedItems: [this.navToolBar, mouseToolbar], plugins: [ { ptype: 'plotZoomPlugin', pluginId: 'plot-zoom-plugin-id' }, { ptype: 'plotExtendShiftPlugin', pluginId: 'plot-extendshift-plugin-id' }], listeners: { scope: this, destroy: function () { var zoomPlugin = this.getPlugin('plot-zoom-plugin-id'); if (zoomPlugin) zoomPlugin.close(); var exttendShiftPlugin = this.getPlugin('plot-extendshift-plugin-id'); if (exttendShiftPlugin) exttendShiftPlugin.close(); } } }; Ext.apply(this, plotResultTabPanelConfig); } });