Commit 444a796ab1d826187be07bf335c19cace76b817b

Authored by Benjamin Renard
2 parents a971060f d0a99d97

Merge branch 'master' of https://gitlab.irap.omp.eu/CDPP/AMDA_IHM

help/visuHOWTO 0 → 100644
... ... @@ -0,0 +1,3 @@
  1 +TBD
  2 +
  3 +
... ...
js/app/AmdaApp.js
... ... @@ -20,6 +20,13 @@ Ext.define('amdaApp.AmdaApp', {
20 20 ],
21 21  
22 22 dynamicModules: {
  23 + visu : {
  24 + id : 'visu-win',
  25 + icon : 'icon-visu_catalog',
  26 + title : 'Visualization',
  27 + source : 'amdaDesktop.VisuModule',
  28 + useLauncher : true
  29 + },
23 30 statistics : {
24 31 id : 'statistics-win',
25 32 icon : 'icon-statistics',
... ... @@ -57,7 +64,7 @@ Ext.define('amdaApp.AmdaApp', {
57 64 },
58 65 plot : {
59 66 id : 'plot-win',
60   - icon : 'icon-plot',
  67 + icon : 'icon-plot',
61 68 title : 'Plot Manager',
62 69 source : 'amdaDesktop.PlotModule',
63 70 useLauncher : true
... ... @@ -281,7 +288,7 @@ Ext.define('amdaApp.AmdaApp', {
281 288 { name: 'Manage TimeTables', iconCls: 'timeTable', module: 'timetab-win' },
282 289 { name: 'TimeTables operations', iconCls: 'operations', module: 'ttsOpe-win' },
283 290 { name: 'Manage catalogs', iconCls: 'catalog', module: 'catalog-win'},
284   - { name: 'Visualize catalogs', iconCls: 'visu_catalog', module: 'visucatalog-win'},
  291 + { name: 'Visualize catalogs', iconCls: 'visu_catalog', module: 'visu-win'},
285 292 { name: 'Interoperability', iconCls: 'interop', module: 'interop-win' }
286 293 ]
287 294 }),
... ...
js/app/controllers/VisuModule.js 0 → 100644
... ... @@ -0,0 +1,35 @@
  1 +/**
  2 + * Project  AMDA-NG
  3 + * Name VisuModule.js
  4 + * @class amdaDesktop.VisuModule
  5 + * @extends amdaDesktop.InteractiveModule
  6 + * @brief Visualization Module controller definition
  7 + * @author elena
  8 + */
  9 +
  10 +Ext.define('amdaDesktop.VisuModule', {
  11 + extend: 'amdaDesktop.InteractiveModule',
  12 +
  13 + requires: [
  14 + 'amdaUI.VisuUI'
  15 + ],
  16 +
  17 + contentId : 'visuUI',
  18 +
  19 + /**
  20 + * @cfg {String} data models
  21 + * @required
  22 + */
  23 + nodeDataModel : 'amdaModel.CatalogNode', // 'amdaModel.MyDataNode'
  24 +
  25 + /**
  26 + * @cfg {String} window definitions
  27 + * @required
  28 + */
  29 + width : 800,
  30 + height: 700,
  31 + uiType : 'panelVisu',
  32 + helpTitle : 'Help on Visualization Module',
  33 + helpFile : 'visuHelp'
  34 +
  35 +});
... ...
js/app/models/CatalogNode.js
... ... @@ -38,11 +38,11 @@ Ext.define('amdaModel.CatalogNode', {
38 38 fnId : 'leaf-download',
39 39 text : 'Download '+ this.self.objectName,
40 40 hidden : true
41   - }/*,{
42   - fnId : 'leaf-operations',
43   - text : 'Operations',
  41 + },{
  42 + fnId : 'leaf-visu',
  43 + text : 'Visualize '+ this.self.objectName,
44 44 hidden : true
45   - }*/];
  45 + }];
46 46  
47 47 return menuItems;
48 48 },
... ... @@ -69,5 +69,16 @@ Ext.define('amdaModel.CatalogNode', {
69 69  
70 70 downloadMulti: function() {
71 71 alert('NOT IMPLEMENTED YET');
  72 + },
  73 +
  74 + visu : function(contextNode) {
  75 +
  76 + var me = this;
  77 +
  78 + myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.visu.id, true, function (module) {
  79 + // Opening parameter window
  80 + module.createWindow();
  81 + module.getUiContent().setObject(me.get('text'), me.get('id'));
  82 + });
72 83 }
73 84 });
... ...
js/app/models/TimeTableNode.js
... ... @@ -117,6 +117,10 @@ Ext.define('amdaModel.TimeTableNode', {
117 117 case 'operationsMulti':
118 118 this.operationsMulti();
119 119 break;
  120 +
  121 + case 'visu':
  122 + this.visu();
  123 + break;
120 124  
121 125 default:
122 126 break;
... ...
js/app/views/ExplorerUI.js
... ... @@ -353,7 +353,9 @@ Ext.define('amdaUI.ExplorerUI', {
353 353 switch (targetNode.data.nodeType)
354 354 {
355 355 case 'localParam' :
356   - case 'myData' :
  356 + case 'remoteParam' :
  357 + case 'remoteSimuParam' :
  358 + case 'myData' :
357 359 return false;
358 360 default :
359 361 if (draggedRecord.data.id == targetNode.data.nodeType+'-treeRootNode')
... ...
js/app/views/VisuUI.js 0 → 100644
... ... @@ -0,0 +1,413 @@
  1 +/**
  2 + * Project AMDA-NG
  3 + * Name VisuUI.js
  4 + * @class amdaUI.visuUI
  5 + * @extends Ext.container.Container
  6 + * @brief Visualization Module UI definition (View)
  7 + * @author elena
  8 + */
  9 +
  10 +Ext.define('amdaUI.VisuUI', {
  11 + extend: 'Ext.container.Container',
  12 + alias: 'widget.panelVisu',
  13 +
  14 + constructor: function(config)
  15 + {
  16 + this.init(config);
  17 + this.callParent(arguments);
  18 +
  19 + //if (this.object) this.loadObject();
  20 + },
  21 +
  22 + setObject : function (name,id)
  23 + {
  24 + // set object
  25 + this.object.set('id',id);
  26 + this.object.set('name',name);
  27 + // load object into view
  28 + this.loadObject();
  29 + },
  30 +
  31 + /**
  32 + * set params description into this.object
  33 + */
  34 + setParamInfo : function(parameters)
  35 + {
  36 + var params = [];
  37 + Ext.Array.each(parameters, function(item, index) {
  38 + params[index] = item;
  39 + }, this);
  40 +
  41 + this.object.set('parameters', params);
  42 + },
  43 +
  44 + updateCount : function()
  45 + {
  46 +// this.object.set('nbIntervals',this.TTGrid.getStore().getTotalCount());
  47 +// this.formPanel.getForm().findField('nbIntervals').setValue(this.object.get('nbIntervals'));
  48 + },
  49 +
  50 + /**
  51 + * load object catalog into this view
  52 + */
  53 + loadObject : function()
  54 + {
  55 + // load object into form
  56 +
  57 + var me = this;
  58 +
  59 + var onAfterInit = function(result, e)
  60 + {
  61 + if (!result || !result.success)
  62 + {
  63 + if (result.message)
  64 + myDesktopApp.errorMsg(result.message);
  65 + else
  66 + myDesktopApp.errorMsg('Unknown error during catalog cache initialisation');
  67 + return;
  68 + }
  69 +
  70 +
  71 +
  72 + var fields = [], i = 0, index;
  73 +
  74 + Ext.Array.each(result.parameters, function(obj)
  75 + {
  76 +
  77 + index = 'param'+i.toString();
  78 + fields[i] = Ext.create('Ext.data.Field', { name : index, id: index, text : obj.name,
  79 + convert: function(value, record) {
  80 + return parseFloat(value);
  81 + }
  82 + }
  83 + );
  84 +
  85 + i++;
  86 + });
  87 +
  88 + var newStore = Ext.create('Ext.data.Store', {
  89 + fields : [ 'text', 'id'],
  90 + data : fields
  91 + });
  92 +
  93 + me.parCombo.bindStore(newStore);
  94 + me.parCombo1.bindStore(newStore);
  95 +
  96 + me.chartStore = Ext.create('Ext.data.Store', {
  97 + fields : fields,
  98 + autoDestroy: false,
  99 + // pageSize : 200,
  100 + // buffered : true,
  101 + // purgePageCount: 0,
  102 + // remoteSort: true,
  103 + autoload: false,
  104 + proxy: {
  105 + type: 'direct',
  106 + api :
  107 + {
  108 + read : AmdaAction.readIntervalsForChart
  109 + },
  110 + // remplir automatiquement tt, sharedtt , catalog, shared catalog
  111 + extraParams : {'typeTT' : 'catalog', 'id' : me.object.get('id')},
  112 + reader:
  113 + {
  114 + type: 'json',
  115 + root: 'intervals',
  116 + totalProperty : 'totalCount'
  117 + }
  118 + },
  119 + listeners: {
  120 + scope : me,
  121 + load: function(store,records) {
  122 + //TODO enable plot button
  123 + }
  124 + }
  125 + });
  126 +
  127 + me.chartStore.load();
  128 +
  129 + }
  130 +
  131 + AmdaAction.initForChartFromTT(this.object.get('id'), 'catalog', onAfterInit);
  132 +
  133 + },
  134 +
  135 + /**
  136 + * updated object catalog into this view
  137 + */
  138 + updateObject : function()
  139 + {
  140 + // load object into form
  141 + //this.formPanel.getForm().loadRecord(this.object);
  142 +
  143 + var me = this;
  144 +
  145 + },
  146 +
  147 + /**
  148 + * Check if changes were made before closing window
  149 + * @return true if changes
  150 + */
  151 + fclose : function()
  152 + {
  153 +
  154 + return false;
  155 + },
  156 +
  157 + plotChart : function () {
  158 +
  159 + this.chartConfig.store=this.chartStore;
  160 +
  161 + var chart = Ext.create('Ext.chart.Chart', this.chartConfig);
  162 + // chart.bindStore(this.chartStore);
  163 + var chartPanel = this.items.items[0].items.items[1];
  164 + var oldChart = chartPanel.down('chart');
  165 + oldIndex = chartPanel.items.indexOf(oldChart);
  166 + chartPanel.remove(oldChart);
  167 + chartPanel.insert(oldIndex, chart);
  168 + },
  169 +
  170 + init : function (config)
  171 + {
  172 + var store = Ext.create('Ext.data.Store', {
  173 + fields : [],
  174 + autoload : false
  175 + });
  176 +
  177 + this.chartConfig = {
  178 + width: 500,
  179 + height: 500,
  180 + animate: true,
  181 + mask: true,
  182 + // theme:'Category2',
  183 + store: store,
  184 + axes: [{
  185 + type: 'Numeric',
  186 + position: 'bottom',
  187 + fields: [],
  188 + title: 'x axe',
  189 + grid : true
  190 + }, {
  191 + type: 'Numeric',
  192 + position: 'left',
  193 + fields: [],
  194 + title: 'y axe',
  195 + grid: true
  196 + }],
  197 + series: [{
  198 + type: 'scatter',
  199 + markerConfig: {
  200 + radius: 5,
  201 + size: 5
  202 + },
  203 + // // axes: ['left', 'bottom'],
  204 + xField: '',
  205 + yField: '',
  206 + label: {
  207 +// display: 'under',
  208 +// render: function(value) {
  209 +// return parseFloat(value);
  210 +// }
  211 + }
  212 + }]
  213 + }
  214 +
  215 + var plotTypeList = Ext.create('Ext.data.Store', {
  216 + fields: ['type'],
  217 + data: [
  218 + { 'type': 'line' },
  219 + { 'type': 'scatter' }
  220 + ]
  221 + });
  222 +
  223 + var parList = Ext.create('Ext.data.Store', {
  224 + fields: [],
  225 + autoload : false
  226 + });
  227 +
  228 + var chart = Ext.create('Ext.chart.Chart', this.chartConfig);
  229 +
  230 + this.parCombo = Ext.create('Ext.form.ComboBox', {
  231 + emptyText: 'select parameter',
  232 + editable: false,
  233 + store: parList,
  234 + queryMode: 'local',
  235 + displayField: 'text',
  236 + valueField: 'id',
  237 + listeners : {
  238 + scope : this,
  239 + change : function(combo, newValue, oldValue) {
  240 +
  241 + this.chartConfig.axes[0].fields = [newValue];
  242 + var rec = combo.findRecordByValue(newValue);
  243 + this.chartConfig.axes[0].title = rec.get('text');
  244 + this.chartConfig.series[0].xField = newValue;
  245 + }
  246 + }
  247 + });
  248 +
  249 + this.parCombo1 = Ext.create('Ext.form.ComboBox', {
  250 + emptyText: 'select parameter',
  251 + editable: false,
  252 + store: parList,
  253 + queryMode: 'local',
  254 + displayField: 'text',
  255 + valueField: 'id',
  256 + listeners : {
  257 + scope : this,
  258 + change : function(combo, newValue, oldValue) {
  259 +
  260 + this.chartConfig.axes[1].fields = [newValue];
  261 + var rec = combo.findRecordByValue(newValue);
  262 + this.chartConfig.axes[1].title = rec.get('text');
  263 + this.chartConfig.series[0].yField = newValue;
  264 + }
  265 + }
  266 + });
  267 +
  268 + var plotTypeCombo = Ext.create('Ext.form.ComboBox', {
  269 + emptyText: 'select plot type',
  270 + editable: false,
  271 + store: plotTypeList,
  272 + queryMode: 'local',
  273 + displayField: 'type',
  274 + valueField: 'type',
  275 + listeners : {
  276 + scope : this,
  277 + change : function(combo, newValue, oldValue) {
  278 + this.chartConfig.series[0].type = newValue;
  279 + }
  280 + }
  281 + });
  282 +
  283 +
  284 + var formPanel = Ext.create('Ext.form.Panel', {
  285 + region : 'center',
  286 + layout: 'hbox',
  287 + bodyStyle: {background : '#dfe8f6'},
  288 + defaults: { border : false, align: 'stretch', padding: '3'},
  289 + fieldDefaults: { labelWidth: 80, labelAlign : 'top' },
  290 + items: [
  291 + {
  292 + xtype: 'form',
  293 + flex : 1,
  294 + bodyStyle: {background : '#dfe8f6'},
  295 + items: [
  296 + {
  297 + xtype : 'fieldset',
  298 + title : 'X axis',
  299 + items : [
  300 + this.parCombo,
  301 + {
  302 + xtype : 'fieldcontainer',
  303 + layout: 'hbox',
  304 + items: [{
  305 + xtype: 'textfield',
  306 + flex: 1
  307 + }, {
  308 + xtype: 'splitter'
  309 + }, {
  310 + xtype: 'textfield',
  311 + flex: 1
  312 + }]
  313 + },
  314 + { xtype : 'checkbox' },
  315 + { xtype : 'checkbox' }
  316 + ]
  317 + },
  318 + {
  319 + xtype : 'fieldset',
  320 + title : 'Y axis',
  321 + items : [
  322 + this.parCombo1,
  323 + {
  324 + xtype : 'fieldcontainer',
  325 + layout: 'hbox',
  326 + items: [{
  327 + xtype: 'textfield',
  328 + flex: 1
  329 + }, {
  330 + xtype: 'splitter'
  331 + }, {
  332 + xtype: 'textfield',
  333 + flex: 1
  334 + }
  335 + ]
  336 + },
  337 + { xtype : 'checkbox' },
  338 + { xtype : 'checkbox' }
  339 + ]
  340 + },
  341 + {
  342 + xtype : 'fieldset',
  343 + title : 'Plotting Options',
  344 + items : [
  345 + plotTypeCombo
  346 + ]
  347 + }
  348 + ],
  349 + fbar:[
  350 + {
  351 + type: 'button',
  352 + text: 'Plot',
  353 + scope : this,
  354 + handler: this.plotChart
  355 +
  356 + },{
  357 + type: 'button',
  358 + text: 'Reset'
  359 +
  360 + }
  361 + ]
  362 + }, {
  363 + xtype: 'form',
  364 + // padding: '3',
  365 + flex: 2,
  366 + items : [
  367 + chart
  368 + ],
  369 + fbar:[
  370 + {
  371 + type: 'button',
  372 + text: 'Save Chart',
  373 + scope: this,
  374 + handler: function() {
  375 + var chartPanel = this.items.items[0].items.items[1];
  376 + var chart = chartPanel.down('chart');
  377 + chart.save({
  378 + type: 'image/png'
  379 + });
  380 + }
  381 +
  382 + }
  383 + ]
  384 + }
  385 + ]
  386 + });
  387 +
  388 +
  389 + var myConf = {
  390 + layout: 'border',
  391 + items: [
  392 + formPanel,
  393 + {
  394 + xtype: 'panel',
  395 + region: 'south',
  396 + title: 'Information',
  397 + collapsible: true,
  398 + height: 100,
  399 + autoHide: false,
  400 + bodyStyle: 'padding:5px',
  401 + iconCls: 'icon-information',
  402 + loader: {
  403 + autoLoad: true,
  404 + url: helpDir+'visuHOWTO'
  405 + }
  406 + }
  407 + ]
  408 + };
  409 +
  410 + Ext.apply (this, Ext.apply(arguments, myConf));
  411 + }
  412 +
  413 +});
... ...
php/classes/AmdaAction.php
... ... @@ -954,6 +954,14 @@ class AmdaAction {
954 954 return $cacheMgr->initFromTT($id, $type);
955 955 }
956 956  
  957 + public function initForChartFromTT($id, $type)
  958 + {
  959 + if ($type == 'catalog') $objMgr = new CatalogMgr();
  960 +
  961 +
  962 + return $objMgr->initForChartFromTT($id, $type);
  963 + }
  964 +
957 965 public function initTTCacheFromTmpObject($folderId, $name, $isCatalog = false)
958 966 {
959 967 if (!$isCatalog) $cacheMgr = new TimeTableCacheMgr();
... ... @@ -978,7 +986,15 @@ class AmdaAction {
978 986  
979 987 return $cacheMgr->getIntervals($o->start,$o->limit,$o->sort,$o->filter);
980 988 }
981   -
  989 +
  990 + public function readIntervalsForChart($o)
  991 + {
  992 + if ($o->typeTT == 'catalog') $objMgr = new CatalogMgr();
  993 +
  994 +
  995 + return $objMgr->getIntervalsForChart($o->id, $o->typeTT);
  996 + }
  997 +
982 998 public function saveTTCacheIntervalsInTT($o)
983 999 {
984 1000 $cacheMgr = new TimeTableCacheMgr();
... ...
php/classes/CatalogMgr.php
... ... @@ -249,6 +249,74 @@ class CatalogMgr extends TimeTableMgr {
249 249  
250 250 }
251 251  
  252 + public function initForChartFromTT($id, $typeTT)
  253 + {
  254 + $intervals_res = $this->loadIntervalsFromTT($id,$typeTT);
  255 +
  256 + if (!$intervals_res['success'])
  257 + return $intervals_res;
  258 +
  259 + $paramHeaders = [];
  260 +
  261 + foreach ( $intervals_res['parameters'] as $param ) {
  262 +
  263 + if ($param['size'] > 1) {
  264 +
  265 + for ($i = 0; $i < $param['size']; $i++) {
  266 + $paramComp = array();
  267 + $paramComp['id'] = $param['id'].'_'.$i;
  268 + $paramComp['name'] = $param['name'].'_'.$i;
  269 + // $paramComp['size'] = 1;
  270 +
  271 + $paramHeaders[] = $paramComp;
  272 + }
  273 + }
  274 + else {
  275 + $paramHeaders[] = $param;
  276 + }
  277 + }
  278 +
  279 + unset($intervals_res);
  280 +
  281 + return array('success' => true, 'parameters' => $paramHeaders);
  282 + }
  283 +
  284 + public function getIntervalsForChart($id, $type) {
  285 +
  286 + $intervals_res = $this->loadIntervalsFromTT($id,$type);
  287 +
  288 + if (!$intervals_res['success'])
  289 + return $intervals_res;
  290 +
  291 + $newIntervals = array();
  292 +
  293 + foreach ($intervals_res['intervals'] as $interval)
  294 + {
  295 + $newIntervalComp = array();
  296 + $k = 0;
  297 +
  298 + for ( $j = 0; $j < count($interval['paramTable']); $j++ ) {
  299 +
  300 + $param = $interval['paramTable'][$j];
  301 + $tempArr = explode(',',$param);
  302 +
  303 + if (count($tempArr) > 1) {
  304 + for ($i = 0; $i < count($tempArr); $i++) {
  305 + $newIntervalComp['param'.$k] = $tempArr[$i];
  306 + $k++;
  307 + }
  308 + }
  309 + else {
  310 + $newIntervalComp['param'.$k] = $param;
  311 + $k++;
  312 + }
  313 + }
  314 + $newIntervals[] = $newIntervalComp;
  315 + }
  316 +
  317 + return array('success' => true, 'intervals' => $newIntervals);
  318 +
  319 + }
252 320  
253 321 }
254 322 ?>
... ...
php/config.php
... ... @@ -241,9 +241,9 @@ $API = array(
241 241 'modifyObject'=>array(
242 242 'len'=>1
243 243 ),
244   - 'validNameObject'=>array(
245   - 'len'=>1
246   - ),
  244 + 'validNameObject'=>array(
  245 + 'len'=>1
  246 + ),
247 247 'getJobs'=>array(
248 248 'len'=>0
249 249 ),
... ... @@ -278,6 +278,9 @@ $API = array(
278 278 'initTTCacheFromTT' => array(
279 279 'len'=>2
280 280 ),
  281 + 'initForChartFromTT' => array(
  282 + 'len'=>2
  283 + ),
281 284 'initTTCacheFromTmpObject' => array(
282 285 'len'=>3
283 286 ),
... ... @@ -287,6 +290,9 @@ $API = array(
287 290 'readTTCacheIntervals'=>array(
288 291 'len'=>1
289 292 ),
  293 + 'readIntervalsForChart'=>array(
  294 + 'len'=>1
  295 + ),
290 296 'addTTCacheInterval'=>array (
291 297 'len'=>1
292 298 ),
... ...